Skip to main content

Python bindings for AnyList API via anylist_rs

Project description

pyanylist

CI PyPI Python Versions

Unofficial Python bindings for the AnyList API, built with Rust and PyO3 for performance.

Features

  • Shopping Lists: Create, read, update, and delete shopping lists and items
  • Favourites: Manage favourite/starter items
  • Recipes: Full recipe CRUD with ingredient scaling
  • Meal Planning: iCalendar integration for meal plan calendars
  • Real-time Sync: WebSocket-based live updates
  • Token Persistence: Save and restore authentication sessions

Installation

uv add pyanylist

Or with pip:

pip install pyanylist

Quick Start

from pyanylist import AnyListClient

# Login with email and password
client = AnyListClient.login("your-email@example.com", "your-password")

# Get all shopping lists
lists = client.get_lists()
for lst in lists:
    print(f"{lst.name}: {len(lst.items)} items")

# Add an item to a list
item = client.add_item(lists[0].id, "Milk")
print(f"Added: {item.name}")

# Add item with details
item = client.add_item_with_details(
    lists[0].id,
    "Apples",
    quantity="6",
    details="Honeycrisp preferred",
    category="Produce"
)

Authentication

Login with credentials

client = AnyListClient.login("email@example.com", "password")

Save and restore session

# Export tokens for persistence
tokens = client.export_tokens()

# Save to file, database, etc.
save_tokens(tokens.access_token, tokens.refresh_token, tokens.user_id)

# Later, restore from saved tokens
from pyanylist import SavedTokens

tokens = SavedTokens(
    access_token="...",
    refresh_token="...",
    user_id="...",
    is_premium_user=False
)
client = AnyListClient.from_tokens(tokens)

Shopping Lists

# Get all lists
lists = client.get_lists()

# Get a specific list
grocery_list = client.get_list_by_name("Groceries")
# or by ID
grocery_list = client.get_list_by_id("list-id-here")

# Create a new list
new_list = client.create_list("Weekly Shopping")

# Rename a list
client.rename_list(new_list.id, "Monthly Shopping")

# Delete a list
client.delete_list(new_list.id)

List Items

# Add a simple item
item = client.add_item(list_id, "Bread")

# Add item with details
item = client.add_item_with_details(
    list_id,
    "Chicken Breast",
    quantity="2 lbs",
    details="Boneless, skinless",
    category="Meat"
)

# Check/uncheck items
client.cross_off_item(list_id, item.id)
client.uncheck_item(list_id, item.id)

# Delete an item
client.delete_item(list_id, item.id)

# Clear all checked items
client.delete_all_crossed_off_items(list_id)

Favourites

# Get all favourite items
favourites = client.get_favourites()

# Get favourites organized by list
fav_lists = client.get_favourites_lists()
for fav_list in fav_lists:
    print(f"{fav_list.name}: {len(fav_list.items)} items")

# Add a favourite
fav = client.add_favourite("Coffee", category="Beverages")

# Remove a favourite
client.remove_favourite(fav_list.id, fav.id)

Recipes

from pyanylist import Ingredient

# Get all recipes
recipes = client.get_recipes()
for recipe in recipes:
    print(f"{recipe.name}: {len(recipe.ingredients)} ingredients")

# Get a specific recipe
recipe = client.get_recipe_by_name("Pasta Carbonara")

# Create a recipe
ingredients = [
    Ingredient("Spaghetti", quantity="400g"),
    Ingredient("Eggs", quantity="4"),
    Ingredient("Parmesan", quantity="100g", note="freshly grated"),
    Ingredient("Pancetta", quantity="200g"),
]
steps = [
    "Boil pasta according to package directions",
    "Fry pancetta until crispy",
    "Mix eggs and parmesan",
    "Combine everything off heat",
]
recipe = client.create_recipe("Carbonara", ingredients, steps)

# Add recipe ingredients to a shopping list
client.add_recipe_to_list(recipe.id, list_id)

# Scale recipe (e.g., double it)
client.add_recipe_to_list(recipe.id, list_id, scale_factor=2.0)

# Delete a recipe
client.delete_recipe(recipe.id)

Meal Plan Calendar (iCalendar)

# Enable iCalendar export
info = client.enable_icalendar()
print(f"Calendar URL: {info.url}")
# Use this URL in any calendar app (Google Calendar, Apple Calendar, etc.)

# Get existing calendar URL
url = client.get_icalendar_url()

# Disable iCalendar
client.disable_icalendar()

Real-time Sync

import time
from pyanylist import SyncEvent

# Start real-time sync
sync = client.start_realtime_sync()

# Poll for events
while sync.is_connected():
    events = sync.poll_events()
    for event in events:
        if event == SyncEvent.ShoppingListsChanged:
            print("Lists changed! Refreshing...")
            lists = client.get_lists()
        elif event == SyncEvent.RecipeDataChanged:
            print("Recipes changed!")
    time.sleep(1)

# Disconnect when done
sync.disconnect()

Available Sync Events

  • ShoppingListsChanged - Shopping lists modified
  • StarterListsChanged - Favourites modified
  • RecipeDataChanged - Recipes modified
  • MealPlanCalendarChanged - Meal plan modified
  • AccountDeleted - Account was deleted

Error Handling

All methods raise RuntimeError on failure:

try:
    client = AnyListClient.login("bad@email.com", "wrongpassword")
except RuntimeError as e:
    print(f"Login failed: {e}")

try:
    client.get_list_by_id("nonexistent-id")
except RuntimeError as e:
    print(f"List not found: {e}")

Development

Prerequisites

  • Python 3.12+
  • Rust 1.70+
  • uv
  • protoc (Protocol Buffers compiler)
    • Ubuntu/Debian: sudo apt-get install protobuf-compiler
    • macOS: brew install protobuf

Setup

# Clone the repository
git clone https://github.com/ozonejunkieau/pyanylist.git
cd pyanylist

# Install dependencies (includes dev dependencies)
uv sync

# Build and install in development mode
uv run maturin develop

Running Tests

# Run unit tests (no credentials needed)
uv run pytest -v -m "not integration"

# Run all tests including integration (requires credentials)
export ANYLIST_EMAIL="your-email@example.com"
export ANYLIST_PASSWORD="your-password"
uv run pytest -v

# Run with coverage
uv run pytest --cov=tests --cov-report=term-missing

Linting & Type Checking

# Check code style
uv run ruff check tests/

# Format code
uv run ruff format tests/

# Type check
uv run pyright tests/

Acknowledgements

This library is built on top of anylist_rs by Phil Denhoff, which provides the core Rust implementation for interacting with the AnyList API.

License

MIT License - see LICENSE for details.

Disclaimer

This is an unofficial library and is not affiliated with or endorsed by AnyList. Use at your own risk and in accordance with AnyList's terms of service.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyanylist-0.0.6.tar.gz (53.5 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pyanylist-0.0.6-cp312-abi3-musllinux_1_2_x86_64.whl (4.6 MB view details)

Uploaded CPython 3.12+musllinux: musl 1.2+ x86-64

pyanylist-0.0.6-cp312-abi3-musllinux_1_2_aarch64.whl (4.5 MB view details)

Uploaded CPython 3.12+musllinux: musl 1.2+ ARM64

pyanylist-0.0.6-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.3 MB view details)

Uploaded CPython 3.12+manylinux: glibc 2.17+ x86-64

pyanylist-0.0.6-cp312-abi3-macosx_11_0_arm64.whl (3.9 MB view details)

Uploaded CPython 3.12+macOS 11.0+ ARM64

pyanylist-0.0.6-cp312-abi3-macosx_10_12_x86_64.whl (4.0 MB view details)

Uploaded CPython 3.12+macOS 10.12+ x86-64

File details

Details for the file pyanylist-0.0.6.tar.gz.

File metadata

  • Download URL: pyanylist-0.0.6.tar.gz
  • Upload date:
  • Size: 53.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyanylist-0.0.6.tar.gz
Algorithm Hash digest
SHA256 8d53544d49740de7744bb8fe328e0a2a356c28430b968997797aaf92d11b49f4
MD5 81739e58b9249dae6fc1c4af68110292
BLAKE2b-256 f5e837a2a69273291b0e85f448c954a7c54b8cd0193cc9afbf8279c8c8feecac

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyanylist-0.0.6.tar.gz:

Publisher: release.yml on ozonejunkieau/pyanylist

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyanylist-0.0.6-cp312-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pyanylist-0.0.6-cp312-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 e562beb0f518e05c94ca883a2b98267f70072f1f4b801405329926510985205f
MD5 d92beae8937c2a8ac0121adc41a373e9
BLAKE2b-256 00d92f7a5ec6e09b3919d6cafc0b46e11074fee0e09dca931d91ba0fca898967

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyanylist-0.0.6-cp312-abi3-musllinux_1_2_x86_64.whl:

Publisher: release.yml on ozonejunkieau/pyanylist

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyanylist-0.0.6-cp312-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for pyanylist-0.0.6-cp312-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 ae120d606f2b3e5ab6852add6456e05b06988920756afa299bad8ab1f0a04670
MD5 480f2f571b93ab2e28b73bf9045ea668
BLAKE2b-256 2c3e95949dff1cf6bfe6d912b2cf3adb54fcb72397cf3d2bf1795e20b4d6af7d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyanylist-0.0.6-cp312-abi3-musllinux_1_2_aarch64.whl:

Publisher: release.yml on ozonejunkieau/pyanylist

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyanylist-0.0.6-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyanylist-0.0.6-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2b5c0de6358e1695b837e1df0120d6e91071e13499fa18b032eed21ad569bc1b
MD5 c7b87a3cbdff66a3eb9bb51c0fb81340
BLAKE2b-256 c8843b5784616f273acb41d16ee232bf7eb8272e80819da41c11f08917639866

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyanylist-0.0.6-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on ozonejunkieau/pyanylist

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyanylist-0.0.6-cp312-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyanylist-0.0.6-cp312-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 93fa3785305b29cb5075fc7172dce87d98159aa445c369c238cd95bf4e99c2cc
MD5 6c847b8b345c093ea02bacc75f07db1e
BLAKE2b-256 8c39c23f77bdb00b907a2b91efbe80684701f80ff663ac907da5fab4a803de36

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyanylist-0.0.6-cp312-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on ozonejunkieau/pyanylist

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyanylist-0.0.6-cp312-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pyanylist-0.0.6-cp312-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 5cef9ede97fa6640a4cf2d67ac85e05ada8b8eaa4d790bb4a4afe37413979f95
MD5 7f57667ad179ccdabd99011f74dfb00b
BLAKE2b-256 983a6aff355961552f1e13cd428546d8aebb3c4e707d77e61a810e76014b8d87

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyanylist-0.0.6-cp312-abi3-macosx_10_12_x86_64.whl:

Publisher: release.yml on ozonejunkieau/pyanylist

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page