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.
Files changed (48) hide show
  1. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/CHANGELOG.md +32 -4
  2. {amazon_orders-4.9.0/amazon_orders.egg-info → amazon_orders-4.9.2}/PKG-INFO +14 -3
  3. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/README.md +13 -2
  4. {amazon_orders-4.9.0 → amazon_orders-4.9.2/amazon_orders.egg-info}/PKG-INFO +14 -3
  5. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/__init__.py +1 -1
  6. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/cli.py +110 -44
  7. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/conf.py +3 -0
  8. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/constants.py +171 -170
  9. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/browser/playwright.py +52 -17
  10. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/waf/anticaptcha.py +14 -11
  11. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/waf/base.py +47 -12
  12. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/waf/capsolver.py +26 -21
  13. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/waf/twocaptcha.py +13 -10
  14. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/order.py +2 -1
  15. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/transaction.py +2 -1
  16. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/exception.py +9 -0
  17. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/forms.py +21 -13
  18. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/orders.py +67 -16
  19. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/selectors.py +1 -0
  20. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/session.py +77 -25
  21. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/LICENSE +0 -0
  22. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/MANIFEST.in +0 -0
  23. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazon_orders.egg-info/SOURCES.txt +0 -0
  24. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazon_orders.egg-info/dependency_links.txt +0 -0
  25. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazon_orders.egg-info/entry_points.txt +0 -0
  26. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazon_orders.egg-info/requires.txt +0 -0
  27. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazon_orders.egg-info/top_level.txt +0 -0
  28. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/banner.txt +0 -0
  29. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/__init__.py +0 -0
  30. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/browser/__init__.py +0 -0
  31. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/contrib/waf/__init__.py +0 -0
  32. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/__init__.py +0 -0
  33. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/gift_card_activity.py +0 -0
  34. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/item.py +0 -0
  35. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/parsable.py +0 -0
  36. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/recipient.py +0 -0
  37. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/seller.py +0 -0
  38. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/shipment.py +0 -0
  39. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/entity/tracking.py +0 -0
  40. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/gift_cards.py +0 -0
  41. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/output.py +0 -0
  42. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/paging.py +0 -0
  43. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/region_data.py +0 -0
  44. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/transactions.py +9 -9
  45. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/amazonorders/util.py +0 -0
  46. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/pyproject.toml +0 -0
  47. {amazon_orders-4.9.0 → amazon_orders-4.9.2}/setup.cfg +0 -0
  48. {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.0...HEAD)
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.0
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="last30") # Last 30 days
129
- orders = amazon_orders.get_order_history(time_filter="months-3") # Past 3 months
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="last30") # Last 30 days
53
- orders = amazon_orders.get_order_history(time_filter="months-3") # Past 3 months
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.0
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="last30") # Last 30 days
129
- orders = amazon_orders.get_order_history(time_filter="months-3") # Past 3 months
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
@@ -1,3 +1,3 @@
1
1
  __copyright__ = "Copyright (c) 2024-2025 Alex Laird"
2
2
  __license__ = "MIT"
3
- __version__ = "4.9.0"
3
+ __version__ = "4.9.2"
@@ -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, Callable, List, Optional
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 echo_progress(noun: str) -> Callable[[int], None]:
81
- """
82
- Build a ``progress`` callback that tells the user, on ``stderr``, how many ``noun`` have been found so far.
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
- @staticmethod
90
- def echo_session_expired() -> None:
91
- click.echo("... Amazon redirected to login, which likely means the persisted session is stale. It was logged "
92
- "out, so call the `login` command again, or `login --browser` to log in on Amazon's own page.\n")
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 `logout` command first.\n")
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: Chrome isn't installed, so a browser to sign in with needs to be downloaded.\n")
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 = "last30"
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 = "months-3"
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
- click.echo("Info: Fetching Order history, this might take a minute ...", err=True)
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
- orders = amazon_orders.get_order_history(year=year,
304
- start_index=start_index,
305
- full_details=full_details,
306
- keep_paging=not single_page,
307
- time_filter=time_filter,
308
- order_filter=order_filter,
309
- progress=IOClick.echo_progress("Orders"))
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
- order_transaction_list = amazon_transactions.get_transactions(order_id=order_id)
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
- click.echo("Info: Fetching Transaction history, this might take a minute ...", err=True)
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
- transaction_list = amazon_transactions.get_transactions(days=days,
452
- progress=IOClick.echo_progress("Transactions"))
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
- click.echo("Info: Fetching Gift Card activity, this might take a minute ...", err=True)
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 = amazon_gift_cards.get_gift_card_activity(
523
- days=days, progress=IOClick.echo_progress("Gift Card activity entries"))
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
- if amazon_session.auth_cookies_stored():
563
- click.echo(
564
- "Info: A persisted session exists. Call the `logout` command first to change users.\n")
565
- else:
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
- click.echo("Info: Successfully logged in to Amazon, session persisted.\n")
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={})
@@ -1,3 +1,6 @@
1
+ __copyright__ = "Copyright (c) 2024-2025 Alex Laird"
2
+ __license__ = "MIT"
3
+
1
4
  import importlib
2
5
  import inspect
3
6
  import logging