Skip to content

feat(amazon): expose item names and product image per in-transit order - #1362

Open
paul43210 wants to merge 1 commit into
moralmunky:devfrom
paul43210:feat/amazon-order-details
Open

feat(amazon): expose item names and product image per in-transit order#1362
paul43210 wants to merge 1 commit into
moralmunky:devfrom
paul43210:feat/amazon-order-details

Conversation

@paul43210

Copy link
Copy Markdown

Why

The Amazon Packages sensor tells you how many parcels are in transit and their order numbers, but not what is coming. The shipping emails already carry both pieces — the plain-text part lists the full item names, and the text/html part carries a product thumbnail — so the information is present and simply discarded during parsing. This surfaces it as a new order_details attribute so a dashboard can show item names and images instead of bare order numbers.

Design

  • utils/amazon.py: get_html_body() (mirrors the existing get_email_body() for the HTML part) and extract_amazon_order_details(subject, body, msg), which returns {"name": ..., "image": ...} or None.
    • Item names come from the plain-text item lines. The quoted subject (Shipped: "Item name,...") is used as a fallback only, since it is truncated.
    • The image is the product thumbnail from the HTML part, restricted to m.media-amazon.com/images/I/. Nothing is downloaded — the URL is passed through as-is.
    • Returns None when neither is extractable, so non-shipping emails add nothing.
  • shippers/amazon.py: details are collected per shipped order during the existing pass. A new "details" parse mode returns them for exactly the same undelivered-order set the order attribute already uses, so the two attributes cannot disagree.
  • sensor.py: exposed as order_details next to the existing order attribute, keyed by order number: {order_id: {"name": ..., "image": ...}}. Only set when non-empty, so sensors without details are unchanged.
  • No new config options, no new sensors, no network calls. Existing attributes are untouched.

Tests

  • Sanitized real shipping email fixture (amazon_shipped_details.eml), including the HTML part with the product image.
  • Unit tests for extract_amazon_order_details: body extraction, the truncated-subject fallback, and a non-match guard returning None.
  • End-to-end shipper test through AmazonShipper.process() with only IMAP mocked, asserting the details map is keyed by order number and that an order arriving later is still not counted as arriving today.

Full suite passes (708 tests, coverage 99.86%), ruff check + format clean. Rebased on current dev as of today.

Running live on my instance since 2026-07-20 — names and images render correctly on a real dashboard.

Happy to adjust: the image could be omitted entirely if you'd rather not carry a third-party URL in an attribute, and the details map could be limited to amazon_packages only if exposing it more widely is a concern.

🤖 Generated with Claude Code

Shipping emails already contain the full item names (plain-text item
lines, with the truncated quoted subject as fallback) and a product
thumbnail URL (text/html part). Extract them into a new
order_details attribute on the Amazon Packages sensor, keyed by order
number: {order_id: {"name": ..., "image": ...}}.

- utils/amazon.py: get_html_body + extract_amazon_order_details
- shippers/amazon.py: collect details per shipped order during
  processing; new "details" parse mode returns them for the same
  undelivered-order set as the order attribute
- sensor.py: expose as order_details next to the existing order attr
- Fixture (sanitized real email incl. product image) + utils and
  end-to-end shipper tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M4JNtf2gPw1jGNjtFy16HF
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 93.87755% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 99.85%. Comparing base (8608d22) to head (aa57e6d).
⚠️ Report is 216 commits behind head on dev.

Files with missing lines Patch % Lines
...ustom_components/mail_and_packages/utils/amazon.py 93.33% 2 Missing ⚠️
custom_components/mail_and_packages/sensor.py 80.00% 1 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##              dev    #1362      +/-   ##
==========================================
+ Coverage   95.07%   99.85%   +4.78%     
==========================================
  Files           8       25      +17     
  Lines        1482     4223    +2741     
==========================================
+ Hits         1409     4217    +2808     
+ Misses         73        6      -67     
Flag Coverage Δ
python 99.85% <93.87%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
custom_components/mail_and_packages/const.py 100.00% <100.00%> (ø)
...om_components/mail_and_packages/shippers/amazon.py 100.00% <100.00%> (ø)
custom_components/mail_and_packages/sensor.py 99.36% <80.00%> (+6.74%) ⬆️
...ustom_components/mail_and_packages/utils/amazon.py 97.92% <93.33%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@firstof9 firstof9 added the feature New feature or request label Aug 9, 2026
@secondof9

This comment was marked as low quality.

@firstof9 firstof9 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please get tests to cover all patch changes.
Thanks.

@secondof9 secondof9 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Review Summary

Tip

