Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/testing-and-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
python-version: ['3.10', '3.14']

env:
KEEPAKEY: ${{ secrets.KEEPAKEY }}
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ tests/htmlcov/
.coverage
.hypothesis
.venv
docs/source/api/

# key storage
tests/key
tests/weak_key

# pycharm IDE
.idea
.idea
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ repos:
rev: v2.4.2
hooks:
- id: codespell
args: [-S ./docs/\*]
args: [-S ./docs/\*, --ignore-words-list, thirdparty]
- repo: https://github.com/pycqa/pydocstyle
rev: 6.3.0
hooks:
Expand Down
78 changes: 52 additions & 26 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ This library is compatible with Python >= 3.10 and requires:

- ``numpy``
- ``aiohttp``
- ``matplotlib``
- ``pandas``
- ``pydantic >= 2``
- ``requests``
- ``tqdm``

Product history can be plotted from the raw data when ``matplotlib``
is installed.

Interfacing with the ``keepa`` requires an access key and a monthly
subscription from `Keepa API <https://keepa.com/#!api>`_.
Interfacing with ``keepa`` requires an access key and a monthly subscription
from `Keepa Pricing <https://get.keepa.com/d7vrq>`_.

Installation
------------
Expand Down Expand Up @@ -69,6 +71,21 @@ Brief Example
# Plot result (requires matplotlib)
keepa.plot_product(products[0])

Typed responses are available with ``typed=True`` for users who prefer
Pydantic models while keeping the default dictionary output unchanged.

.. code:: python

products = api.query('B0088PUEPK', typed=True)
product = products[0]
print(product.asin)
print(product.title)
product_dict = product.model_dump(exclude_none=True, by_alias=True)

See the `typed response documentation
<https://keepaapi.readthedocs.io/en/latest/>`_ Typed Responses page for
supported methods, complete return shapes, serialization, and async usage.

.. figure:: https://github.com/akaszynski/keepa/raw/main/docs/source/images/Product_Price_Plot.png
:width: 500pt

Expand All @@ -80,10 +97,10 @@ Brief Example
Product Offers Plot


Brief Example using async
Brief Example Using Async
-------------------------
Here's an example of obtaining a product and plotting its price and
offer history using the ``keepa.AsyncKeepa`` class:
Here's an example of finding product ASINs using the
``keepa.AsyncKeepa`` class:

.. code:: python

Expand All @@ -92,7 +109,7 @@ offer history using the ``keepa.AsyncKeepa`` class:
>>> product_parms = {'author': 'jim butcher'}
>>> async def main():
... key = '<REAL_KEEPA_KEY>'
... api = await keepa.AsyncKeepa().create(key)
... api = await keepa.AsyncKeepa.create(key)
... return await api.product_finder(product_parms)
>>> asins = asyncio.run(main())
>>> asins
Expand All @@ -113,7 +130,7 @@ keepa interface.
>>> import keepa
>>> async def main():
... key = '<REAL_KEEPA_KEY>'
... api = await keepa.AsyncKeepa().create(key)
... api = await keepa.AsyncKeepa.create(key)
... return await api.query('B0088PUEPK')
>>> response = asyncio.run(main())
>>> response[0]['title']
Expand Down Expand Up @@ -141,20 +158,19 @@ Single ASIN query
# See help(api.query) for available options when querying the API


You can use keepa witch async / await too
The asynchronous client uses the same query interface:

.. code:: python

import asyncio
import keepa
accesskey = 'XXXXXXXXXXXXXXXX' # enter real access key here
api = await keepa.AsyncKeepa.create(accesskey)


Single ASIN query (async)

.. code:: python
async def main():
accesskey = 'XXXXXXXXXXXXXXXX' # enter real access key here
api = await keepa.AsyncKeepa.create(accesskey)
return await api.query('059035342X')

products = await api.query('059035342X')
products = asyncio.run(main())


