Skip to content

SDK audit (Nov 2026): validate required ID lists, detect required params defaulting to None - #48

Merged
amitray007 merged 3 commits into
masterfrom
claude/clever-sagan-1g8uj5
Nov 1, 2026
Merged

amitray007 merged 3 commits into
masterfrom
claude/clever-sagan-1g8uj5

Conversation

@amitray007

@amitray007 amitray007 commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

Audit result: 1 Must Fix, 0 Should Fix, 0 Informational. A follow-up code review widened the fix to the whole class of bug.

Run against specs/baseline.json (2026-10-23). The live spec and Etsy release notes couldn't be fetched from this environment (proxy 403), so this audit doesn't cover anything Etsy changed after that date. The baseline was not updated.

Fix

  • get_listings_by_shop_section_id: Etsy marks shop_section_ids as required, but the SDK defaulted it to None and sent the request without it. It's now a required argument.
  • New join_ids(name, ids) helper in common/Utils.py, used by all six methods that take a spec-required ID list: get_listings_by_shop_section_id, get_listings_by_listing_ids, get_listings_inventory_by_listing_ids, get_listings_shipping_by_listing_ids, get_payment_account_ledger_entry_payments and get_payments. It raises ValueError for an empty list (empty generators included) and TypeError for a string, which used to be split into characters ("111,222" became 1,1,1,,,2,2,2).
  • Behavior change: these methods now raise ValueError/TypeError locally for empty or string ID lists, instead of sending a request that Etsy rejects with a RequestException. This is documented in CLAUDE.md and the method docstring. Those calls never worked, so this ships as a patch.

Audit tooling

  • audit_sdk.py: param_drift has a new optional direction. It flags params the spec marks required but the SDK defaults to None, so /maintain-audit will catch this kind of bug next time. Run against master's Listing.py, it flags shop_section_ids.

Audit findings

  • Coverage is 100% (104/104 operations). No param, body or enum drift, no code issues.
  • All 20 audit-ignore.json suppressions re-checked against the code, and each reason still holds. No stale ignores.

Test plan

  • pytest: 495 passed
  • New tests: join_ids (lists, tuples, generators, empty, None, strings); every one of the six methods rejects bad ID lists without calling make_request; audit optional direction and none_defaults scan
  • python scripts/audit_sdk.py: clean on this branch, flags shop_section_ids on master's code
  • Re-run /maintain-audit somewhere that can reach etsy.com, to check against the live spec

🤖 Generated with Claude Code

https://claude.ai/code/session_01F8uubJkTpeiKDrKinRqZDy

Etsy marks shop_section_ids as required on getListingsByShopSectionId, but
the SDK defaulted it to None and silently sent the request without it,
which Etsy rejects. Make it a required argument so the mistake surfaces at
call time. Positional and keyword callers that already pass it are
unaffected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F8uubJkTpeiKDrKinRqZDy
Passing None or [] to get_listings_by_shop_section_id built an invalid
request (the literal "None" or an empty value). Raise ValueError instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F8uubJkTpeiKDrKinRqZDy
@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Test Coverage Report

Overall: 100% (1775/1775 statements covered)

Coverage by file
File Statements Missing Coverage
etsy_python/__init__.py 2 0 100%
etsy_python/_version.py 1 0 100%
etsy_python/v3/auth/OAuth.py 33 0 100%
etsy_python/v3/auth/__init__.py 1 0 100%
etsy_python/v3/common/Env.py 10 0 100%
etsy_python/v3/common/Request.py 3 0 100%
etsy_python/v3/common/Utils.py 41 0 100%
etsy_python/v3/enums/HolidayPreferences.py 29 0 100%
etsy_python/v3/enums/Language.py 12 0 100%
etsy_python/v3/enums/Listing.py 78 0 100%
etsy_python/v3/enums/ListingInventory.py 4 0 100%
etsy_python/v3/enums/ProcessingProfile.py 7 0 100%
etsy_python/v3/enums/ShippingProfile.py 261 0 100%
etsy_python/v3/enums/ShopReceipt.py 12 0 100%
etsy_python/v3/exceptions/BaseAPIException.py 10 0 100%
etsy_python/v3/exceptions/RequestException.py 8 0 100%
etsy_python/v3/exceptions/__init__.py 2 0 100%
etsy_python/v3/models/FileRequest.py 7 0 100%
etsy_python/v3/models/HolidayPreferences.py 8 0 100%
etsy_python/v3/models/Listing.py 201 0 100%
etsy_python/v3/models/Miscellaneous.py 8 0 100%
etsy_python/v3/models/ProcessingProfile.py 21 0 100%
etsy_python/v3/models/Product.py 7 0 100%
etsy_python/v3/models/Receipt.py 39 0 100%
etsy_python/v3/models/Request.py 22 0 100%
etsy_python/v3/models/ShippingProfile.py 85 0 100%
etsy_python/v3/models/Shop.py 24 0 100%
etsy_python/v3/models/ShopReturnPolicy.py 25 0 100%
etsy_python/v3/models/Utils.py 19 0 100%
etsy_python/v3/models/__init__.py 10 0 100%
etsy_python/v3/resources/HolidayPreferences.py 19 0 100%
etsy_python/v3/resources/Listing.py 102 0 100%
etsy_python/v3/resources/ListingFile.py 22 0 100%
etsy_python/v3/resources/ListingImage.py 22 0 100%
etsy_python/v3/resources/ListingInventory.py 25 0 100%
etsy_python/v3/resources/ListingOffering.py 12 0 100%
etsy_python/v3/resources/ListingProduct.py 12 0 100%
etsy_python/v3/resources/ListingTranslation.py 19 0 100%
etsy_python/v3/resources/ListingVariationImages.py 16 0 100%
etsy_python/v3/resources/ListingVideo.py 25 0 100%
etsy_python/v3/resources/Miscellaneous.py 16 0 100%
etsy_python/v3/resources/Payment.py 24 0 100%
etsy_python/v3/resources/PaymentLedgerEntry.py 15 0 100%
etsy_python/v3/resources/ProcessingProfile.py 26 0 100%
etsy_python/v3/resources/Receipt.py 25 0 100%
etsy_python/v3/resources/ReceiptTransactions.py 27 0 100%
etsy_python/v3/resources/Response.py 9 0 100%
etsy_python/v3/resources/Review.py 16 0 100%
etsy_python/v3/resources/Session.py 105 0 100%
etsy_python/v3/resources/ShippingProfile.py 58 0 100%
etsy_python/v3/resources/Shop.py 23 0 100%
etsy_python/v3/resources/ShopProductionPartner.py 11 0 100%
etsy_python/v3/resources/ShopReturnPolicy.py 28 0 100%
etsy_python/v3/resources/ShopSection.py 25 0 100%
etsy_python/v3/resources/Taxonomy.py 24 0 100%
etsy_python/v3/resources/User.py 14 0 100%
etsy_python/v3/resources/UserAddress.py 21 0 100%
etsy_python/v3/resources/__init__.py 29 0 100%
etsy_python/v3/resources/enums/RateLimit.py 8 0 100%
etsy_python/v3/resources/enums/Request.py 7 0 100%

Updated by PR Tests

@amitray007 amitray007 self-assigned this Nov 1, 2026
- Add join_ids(name, ids) in common/Utils.py: raises ValueError for an
  empty list (including an empty generator) and TypeError for a string,
  which previously got split into characters ("111,222" -> "1,1,1,,,2,2,2").
- Use it in all six methods with spec-required ID lists:
  get_listings_by_shop_section_id, get_listings_by_listing_ids,
  get_listings_inventory_by_listing_ids, get_listings_shipping_by_listing_ids,
  get_payment_account_ledger_entry_payments, get_payments.
- Behavior note: these methods now raise ValueError/TypeError locally for
  empty or string ID lists instead of sending a request Etsy rejects with
  a RequestException. Documented in CLAUDE.md and the method docstring.
- audit_sdk.py: param_drift gains an "optional" direction flagging params
  the spec marks required but the SDK defaults to None, so this class of
  bug is caught by /maintain-audit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F8uubJkTpeiKDrKinRqZDy
@amitray007 amitray007 changed the title SDK audit (Nov 2026): require shop_section_ids on get_listings_by_shop_section_id SDK audit (Nov 2026): validate required ID lists, detect required params defaulting to None Nov 1, 2026
@amitray007
amitray007 merged commit 30b7a19 into master Nov 1, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants