feat(ads): typed flags Title2/Mobile/VCard/Sitelinks/Turbo/AdExtensions (#202)#216
Conversation
…nsions (#202) Mirrors WSDL TextAdAdd/TextAdUpdate 1:1 so production ads can be created and updated from the CLI without falling back to the Direct web UI. The downstream yandex-direct-mcp-plugin needs these flags to ship picture-ad extensions, sitelinks, callouts, vCards and Turbo pages. ads add (TEXT_AD): --title2, --display-url-path, --mobile [YES|NO] (default NO), --vcard-id, --sitelink-set-id, --turbo-page-id, --ad-extensions. TEXT_IMAGE_AD also accepts --turbo-page-id (it's in the TextImageAdAdd WSDL type). ads update: same TEXT_AD subset minus --mobile (TextAdUpdate has no Mobile field) and --ad-extensions (TextAdUpdateBase exposes the complex CalloutSetting type instead of the AdExtensionIds array; out of scope here). All new flags route through the existing _reject_incompatible_flags guard, so attaching --title2 to TEXT_IMAGE_AD or --ad-extensions to MOBILE_APP_AD fails loudly via click.UsageError before the request is built. WSDL_FIELD_TO_CLI_OPTION gains entries for each new field. Closes #202 Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Found in code review: the previous guard masked an explicit ``--mobile NO`` on TEXT_IMAGE_AD/MOBILE_APP_AD because ``mobile_provided`` collapsed to None whenever the value happened to equal the default. That re-introduced the silent-data-loss class the WSDL parity gate is meant to prevent (#198 H2). Switch to ``ctx.get_parameter_source("mobile")`` so we react to user intent rather than value: explicit ``--mobile NO`` now raises UsageError on non- TEXT_AD subtypes, while omitting the flag still passes through unchanged (default Mobile: NO is filled into the TEXT_AD payload only). Two regression tests added: - test_ads_add_rejects_explicit_mobile_no_on_text_image_ad - test_ads_add_text_image_ad_default_mobile_does_not_leak Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
@claude review. Focus on critical issues: bugs, security vulnerabilities, logical errors, data loss risks, performance problems. Do NOT nitpick style, naming conventions, minor formatting, or subjective preferences — only flag issues that could break functionality or cause real harm in production. |
|
Claude finished @axisrow's task in 3m 47s —— View job Claude Code Review
Verdict: no critical issues foundI verified the load-bearing claims of the PR against the WSDL cache ( What I verified1. The
2. The WSDL 3. The "no
4. Pattern A empty-subtype guard still holds for 5. Minor observations (not blocking)
Test coverageThe 16 new dry-run tests in No bugs, no security concerns, no data-loss risks, no performance regressions. |
There was a problem hiding this comment.
Pull request overview
This PR extends the direct ads add / direct ads update commands with additional typed flags to reach closer WSDL parity for production-grade ad creation and updates (Title2, DisplayUrlPath, TurboPageId, etc.), and updates tests/docs accordingly.
Changes:
- Added new typed Click options for
ads add(including add-only--mobileand--ad-extensions) and forads update(Title2/DisplayUrlPath/VCardId/SitelinkSetId/TurboPageId). - Updated request-body construction and subtype incompatibility guarding to prevent silent data loss (notably around
--mobiledefaults). - Expanded dry-run / parity-gate / API coverage tests and refreshed README examples (EN/RU).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
direct_cli/commands/ads.py |
Adds new typed flags for ads add/update, extends subtype allow-lists, and maps flags into the WSDL-shaped payload. |
tests/test_dry_run.py |
Adds dry-run assertions and incompatibility-guard coverage for the new flags across ad subtypes. |
tests/test_wsdl_parity_gate.py |
Extends WSDL→CLI option mapping for the new ads fields. |
tests/api_coverage_payloads.py |
Extends payload cases to exercise the new ads flags in coverage gating. |
tests/test_cli.py |
Makes the help-text assertion resilient to Click’s line-wrapping. |
README.md |
Updates examples and documents add-only vs update-available flag scope (EN/RU). |
Comments suppressed due to low confidence (1)
direct_cli/commands/ads.py:577
- Same silent-drop issue for the new update flags:
if vcard_id:/if sitelink_set_id:/if turbo_page_id:will ignore an explicitly provided value of 0. Either enforce a positive range in the Click option types or useis not Nonechecks so that explicit values aren’t silently omitted.
if vcard_id:
text_ad["VCardId"] = vcard_id
if sitelink_set_id:
text_ad["SitelinkSetId"] = sitelink_set_id
if turbo_page_id:
text_ad["TurboPageId"] = turbo_page_id
| if vcard_id: | ||
| text_ad["VCardId"] = vcard_id | ||
| if sitelink_set_id: | ||
| text_ad["SitelinkSetId"] = sitelink_set_id | ||
| if turbo_page_id: | ||
| text_ad["TurboPageId"] = turbo_page_id |
|
Re: Copilot's truthy-vs- In The |
Click 8.1 writes ``No such option: --mobile`` while 8.2+ uses ``No such option '--mobile'``. Loosen the two ads-update unknown-flag assertions to match the stable substring across CI's 3.11 / 3.13 jobs. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Summary
direct ads addand 5 todirect ads update, mirroring WSDLTextAdAdd/TextAdUpdate/TextImageAdAdd/TextImageAdUpdate1:1. Downstreamyandex-direct-mcp-plugincan now create production ads with image extensions, sitelinks, callouts, vCards, Turbo pages, and second headlines without falling back to the Direct web UI._reject_incompatible_flagsguard; explicit--mobile NOon TEXT_IMAGE_AD/MOBILE_APP_AD now correctly fails viactx.get_parameter_source(no silent data loss).--mobileand--ad-extensionsareadd-only (TextAdUpdate has noMobile; TextAdUpdateBase uses the complexCalloutSettingtype, out of scope);--turbo-page-idapplies to both TEXT_AD and TEXT_IMAGE_AD.Test plan
pytest— 814 passed, 45 skipped, 0 failedpytest tests/test_dry_run.py -k "ads_add or ads_update"— 31 passed (16 new tests)pytest tests/test_wsdl_parity_gate.py— 46 passed (Patterns A/B/C/D hold)pytest tests/test_api_coverage.py— 158 passed (PAYLOAD_CASES extended)black+flake8on touched files — cleandirect ads add --type TEXT_AD ... --title2 ... --display-url-path ... --mobile YES --vcard-id ... --sitelink-set-id ... --turbo-page-id ... --ad-extensions "1,2" --dry-runemits all 11 fields underTextAddirect ads update --id N --type TEXT_AD --mobile YESrejected withNo such option: --mobiledirect ads add --type TEXT_IMAGE_AD ... --mobile NO --dry-runrejected (regression for the code-review finding)Closes #202
🤖 Generated with Claude Code