refactor: migrate criteria-limit ad-target get to make_get_command (part of #587)#597
Conversation
) dynamicads/smartadtargets/dynamicfeedadtargets get were three byte-identical hand-rolled bodies. Register them through the shared make_get_command factory instead, extending the factory with two generic optional params: - criteria_limits: forwarded to enforce_criteria_array_limits, command name derived as f"{group.name} get" (== the previous hardcoded strings). - require_criteria_message: the "provide at least one filter" empty-criteria guard (i18n key). Adds a shared ids_adgroup_campaign_states_criteria builder for the Ids/AdGroupIds/CampaignIds/States selection shape. Net -131 lines. Byte-identity preserved (verified against pre-migration baselines): --help, --dry-run payloads, over-limit and empty-criteria errors, and per-module create_client patchability are unchanged. Part of #587 (Group 3 / criteria-limits). Group 2 (nested *FieldNames) and the no---ids commands (bids/keywordbids/bidmodifiers) follow in a separate PR. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@claude @codex 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 2m 9s —— View job Review: PR #597 — criteria-limit
|
| Concern | Original | After migration | OK |
|---|---|---|---|
| Order: limits enforced before empty-criteria guard | enforce… then if not criteria |
_get.py:119-124 same order |
✅ |
| Error command name | hardcoded "dynamicads get" |
f"{svc} get", svc = group.name |
✅ |
| Client service call | client.dynamicads() |
getattr(client, svc)(), svc == group.name |
✅ |
Criteria shape (Ids/AdGroupIds/CampaignIds/States, key order) |
inline | ids_adgroup_campaign_states_criteria _get.py:44-61 |
✅ |
Empty --states → {"States": []} (truthy → guard not tripped) |
parse_csv_upper(states) or [] |
identical | ✅ |
--dry-run / fetch_all / extract paths |
inline | _get.py:130-149 |
✅ |
create_client patchability |
client_from_ctx |
resolve_module_create_client (lifecycle contract) |
✅ |
i18n: checked the one risk that could have bitten
Moving t("Provide at least one typed filter") out of the module and into _get.py (now t(require_criteria_message)) is safe — i18n._load_translations merges all translations/*.json into a single global _RU table keyed by source string (i18n.py:41-63). Lookup is not caller-module-scoped, so resolving the key from _get.py yields the same Russian string. The literal is still present in source and in translations/dynamicfeedadtargets.json, so it remains catalog-covered. No localization regression.
Minor observations (non-blocking, not introduced by this PR)
command_name=f"{svc} get"relies ongroup.name == client service attr name. True for all three modules here and asserted indirectly by the byte-identity snapshots, but it's now a structural assumption baked into the factory — worth a one-line note if a future resource ever has a group name that diverges from its API service name.- Passing
--stateswith only empty/whitespace tokens still emits{"States": []}and skips the "provide a filter" guard. This is pre-existing behavior, faithfully preserved — flagging only so it isn't mistaken for new.
Note
I couldn't execute pytest in this environment (commands required interactive approval), so I relied on static line-by-line comparison rather than a local run. The PR reports the offline suite green (2552 passed) including test_dry_run, test_api_coverage, test_comprehensive, and test_read_cassettes, and ruff clean — consistent with my read (no dead imports; t still used by the add/update bodies in each module).
Clean refactor, −131 lines, behavior preserved. 👍
• feat/587-group3-criteria-limits
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Non-blocking follow-up to the PR #597 review (Claude): svc = group.name now feeds both the client service call and the criteria_limits error prefix, so document the group-name-matches-service-name assumption inline. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What
Migrate
dynamicads get,smartadtargets getanddynamicfeedadtargets get— three byte-for-byte identical hand-rolled command bodies — onto the sharedmake_get_commandfactory (direct_cli/commands/_get.py), following the dedup epic #584 / factory introduced in #582.Net −131 lines (91 added, 222 removed).
Factory extension (two generic optional params)
criteria_limits—{SelectionCriteria key: max count}dict, forwarded to the existingenforce_criteria_array_limitsutil. Command name for the error is derived asf"{group.name} get"(== the previous hardcoded"dynamicads get"etc.).require_criteria_message— i18n key; an emptySelectionCriteriaraisesUsageErrorwith this message (the "provide at least one filter" guard).ids_adgroup_campaign_states_criteriabuilder for theIds/AdGroupIds/CampaignIds/Statesselection shape (composes on the existing_default_ids_criteria).Both new params default to
None, so the 5 existing factory callers (advideos/businesses/turbopages/vcards/negativekeywordsharedsets) are untouched.Byte-identity (hard invariant of #587)
Verified each command against pre-migration baselines — all 15 snapshots identical:
--help(option order, i18n keys)--dry-runpayload (typed-flags + states)CampaignIdscap)create_clientpatchability (viaresolve_module_create_client)Tests
test_dry_run,test_api_coverage,test_comprehensive,test_read_cassettesincluded.ruff checkclean (dead imports from the removedgetbodies dropped).Scope
Part of #587 — Group 3 (criteria-limits commands). The remaining work follows in a separate PR:
*FieldNames): adextensions, adimages, leads, retargeting, sitelinks, feeds, clients, agencyclients.--ids/ nested-field hybrids:bids,keywordbids,bidmodifiers(need factory support for omitting the mandatory--idsand/ornested_field_options).reports getis intentionally excluded (custom TSV-stream endpoint, not a SOAPget).🤖 Generated with Claude Code