amazon-orders 3.2.3__tar.gz → 3.2.4__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-3.2.3 → amazon_orders-3.2.4}/CHANGELOG.md +14 -3
- {amazon_orders-3.2.3/amazon_orders.egg-info → amazon_orders-3.2.4}/PKG-INFO +2 -2
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/README.md +1 -1
- {amazon_orders-3.2.3 → amazon_orders-3.2.4/amazon_orders.egg-info}/PKG-INFO +2 -2
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/__init__.py +1 -1
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/entity/order.py +9 -2
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/entity/parsable.py +21 -3
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/orders.py +2 -3
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/selectors.py +12 -3
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/tests/test_orders.py +24 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/LICENSE +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/MANIFEST.in +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazon_orders.egg-info/SOURCES.txt +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazon_orders.egg-info/dependency_links.txt +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazon_orders.egg-info/entry_points.txt +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazon_orders.egg-info/requires.txt +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazon_orders.egg-info/top_level.txt +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/banner.txt +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/cli.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/conf.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/constants.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/entity/__init__.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/entity/item.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/entity/recipient.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/entity/seller.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/entity/shipment.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/entity/transaction.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/exception.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/forms.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/session.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/transactions.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/amazonorders/util.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/pyproject.toml +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/setup.cfg +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/tests/test_cli.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/tests/test_conf.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/tests/test_session.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/tests/test_transactions.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/tests/test_util.py +0 -0
- {amazon_orders-3.2.3 → amazon_orders-3.2.4}/tests/testcase.py +0 -0
|
@@ -4,9 +4,20 @@ 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/3.2.
|
|
7
|
+
## [Unreleased](https://github.com/alexdlaird/amazon-orders/compare/3.2.4...HEAD)
|
|
8
8
|
|
|
9
|
-
## [3.2.
|
|
9
|
+
## [3.2.4](https://github.com/alexdlaird/amazon-orders/compare/3.2.3...3.2.4) - 2025-02-11
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `Order.promotion_applied` field, which is now parsed alongside other subtotals.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Broken parsing of Whole Foods Market orders, these are now skipped.
|
|
18
|
+
- Parsing issue on `Order.order_number` and `Order.order_placed` due to changes in Amazon.com DOM.
|
|
19
|
+
|
|
20
|
+
## [3.2.3](https://github.com/alexdlaird/amazon-orders/compare/3.2.2...3.2.3) - 2025-02-06
|
|
10
21
|
|
|
11
22
|
### Added
|
|
12
23
|
|
|
@@ -263,7 +274,7 @@ Build and stability improvements.
|
|
|
263
274
|
- [AuthForm](https://amazon-orders.readthedocs.io/api.html#amazonorders.forms.AuthForm) abstract class, and
|
|
264
275
|
migrated all auth flow items to subclasses of this class.
|
|
265
276
|
- [Parsable.simple_parse()](https://amazon-orders.readthedocs.io/api.html#amazonorders.entities.parsable.Parsable.simple_parse),
|
|
266
|
-
which can handle most basic fields when
|
|
277
|
+
which can handle most basic fields when parsed with CSS selectors.
|
|
267
278
|
- Stability improvements.
|
|
268
279
|
- Test improvements.
|
|
269
280
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: amazon-orders
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.4
|
|
4
4
|
Summary: A CLI and library for interacting with Amazon order history.
|
|
5
5
|
Maintainer-email: Alex Laird <contact@alexlaird.com>
|
|
6
6
|
License: MIT License
|
|
@@ -88,7 +88,7 @@ be used to interact with Amazon.com's consumer-facing website.
|
|
|
88
88
|
|
|
89
89
|
This works by parsing website data from Amazon.com. A periodic build validates functionality to ensure its
|
|
90
90
|
stability, but as Amazon provides no official API to use, this package may break at any time. This
|
|
91
|
-
package only officially supports the English version of
|
|
91
|
+
package only officially supports the English, `.com` version of Amazon.
|
|
92
92
|
|
|
93
93
|
## Installation
|
|
94
94
|
|
|
@@ -12,7 +12,7 @@ be used to interact with Amazon.com's consumer-facing website.
|
|
|
12
12
|
|
|
13
13
|
This works by parsing website data from Amazon.com. A periodic build validates functionality to ensure its
|
|
14
14
|
stability, but as Amazon provides no official API to use, this package may break at any time. This
|
|
15
|
-
package only officially supports the English version of
|
|
15
|
+
package only officially supports the English, `.com` version of Amazon.
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: amazon-orders
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.4
|
|
4
4
|
Summary: A CLI and library for interacting with Amazon order history.
|
|
5
5
|
Maintainer-email: Alex Laird <contact@alexlaird.com>
|
|
6
6
|
License: MIT License
|
|
@@ -88,7 +88,7 @@ be used to interact with Amazon.com's consumer-facing website.
|
|
|
88
88
|
|
|
89
89
|
This works by parsing website data from Amazon.com. A periodic build validates functionality to ensure its
|
|
90
90
|
stability, but as Amazon provides no official API to use, this package may break at any time. This
|
|
91
|
-
package only officially supports the English version of
|
|
91
|
+
package only officially supports the English, `.com` version of Amazon.
|
|
92
92
|
|
|
93
93
|
## Installation
|
|
94
94
|
|
|
@@ -43,7 +43,9 @@ class Order(Parsable):
|
|
|
43
43
|
#: The Order number.
|
|
44
44
|
self.order_number: str = clone.order_number if clone else self.safe_simple_parse(
|
|
45
45
|
selector=self.config.selectors.FIELD_ORDER_NUMBER_SELECTOR,
|
|
46
|
-
required=True
|
|
46
|
+
required=True,
|
|
47
|
+
prefix_split="#",
|
|
48
|
+
prefix_split_fuzzy=True)
|
|
47
49
|
#: The Order details link.
|
|
48
50
|
self.order_details_link: Optional[str] = clone.order_details_link if clone else self.safe_parse(
|
|
49
51
|
self._parse_order_details_link)
|
|
@@ -51,7 +53,10 @@ class Order(Parsable):
|
|
|
51
53
|
self.grand_total: float = clone.grand_total if clone else self.safe_parse(self._parse_grand_total)
|
|
52
54
|
#: The Order placed date.
|
|
53
55
|
self.order_placed_date: date = clone.order_placed_date if clone else self.safe_simple_parse(
|
|
54
|
-
selector=self.config.selectors.FIELD_ORDER_PLACED_DATE_SELECTOR,
|
|
56
|
+
selector=self.config.selectors.FIELD_ORDER_PLACED_DATE_SELECTOR,
|
|
57
|
+
suffix_split="Order #",
|
|
58
|
+
suffix_split_fuzzy=True,
|
|
59
|
+
parse_date=True)
|
|
55
60
|
#: The Order Recipients.
|
|
56
61
|
self.recipient: Recipient = clone.recipient if clone else self.safe_parse(self._parse_recipient)
|
|
57
62
|
|
|
@@ -69,6 +74,8 @@ class Order(Parsable):
|
|
|
69
74
|
self.subtotal: Optional[float] = self._if_full_details(self._parse_currency("subtotal"))
|
|
70
75
|
#: The Order shipping total. Only populated when ``full_details`` is ``True``.
|
|
71
76
|
self.shipping_total: Optional[float] = self._if_full_details(self._parse_currency("shipping"))
|
|
77
|
+
#: The Order promotion applied. Only populated when ``full_details`` is ``True``.
|
|
78
|
+
self.promotion_applied: Optional[float] = self._if_full_details(self._parse_currency("promotion"))
|
|
72
79
|
#: The Order Subscribe & Save discount. Only populated when ``full_details`` is ``True``.
|
|
73
80
|
self.subscription_discount: Optional[float] = self._if_full_details(self._parse_currency("subscribe"))
|
|
74
81
|
#: The Order total before tax. Only populated when ``full_details`` is ``True``.
|
|
@@ -67,7 +67,10 @@ class Parsable:
|
|
|
67
67
|
required: bool = False,
|
|
68
68
|
prefix_split: Optional[str] = None,
|
|
69
69
|
wrap_tag: Optional[Type] = None,
|
|
70
|
-
parse_date: bool = False
|
|
70
|
+
parse_date: bool = False,
|
|
71
|
+
prefix_split_fuzzy: bool = False,
|
|
72
|
+
suffix_split: Optional[str] = None,
|
|
73
|
+
suffix_split_fuzzy: bool = False) -> Any:
|
|
71
74
|
"""
|
|
72
75
|
Will attempt to extract the text value of the given CSS selector(s) for a field, and
|
|
73
76
|
is suitable for most basic functionality on a well-formed page.
|
|
@@ -86,6 +89,9 @@ class Parsable:
|
|
|
86
89
|
:param wrap_tag: Wrap the selected tag in this class before returning.
|
|
87
90
|
:param parse_date: ``True`` if the resulting value should be fuzzy parsed in to a date (returning ``None`` if
|
|
88
91
|
parsing fails).
|
|
92
|
+
:param prefix_split_fuzzy: ``True`` if the value should still be used even if ``prefix_split`` is not found.
|
|
93
|
+
:param suffix_split: Only select the field with the given suffix, returning the left side of the split if so.
|
|
94
|
+
:param suffix_split_fuzzy: ``True`` if the value should still be used even if ``suffix_split`` is not found.
|
|
89
95
|
:return: The cleaned up return value from the parsed ``selector``.
|
|
90
96
|
"""
|
|
91
97
|
if isinstance(selector, str):
|
|
@@ -109,12 +115,24 @@ class Parsable:
|
|
|
109
115
|
|
|
110
116
|
if prefix_split:
|
|
111
117
|
if prefix_split not in tag.text:
|
|
112
|
-
|
|
118
|
+
if prefix_split_fuzzy:
|
|
119
|
+
value = tag.text.strip()
|
|
120
|
+
else:
|
|
121
|
+
continue
|
|
113
122
|
else:
|
|
114
123
|
value = tag.text.strip().split(prefix_split)[1]
|
|
115
124
|
else:
|
|
116
125
|
value = tag.text
|
|
117
126
|
|
|
127
|
+
if suffix_split:
|
|
128
|
+
if suffix_split not in value:
|
|
129
|
+
if suffix_split_fuzzy:
|
|
130
|
+
value = value.strip()
|
|
131
|
+
else:
|
|
132
|
+
continue
|
|
133
|
+
else:
|
|
134
|
+
value = value.strip().split(suffix_split)[0]
|
|
135
|
+
|
|
118
136
|
if wrap_tag:
|
|
119
137
|
value = wrap_tag(tag, self.config)
|
|
120
138
|
else:
|
|
@@ -142,7 +160,7 @@ class Parsable:
|
|
|
142
160
|
"""
|
|
143
161
|
A helper function that uses :func:`simple_parse` as the ``parse_function()`` passed to :func:`safe_parse`.
|
|
144
162
|
|
|
145
|
-
:param selector: The selector to pass to :func:`simple_parse`.
|
|
163
|
+
:param selector: The CSS selector to pass to :func:`simple_parse`.
|
|
146
164
|
:param kwargs: The ``kwargs`` will be passed to ``parse_function``.
|
|
147
165
|
:return: The return value from :func:`simple_parse`.
|
|
148
166
|
"""
|
|
@@ -73,9 +73,8 @@ class AmazonOrders:
|
|
|
73
73
|
response_parsed = self.amazon_session.last_response_parsed
|
|
74
74
|
|
|
75
75
|
for order_tag in util.select(response_parsed, self.config.selectors.ORDER_HISTORY_ENTITY_SELECTOR):
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
# these orders.
|
|
76
|
+
# First check if this Order is known to be of a type that we do not currently have a way to support
|
|
77
|
+
# parsing, meaning it should be skipped
|
|
79
78
|
if util.select(order_tag, self.config.selectors.ORDER_HISTORY_BRAND_SELECTOR):
|
|
80
79
|
continue
|
|
81
80
|
|
|
@@ -55,7 +55,14 @@ class Selectors:
|
|
|
55
55
|
SHIPMENT_ENTITY_SELECTOR = ["[data-component='orderCard'] [data-component='shipments'] .a-box",
|
|
56
56
|
"div.shipment",
|
|
57
57
|
"div.delivery-box"]
|
|
58
|
-
|
|
58
|
+
# Selectors defined here, if found in an Order, will cause the Order to be skipped, since it means we currently
|
|
59
|
+
# do not have a way to support fully parsing its details
|
|
60
|
+
ORDER_HISTORY_BRAND_SELECTOR = [
|
|
61
|
+
# Amazon Fresh is not supported
|
|
62
|
+
".brand-info-box .brand-logo img",
|
|
63
|
+
# Whole Foods Market is not supported
|
|
64
|
+
"a.yohtmlc-order-details-link[href^='/wholefoodsmarket']"
|
|
65
|
+
]
|
|
59
66
|
|
|
60
67
|
#####################################
|
|
61
68
|
# CSS selectors for Item fields
|
|
@@ -81,12 +88,14 @@ class Selectors:
|
|
|
81
88
|
#####################################
|
|
82
89
|
|
|
83
90
|
FIELD_ORDER_DETAILS_LINK_SELECTOR = "a.yohtmlc-order-details-link"
|
|
84
|
-
FIELD_ORDER_NUMBER_SELECTOR = ["
|
|
91
|
+
FIELD_ORDER_NUMBER_SELECTOR = ["[data-component='briefOrderInfo'] div.a-column",
|
|
92
|
+
".order-date-invoice-item bdi[dir='ltr']",
|
|
85
93
|
"bdi[dir='ltr']",
|
|
86
94
|
"span[dir='ltr']"]
|
|
87
95
|
FIELD_ORDER_GRAND_TOTAL_SELECTOR = ["div.yohtmlc-order-total span.value",
|
|
88
96
|
"div.order-header div.a-column.a-span2"]
|
|
89
|
-
FIELD_ORDER_PLACED_DATE_SELECTOR = ["
|
|
97
|
+
FIELD_ORDER_PLACED_DATE_SELECTOR = ["[data-component='briefOrderInfo'] div.a-column",
|
|
98
|
+
"span.order-date-invoice-item",
|
|
90
99
|
"div.a-span3"]
|
|
91
100
|
FIELD_ORDER_PAYMENT_METHOD_SELECTOR = "img.pmts-payment-credit-card-instrument-logo"
|
|
92
101
|
FIELD_ORDER_PAYMENT_METHOD_LAST_4_SELECTOR = "span:has(img.pmts-payment-credit-card-instrument-logo):last-child"
|
|
@@ -127,6 +127,30 @@ class TestOrders(UnitTestCase):
|
|
|
127
127
|
self.assertEqual(1, resp1.call_count)
|
|
128
128
|
self.assertEqual(1, resp2.call_count)
|
|
129
129
|
|
|
130
|
+
@responses.activate
|
|
131
|
+
def test_get_order_history_skip_wholefoods(self):
|
|
132
|
+
# GIVEN
|
|
133
|
+
self.amazon_session.is_authenticated = True
|
|
134
|
+
year = 2024
|
|
135
|
+
start_index = 0
|
|
136
|
+
resp1 = self.given_order_history_landing_exists()
|
|
137
|
+
with open(os.path.join(self.RESOURCES_DIR, "order-history-wholefoods.html"), "r",
|
|
138
|
+
encoding="utf-8") as f:
|
|
139
|
+
resp2 = responses.add(
|
|
140
|
+
responses.GET,
|
|
141
|
+
self.test_config.constants.ORDER_HISTORY_URL,
|
|
142
|
+
body=f.read(),
|
|
143
|
+
status=200,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# WHEN
|
|
147
|
+
orders = self.amazon_orders.get_order_history(year=year, start_index=start_index)
|
|
148
|
+
|
|
149
|
+
# THEN
|
|
150
|
+
self.assertEqual(9, len(orders))
|
|
151
|
+
self.assertEqual(1, resp1.call_count)
|
|
152
|
+
self.assertEqual(1, resp2.call_count)
|
|
153
|
+
|
|
130
154
|
@responses.activate
|
|
131
155
|
def test_get_order_history_full_details(self):
|
|
132
156
|
# GIVEN
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|