amazon-orders 4.9.0__tar.gz → 4.9.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/CHANGELOG.md +32 -4
- {amazon_orders-4.9.0/amazon_orders.egg-info → amazon_orders-4.9.2}/PKG-INFO +14 -3
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/README.md +13 -2
- {amazon_orders-4.9.0 → amazon_orders-4.9.2/amazon_orders.egg-info}/PKG-INFO +14 -3
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/__init__.py +1 -1
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/cli.py +110 -44
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/conf.py +3 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/constants.py +171 -170
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/browser/playwright.py +52 -17
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/waf/anticaptcha.py +14 -11
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/waf/base.py +47 -12
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/waf/capsolver.py +26 -21
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/waf/twocaptcha.py +13 -10
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/order.py +2 -1
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/transaction.py +2 -1
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/exception.py +9 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/forms.py +21 -13
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/orders.py +67 -16
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/selectors.py +1 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/session.py +77 -25
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/LICENSE +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/MANIFEST.in +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazon_orders.egg-info/SOURCES.txt +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazon_orders.egg-info/dependency_links.txt +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazon_orders.egg-info/entry_points.txt +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazon_orders.egg-info/requires.txt +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazon_orders.egg-info/top_level.txt +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/banner.txt +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/__init__.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/browser/__init__.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/waf/__init__.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/__init__.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/gift_card_activity.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/item.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/parsable.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/recipient.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/seller.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/shipment.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/tracking.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/gift_cards.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/output.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/paging.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/region_data.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/transactions.py +9 -9
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/util.py +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/pyproject.toml +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/setup.cfg +0 -0
- {amazon_orders-4.9.0 → amazon_orders-4.9.2}/tests/testcase.py +0 -0
|
@@ -4,16 +4,44 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
-
## [Unreleased](https://github.com/alexdlaird/amazon-orders/compare/4.9.
|
|
7
|
+
## [Unreleased](https://github.com/alexdlaird/amazon-orders/compare/4.9.2...HEAD)
|
|
8
|
+
|
|
9
|
+
## [4.9.2](https://github.com/alexdlaird/amazon-orders/compare/4.9.1...4.9.2) - 2026-10-15
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `Constants.BROWSER_HEADERS`, `REGION_CURRENCY_OVERRIDES`, `ZERO_DECIMAL_CURRENCY_SYMBOLS`, `region_auth_cookie()`, and `region_currency_symbol()`, so a `constants_class` can override a browser's headers, or a site's auth cookie or currency symbol.
|
|
14
|
+
|
|
15
|
+
### Deprecated
|
|
16
|
+
|
|
17
|
+
- `AwsWafForm`'s `_solve_token()` and `_solve_visual_captcha()`, renamed to `solve_token()` and `solve_visual_captcha()`.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Sign-in on Amazon sites other than `.com`, `.ca`, `.co.jp`, `.co.uk`, `.com.au`, `.de`, `.in`, and `.it` now checks for that site's own auth cookie.
|
|
22
|
+
- Bug fixes and stability improvements.
|
|
23
|
+
|
|
24
|
+
## [4.9.1](https://github.com/alexdlaird/amazon-orders/compare/4.9.0...4.9.1) - 2026-10-14
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `--progress` and `--no-progress` CLI flags, to force the progress status on or off.
|
|
29
|
+
- Browser sign-in first tries Chrome, then Edge, and then falls back to downloading a browser.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- The CLI's progress spammed a newline for every update in `4.9.0` instead of animating, and now shows the overall total when known.
|
|
34
|
+
- Bug fixes and stability improvements.
|
|
8
35
|
|
|
9
36
|
## [4.9.0](https://github.com/alexdlaird/amazon-orders/compare/4.8.1...4.9.0) - 2026-10-14
|
|
10
37
|
|
|
11
38
|
### Added
|
|
12
39
|
|
|
13
|
-
- English pages on any Amazon site that offers them, with `domain` and no language package (e.g. `amazon.de`, `amazon.fr`, `amazon.co.jp`).
|
|
40
|
+
- English pages on any Amazon site that offers them, whatever language the account is set to, including `amazon.com`, and with `domain` and no language package (e.g. `amazon.de`, `amazon.fr`, `amazon.co.jp`).
|
|
14
41
|
- Sign-in and currency symbols for more non-`.com` Amazon sites (e.g. `amazon.fr`, `amazon.co.za`).
|
|
15
42
|
- Browser sign-in with any browser Playwright supports, using the installed Chrome by default, with `browser` and `browser_executable_path`.
|
|
16
|
-
- `AMAZON_<KEY>` environment variables for every config value (e.g. `AMAZON_MAX_AUTH_ATTEMPTS`).
|
|
43
|
+
- `AMAZON_<KEY>` environment variables for every config value (e.g. `AMAZON_MAX_AUTH_ATTEMPTS`), which take precedence over `config.yml`.
|
|
44
|
+
- Progress status while the CLI fetches history, and a `progress` callback to do the same with the API.
|
|
17
45
|
|
|
18
46
|
### Changed
|
|
19
47
|
|
|
@@ -25,7 +53,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
25
53
|
|
|
26
54
|
### Removed
|
|
27
55
|
|
|
28
|
-
- `AMAZON_CURRENCY_SYMBOL
|
|
56
|
+
- `AMAZON_CURRENCY_SYMBOL`, superseded by full regional support.
|
|
29
57
|
|
|
30
58
|
### Fixed
|
|
31
59
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: amazon-orders
|
|
3
|
-
Version: 4.9.
|
|
3
|
+
Version: 4.9.2
|
|
4
4
|
Summary: A Python library (and CLI) for Amazon order history, line items, and transactions
|
|
5
5
|
Author-email: Alex Laird <contact@alexlaird.com>
|
|
6
6
|
Maintainer-email: Alex Laird <contact@alexlaird.com>
|
|
@@ -112,6 +112,7 @@ to interact with account data. [`get_order_history`](https://amazon-orders.readt
|
|
|
112
112
|
and [`get_order`](https://amazon-orders.readthedocs.io/api.html#amazonorders.orders.AmazonOrders.get_order) are good places to start.
|
|
113
113
|
|
|
114
114
|
```python
|
|
115
|
+
from amazonorders.constants import Constants
|
|
115
116
|
from amazonorders.session import AmazonSession
|
|
116
117
|
from amazonorders.orders import AmazonOrders
|
|
117
118
|
|
|
@@ -125,8 +126,8 @@ amazon_orders = AmazonOrders(amazon_session)
|
|
|
125
126
|
orders = amazon_orders.get_order_history(year=2023)
|
|
126
127
|
|
|
127
128
|
# Or use time filters for recent orders
|
|
128
|
-
orders = amazon_orders.get_order_history(time_filter=
|
|
129
|
-
orders = amazon_orders.get_order_history(time_filter=
|
|
129
|
+
orders = amazon_orders.get_order_history(time_filter=Constants.LAST_30_DAYS_TIME_FILTER)
|
|
130
|
+
orders = amazon_orders.get_order_history(time_filter=Constants.LAST_3_MONTHS_TIME_FILTER)
|
|
130
131
|
|
|
131
132
|
for order in orders:
|
|
132
133
|
print(f"{order.order_number} - {order.grand_total}")
|
|
@@ -210,6 +211,9 @@ environment variables `amazon-orders` looks for are:
|
|
|
210
211
|
|
|
211
212
|
Any other config value can be set the same way, as `AMAZON_<KEY>` (see [`AmazonOrdersConfig`](https://amazon-orders.readthedocs.io/api.html#amazonorders.conf.AmazonOrdersConfig)).
|
|
212
213
|
|
|
214
|
+
A configured username also applies to `amazon-orders login --browser`: it's filled in and submitted for you, so the
|
|
215
|
+
browser opens on Amazon's password or passkey step. The browser never fills in your password.
|
|
216
|
+
|
|
213
217
|
### Languages and Regions
|
|
214
218
|
|
|
215
219
|
`amazon-orders` reads Amazon's pages in English. The `.com` site is validated nightly.
|
|
@@ -221,6 +225,13 @@ Any other config value can be set the same way, as `AMAZON_<KEY>` (see [`AmazonO
|
|
|
221
225
|
lets `amazon-orders` read the site's pages; its own CLI and messages stay in English. See
|
|
222
226
|
[Language Packages](https://amazon-orders.readthedocs.io/language-packages.html).
|
|
223
227
|
|
|
228
|
+
### AI Assistants
|
|
229
|
+
|
|
230
|
+
An AI assistant has two ways to use `amazon-orders`. One that runs commands uses the CLI or the library directly, just
|
|
231
|
+
as shown above. Any MCP client gets the same as tools through
|
|
232
|
+
[`amazon-orders-mcp`](https://github.com/alexdlaird/amazon-orders-mcp#readme), a server built on `amazon-orders` — see
|
|
233
|
+
its README for setup.
|
|
234
|
+
|
|
224
235
|
## Documentation
|
|
225
236
|
|
|
226
237
|
For more advanced usage, `amazon-orders`'s official documentation is available
|
|
@@ -36,6 +36,7 @@ to interact with account data. [`get_order_history`](https://amazon-orders.readt
|
|
|
36
36
|
and [`get_order`](https://amazon-orders.readthedocs.io/api.html#amazonorders.orders.AmazonOrders.get_order) are good places to start.
|
|
37
37
|
|
|
38
38
|
```python
|
|
39
|
+
from amazonorders.constants import Constants
|
|
39
40
|
from amazonorders.session import AmazonSession
|
|
40
41
|
from amazonorders.orders import AmazonOrders
|
|
41
42
|
|
|
@@ -49,8 +50,8 @@ amazon_orders = AmazonOrders(amazon_session)
|
|
|
49
50
|
orders = amazon_orders.get_order_history(year=2023)
|
|
50
51
|
|
|
51
52
|
# Or use time filters for recent orders
|
|
52
|
-
orders = amazon_orders.get_order_history(time_filter=
|
|
53
|
-
orders = amazon_orders.get_order_history(time_filter=
|
|
53
|
+
orders = amazon_orders.get_order_history(time_filter=Constants.LAST_30_DAYS_TIME_FILTER)
|
|
54
|
+
orders = amazon_orders.get_order_history(time_filter=Constants.LAST_3_MONTHS_TIME_FILTER)
|
|
54
55
|
|
|
55
56
|
for order in orders:
|
|
56
57
|
print(f"{order.order_number} - {order.grand_total}")
|
|
@@ -134,6 +135,9 @@ environment variables `amazon-orders` looks for are:
|
|
|
134
135
|
|
|
135
136
|
Any other config value can be set the same way, as `AMAZON_<KEY>` (see [`AmazonOrdersConfig`](https://amazon-orders.readthedocs.io/api.html#amazonorders.conf.AmazonOrdersConfig)).
|
|
136
137
|
|
|
138
|
+
A configured username also applies to `amazon-orders login --browser`: it's filled in and submitted for you, so the
|
|
139
|
+
browser opens on Amazon's password or passkey step. The browser never fills in your password.
|
|
140
|
+
|
|
137
141
|
### Languages and Regions
|
|
138
142
|
|
|
139
143
|
`amazon-orders` reads Amazon's pages in English. The `.com` site is validated nightly.
|
|
@@ -145,6 +149,13 @@ Any other config value can be set the same way, as `AMAZON_<KEY>` (see [`AmazonO
|
|
|
145
149
|
lets `amazon-orders` read the site's pages; its own CLI and messages stay in English. See
|
|
146
150
|
[Language Packages](https://amazon-orders.readthedocs.io/language-packages.html).
|
|
147
151
|
|
|
152
|
+
### AI Assistants
|
|
153
|
+
|
|
154
|
+
An AI assistant has two ways to use `amazon-orders`. One that runs commands uses the CLI or the library directly, just
|
|
155
|
+
as shown above. Any MCP client gets the same as tools through
|
|
156
|
+
[`amazon-orders-mcp`](https://github.com/alexdlaird/amazon-orders-mcp#readme), a server built on `amazon-orders` — see
|
|
157
|
+
its README for setup.
|
|
158
|
+
|
|
148
159
|
## Documentation
|
|
149
160
|
|
|
150
161
|
For more advanced usage, `amazon-orders`'s official documentation is available
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: amazon-orders
|
|
3
|
-
Version: 4.9.
|
|
3
|
+
Version: 4.9.2
|
|
4
4
|
Summary: A Python library (and CLI) for Amazon order history, line items, and transactions
|
|
5
5
|
Author-email: Alex Laird <contact@alexlaird.com>
|
|
6
6
|
Maintainer-email: Alex Laird <contact@alexlaird.com>
|
|
@@ -112,6 +112,7 @@ to interact with account data. [`get_order_history`](https://amazon-orders.readt
|
|
|
112
112
|
and [`get_order`](https://amazon-orders.readthedocs.io/api.html#amazonorders.orders.AmazonOrders.get_order) are good places to start.
|
|
113
113
|
|
|
114
114
|
```python
|
|
115
|
+
from amazonorders.constants import Constants
|
|
115
116
|
from amazonorders.session import AmazonSession
|
|
116
117
|
from amazonorders.orders import AmazonOrders
|
|
117
118
|
|
|
@@ -125,8 +126,8 @@ amazon_orders = AmazonOrders(amazon_session)
|
|
|
125
126
|
orders = amazon_orders.get_order_history(year=2023)
|
|
126
127
|
|
|
127
128
|
# Or use time filters for recent orders
|
|
128
|
-
orders = amazon_orders.get_order_history(time_filter=
|
|
129
|
-
orders = amazon_orders.get_order_history(time_filter=
|
|
129
|
+
orders = amazon_orders.get_order_history(time_filter=Constants.LAST_30_DAYS_TIME_FILTER)
|
|
130
|
+
orders = amazon_orders.get_order_history(time_filter=Constants.LAST_3_MONTHS_TIME_FILTER)
|
|
130
131
|
|
|
131
132
|
for order in orders:
|
|
132
133
|
print(f"{order.order_number} - {order.grand_total}")
|
|
@@ -210,6 +211,9 @@ environment variables `amazon-orders` looks for are:
|
|
|
210
211
|
|
|
211
212
|
Any other config value can be set the same way, as `AMAZON_<KEY>` (see [`AmazonOrdersConfig`](https://amazon-orders.readthedocs.io/api.html#amazonorders.conf.AmazonOrdersConfig)).
|
|
212
213
|
|
|
214
|
+
A configured username also applies to `amazon-orders login --browser`: it's filled in and submitted for you, so the
|
|
215
|
+
browser opens on Amazon's password or passkey step. The browser never fills in your password.
|
|
216
|
+
|
|
213
217
|
### Languages and Regions
|
|
214
218
|
|
|
215
219
|
`amazon-orders` reads Amazon's pages in English. The `.com` site is validated nightly.
|
|
@@ -221,6 +225,13 @@ Any other config value can be set the same way, as `AMAZON_<KEY>` (see [`AmazonO
|
|
|
221
225
|
lets `amazon-orders` read the site's pages; its own CLI and messages stay in English. See
|
|
222
226
|
[Language Packages](https://amazon-orders.readthedocs.io/language-packages.html).
|
|
223
227
|
|
|
228
|
+
### AI Assistants
|
|
229
|
+
|
|
230
|
+
An AI assistant has two ways to use `amazon-orders`. One that runs commands uses the CLI or the library directly, just
|
|
231
|
+
as shown above. Any MCP client gets the same as tools through
|
|
232
|
+
[`amazon-orders-mcp`](https://github.com/alexdlaird/amazon-orders-mcp#readme), a server built on `amazon-orders` — see
|
|
233
|
+
its README for setup.
|
|
234
|
+
|
|
224
235
|
## Documentation
|
|
225
236
|
|
|
226
237
|
For more advanced usage, `amazon-orders`'s official documentation is available
|
|
@@ -8,8 +8,9 @@ import logging
|
|
|
8
8
|
import os
|
|
9
9
|
import platform
|
|
10
10
|
import sys
|
|
11
|
+
import threading
|
|
11
12
|
import time
|
|
12
|
-
from typing import Any,
|
|
13
|
+
from typing import Any, List, Optional
|
|
13
14
|
|
|
14
15
|
import click
|
|
15
16
|
from click.core import Context
|
|
@@ -77,19 +78,69 @@ class IOClick(IODefault):
|
|
|
77
78
|
click.echo(banner.format(version=__version__), err=True)
|
|
78
79
|
|
|
79
80
|
@staticmethod
|
|
80
|
-
def
|
|
81
|
-
""
|
|
82
|
-
|
|
83
|
-
"""
|
|
84
|
-
def echo(count: int) -> None:
|
|
85
|
-
click.echo(f"Info: {count} {noun} found so far ...", err=True)
|
|
81
|
+
def echo_session_expired() -> None:
|
|
82
|
+
click.echo("... Amazon redirected to login, so it wants the persisted session's sign-in confirmed. Call the "
|
|
83
|
+
"`login` command to sign in again, or `login --browser` to log in on Amazon's own page.\n")
|
|
86
84
|
|
|
87
|
-
return echo
|
|
88
85
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
class ProgressSpinner:
|
|
87
|
+
"""
|
|
88
|
+
While a fetch runs, show a spinner and how many ``noun`` have been found so far on a single ``stderr`` line,
|
|
89
|
+
redrawn in place, and how many are expected if a total is known. The line is cleared when the fetch ends, whether
|
|
90
|
+
or not it succeeded. Pass it as a ``progress`` or ``progress_with_total`` callback. When not ``enabled``, nothing
|
|
91
|
+
is shown.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
FRAMES = "|/-\\"
|
|
95
|
+
INTERVAL_SECONDS = 0.1
|
|
96
|
+
|
|
97
|
+
def __init__(self,
|
|
98
|
+
noun: str,
|
|
99
|
+
enabled: bool) -> None:
|
|
100
|
+
self.noun: str = noun
|
|
101
|
+
self.enabled: bool = enabled
|
|
102
|
+
self._count: int = 0
|
|
103
|
+
self._total: Optional[int] = None
|
|
104
|
+
self._line_length: int = 0
|
|
105
|
+
self._lock: threading.Lock = threading.Lock()
|
|
106
|
+
self._stopped: threading.Event = threading.Event()
|
|
107
|
+
self._thread: Optional[threading.Thread] = None
|
|
108
|
+
|
|
109
|
+
def __call__(self,
|
|
110
|
+
count: int,
|
|
111
|
+
total: Optional[int] = None) -> None:
|
|
112
|
+
with self._lock:
|
|
113
|
+
self._count = count
|
|
114
|
+
self._total = total
|
|
115
|
+
|
|
116
|
+
def __enter__(self) -> "ProgressSpinner":
|
|
117
|
+
if self.enabled:
|
|
118
|
+
self._thread = threading.Thread(target=self._spin, daemon=True)
|
|
119
|
+
self._thread.start()
|
|
120
|
+
|
|
121
|
+
return self
|
|
122
|
+
|
|
123
|
+
def __exit__(self,
|
|
124
|
+
*exc_info: Any) -> None:
|
|
125
|
+
if self._thread:
|
|
126
|
+
self._stopped.set()
|
|
127
|
+
self._thread.join()
|
|
128
|
+
click.echo(f"\r{' ' * self._line_length}\r", nl=False, err=True)
|
|
129
|
+
|
|
130
|
+
def _spin(self) -> None:
|
|
131
|
+
frame = 0
|
|
132
|
+
while not self._stopped.is_set():
|
|
133
|
+
with self._lock:
|
|
134
|
+
count = self._count
|
|
135
|
+
optional_total = f" of {self._total}" if self._total is not None else ""
|
|
136
|
+
self._redraw(f"{self.FRAMES[frame % len(self.FRAMES)]} {self.noun} found so far: {count}{optional_total}")
|
|
137
|
+
frame += 1
|
|
138
|
+
self._stopped.wait(self.INTERVAL_SECONDS)
|
|
139
|
+
|
|
140
|
+
def _redraw(self,
|
|
141
|
+
line: str) -> None:
|
|
142
|
+
click.echo(f"\r{line.ljust(self._line_length)}", nl=False, err=True)
|
|
143
|
+
self._line_length = max(self._line_length, len(line))
|
|
93
144
|
|
|
94
145
|
|
|
95
146
|
class CliAuth:
|
|
@@ -105,7 +156,7 @@ class CliAuth:
|
|
|
105
156
|
if amazon_session.username or amazon_session.password:
|
|
106
157
|
click.echo(
|
|
107
158
|
"Info: The given username and password are being ignored because a previous session still "
|
|
108
|
-
"exists. To reauthenticate, call the `
|
|
159
|
+
"exists. To reauthenticate, call the `login` command.\n")
|
|
109
160
|
else:
|
|
110
161
|
if not amazon_session.username:
|
|
111
162
|
amazon_session.username = click.prompt("Username")
|
|
@@ -143,7 +194,7 @@ class CliAuth:
|
|
|
143
194
|
raise
|
|
144
195
|
browser_type = browser_types[0]
|
|
145
196
|
else:
|
|
146
|
-
click.echo("Info:
|
|
197
|
+
click.echo("Info: No default browser was found, so one to sign in with needs to be downloaded.\n")
|
|
147
198
|
browser_type = IOClick.prompt_for_choice("Choose a browser to download", browser_types)
|
|
148
199
|
|
|
149
200
|
browser_selected = PlaywrightBrowserLauncher(self.amazon_session.config).install(browser_type)
|
|
@@ -168,6 +219,9 @@ class CliAuth:
|
|
|
168
219
|
@click.option("--domain",
|
|
169
220
|
help="The Amazon domain to target (e.g. amazon.com, amazon.co.uk, amazon.com.au). "
|
|
170
221
|
"Defaults to amazon.com.")
|
|
222
|
+
@click.option("--progress/--no-progress", default=None,
|
|
223
|
+
help="Show a running count while fetching. Defaults to showing it only in an interactive terminal, "
|
|
224
|
+
"and not with --debug.")
|
|
171
225
|
@click.pass_context
|
|
172
226
|
def amazon_orders_cli(ctx: Context,
|
|
173
227
|
**kwargs: Any) -> None:
|
|
@@ -195,6 +249,9 @@ def amazon_orders_cli(ctx: Context,
|
|
|
195
249
|
logger.setLevel(logging.DEBUG)
|
|
196
250
|
logger.addHandler(logging.StreamHandler())
|
|
197
251
|
|
|
252
|
+
ctx.obj["show_progress"] = (kwargs["progress"] if kwargs["progress"] is not None
|
|
253
|
+
else _is_interactive_terminal() and not kwargs["debug"])
|
|
254
|
+
|
|
198
255
|
data = {}
|
|
199
256
|
if kwargs.get("output_dir"):
|
|
200
257
|
data["output_dir"] = kwargs["output_dir"]
|
|
@@ -274,10 +331,10 @@ def history(ctx: Context,
|
|
|
274
331
|
# Determine time filter
|
|
275
332
|
time_filter = None
|
|
276
333
|
if last_30_days:
|
|
277
|
-
time_filter =
|
|
334
|
+
time_filter = amazon_session.config.constants.LAST_30_DAYS_TIME_FILTER
|
|
278
335
|
filter_description = "last 30 days"
|
|
279
336
|
elif last_3_months:
|
|
280
|
-
time_filter =
|
|
337
|
+
time_filter = amazon_session.config.constants.LAST_3_MONTHS_TIME_FILTER
|
|
281
338
|
filter_description = "past 3 months"
|
|
282
339
|
else:
|
|
283
340
|
if year is None:
|
|
@@ -293,20 +350,22 @@ Order History for {filter_description}{optional_start_index}{optional_full_detai
|
|
|
293
350
|
.format(filter_description=filter_description,
|
|
294
351
|
optional_start_index=optional_start_index,
|
|
295
352
|
optional_full_details=optional_full_details), err=True)
|
|
296
|
-
|
|
353
|
+
if not ctx.obj["show_progress"]:
|
|
354
|
+
click.echo("Info: Fetching Order history, this might take a minute ...", err=True)
|
|
297
355
|
|
|
298
356
|
config = ctx.obj["conf"]
|
|
299
357
|
amazon_orders = AmazonOrders(amazon_session,
|
|
300
358
|
config=config)
|
|
301
359
|
|
|
302
360
|
start_time = time.time()
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
361
|
+
with ProgressSpinner("Orders", ctx.obj["show_progress"]) as progress:
|
|
362
|
+
orders = amazon_orders.get_order_history(year=year,
|
|
363
|
+
start_index=start_index,
|
|
364
|
+
full_details=full_details,
|
|
365
|
+
keep_paging=not single_page,
|
|
366
|
+
time_filter=time_filter,
|
|
367
|
+
order_filter=order_filter,
|
|
368
|
+
progress_with_total=progress)
|
|
310
369
|
end_time = time.time()
|
|
311
370
|
|
|
312
371
|
click.echo(config.output_cls(config).format(orders, output))
|
|
@@ -403,7 +462,8 @@ def order_transactions(ctx: Context,
|
|
|
403
462
|
output = kwargs["output"]
|
|
404
463
|
|
|
405
464
|
start_time = time.time()
|
|
406
|
-
|
|
465
|
+
with ProgressSpinner("Transactions", ctx.obj["show_progress"]) as progress:
|
|
466
|
+
order_transaction_list = amazon_transactions.get_transactions(order_id=order_id, progress=progress)
|
|
407
467
|
end_time = time.time()
|
|
408
468
|
|
|
409
469
|
click.echo(config.output_cls(config).format(order_transaction_list, output))
|
|
@@ -441,15 +501,16 @@ def transactions(ctx: Context, **kwargs: Any) -> None:
|
|
|
441
501
|
Transaction History for {days} days
|
|
442
502
|
-----------------------------------------------------------------------\n""".format(days=days), err=True
|
|
443
503
|
)
|
|
444
|
-
|
|
504
|
+
if not ctx.obj["show_progress"]:
|
|
505
|
+
click.echo("Info: Fetching Transaction history, this might take a minute ...", err=True)
|
|
445
506
|
|
|
446
507
|
config = ctx.obj["conf"]
|
|
447
508
|
amazon_transactions = AmazonTransactions(amazon_session,
|
|
448
509
|
config=config)
|
|
449
510
|
|
|
450
511
|
start_time = time.time()
|
|
451
|
-
|
|
452
|
-
|
|
512
|
+
with ProgressSpinner("Transactions", ctx.obj["show_progress"]) as progress:
|
|
513
|
+
transaction_list = amazon_transactions.get_transactions(days=days, progress=progress)
|
|
453
514
|
end_time = time.time()
|
|
454
515
|
|
|
455
516
|
click.echo(config.output_cls(config).format(transaction_list, output))
|
|
@@ -512,15 +573,16 @@ def gift_card_activity(ctx: Context, **kwargs: Any) -> None:
|
|
|
512
573
|
Gift Card Activity for {days} days
|
|
513
574
|
-----------------------------------------------------------------------\n""".format(days=days), err=True
|
|
514
575
|
)
|
|
515
|
-
|
|
576
|
+
if not ctx.obj["show_progress"]:
|
|
577
|
+
click.echo("Info: Fetching Gift Card activity, this might take a minute ...", err=True)
|
|
516
578
|
|
|
517
579
|
config = ctx.obj["conf"]
|
|
518
580
|
amazon_gift_cards = AmazonGiftCards(amazon_session,
|
|
519
581
|
config=config)
|
|
520
582
|
|
|
521
583
|
start_time = time.time()
|
|
522
|
-
activity
|
|
523
|
-
days=days, progress=
|
|
584
|
+
with ProgressSpinner("Gift Card activity entries", ctx.obj["show_progress"]) as progress:
|
|
585
|
+
activity = amazon_gift_cards.get_gift_card_activity(days=days, progress=progress)
|
|
524
586
|
end_time = time.time()
|
|
525
587
|
|
|
526
588
|
click.echo(config.output_cls(config).format(activity, output))
|
|
@@ -559,20 +621,20 @@ def login(ctx: Context, **kwargs: Any) -> None:
|
|
|
559
621
|
"""
|
|
560
622
|
amazon_session = ctx.obj["amazon_session"]
|
|
561
623
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
"Info:
|
|
565
|
-
|
|
566
|
-
try:
|
|
567
|
-
if kwargs["browser"]:
|
|
568
|
-
CliAuth(amazon_session).authenticate_with_browser()
|
|
569
|
-
else:
|
|
570
|
-
CliAuth(amazon_session).authenticate()
|
|
571
|
-
except AmazonOrdersError as e:
|
|
572
|
-
logger.debug("An error occurred.", exc_info=True)
|
|
573
|
-
ctx.fail(str(e))
|
|
624
|
+
try:
|
|
625
|
+
if amazon_session.auth_cookies_stored():
|
|
626
|
+
click.echo("Info: Logging out of the persisted session first, so this login starts fresh.\n")
|
|
627
|
+
amazon_session.logout()
|
|
574
628
|
|
|
575
|
-
|
|
629
|
+
if kwargs["browser"]:
|
|
630
|
+
CliAuth(amazon_session).authenticate_with_browser()
|
|
631
|
+
else:
|
|
632
|
+
CliAuth(amazon_session).authenticate()
|
|
633
|
+
except AmazonOrdersError as e:
|
|
634
|
+
logger.debug("An error occurred.", exc_info=True)
|
|
635
|
+
ctx.fail(str(e))
|
|
636
|
+
|
|
637
|
+
click.echo("Info: Successfully logged in to Amazon, session persisted.\n")
|
|
576
638
|
|
|
577
639
|
|
|
578
640
|
@amazon_orders_cli.command()
|
|
@@ -620,5 +682,9 @@ def version(ctx: Context) -> None:
|
|
|
620
682
|
ctx.exit(0)
|
|
621
683
|
|
|
622
684
|
|
|
685
|
+
def _is_interactive_terminal() -> bool:
|
|
686
|
+
return sys.stderr.isatty() and os.environ.get("TERM") != "dumb"
|
|
687
|
+
|
|
688
|
+
|
|
623
689
|
if __name__ == "__main__":
|
|
624
690
|
amazon_orders_cli(obj={})
|