Review Status: 🟢 APPROVED
Change Type: 🛠️ Refactor (feat)
Review Effort: 🟢 Low
Core Impact: Adds order_details (item name + product image URL) to Amazon in-transit order attributes, surfaced from shipping emails' plain-text item lines and HTML thumbnail — no new sensors, no network calls, fully backward-compatible.


🚦 CI & Pipeline Health Summary

Check / Workflow Name Status Impact on Review
coverage ✅ PASSED Clean — 708 tests, 99.86% coverage
main ✅ PASSED Baseline build ok
Pre-commit checks ✅ PASSED ruff + format + pre-commit clean
Python 3.14 ✅ PASSED No Python 3.14 regressions
Validate ✅ PASSED Validation passes
Autolabel PR ⏩ SKIPPED Not applicable

Note

CI Pipeline Clear: All GitHub Actions workflows completed successfully.


🔍 Architectural Walkthrough

utils/amazon.py — New: `get_html_body()` + `extract_amazon_order_details()`
  • path/to/utils/amazon.py
    • get_html_body(msg) (line 152) — Extracts the text/html body part via msg.walk() with graceful error handling (ValueError, TypeError, AttributeError caught, logged as DEBUG). Returns empty string on failure — safe fallback. Good defensive practice.
    • AMAZON_PRODUCT_IMG_REGEX (line 160) — Matches m.media-amazon.com/images/I/ and images-amazon.com/images/I/ URLs. Restrictive pattern; won't match arbitrary image URLs. Safe.
    • AMAZON_ITEM_LINE_REGEX (line 162) — ^\* (.+)$ with re.MULTILINE. Matches Amazon's * item name format. Good.
    • AMAZON_SHIPPED_SUBJECT_REGEX (line 164) — Pattern "(.+?)" (with unicode smart quotes). Used as fallback for truncated subject line. Good fallback logic.
    • extract_amazon_order_details(subject, body, msg) (line 169) — Returns dict[str, str] | None. Prefers plain-text item lines, falls back to subject. Only returns details when at least one signal is present (defensive). No network calls, no downloading. Fully safe.
shippers/amazon.py — Two-pass email parsing with details aggregation
  • path/to/shippers/amazon.py
    • process() (line 118) — Now calls _parse_amazon_emails() twice (parallel, same email set): once for "order", once for "details". This is the core of the new feature. The details result is keyed by order ID and returned alongside the existing order list.
    • _parse_amazon_emails() (line 219) — New "order_details" key initialized to {} in context. details branch (line 249) returns an order_id -> details mapping. Clean separation.
    • _process_amazon_email() (line 287) — Passes msg through to _handle_shipping_email() — this is the key change that enables HTML body extraction. Good threading of the message object.
    • _handle_shipping_email() (line 319) — New msg parameter. extract_amazon_order_details() is called here with msg so it can access the HTML part. Defensive: only processes details if msg is provided. Good.
    • Tuple unpacking cleanup (lines 427, 604, 648, 685) — (server_response, data) = await email_search(...) refactored to server_response, data = await email_search(...). This is a code-style improvement but functionally equivalent. Minor.
sensor.py — Exposing order_details as sensor attribute
  • path/to/sensor.py
    • _add_amazon_order_attributes() (line 179) — New helper that attaches AMAZON_ORDER_DETAILS to sensor attributes alongside AMAZON_ORDER. Only set when details is non-empty. Backward-compatible: sensors without details are unchanged.
    • _add_amazon_attributes() (line 195) — Calls _add_amazon_order_attributes when an order is present. Clean integration.
const.py — New constants
  • path/to/const.py
    • ATTR_ORDER_DETAILS = "order_details" (line 30) — Attribute name for sensor.
    • AMAZON_ORDER_DETAILS = "amazon_order_details" (line 196) — Shipper result key. Consistent naming convention.
tests/ — Comprehensive new test coverage
  • path/to/tests/utils/test_amazon.py (line 484) — Unit tests for extract_amazon_order_details: main path (name + image), subject fallback, nothing-extractable guard. All three cases covered.
  • path/to/tests/shippers/test_amazon.py (line 1352) — Integration test via AmazonShipper.process(): validates that order details are keyed by order number, name extraction works, image URL starts with expected prefix. Uses real sanitized EML fixture.
  • path/to/tests/test_emails/amazon_shipped_details.eml — Real sanitized shipping email with both plain-text item lines and HTML thumbnail. Good test fixture.

🚨 Critical / ⚠️ Warning Issues

No critical issues found. The code is clean, defensive, and well-tested. All CI checks pass. The implementation correctly follows HA core patterns: no blocking I/O, no new config options, no network calls, proper type hints, and clean separation of concerns.

@github-actions

Copy link
Copy Markdown

This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@github-actions github-actions Bot added the no-pr-activity Stale PR label Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request no-pr-activity Stale PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants