Skip to content

Commit

Permalink
Merge branch 'develop' into pr/21
Browse files Browse the repository at this point in the history
  • Loading branch information
alexdlaird committed Nov 3, 2024
2 parents aedf363 + 1674c6e commit 265dbec
Show file tree
Hide file tree
Showing 33 changed files with 27,028 additions and 164 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
FORCE_COLOR: 1
AMAZON_USERNAME: ${{ secrets.AMAZON_USERNAME }}
AMAZON_PASSWORD: ${{ secrets.AMAZON_PASSWORD }}
START_INDEX: ${{ vars.START_INDEX }}
START_INDEX_FULL_HISTORY: ${{ vars.START_INDEX_FULL_HISTORY }}
TWILIO_ACCOUNT_SID: ${{ secrets.TWILIO_ACCOUNT_SID }}
TWILIO_AUTH_TOKEN: ${{ secrets.TWILIO_AUTH_TOKEN }}
TWILIO_PHONE_NUMBER: ${{ secrets.TWILIO_PHONE_NUMBER }}
Expand Down
54 changes: 51 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,55 @@ All notable changes to this project will be documented in this file.

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased](https://github.com/alexdlaird/amazon-orders/compare/2.0.0...HEAD)
## [Unreleased](https://github.com/alexdlaird/amazon-orders/compare/3.0.0...HEAD)

## [3.0.0](https://github.com/alexdlaird/amazon-orders/compare/2.0.3...3.0.0) - 2024-11-03

### Added

- Retry support to CLI when stale session fails to authenticate the first time.
- Improvements to exception messages on auth failures.
- Documentation improvements.

### Fixed

- Several parsing issues with the implementation of Amazon's new `data-component` tag.

### Removed

- `Order.order_shipped_date`, this cannot be consistently parsed from Amazon.
- `Order.refund_completed_date`, this cannot be consistently parsed from Amazon.

## [2.0.3](https://github.com/alexdlaird/amazon-orders/compare/2.0.2...2.0.3) - 2024-11-01

### Added

- Further support for Amazon's new `data-component` tag on order price, seller, and return eligibility, and fixing an issue with `Shipment` parsing.
- [`Parsable.to_date()`](https://amazon-orders.readthedocs.io/api.html#amazonorders.entity.parsable.Parsable.to_date) attempts multiple date formats.

### Fixed

- An issue with `Shipment`s parsing with Amazon's new `data-component`.

## [2.0.2](https://github.com/alexdlaird/amazon-orders/compare/2.0.1...2.0.2) - 2024-10-30

### Added

- `item_class` to the config file, which allows for overriding the `Item` class.
- Support for Amazon's new `data-component` tag on order subtotals.
- Build and stability improvements.

### Fixed

- The return value of `Order._parse_recipient()` is now optional, so parsing doesn't break digital goods without a shipping address.
- Redundant order ID logic to parse from the URI, simplified to consistently fetch from page.
- Support for order details selector on Amazon's legacy digital orders page.

## [2.0.1](https://github.com/alexdlaird/amazon-orders/compare/2.0.0...2.0.1) - 2024-10-27

### Added

Build and stability improvements.

## [2.0.0](https://github.com/alexdlaird/amazon-orders/compare/1.1.4...2.0.0) - 2024-10-26

Expand All @@ -18,11 +66,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Changed

- Removed global constants in `amazonorders.constants`. Now `amazonorders.constants.Constants` and `amazonorders.selectors.Selectors` classes are used, can be overridden with `constants_class` and `selectors_class` in the config file.
- Removed global constants in `amazonorders.constants`. Now [`amazonorders.constants.Constants`](https://amazon-orders.readthedocs.io/api.html#amazonorders.constants.Constants) and [`amazonorders.selectors.Selectors`](https://amazon-orders.readthedocs.io/api.html#amazonorders.selectors.Selectors) classes are used, can be overridden with `constants_class` and `selectors_class` in the config file.

### Removed

- `session.AUTH_FORMS`. Pass `auth_forms` when instantiating `AmazonSession` instead.
- `session.AUTH_FORMS`. Pass [`auth_forms` when instantiating `AmazonSession`](https://amazon-orders.readthedocs.io/api.html#amazonorders.session.AmazonSession) instead.

## [1.1.4](https://github.com/alexdlaird/amazon-orders/compare/1.1.3...1.1.4) - 2024-06-07

Expand Down
4 changes: 2 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

| Version | Supported |
|---------|--------------------|
| 2.0.x | :white_check_mark: |
| < 2.0 | :x: |
| 3.0.x | :white_check_mark: |
| < 3.0 | :x: |

## Reporting a Vulnerability

Expand Down
2 changes: 1 addition & 1 deletion amazonorders/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__copyright__ = "Copyright (c) 2024 Alex Laird"
__license__ = "MIT"
__version__ = "2.0.0"
__version__ = "3.0.0"
55 changes: 34 additions & 21 deletions amazonorders/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from amazonorders import __version__, util
from amazonorders.conf import AmazonOrdersConfig
from amazonorders.entity.order import Order
from amazonorders.exception import AmazonOrdersError
from amazonorders.exception import AmazonOrdersError, AmazonOrdersAuthError
from amazonorders.orders import AmazonOrders
from amazonorders.session import AmazonSession, IODefault

Expand Down Expand Up @@ -291,21 +291,34 @@ def _print_banner() -> None:
click.echo(banner.format(version=__version__))


def _authenticate(amazon_session: AmazonSession) -> None:
if amazon_session.auth_cookies_stored():
if amazon_session.username or amazon_session.password:
click.echo(
"Info: The --username and --password flags are ignored because a previous session "
"still exists. If you would like to reauthenticate, call the `logout` command "
"first.\n")
else:
if not amazon_session.username:
amazon_session.username = click.prompt("Username")
if not amazon_session.password:
amazon_session.password = click.prompt("Password", hide_input=True)
click.echo("")

amazon_session.login()
def _authenticate(amazon_session: AmazonSession,
retries: int = 0) -> None:
try:
if amazon_session.auth_cookies_stored():
if amazon_session.username or amazon_session.password:
click.echo(
"Info: The --username and --password flags are ignored because a previous session "
"still exists. If you would like to reauthenticate, call the `logout` command "
"first.\n")
else:
if not amazon_session.username:
amazon_session.username = click.prompt("Username")
if not amazon_session.password:
amazon_session.password = click.prompt("Password", hide_input=True)
click.echo("")

amazon_session.login()
except AmazonOrdersAuthError as e:
if retries < 1:
if amazon_session.username:
click.echo(
f"Info: Authenticating '{amazon_session.username}' failed, retrying ...\n")

amazon_session.password = None

_authenticate(amazon_session, retries=retries + 1)
else:
raise e


def _order_output(order: Order) -> str:
Expand All @@ -318,7 +331,11 @@ def _order_output(order: Order) -> str:
order_str += f"\n Order Details Link: {order.order_details_link}"
order_str += f"\n Grand Total: ${order.grand_total:,.2f}"
order_str += f"\n Order Placed Date: {order.order_placed_date}"
order_str += f"\n {order.recipient}"
if order.recipient:
order_str += f"\n {order.recipient}"
else:
order_str += "\n Recipient: None"

if order.payment_method:
order_str += f"\n Payment Method: {order.payment_method}"
if order.payment_method_last_4:
Expand All @@ -335,10 +352,6 @@ def _order_output(order: Order) -> str:
order_str += f"\n Estimated Tax: ${order.estimated_tax:,.2f}"
if order.refund_total:
order_str += f"\n Refund Total: ${order.refund_total:,.2f}"
if order.order_shipped_date:
order_str += f"\n Order Shipped Date: {order.order_shipped_date}"
if order.refund_completed_date:
order_str += f"\n Refund Completed Date: {order.refund_completed_date}"

order_str += "\n-----------------------------------------------------------------------"

Expand Down
3 changes: 3 additions & 0 deletions amazonorders/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def __init__(self,
"selectors_class": "amazonorders.selectors.Selectors",
"order_class": "amazonorders.entity.order.Order",
"shipment_class": "amazonorders.entity.shipment.Shipment",
"item_class": "amazonorders.entity.item.Item",
}

if os.path.exists(self.config_path):
Expand Down Expand Up @@ -62,11 +63,13 @@ def __init__(self,
selectors_class_split = self.selectors_class.split(".")
order_class_split = self.order_class.split(".")
shipment_class_split = self.shipment_class.split(".")
item_class_split = self.item_class.split(".")

self.constants = util.load_class(constants_class_split[:-1], constants_class_split[-1])()
self.selectors = util.load_class(selectors_class_split[:-1], selectors_class_split[-1])()
self.order_cls = util.load_class(order_class_split[:-1], order_class_split[-1])
self.shipment_cls = util.load_class(shipment_class_split[:-1], shipment_class_split[-1])
self.item_cls = util.load_class(item_class_split[:-1], item_class_split[-1])

def __getattr__(self,
key: str) -> Any:
Expand Down
16 changes: 16 additions & 0 deletions amazonorders/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@


class Constants:
"""
A class containing useful constants. Extend and override with `constants_class` in the config:
.. code-block:: python
from amazonorders.conf import AmazonOrdersConfig
config = AmazonOrdersConfig(data={"constants_class": "my_module.MyConstants"})
"""

##########################################################################
# General URL
##########################################################################
Expand Down Expand Up @@ -62,3 +72,9 @@ class Constants:
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
}

##########################################################################
# Formats
##########################################################################

VALID_DATE_FORMATS = ["%b %d, %Y", "%B %d, %Y"]
11 changes: 6 additions & 5 deletions amazonorders/entity/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
__license__ = "MIT"

import logging
from datetime import date, datetime
from datetime import date
from typing import Optional, TypeVar

from bs4 import Tag
Expand Down Expand Up @@ -35,11 +35,11 @@ def __init__(self,
link=True, required=True)
#: The Item price.
self.price: Optional[float] = self.to_currency(
self.safe_simple_parse(selector=self.config.selectors.FIELD_ITEM_TAG_ITERATOR_SELECTOR,
self.safe_simple_parse(selector=self.config.selectors.FIELD_ITEM_PRICE_SELECTOR,
prefix_split="$"))
#: The Item Seller.
self.seller: Optional[Seller] = self.safe_simple_parse(
selector=self.config.selectors.FIELD_ITEM_TAG_ITERATOR_SELECTOR,
selector=self.config.selectors.FIELD_ITEM_SELLER_SELECTOR,
text_contains="Sold by:",
wrap_tag=Seller)
#: The Item condition.
Expand Down Expand Up @@ -69,14 +69,15 @@ def __lt__(self,
def _parse_return_eligible_date(self) -> Optional[date]:
value = None

for tag in util.select(self.parsed, self.config.selectors.FIELD_ITEM_TAG_ITERATOR_SELECTOR):
for tag in util.select(self.parsed, self.config.selectors.FIELD_ITEM_RETURN_SELECTOR):
if "Return" in tag.text:
tag_str = tag.text.strip()
split_str = "through "
if "closed on " in tag.text:
split_str = "closed on "
if split_str in tag_str:
date_str = tag_str.split(split_str)[1]
value = datetime.strptime(date_str, "%b %d, %Y").date()
value = self.to_date(date_str)
break

return value
Loading

0 comments on commit 265dbec

Please sign in to comment.