Multiple ASIN query from List
Expand All @@ -168,10 +184,14 @@ Multiple ASIN query from numpy array

.. code:: python

import numpy as np

asins = np.asarray(['0022841350', '0022841369', '0022841369', '0022841369'])
products = api.query(asins)

Products is a list of product data with one entry per successful result from the Keepa server. Each entry is a dictionary containing the same product data available from `Amazon <http://www.amazon.com>`_.
``products`` is a list with one entry per successful result from the Keepa
server. By default, each entry is a dictionary containing the available
Amazon product data.

.. code:: python

Expand All @@ -182,20 +202,25 @@ Products is a list of product data with one entry per successful result from the
print('ASIN is ' + products[0]['asin'])
print('Title is ' + products[0]['title'])

The raw data is contained within each product result. Raw data is stored as a dictionary with each key paired with its associated time history.
# Index batch results by ASIN when random access is more convenient
products_by_asin = {product['asin']: product for product in products}

When Keepa has history for a product, ``data`` contains arrays paired with
corresponding ``*_time`` arrays. Individual history types may be absent.

.. code:: python

# Access new price history and associated time data
newprice = products[0]['data']['NEW']
newpricetime = products[0]['data']['NEW_time']
history = products[0].get('data', {})
newprice = history.get('NEW', [])
newpricetime = history.get('NEW_time', [])

# Can be plotted with matplotlib using:
import matplotlib.pyplot as plt
plt.step(newpricetime, newprice, where='pre')

# Keys can be listed by
print(products[0]['data'].keys())
print(history.keys())

The product history can also be plotted from the module if ``matplotlib`` is installed

Expand Down Expand Up @@ -237,12 +262,13 @@ You can obtain the offers history for an ASIN (or multiple ASINs) using the ``of
plt.step(offer_times[i], offer_prices[i])
plt.show()

If you plan to do a lot of simulatneous query, you might want to speedup query using
``wait=False`` arguments.
By default, the client waits for Keepa tokens when necessary. Use ``wait=False``
only when your application manages token availability itself; it does not make
the API response faster and may produce a token error.

.. code:: python

products = await api.query('059035342X', wait=False)
products = api.query('059035342X', wait=False)


Buy Box Statistics
Expand Down Expand Up @@ -297,8 +323,8 @@ Finally, `create a pull request`_ from your fork and I'll be sure to review it.

Credits
-------
This Python module, written by Alex Kaszynski and several contribitors, is
based on Java code written by Marius Johann, CEO Keepa. Java source is can be
This Python module, written by Alex Kaszynski and several contributors, is
based on Java code written by Marius Johann, CEO of Keepa. Java source can be
found at `keepacom/api_backend <https://github.com/keepacom/api_backend/>`_.


Expand Down
31 changes: 31 additions & 0 deletions docs/source/_static/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.plot-gallery {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1.5rem;
margin: 1.5rem 0 2rem;
}

.plot-gallery figure {
margin: 0;
}

.plot-gallery img {
width: 100%;
height: auto;
}

html[data-theme="dark"] .navbar-brand img {
filter: brightness(0) invert(0.9);
}

@media (max-width: 767px) {
.plot-gallery {
grid-template-columns: 1fr;
}

.bd-footer .bd-footer__inner {
align-items: flex-start;
flex-direction: column;
gap: 0.5rem;
}
}
18 changes: 18 additions & 0 deletions docs/source/_templates/autosummary/enum.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{{ fullname | escape | underline }}

.. currentmodule:: {{ module }}

.. autoclass:: {{ objname }}

{% if attributes %}
.. rubric:: Members

.. autosummary::
{% for item in attributes %}
~{{ objname }}.{{ item }}
{% endfor %}

{% for item in attributes %}
.. autoattribute:: {{ objname }}.{{ item }}
{% endfor %}
{% endif %}
7 changes: 7 additions & 0 deletions docs/source/_templates/autosummary/pydantic_model.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{{ fullname | escape | underline }}

