From 4fa8a0a14091ed3bc885b199fcd33d2f2484d7e4 Mon Sep 17 00:00:00 2001 From: Alex Kaszynski Date: Thu, 2 Nov 2023 10:09:58 -0600 Subject: [PATCH 1/4] add back in a few missing imports; use ruff --- .flake8 | 4 -- .pre-commit-config.yaml | 13 +++-- docs/source/conf.py | 2 - pyproject.toml | 12 +++-- src/keepa/__init__.py | 5 ++ src/keepa/interface.py | 98 +++++++++++++++++------------------ tests/test_async_interface.py | 2 +- tests/test_interface.py | 2 +- 8 files changed, 70 insertions(+), 68 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index ad9b427..0000000 --- a/.flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -max-line-length = 120 -show-source = True -exclude=.git,.tox,dist,*egg,build,backoffice/*/migrations/*,.*,docker/*,docs/*,keepa/__init__.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6606752..0f6a4e6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,10 +4,6 @@ ci: autofix_prs: true autoupdate_schedule: monthly repos: -- repo: https://github.com/psf/black - rev: 23.10.1 - hooks: - - id: black - repo: https://github.com/keewis/blackdoc rev: v0.3.8 hooks: @@ -17,10 +13,13 @@ repos: rev: 5.12.0 hooks: - id: isort -- repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.3 hooks: - - id: flake8 + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + exclude: ^(docs/|tests) + - id: ruff-format - repo: https://github.com/codespell-project/codespell rev: v2.2.6 hooks: diff --git a/docs/source/conf.py b/docs/source/conf.py index de8eceb..9eee1de 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,8 +1,6 @@ """Sphinx configuration file for keepaapi.""" # import pydata_sphinx_theme # noqa from datetime import datetime -from io import open as io_open -import os from keepa import __version__ diff --git a/pyproject.toml b/pyproject.toml index 8c3e01c..6291e98 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,8 +59,12 @@ force_sort_within_sections = true # Combines "as" imports on the same line combine_as_imports = true -[tool.black] +[tool.ruff] line-length = 100 -skip-string-normalization = true -target-version = ['py39'] -exclude='\.eggs|\.git|\.mypy_cache|\.tox|\.venv|_build|buck-out|build|dist|node_modules' + +[tool.ruff.lint] +# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. +# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or +# McCabe complexity (`C901`) by default. +select = ["E4", "E7", "E9", "F"] +ignore = [] \ No newline at end of file diff --git a/src/keepa/__init__.py b/src/keepa/__init__.py index 0d40377..741e297 100644 --- a/src/keepa/__init__.py +++ b/src/keepa/__init__.py @@ -2,11 +2,16 @@ __version__ = "1.4.dev0" from keepa.interface import ( # noqa: F401 + DCODES, + KEEPA_ST_ORDINAL, + SCODES, AsyncKeepa, Keepa, convert_offer_history, + csv_indices, format_items, keepa_minutes_to_time, + parse_csv, process_used_buybox, run_and_get, ) diff --git a/src/keepa/interface.py b/src/keepa/interface.py index fddee35..b5dbfe4 100644 --- a/src/keepa/interface.py +++ b/src/keepa/interface.py @@ -364,28 +364,28 @@ class Keepa: Create the api object. >>> import keepa - >>> key = '' + >>> key = "" >>> api = keepa.Keepa(key) Request data from two ASINs. - >>> products = api.query(['0439064872', '1426208081']) + >>> products = api.query(["0439064872", "1426208081"]) Print item details. - >>> print('Item 1') - >>> print('\t ASIN: {:s}'.format(products[0]['asin'])) - >>> print('\t Title: {:s}'.format(products[0]['title'])) + >>> print("Item 1") + >>> print("\t ASIN: {:s}".format(products[0]["asin"])) + >>> print("\t Title: {:s}".format(products[0]["title"])) Item 1 ASIN: 0439064872 Title: Harry Potter and the Chamber of Secrets (2) Print item price. - >>> usedprice = products[0]['data']['USED'] - >>> usedtimes = products[0]['data']['USED_time'] - >>> print('\t Used price: ${:.2f}'.format(usedprice[-1])) - >>> print('\t as of: {:s}'.format(str(usedtimes[-1]))) + >>> usedprice = products[0]["data"]["USED"] + >>> usedtimes = products[0]["data"]["USED_time"] + >>> print("\t Used price: ${:.2f}".format(usedprice[-1])) + >>> print("\t as of: {:s}".format(str(usedtimes[-1]))) Used price: $0.52 as of: 2023-01-03 04:46:00 @@ -418,7 +418,7 @@ def time_to_refill(self) -> float: should be 0.0 seconds. >>> import keepa - >>> key = '' + >>> key = "" >>> api = keepa.Keepa(key) >>> api.time_to_refill 0.0 @@ -738,10 +738,10 @@ def query( keepa interface. >>> import keepa - >>> key = '' + >>> key = "" >>> api = keepa.Keepa(key) - >>> response = api.query('B0088PUEPK') - >>> response[0]['title'] + >>> response = api.query("B0088PUEPK") + >>> response[0]["title"] 'Western Digital 1TB WD Blue PC Internal Hard Drive HDD - 7200 RPM, SATA 6 Gb/s, 64 MB Cache, 3.5" - WD10EZEX' @@ -751,12 +751,12 @@ def query( >>> import asyncio >>> import keepa >>> async def main(): - ... key = '' + ... key = "" ... api = await keepa.AsyncKeepa().create(key) - ... return await api.query('B0088PUEPK') + ... return await api.query("B0088PUEPK") ... >>> response = asyncio.run(main()) - >>> response[0]['title'] + >>> response[0]["title"] 'Western Digital 1TB WD Blue PC Internal Hard Drive HDD - 7200 RPM, SATA 6 Gb/s, 64 MB Cache, 3.5" - WD10EZEX' @@ -764,11 +764,11 @@ def query( ``pandas.DataFrame``. >>> import keepa - >>> key = '' + >>> key = "" >>> api = keepa.Keepa(key) - >>> response = api.query('B0088PUEPK', offers=20) + >>> response = api.query("B0088PUEPK", offers=20) >>> product = response[0] - >>> buybox_info = product['buyBoxUsedHistory'] + >>> buybox_info = product["buyBoxUsedHistory"] >>> df = keepa.process_used_buybox(buybox_info) datetime user_id condition isFBA 0 2022-11-02 16:46:00 A1QUAC68EAM09F Used - Like New True @@ -1040,7 +1040,7 @@ def best_sellers_query(self, category, rank_avg_range=0, domain="US", wait=True) Query for the best sellers among the ``"movies"`` category. >>> import keepa - >>> key = '' + >>> key = "" >>> api = keepa.Keepa(key) >>> categories = api.search_for_categories("movies") >>> category = list(categories.items())[0][0] @@ -1060,7 +1060,7 @@ def best_sellers_query(self, category, rank_avg_range=0, domain="US", wait=True) >>> import asyncio >>> import keepa >>> async def main(): - ... key = '' + ... key = "" ... api = await keepa.AsyncKeepa().create(key) ... categories = await api.search_for_categories("movies") ... category = list(categories.items())[0][0] @@ -1120,11 +1120,11 @@ def search_for_categories(self, searchterm, domain="US", wait=True) -> list: Print all categories from science. >>> import keepa - >>> key = '' + >>> key = "" >>> api = keepa.Keepa(key) - >>> categories = api.search_for_categories('science') + >>> categories = api.search_for_categories("science") >>> for cat_id in categories: - ... print(cat_id, categories[cat_id]['name']) + ... print(cat_id, categories[cat_id]["name"]) ... 9091159011 Behavioral Sciences 8407535011 Fantasy, Horror & Science Fiction @@ -1182,7 +1182,7 @@ def category_lookup(self, category_id, domain="US", include_parents=False, wait= Use 0 to return all root categories. >>> import keepa - >>> key = '' + >>> key = "" >>> api = keepa.Keepa(key) >>> categories = api.category_lookup(0) @@ -1300,10 +1300,10 @@ def seller_query( Return the information from seller ``'A2L77EE7U53NWQ'``. >>> import keepa - >>> key = '' + >>> key = "" >>> api = keepa.Keepa(key) - >>> seller_info = api.seller_query('A2L77EE7U53NWQ', 'US') - >>> seller_info['A2L77EE7U53NWQ']['sellerName'] + >>> seller_info = api.seller_query("A2L77EE7U53NWQ", "US") + >>> seller_info["A2L77EE7U53NWQ"]["sellerName"] 'Amazon Warehouse' Notes @@ -2376,10 +2376,10 @@ def product_finder(self, product_parms, domain="US", wait=True, n_products=50) - ``keepa.Keepa`` class. Sort by current sales. >>> import keepa - >>> api = keepa.Keepa('') + >>> api = keepa.Keepa("") >>> product_parms = { - ... 'author': 'jim butcher', - ... 'sort': ["current_SALES", "asc"], + ... "author": "jim butcher", + ... "sort": ["current_SALES", "asc"], ... } >>> asins = api.product_finder(product_parms, n_products=100) >>> asins @@ -2396,9 +2396,9 @@ def product_finder(self, product_parms, domain="US", wait=True, n_products=50) - >>> import asyncio >>> import keepa - >>> product_parms = {'author': 'jim butcher'} + >>> product_parms = {"author": "jim butcher"} >>> async def main(): - ... key = '' + ... key = "" ... api = await keepa.AsyncKeepa().create(key) ... return await api.product_finder(product_parms) ... @@ -2425,7 +2425,7 @@ def product_finder(self, product_parms, domain="US", wait=True, n_products=50) - payload = { "key": self.accesskey, "domain": DCODES.index(domain), - "selection": json.dumps({**product_parms, **{'perPage': n_products}}), + "selection": json.dumps({**product_parms, **{"perPage": n_products}}), } response = self._request("query", payload, wait=wait) @@ -2496,7 +2496,7 @@ def deals(self, deal_parms, domain="US", wait=True) -> dict: ``keepa.Keepa`` class >>> import keepa - >>> key = '' + >>> key = "" >>> api = keepa.Keepa(key) >>> deal_parms = { ... "page": 0, @@ -2508,7 +2508,7 @@ def deals(self, deal_parms, domain="US", wait=True) -> dict: Get the title of the first deal. - >>> deals['dr'][0]['title'] + >>> deals["dr"][0]["title"] 'Orange Cream Rooibos, Tea Bags - Vanilla, Orange | Caffeine-Free, Antioxidant-rich, Hot & Iced | The Spice Hut, First Sip Of Tea' @@ -2524,7 +2524,7 @@ def deals(self, deal_parms, domain="US", wait=True) -> dict: ... "includeCategories": [16310101], ... } >>> async def main(): - ... key = '' + ... key = "" ... api = await keepa.AsyncKeepa().create(key) ... categories = await api.search_for_categories("movies") ... return await api.deals(deal_parms) @@ -2630,9 +2630,9 @@ class AsyncKeepa: >>> import asyncio >>> import keepa - >>> product_parms = {'author': 'jim butcher'} + >>> product_parms = {"author": "jim butcher"} >>> async def main(): - ... key = '' + ... key = "" ... api = await keepa.AsyncKeepa().create(key) ... return await api.product_finder(product_parms) ... @@ -2652,12 +2652,12 @@ class AsyncKeepa: >>> import asyncio >>> import keepa >>> async def main(): - ... key = '' + ... key = "" ... api = await keepa.AsyncKeepa().create(key) - ... return await api.query('B0088PUEPK') + ... return await api.query("B0088PUEPK") ... >>> response = asyncio.run(main()) - >>> response[0]['title'] + >>> response[0]["title"] 'Western Digital 1TB WD Blue PC Internal Hard Drive HDD - 7200 RPM, SATA 6 Gb/s, 64 MB Cache, 3.5" - WD10EZEX' @@ -3115,11 +3115,11 @@ def process_used_buybox(buybox_info: List[str]) -> pd.DataFrame: ``pandas.DataFrame``. >>> import keepa - >>> key = '' + >>> key = "" >>> api = keepa.Keepa(key) - >>> response = api.query('B0088PUEPK', offers=20) + >>> response = api.query("B0088PUEPK", offers=20) >>> product = response[0] - >>> buybox_info = product['buyBoxUsedHistory'] + >>> buybox_info = product["buyBoxUsedHistory"] >>> df = keepa.process_used_buybox(buybox_info) datetime user_id condition isFBA 0 2022-11-02 16:46:00 A1QUAC68EAM09F Used - Like New True @@ -3156,10 +3156,10 @@ def process_used_buybox(buybox_info: List[str]) -> pd.DataFrame: df = pd.DataFrame( { - 'datetime': datetime_arr, - 'user_id': user_id_arr, - 'condition': condition_arr, - 'isFBA': isFBA_arr, + "datetime": datetime_arr, + "user_id": user_id_arr, + "condition": condition_arr, + "isFBA": isFBA_arr, } ) diff --git a/tests/test_async_interface.py b/tests/test_async_interface.py index efc7244..c79e5bc 100644 --- a/tests/test_async_interface.py +++ b/tests/test_async_interface.py @@ -262,7 +262,7 @@ async def test_bestsellers(api): @pytest.mark.asyncio async def test_buybox_used(api): request = await api.query(HARD_DRIVE_PRODUCT_ASIN, history=False, offers=20) - df = keepa.process_used_buybox(request[0]['buyBoxUsedHistory']) + df = keepa.process_used_buybox(request[0]["buyBoxUsedHistory"]) assert isinstance(df, pd.DataFrame) diff --git a/tests/test_interface.py b/tests/test_interface.py index c9853a8..ec62916 100644 --- a/tests/test_interface.py +++ b/tests/test_interface.py @@ -331,7 +331,7 @@ def test_bestsellers(api): def test_buybox_used(api): request = api.query(HARD_DRIVE_PRODUCT_ASIN, history=False, offers=20) - df = keepa.process_used_buybox(request[0]['buyBoxUsedHistory']) + df = keepa.process_used_buybox(request[0]["buyBoxUsedHistory"]) assert isinstance(df, pd.DataFrame) From 32d807c57b156ff8cb16ed9c446ce9db13cb5cd0 Mon Sep 17 00:00:00 2001 From: Alex Kaszynski Date: Thu, 2 Nov 2023 10:12:37 -0600 Subject: [PATCH 2/4] quarterly update pre-commit --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0f6a4e6..4e8d735 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.ci/ ci: autofix_prs: true - autoupdate_schedule: monthly + autoupdate_schedule: quarterly repos: - repo: https://github.com/keewis/blackdoc rev: v0.3.8 @@ -32,7 +32,7 @@ repos: additional_dependencies: [toml] exclude: "tests/" - repo: https://github.com/asottile/pyupgrade - rev: v3.10.1 + rev: v3.15.0 hooks: - id: pyupgrade args: [--py38-plus, --keep-runtime-typing] From df108b562fb32e4e0da2f6c17927ced85c4d0220 Mon Sep 17 00:00:00 2001 From: Alex Kaszynski Date: Thu, 2 Nov 2023 10:13:18 -0600 Subject: [PATCH 3/4] use latest download artifact --- .github/workflows/testing-and-deployment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testing-and-deployment.yml b/.github/workflows/testing-and-deployment.yml index bcf51e1..af39cec 100644 --- a/.github/workflows/testing-and-deployment.yml +++ b/.github/workflows/testing-and-deployment.yml @@ -75,7 +75,7 @@ jobs: permissions: id-token: write # this permission is mandatory for trusted publishing steps: - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: path: dist/ - name: Flatten directory structure From 08b1627dcc23b56f4acd36bba4f0ae80ff1ec657 Mon Sep 17 00:00:00 2001 From: Alex Kaszynski Date: Thu, 2 Nov 2023 10:17:56 -0600 Subject: [PATCH 4/4] move target for live data back to 60 days --- requirements_test.txt | 5 ----- tests/test_async_interface.py | 2 +- tests/test_interface.py | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 requirements_test.txt diff --git a/requirements_test.txt b/requirements_test.txt deleted file mode 100644 index 589a5ba..0000000 --- a/requirements_test.txt +++ /dev/null @@ -1,5 +0,0 @@ -matplotlib==3.7.1 -pandas -pytest==7.3.1 -pytest-asyncio==0.21.0 -pytest-cov==4.0.0 diff --git a/tests/test_async_interface.py b/tests/test_async_interface.py index c79e5bc..a74c5df 100644 --- a/tests/test_async_interface.py +++ b/tests/test_async_interface.py @@ -182,7 +182,7 @@ async def test_productquery_update(api): # should be live data now = datetime.datetime.now() delta = now - product["data"]["USED_time"][-1] - assert delta.days <= 35 + assert delta.days <= 60 # check for empty arrays history = product["data"] diff --git a/tests/test_interface.py b/tests/test_interface.py index ec62916..8c3dd07 100644 --- a/tests/test_interface.py +++ b/tests/test_interface.py @@ -191,7 +191,7 @@ def test_productquery_update(api): # should be live data now = datetime.datetime.now() delta = now - product["data"]["USED_time"][-1] - assert delta.days <= 35 + assert delta.days <= 60 # check for empty arrays history = product["data"]