Skip to main content

supermercapy

typed clients for the public storefront apis of fourteen spanish supermarkets, for sync code and, through AsyncClient, for asyncio. a shared base client defines the standard operations, each store implements them against its own backend, and every client declares which optional operations and data shapes its storefront supports.

this is an unofficial project. it is not affiliated with, endorsed by, or maintained by any of the retailers it reads. the upstream apis are undocumented and may change without notice.

installation

supermercapy supports cpython 3.11 through 3.14. the distribution and the import name are both supermercapy.

python -m pip install supermercapy

quick start

bind a client to a place, search, then ask for the complete product:

from supermercapy import Mercadona

with Mercadona.from_postal_code("28001") as mercadona:
    page = mercadona.search_products("leche sin lactosa", page_size=10)

    for summary in page.products:
        print(summary.name, summary.price.amount)

    if page.products:
        product = mercadona.get_product(page.products[0].id)
        print(product.ean)
        print(product.nutrition.ingredients)

every client is built the same way, so the same code reads another store:

from supermercapy import Capability, Lidl

with Lidl.from_postal_code("08013") as lidl:
    page = lidl.search_products("chocolate", page_size=10)
    if lidl.supports(Capability.OFFERS):
        offers = lidl.get_offers()

construction performs no request. from_postal_code() costs one request at mercadona and more at lidl, which pages through its store list. the request counts give every store's figure. a client reuses its connections, so close it with a with block.

search_all() asks several stores at once, each on its own thread with its own client. it reports every store separately, so one store's failure never hides what the others found:

from supermercapy import search_all

result = search_all("leche", postal_code="08013", page_size=5)
for store, product in result.products:
    print(store, product.name, product.price.amount)
for entry in result.failed:
    print(entry.store, entry.error_type, entry.reason)

command line

installing the package also installs a supermercapy command, which prints aligned tables, or one json document with --json:

supermercapy stores
supermercapy search leche --postal-code 08013 --limit 3
supermercapy product consum 7080604
supermercapy ean 8431876011937 --json

the command line guide covers every command, its request count, and its exit codes.

stores

store class binds to page
mercadona Mercadona a warehouse docs
consum Consum a zone, optionally docs
plusfresc Plusfresc a preparation center docs
bonàrea Bonarea nothing docs
carrefour Carrefour a sale point, optionally docs
lidl Lidl an offer region and a price zone docs
bonpreu Bonpreu nothing docs
dia Dia a delivery postcode, optionally docs
eroski Eroski nothing docs
caprabo Caprabo nothing docs
aldi Aldi a price region docs
ahorramás Ahorramas nothing docs
alcampo Alcampo a click-and-collect point, optionally docs
condis Condis a picking centre docs

supermercapy.ALL_CLIENTS holds all fourteen, so generic code never has to name one.

capabilities

search_products(), get_product(), get_categories() and get_category() work everywhere. everything else is optional and declared, because no two storefronts publish the same things:

capability stores
POSTAL_CODE mercadona, consum, plusfresc, carrefour, lidl, dia, aldi, condis
STORES mercadona, consum, plusfresc, carrefour, lidl, alcampo
CATALOG mercadona, consum, plusfresc, bonàrea, lidl, dia, eroski, caprabo, aldi, ahorramás, condis
EAN_LOOKUP consum, carrefour
NEW_ARRIVALS mercadona, consum, plusfresc, bonpreu, dia, alcampo, condis
OFFERS consum, plusfresc, lidl, bonpreu, dia, aldi, ahorramás, alcampo, condis
HOME mercadona, carrefour
EAN mercadona, consum, carrefour, lidl
NUTRITION mercadona, plusfresc, bonàrea, carrefour, bonpreu, dia, eroski, caprabo, alcampo, condis
PROMOTIONS consum, plusfresc, carrefour, lidl, bonpreu, dia, eroski, caprabo, aldi, ahorramás, alcampo, condis
FUTURE_PRICES lidl, aldi

an undeclared operation raises UnsupportedOperationError before making any request, and Client.supports(capability) answers before a client is even built. a test checks the full matrix against the code, so it cannot drift.

behavior

  • client methods make the requests. reading a returned model never performs i/o.
  • listing calls return ProductSummary, and get_product() returns a complete Product. each store narrows both to its own subclass.
  • models are frozen, slotted dataclasses. collections are tuples, ids are strings, and prices and quantities use Decimal.
  • parsers ignore unknown response fields. missing optional values become None or an empty tuple.
  • pagination is one opaque cursor, whatever the store does underneath.
  • failures raise a SupermercapyError subclass. library code never prints.
  • connection failures, http 429 and selected 5xx responses go through one bounded retry policy. stores that answer with challenges or expired tokens extend the classification, not the loop.
  • request pacing is per client, and a store that needs it ships a default.

documentation

supermercapy is distributed under the mit license.

Metadata

Release files for supermercapy 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for supermercapy 0.1.0
File Size Uploaded
supermercapy-0.1.0.tar.gz 725.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for supermercapy 0.1.0
File Interpreter ABI Platform
supermercapy-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 981.7 kB

Release files / supermercapy-0.1.0.tar.gz

Download URL supermercapy-0.1.0.tar.gz
Size 725.7 kB
Tags Source
SHA-256 checksum
How to use checksums
843239e428662b9b6bc77f9c25a663292b00ad325ac2f99ed6b362eb7fc74bf9
BLAKE2b-256 checksum
How to use checksums
1335851b686b381fa31a20ba49270d487ca9eade053a87f1d6f320370fda9fa2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / supermercapy-0.1.0-py3-none-any.whl

Download URL supermercapy-0.1.0-py3-none-any.whl
Size 256.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e0c7ad39459ef6b4a49e050b729fc9dfc77a43e7c7128cc60e8d5fbd6a85124c
BLAKE2b-256 checksum
How to use checksums
a7188390826f74b873eaebca94b6be37c7bb0629e2f74261b52a8e4f1e869b2c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page