.. currentmodule:: {{ module }}

.. autopydantic_model:: {{ objname }}
:members:
:undoc-members:
31 changes: 12 additions & 19 deletions docs/source/api_methods.rst
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
.. _ref_api_methods:

keepa.Api Methods
-----------------
These are the core ``keepa`` classes.
API Reference
-------------
Use :doc:`sync_client` for regular Python applications and
:doc:`async_client` when requests must integrate with an asyncio event loop.
Both clients expose the same Keepa endpoints. Shared client types are listed
in :doc:`api_types`, and generated backend request and response models are
introduced in :doc:`backend_models`.

.. autoclass:: keepa.Keepa
:members:
.. toctree::
:maxdepth: 1

Types
-----
These types and enumerators are used by ``keepa`` for data validation.

.. autoclass:: keepa.Domain
:members:
:undoc-members:
:member-order: bysource

.. autoclass:: keepa.ProductParams
:members:
:undoc-members:
:member-order: bysource
:exclude-members: model_computed_fields, model_config, model_fields, construct,dict,from_orm,json,parse_file,parse_obj,parse_raw,schema,schema_json,update_forward_refs,validate,copy,model_construct,model_copy,model_dump,model_dump_json,model_json_schema,model_parametrized_name,model_post_init,model_rebuild,model_validate,model_validate_json,model_validate_strings, model_extra, model_fields_set
sync_client
async_client
api_types
38 changes: 38 additions & 0 deletions docs/source/api_types.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Client and Backend Types
------------------------
These hand-written types validate domains and product-finder parameters.

.. autosummary::
:toctree: api/types

keepa.Domain

.. autosummary::
:toctree: api/types
:template: pydantic_model

keepa.ProductParams

Generated Request Models
~~~~~~~~~~~~~~~~~~~~~~~~
The backend schema also defines request-shaped structs. They are exported from
``keepa.backend_models`` and documented here for schema tooling and advanced
users. High-level client methods still accept the existing Python arguments by
default for backwards compatibility.

* :class:`keepa.models.backend.DealRequest`
* :class:`keepa.models.backend.ProductFinderRequest`
* :class:`keepa.models.backend.Request`
* :class:`keepa.models.backend.TrackingRequest`

Common Response Models
~~~~~~~~~~~~~~~~~~~~~~
The full generated model reference is available in
:doc:`backend_model_reference`. These are the response models returned directly
by high-level client methods with ``typed=True``.

* :class:`keepa.models.backend.BestSellers`
* :class:`keepa.models.backend.Category`
* :class:`keepa.models.backend.DealResponse`
* :class:`keepa.models.backend.Product`
* :class:`keepa.models.backend.Seller`
45 changes: 45 additions & 0 deletions docs/source/async_client.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
Asynchronous Client
-------------------
Create ``AsyncKeepa`` with its asynchronous classmethod, then await endpoint
calls.

.. code:: python

import keepa

api = await keepa.AsyncKeepa.create("<REAL_KEEPA_KEY>")
products = await api.query("B0088PUEPK")

Client
~~~~~~

.. autosummary::
:toctree: api/async

keepa.AsyncKeepa

Methods
~~~~~~~

.. autosummary::
:toctree: api/async

keepa.AsyncKeepa.best_sellers_query
keepa.AsyncKeepa.category_lookup
keepa.AsyncKeepa.create
keepa.AsyncKeepa.deals
keepa.AsyncKeepa.download_graph_image
keepa.AsyncKeepa.product_finder
keepa.AsyncKeepa.query
keepa.AsyncKeepa.search_for_categories
keepa.AsyncKeepa.seller_query
keepa.AsyncKeepa.update_status
keepa.AsyncKeepa.wait_for_tokens

Attributes
~~~~~~~~~~

.. autosummary::
:toctree: api/async

keepa.AsyncKeepa.time_to_refill
Loading
Loading