direct-cli 0.4.1__tar.gz → 0.4.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {direct_cli-0.4.1 → direct_cli-0.4.3}/CHANGELOG.md +258 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/CLAUDE.md +3 -3
- {direct_cli-0.4.1 → direct_cli-0.4.3}/PKG-INFO +45 -22
- {direct_cli-0.4.1 → direct_cli-0.4.3}/README.md +44 -21
- direct_cli-0.4.3/direct_cli/_autotargeting.py +206 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_bidding_strategy.py +876 -882
- direct_cli-0.4.3/direct_cli/_flag_validation.py +53 -0
- direct_cli-0.4.3/direct_cli/_smoke_probes.py +173 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +12 -4
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +1 -1
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +4 -2
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/api.py +23 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/auth.py +179 -68
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/cli.py +10 -1
- direct_cli-0.4.3/direct_cli/commands/_batch.py +181 -0
- direct_cli-0.4.3/direct_cli/commands/_lifecycle.py +99 -0
- direct_cli-0.4.3/direct_cli/commands/adextensions.py +124 -0
- direct_cli-0.4.3/direct_cli/commands/adgroups.py +2092 -0
- direct_cli-0.4.3/direct_cli/commands/adimages.py +122 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/ads.py +1654 -1058
- direct_cli-0.4.3/direct_cli/commands/advideos.py +96 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/agencyclients.py +150 -207
- direct_cli-0.4.3/direct_cli/commands/audiencetargets.py +210 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/auth.py +139 -7
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/balance.py +12 -25
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/bidmodifiers.py +169 -248
- direct_cli-0.4.3/direct_cli/commands/bids.py +226 -0
- direct_cli-0.4.3/direct_cli/commands/businesses.py +57 -0
- direct_cli-0.4.3/direct_cli/commands/campaigns.py +7207 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/changes.py +30 -49
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/clients.py +93 -126
- direct_cli-0.4.3/direct_cli/commands/creatives.py +150 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/dictionaries.py +26 -42
- direct_cli-0.4.3/direct_cli/commands/dynamicads.py +203 -0
- direct_cli-0.4.3/direct_cli/commands/dynamicfeedadtargets.py +192 -0
- direct_cli-0.4.3/direct_cli/commands/feeds.py +404 -0
- direct_cli-0.4.3/direct_cli/commands/keywordbids.py +316 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/keywords.py +181 -514
- direct_cli-0.4.3/direct_cli/commands/keywordsresearch.py +68 -0
- direct_cli-0.4.3/direct_cli/commands/leads.py +80 -0
- direct_cli-0.4.3/direct_cli/commands/negativekeywordsharedsets.py +130 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/reports.py +63 -67
- direct_cli-0.4.3/direct_cli/commands/retargeting.py +216 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/sitelinks.py +67 -105
- direct_cli-0.4.3/direct_cli/commands/smartadtargets.py +296 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/strategies.py +195 -289
- direct_cli-0.4.3/direct_cli/commands/turbopages.py +67 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/v4account.py +6 -77
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/v4adimage.py +6 -44
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/v4events.py +6 -31
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/v4finance.py +38 -136
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/v4forecast.py +12 -84
- direct_cli-0.4.3/direct_cli/commands/v4goals.py +47 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/v4keywords.py +6 -30
- direct_cli-0.4.3/direct_cli/commands/v4shells.py +54 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/v4tags.py +10 -78
- direct_cli-0.4.3/direct_cli/commands/v4wordstat.py +90 -0
- direct_cli-0.4.3/direct_cli/commands/vcards.py +247 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/output.py +34 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/smoke_matrix.py +4 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/adgroups.json +42 -2
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/ads.json +40 -3
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/audiencetargets.json +2 -1
- direct_cli-0.4.3/direct_cli/translations/auth.json +25 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/common.json +4 -3
- direct_cli-0.4.3/direct_cli/translations/v4shells.json +7 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/utils.py +166 -6
- direct_cli-0.4.3/direct_cli/v4/emit.py +79 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/v4/money.py +8 -27
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli.egg-info/PKG-INFO +45 -22
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli.egg-info/SOURCES.txt +21 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/pyproject.toml +1 -1
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/build_api_coverage_report.py +11 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/check_all_docs_urls.py +30 -13
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/patch_vendor_imports.py +109 -2
- direct_cli-0.4.3/tests/MANUAL_COVERAGE.md +147 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/WSDL_OPTIONAL_FIELD_AUDIT.md +3 -3
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/api_coverage_payloads.py +5 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[creatives_get].yaml +2 -2
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[retargeting_get].yaml +2 -2
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[strategies_get].yaml +2 -2
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_ads_add_update_delete.yaml +64 -64
- direct_cli-0.4.3/tests/cassettes/test_v5_live_write/test_v5_live_draft_audiencetargets_add_delete.yaml +560 -0
- direct_cli-0.4.3/tests/cassettes/test_v5_live_write/test_v5_live_draft_audiencetargets_suspend_resume.yaml +622 -0
- direct_cli-0.4.3/tests/cassettes/test_v5_live_write/test_v5_live_draft_feeds_add_update_delete.yaml +250 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywords_add_update_delete.yaml +122 -60
- direct_cli-0.4.1/tests/cassettes/test_v5_live_write/test_v5_live_draft_audiencetargets_suspend_resume.yaml → direct_cli-0.4.3/tests/cassettes/test_v5_live_write/test_v5_live_draft_retargeting_add_update_delete.yaml +40 -103
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_smartadtargets_add_update_delete.yaml +24 -24
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_smartadtargets_suspend_resume.yaml +24 -24
- direct_cli-0.4.1/tests/cassettes/test_v5_live_write/test_v5_live_draft_audiencetargets_add_delete.yaml → direct_cli-0.4.3/tests/cassettes/test_v5_live_write/test_v5_live_draft_strategies_add_update_archive_unarchive.yaml +49 -50
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/conftest.py +77 -6
- direct_cli-0.4.3/tests/test_adgroups_build_adgroup_object.py +215 -0
- direct_cli-0.4.3/tests/test_adgroups_build_adgroup_update_object.py +129 -0
- direct_cli-0.4.3/tests/test_ads_build_ad_object.py +201 -0
- direct_cli-0.4.3/tests/test_ads_build_ad_update_object.py +163 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_audit_wire_shape.py +37 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_auth_bw.py +30 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_auth_oauth.py +293 -5
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_auth_op.py +30 -0
- direct_cli-0.4.3/tests/test_autotargeting.py +228 -0
- direct_cli-0.4.3/tests/test_bidding_strategy_constants.py +197 -0
- direct_cli-0.4.3/tests/test_cassette_integrity.py +87 -0
- direct_cli-0.4.3/tests/test_check_all_docs_urls.py +16 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_cli.py +6 -2
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_dry_run.py +1858 -20
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_env_loading.py +54 -0
- direct_cli-0.4.3/tests/test_field_names_option.py +85 -0
- direct_cli-0.4.3/tests/test_flag_validation.py +130 -0
- direct_cli-0.4.3/tests/test_handle_api_errors.py +101 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_integration.py +87 -14
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_low_coverage_payloads.py +71 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_read_cassettes.py +6 -2
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_transport_contract.py +20 -10
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4_exit_codes.py +9 -9
- direct_cli-0.4.3/tests/test_v4_output_options.py +134 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4account.py +26 -26
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4adimage.py +2 -2
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4events.py +4 -4
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4finance_money.py +42 -10
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4finance_read.py +9 -9
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4forecast.py +6 -6
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4goals.py +6 -6
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4keywords.py +2 -2
- direct_cli-0.4.3/tests/test_v4meta.py +71 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4tags.py +4 -4
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4wordstat.py +7 -7
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v5_live_write.py +218 -7
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_vendor_imports.py +119 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_wsdl_parity_gate.py +62 -9
- direct_cli-0.4.1/direct_cli/_smoke_probes.py +0 -94
- direct_cli-0.4.1/direct_cli/commands/adextensions.py +0 -164
- direct_cli-0.4.1/direct_cli/commands/adgroups.py +0 -1392
- direct_cli-0.4.1/direct_cli/commands/adimages.py +0 -158
- direct_cli-0.4.1/direct_cli/commands/advideos.py +0 -119
- direct_cli-0.4.1/direct_cli/commands/audiencetargets.py +0 -306
- direct_cli-0.4.1/direct_cli/commands/bids.py +0 -262
- direct_cli-0.4.1/direct_cli/commands/businesses.py +0 -67
- direct_cli-0.4.1/direct_cli/commands/campaigns.py +0 -7610
- direct_cli-0.4.1/direct_cli/commands/creatives.py +0 -173
- direct_cli-0.4.1/direct_cli/commands/dynamicads.py +0 -296
- direct_cli-0.4.1/direct_cli/commands/dynamicfeedadtargets.py +0 -299
- direct_cli-0.4.1/direct_cli/commands/feeds.py +0 -457
- direct_cli-0.4.1/direct_cli/commands/keywordbids.py +0 -331
- direct_cli-0.4.1/direct_cli/commands/keywordsresearch.py +0 -88
- direct_cli-0.4.1/direct_cli/commands/leads.py +0 -84
- direct_cli-0.4.1/direct_cli/commands/negativekeywordsharedsets.py +0 -180
- direct_cli-0.4.1/direct_cli/commands/retargeting.py +0 -244
- direct_cli-0.4.1/direct_cli/commands/smartadtargets.py +0 -397
- direct_cli-0.4.1/direct_cli/commands/turbopages.py +0 -79
- direct_cli-0.4.1/direct_cli/commands/v4goals.py +0 -106
- direct_cli-0.4.1/direct_cli/commands/v4shells.py +0 -20
- direct_cli-0.4.1/direct_cli/commands/v4wordstat.py +0 -160
- direct_cli-0.4.1/direct_cli/commands/vcards.py +0 -289
- direct_cli-0.4.1/direct_cli/translations/auth.json +0 -23
- direct_cli-0.4.1/direct_cli/translations/v4shells.json +0 -3
- direct_cli-0.4.1/tests/MANUAL_COVERAGE.md +0 -92
- {direct_cli-0.4.1 → direct_cli-0.4.3}/.env.example +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/.github/copilot-instructions.md +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/.github/workflows/api-coverage.yml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/.github/workflows/claude.yml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/.github/workflows/quality.yml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/.gitignore +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/AGENTS.md +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/MANIFEST.in +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/__init__.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_deprecated.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_vendor/__init__.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_vendor/tapi_yandex_direct/endpoints.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/commands/__init__.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/i18n.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/reports_coverage.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/adextensions.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/adimages.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/advideos.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/agencyclients.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/balance.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/bidmodifiers.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/bids.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/businesses.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/campaigns.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/changes.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/clients.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/creatives.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/dictionaries.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/dynamicads.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/dynamicfeedadtargets.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/feeds.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/keywordbids.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/keywords.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/keywordsresearch.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/leads.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/negativekeywordsharedsets.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/reports.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/retargeting.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/sitelinks.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/smartadtargets.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/strategies.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/turbopages.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/v4account.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/v4adimage.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/v4events.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/v4finance.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/v4forecast.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/v4goals.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/v4keywords.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/v4tags.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/v4wordstat.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/translations/vcards.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/v4/__init__.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/v4_contracts.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli/wsdl_coverage.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli.egg-info/dependency_links.txt +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli.egg-info/entry_points.txt +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli.egg-info/requires.txt +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/direct_cli.egg-info/top_level.txt +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/docs/audits/API_COVERAGE.md +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/docs/audits/PROJECT_WIRE_SHAPE_AUDIT_2026-05-30.md +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/docs/audits/WIRE_SHAPE_TRIAGE_2026-05-30.md +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/docs/audits/issue-198-mutating-wsdl-audit.md +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/docs/audits/wire_shape.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/anonymize_cassettes.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/audit_wire_shape.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/build_api_coverage_checklist.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/build_wsdl_optional_field_audit.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/check_reports_drift.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/check_wsdl_drift.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/preflight_check.sh +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/probe_drift_urls.sh +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/refresh_reports_cache.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/refresh_wsdl_cache.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/release_pypi.sh +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/sandbox_write_audit.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/sandbox_write_live.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/test_dangerous_commands.sh +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/test_safe_commands.sh +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/test_sandbox_write.sh +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/scripts/update_vendor.sh +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/setup.cfg +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/setup.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/API_COVERAGE.md +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/API_ISSUE_AUDIT.md +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/__init__.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/_orphan_store.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteBidsRead.test_bids_get.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteBidsRead.test_bids_set_auto.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteRetargetingUpdate.test_retargeting_update.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteStrategies.test_strategies_lifecycle.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[adextensions_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[adgroups_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[adimages_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[ads_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[advideos_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[audiencetargets_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[bidmodifiers_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[bids_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[businesses_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[campaigns_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[changes_check].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[changes_check_campaigns].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[changes_check_dictionaries].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[clients_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[dictionaries_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[dynamicads_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[dynamicfeedadtargets_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[feeds_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[keywordbids_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[keywords_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[keywordsresearch_deduplicate].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[keywordsresearch_has_search_volume].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[leads_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[negativekeywordsharedsets_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[reports_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[sitelinks_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[smartadtargets_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[turbopages_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[v4events_get_events_log].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[v4finance_get_clients_units].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[v4forecast_list].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[v4goals_get_stat_goals].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[v4tags_get_campaigns].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[v4wordstat_list_reports].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_read_command[vcards_get].yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_read_cassettes/test_v4finance_check_payment_unknown_transaction.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_adgroups_add_update_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_adimages_add_get_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_ads_suspend_resume_archive_unarchive.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_advideos_add_get.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_bids_set.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_campaign_create_get_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_creatives_chain_advideo_to_creative.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_dynamicads_add_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_dynamicads_suspend_resume.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywordbids_set.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywords_suspend_resume.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/cassettes/test_v5_live_write/test_v5_live_draft_sitelinks_add_get_delete.yaml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/fixtures/test-video.mp4 +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/reports_cache/raw/fields-list.html +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/reports_cache/raw/headers.html +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/reports_cache/raw/period.html +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/reports_cache/raw/spec.html +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/reports_cache/raw/type.html +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/reports_cache/spec.json +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_api_coverage.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_auth_write_json.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_balance.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_changes.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_cli_contract.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_comprehensive.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_i18n.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_integration_write.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_reports_drift.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_reports_parsing.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_sandbox_write_audit.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_smoke_matrix.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_unknown_option_hints.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4_contracts.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4_foundation.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4_live_contracts.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4_runtime_shape.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/test_v4_safety.py +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/adextensions.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/adgroups.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/adimages.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/ads.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/advideos.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/agencyclients.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/audiencetargets.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/bidmodifiers.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/bids.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/businesses.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/campaigns.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/changes.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/clients.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/creatives.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/dictionaries.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/feeds.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/imports/adextensiontypes.xsd +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/imports/general.xsd +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/imports/generalclients.xsd +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/keywordbids.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/keywords.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/keywordsresearch.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/leads.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/retargetinglists.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/sitelinks.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/smartadtargets.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/strategies.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/turbopages.xml +0 -0
- {direct_cli-0.4.1 → direct_cli-0.4.3}/tests/wsdl_cache/vcards.xml +0 -0
|
@@ -1,5 +1,263 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.3
|
|
4
|
+
|
|
5
|
+
**Features — batch `ads add` via `--from-file` / `--ads-json` (#562, #558 follow-up):**
|
|
6
|
+
|
|
7
|
+
- `ads add` now accepts a batch of flag-form ad rows from a JSONL file
|
|
8
|
+
(`--from-file`) or an inline JSON array (`--ads-json`); each row is the same
|
|
9
|
+
flag set keyed by the kebab flag name without the leading dashes (e.g.
|
|
10
|
+
`{"type":"TEXT_AD","title":"...","text":"...","href":"...","adgroup-id":1}`).
|
|
11
|
+
`--adgroup-id` becomes the batch default and may be overridden per row. Single
|
|
12
|
+
typed-flag mode is unchanged.
|
|
13
|
+
- The ~400-line flag→object logic of `ads add` was extracted into a reusable,
|
|
14
|
+
ctx-free `build_ad_object()` so the single-flag command and the batch
|
|
15
|
+
normalizer emit byte-identical ad objects (golden-tested across every
|
|
16
|
+
subtype).
|
|
17
|
+
- New shared `direct_cli/commands/_batch.py` engine (JSONL/inline loading,
|
|
18
|
+
chunking, per-chunk send with partial-success reporting, dry-run preview,
|
|
19
|
+
`add`/`update`-aware result key). `keywords add` was migrated onto it with no
|
|
20
|
+
behavior change (its existing batch suite is the proof).
|
|
21
|
+
- Chunk size `ADS_ADD_MAX_BATCH = 100` (conservative chunk, not the 1000-object
|
|
22
|
+
API ceiling — a partial failure rolls back at most 100 ads).
|
|
23
|
+
|
|
24
|
+
**Features — batch `ads update` via `--from-file` / `--ads-json` (#563, #558 follow-up):**
|
|
25
|
+
|
|
26
|
+
- `ads update` now accepts a batch of flag-form ad-update rows from a JSONL file
|
|
27
|
+
(`--from-file`) or an inline JSON array (`--ads-json`); each row is the same
|
|
28
|
+
flag set keyed by the kebab flag name without the leading dashes plus its own
|
|
29
|
+
`id` and `type` (e.g. `{"id":5,"type":"TEXT_AD","title":"New"}`). The
|
|
30
|
+
`--clear-image-hash` mechanic works per row as a JSON boolean. Single
|
|
31
|
+
typed-flag mode is unchanged.
|
|
32
|
+
- The subtype-dispatch body of `ads update` (type validation, the
|
|
33
|
+
incompatible-flag / "does not convert between subtypes" guard, per-subtype
|
|
34
|
+
assembly, and the empty-subtype no-op guard) was extracted into a reusable,
|
|
35
|
+
ctx-free `build_ad_update_object()` so the single-flag command and the batch
|
|
36
|
+
normalizer emit byte-identical ad-update objects (golden-tested across every
|
|
37
|
+
subtype). Reuses the shared `_batch.py` engine with `method="update"` /
|
|
38
|
+
`result_key="UpdateResults"`.
|
|
39
|
+
- `--id` and `--type` become per-row in batch mode (each row carries its own);
|
|
40
|
+
single-item mode still requires both. The per-row normalizer reproduces the
|
|
41
|
+
command's `--id`/`--type` required checks, the `--image-hash` /
|
|
42
|
+
`--clear-image-hash` mutex, and the same Click-type coercion as the single
|
|
43
|
+
path (a JSON float `id` is rejected, not truncated).
|
|
44
|
+
|
|
45
|
+
**Features — batch `adgroups add` via `--from-file` / `--adgroups-json` (#564, #558 follow-up):**
|
|
46
|
+
|
|
47
|
+
- `adgroups add` now accepts a batch of flag-form ad-group rows from a JSONL
|
|
48
|
+
file (`--from-file`) or an inline JSON array (`--adgroups-json`); each row is
|
|
49
|
+
the same flag set keyed by the kebab flag name without the leading dashes
|
|
50
|
+
(e.g. `{"name":"G","campaign-id":12,"region-ids":"225","type":"TEXT_AD_GROUP"}`).
|
|
51
|
+
`--campaign-id` becomes the batch default and may be overridden per row.
|
|
52
|
+
Single typed-flag mode is unchanged.
|
|
53
|
+
- The flag→object logic of `adgroups add` (type validation, the
|
|
54
|
+
incompatible-flag guard, the negative-keyword compatibility check, region IDs,
|
|
55
|
+
and per-subtype assembly) was extracted into a reusable, ctx-free
|
|
56
|
+
`build_adgroup_object()` so the single-flag command and the batch normalizer
|
|
57
|
+
emit byte-identical ad-group objects (golden-tested across every subtype).
|
|
58
|
+
`--name` / `--campaign-id` / `--region-ids` become per-row in batch mode;
|
|
59
|
+
single-item mode still requires them (parity-gate `INTERNAL_VALIDATION`
|
|
60
|
+
entries). Per-row coercion runs every typed field through its single-flag
|
|
61
|
+
Click type (a JSON float `campaign-id` is rejected, not truncated).
|
|
62
|
+
- The shared `_batch.send_batch` gained an optional `post` callable so
|
|
63
|
+
`adgroups` keeps its endpoint routing: a `UnifiedAdGroup` payload must use API
|
|
64
|
+
v501 (`_post_adgroups`). Because that routing keys off the whole body, a batch
|
|
65
|
+
may **not** mix `UNIFIED_AD_GROUP` with other ad-group types — the CLI refuses
|
|
66
|
+
the mix up front with a clear `UsageError` rather than send non-unified groups
|
|
67
|
+
to the v501 endpoint.
|
|
68
|
+
|
|
69
|
+
**Features — batch `adgroups update` via `--from-file` / `--adgroups-json` (#565, #558 follow-up):**
|
|
70
|
+
|
|
71
|
+
- `adgroups update` now accepts a batch of flag-form ad-group-update rows from a
|
|
72
|
+
JSONL file (`--from-file`) or an inline JSON array (`--adgroups-json`); each
|
|
73
|
+
row is the same flag set keyed by the kebab flag name without the leading
|
|
74
|
+
dashes plus its own `id` (e.g. `{"id":5,"name":"New"}`). The `--dynamic-feed`
|
|
75
|
+
routing works per row as a JSON boolean. Single typed-flag mode is unchanged.
|
|
76
|
+
- The subtype-dispatch body of `adgroups update` (the mixed-subtype reject
|
|
77
|
+
guard, per-subtype assembly, the `--dynamic-feed` DynamicTextAdGroup ↔
|
|
78
|
+
DynamicTextFeedAdGroup routing, and the empty-payload no-op guard) was
|
|
79
|
+
extracted into a reusable, ctx-free `build_adgroup_update_object()` so the
|
|
80
|
+
single-flag command and the batch normalizer emit byte-identical objects
|
|
81
|
+
(golden-tested across every subtype). `--id` becomes per-row in batch mode;
|
|
82
|
+
single-item mode still requires it (parity-gate `INTERNAL_VALIDATION` entry).
|
|
83
|
+
Per-row coercion runs every typed field through its single-flag Click type (a
|
|
84
|
+
JSON float `id` is rejected, not truncated).
|
|
85
|
+
- Reuses the shared `_batch.send_batch` with `method="update"` /
|
|
86
|
+
`result_key="UpdateResults"` and the `post=_post_adgroups` endpoint routing.
|
|
87
|
+
As with `adgroups add`, a batch may **not** mix `UNIFIED_AD_GROUP` with other
|
|
88
|
+
ad-group types (unified groups use API v501) — the CLI refuses the mix up
|
|
89
|
+
front with a clear `UsageError`.
|
|
90
|
+
|
|
91
|
+
**Fixes — reject non-positive IDs before the request (#558):**
|
|
92
|
+
|
|
93
|
+
- Mutating commands and lifecycle ops took their object-ID selector
|
|
94
|
+
(`--id` / `--adgroup-id` / `--campaign-id` / `--keyword-id` / `--client-id`)
|
|
95
|
+
as a bare `int`, which accepted `0` and negatives and forwarded them to the
|
|
96
|
+
API (opaque rejection). Every such selector now uses `click.IntRange(min=1)`
|
|
97
|
+
and rejects a non-positive id with a clear `UsageError` (exit 2) before any
|
|
98
|
+
request. Coverage is the full mutation surface, not a subset:
|
|
99
|
+
- every `delete` / `suspend` / `resume` / `archive` / `unarchive` /
|
|
100
|
+
`moderate` lifecycle command (via the shared `_lifecycle.py` factory);
|
|
101
|
+
- `ads add` / `ads update`, `adgroups add` / `adgroups update`,
|
|
102
|
+
`keywords add` / `keywords update`;
|
|
103
|
+
- `campaigns update`, `feeds update`, `strategies update`,
|
|
104
|
+
`retargeting update`, `negativekeywordsharedsets update`, `vcards add`;
|
|
105
|
+
- `smartadtargets add` / `update` / `set-bids`,
|
|
106
|
+
`audiencetargets add` / `set-bids`, `dynamicads add` / `set-bids`,
|
|
107
|
+
`dynamicfeedadtargets add` / `set-bids`;
|
|
108
|
+
- the bid setters `bids set` / `set-auto`, `keywordbids set` / `set-auto`
|
|
109
|
+
(the `campaign-id` / `adgroup-id` / `keyword-id` "exactly one of" trios),
|
|
110
|
+
`bidmodifiers add` / `set`;
|
|
111
|
+
- `agencyclients update --client-id`.
|
|
112
|
+
|
|
113
|
+
The ad-image lifecycle (`--hash`, a string) is unchanged. Secondary
|
|
114
|
+
reference-ID flags that point at *other* objects inside a write payload
|
|
115
|
+
(e.g. `--feed-id`, `--counter-id`, `--vcard-id`, `--region-id`,
|
|
116
|
+
`--retargeting-list-id`) are left as-is for now and tracked as follow-up.
|
|
117
|
+
- Batch-size caps (the docs allow up to 1000 objects per add/update and 10000
|
|
118
|
+
ids per delete) are intentionally **not** added: the CLI builds a
|
|
119
|
+
single-item payload for every mutation, so there is no caller-controllable
|
|
120
|
+
array to overflow. Multi-item batch mode (`--from-file`) for ads/adgroups is
|
|
121
|
+
tracked as follow-up work.
|
|
122
|
+
- De-staled the `KEYWORDS_ADD_MAX_BATCH` comment: it claimed the API caps a
|
|
123
|
+
`keywords.add` request at 10 (citing an outdated doc page that states no such
|
|
124
|
+
number). The real documented per-call limit is 1000; the value `10` is a
|
|
125
|
+
conservative chunk size for batch add, not the API ceiling — comment fixed,
|
|
126
|
+
value unchanged.
|
|
127
|
+
|
|
128
|
+
**Fixes — explain Error 8300 on delete/moderate (#548):**
|
|
129
|
+
|
|
130
|
+
- `raise_for_api_result_errors` now appends a hint when the API returns code
|
|
131
|
+
8300, mirroring the existing 8800 hint: the ad is likely not in `DRAFT`
|
|
132
|
+
status, and `Status=UNKNOWN` is an API fallback value (a status outside the
|
|
133
|
+
v5 enum), not a business status — such ads can only be archived/unarchived,
|
|
134
|
+
not deleted or sent to moderation. Covers `ads delete` / `ads moderate` and
|
|
135
|
+
any command routing through `format_output`. English-only, matching the 8800
|
|
136
|
+
hint (`output.py` does not import i18n).
|
|
137
|
+
|
|
138
|
+
**Docs — audiencetargets get requires a filter (#554):**
|
|
139
|
+
|
|
140
|
+
- Clarified that `audiencetargets get` cannot page the whole account: unlike
|
|
141
|
+
`retargeting get --fetch-all`, the live API hard-rejects an empty
|
|
142
|
+
`SelectionCriteria` (error 8000 with no criteria, 4001 with `{}`). The
|
|
143
|
+
required-filter guard now explains this and recommends the `campaigns get` →
|
|
144
|
+
batched `campaign_ids` sweep instead. No API behavior change; message only.
|
|
145
|
+
|
|
146
|
+
**Fixes — preflight SelectionCriteria array limits on get (#555, P0):**
|
|
147
|
+
|
|
148
|
+
- `keywordbids get` now rejects `--campaign-ids` >10, `--adgroup-ids` >1000,
|
|
149
|
+
`--keyword-ids` >10000; `dynamicads get` / `smartadtargets get` reject
|
|
150
|
+
`--campaign-ids` >2 — before the request, with a clear `UsageError` (exit 2)
|
|
151
|
+
naming the array and ceiling, instead of the opaque API `error_code=4001`.
|
|
152
|
+
These are runtime ceilings (the WSDL declares the arrays `unbounded`), pinned
|
|
153
|
+
next to each command with a doc/live-4001 citation, the same discipline as
|
|
154
|
+
`KEYWORDS_ADD_MAX_BATCH`. Verified live 2026-06-16. Other `get` arrays
|
|
155
|
+
(`AdGroupIds`/`Ids` on dynamic/smart, etc.) are intentionally **not** capped
|
|
156
|
+
because the live API accepts them.
|
|
157
|
+
|
|
158
|
+
**Internal — dedup v4 Live output-option stack (#550):**
|
|
159
|
+
|
|
160
|
+
- Replaced the byte-identical `--format`/`--output`/`--dry-run` trio across the
|
|
161
|
+
standard v4 Live and `balance` commands with a shared `v4_output_options`
|
|
162
|
+
decorator (the v4 analogue of `get_options`, epic #491). The CLI surface is
|
|
163
|
+
unchanged — same option order, names, `click.Choice(["json","table","csv",
|
|
164
|
+
"tsv"])` format, defaults, and help. `v4account enable-shared-account` /
|
|
165
|
+
`account-management` (reversed order, custom `--dry-run` help) and the
|
|
166
|
+
dry-run-only `v4finance transfer-money` / `pay-campaigns` /
|
|
167
|
+
`pay-campaigns-by-card` (no `--format`/`--output`) keep their divergent
|
|
168
|
+
stacks and are intentionally excluded.
|
|
169
|
+
|
|
170
|
+
**Fixes — `ads update` can now clear AdImageHash (#552):**
|
|
171
|
+
|
|
172
|
+
- Added `--clear-image-hash` to `ads update`. The flag sends
|
|
173
|
+
`AdImageHash: null` so an image can be removed from an existing ad — e.g.
|
|
174
|
+
unblocking a `TEXT_AD` whose image was restricted in moderation — without
|
|
175
|
+
recreating the ad. Supported for the three subtypes whose WSDL `AdImageHash`
|
|
176
|
+
is nillable: `TEXT_AD`, `DYNAMIC_TEXT_AD`, `MOBILE_APP_AD`. It is **rejected**
|
|
177
|
+
for `TEXT_IMAGE_AD` and `MOBILE_APP_IMAGE_AD`, which share the non-nillable
|
|
178
|
+
`ImageAdUpdateBase.AdImageHash` — the live API returns error 8000
|
|
179
|
+
(`AdImageHash cannot have the null value`) for those, verified directly.
|
|
180
|
+
`--image-hash` and `--clear-image-hash` are mutually exclusive.
|
|
181
|
+
Previously there was no way to reset the image: `--image-hash ""` was dropped
|
|
182
|
+
by a truthy check, and `--image-hash null` sent the literal string `"null"`.
|
|
183
|
+
|
|
184
|
+
**Fixes — docs-URL drift regression (re-fixes #463):**
|
|
185
|
+
|
|
186
|
+
- Restored the four WSDL `docs` URLs for `dynamicads`,
|
|
187
|
+
`dynamicfeedadtargets`, `smartadtargets` and `vcards` that the
|
|
188
|
+
`tapi-yandex-direct` 2026.5.29 vendor update silently reverted back to the
|
|
189
|
+
removed `…/dev/direct/doc/ru/<service>` HTML pages (which 404 since Yandex
|
|
190
|
+
dropped those pages in September 2025). The fix from #464 was overwritten by
|
|
191
|
+
the `rm -rf` + `cp -R` vendor sync; preflight
|
|
192
|
+
(`scripts/check_all_docs_urls.py`) caught it. URLs now point back at the live
|
|
193
|
+
`https://api.direct.yandex.com/v5/<service>?wsdl` endpoints — the only
|
|
194
|
+
authoritative source still served.
|
|
195
|
+
- Fixed the same URLs at the source in the `axisrow/tapi-yandex-direct` fork so
|
|
196
|
+
the next vendor update no longer re-introduces the dead pages.
|
|
197
|
+
- Added an offline regression guard
|
|
198
|
+
(`tests/test_audit_wire_shape.py::test_removed_doc_services_pin_wsdl_url`):
|
|
199
|
+
the four doc-removed services must keep WSDL `docs` URLs, failing in CI before
|
|
200
|
+
the network preflight ever runs.
|
|
201
|
+
|
|
202
|
+
**Bug Fixes — reject empty-string CSV-ID flags in `adgroups` (#570):**
|
|
203
|
+
|
|
204
|
+
- `adgroups add` and `adgroups update` now reject an explicitly-provided
|
|
205
|
+
empty/whitespace value for `--region-ids`, `--negative-keyword-shared-set-ids`
|
|
206
|
+
and `--feed-category-ids` (e.g. `--region-ids ""`, `--region-ids " "`,
|
|
207
|
+
`--region-ids ","`, or a batch row `{"region-ids":""}`) with a clear
|
|
208
|
+
`UsageError` instead of silently dropping the field. Previously `parse_ids("")`
|
|
209
|
+
returned `None` and the `if region_ids:` guards treated a provided-but-empty
|
|
210
|
+
value identically to an omitted option; for `RegionIds` (WSDL `minOccurs=1` on
|
|
211
|
+
add) that stripped a required field and sent an invalid body to the live API.
|
|
212
|
+
- The fix is centralized in a new `_require_nonempty_ids_option` helper that
|
|
213
|
+
distinguishes `None` (option omitted) from an all-blank value, so single mode
|
|
214
|
+
and `--from-file` / `--adgroups-json` batch mode behave identically for both
|
|
215
|
+
add and update. A genuinely malformed value with real tokens
|
|
216
|
+
(e.g. `225,,226`) still reports the precise `Invalid ID` error, unchanged.
|
|
217
|
+
|
|
218
|
+
## 0.4.2
|
|
219
|
+
|
|
220
|
+
**BREAKING CHANGES - get requires SelectionCriteria (#498):**
|
|
221
|
+
|
|
222
|
+
- `adgroups` / `ads` / `keywords` / `strategies` / `creatives` / `dynamicads` /
|
|
223
|
+
`smartadtargets` / `audiencetargets` `get` now refuse an empty
|
|
224
|
+
`SelectionCriteria` before the API call, raising a `UsageError` that asks for
|
|
225
|
+
at least one filter — instead of sending `{"SelectionCriteria": {}}` (which the
|
|
226
|
+
API rejects with the opaque error 4001 for ad-group/ad/keyword resources).
|
|
227
|
+
Extends the same guard already shipped for `bids` / `keywordbids` in 0.4.1
|
|
228
|
+
(#483). WSDL declares `GetRequest.SelectionCriteria` as `minOccurs=1` for all
|
|
229
|
+
eight resources.
|
|
230
|
+
- `retargeting get` gains `--dry-run` and the shared read/pagination option
|
|
231
|
+
stack; its `SelectionCriteria` stays optional (WSDL `minOccurs=0`), so a
|
|
232
|
+
no-filter call is still valid and now omits the empty criteria from the
|
|
233
|
+
payload.
|
|
234
|
+
- All eight commands and `retargeting get` build their request via the shared
|
|
235
|
+
`build_common_params` helper, completing the dedup epic #491 (B3c).
|
|
236
|
+
|
|
237
|
+
**BREAKING CHANGES - auth precedence (#489):**
|
|
238
|
+
|
|
239
|
+
- Base `YANDEX_DIRECT_TOKEN` / `YANDEX_DIRECT_LOGIN` credentials from the
|
|
240
|
+
environment or current-directory `.env` now win over the active OAuth profile
|
|
241
|
+
selected by `direct auth use` when `--profile` is not passed. Explicit
|
|
242
|
+
`--token`, `--login`, and `--profile` still take priority.
|
|
243
|
+
- `direct auth status` reports the selected effective credentials, including
|
|
244
|
+
base env/`.env` and secret-manager fallbacks, instead of reporting only the
|
|
245
|
+
active OAuth profile.
|
|
246
|
+
- `direct auth login` can now ask interactive users whether to save the OAuth
|
|
247
|
+
access token and resolved login into the current-directory `.env`; the default
|
|
248
|
+
answer is no.
|
|
249
|
+
|
|
250
|
+
**Docs — live-write coverage limitation (#538):**
|
|
251
|
+
|
|
252
|
+
- Documented why the SMART_CAMPAIGN / DYNAMIC_TEXT_CAMPAIGN / `adimages`
|
|
253
|
+
live-write lifecycle (`dynamicads`, `smartadtargets`, `adimages`) stays
|
|
254
|
+
recorded only as 3500/5004 error cassettes. Verified via direct API calls that
|
|
255
|
+
the available sandbox **agency** account has no client accounts under it
|
|
256
|
+
(`agencyclients.get` → empty), cannot create one (3001 "No rights to create
|
|
257
|
+
clients", access by request only), and that without a client login every
|
|
258
|
+
agency-scoped mutation returns 8000. Closed #538 as a documented account-tier
|
|
259
|
+
limitation; no CLI code change. See `tests/MANUAL_COVERAGE.md`.
|
|
260
|
+
|
|
3
261
|
## 0.4.1
|
|
4
262
|
|
|
5
263
|
Russian-default CLI localization across all command modules (epic #466).
|
|
@@ -24,9 +24,9 @@ Click group-of-groups. Each Yandex Direct API resource = one file in `direct_cli
|
|
|
24
24
|
|
|
25
25
|
**Request flow:** `cli.py` → `auth.py` (resolves token/login) → `api.py` (`create_client`) → `tapi_yandex_direct.YandexDirect` → Yandex API → `output.py` (format/print).
|
|
26
26
|
|
|
27
|
-
**Credentials priority (CLI):** CLI flags (`--token`, `--login`) >
|
|
27
|
+
**Credentials priority (CLI):** explicit CLI flags (`--token`, `--login`, `--profile`) > base env/current working directory `.env` (`YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN`) > active profile from `direct auth login` / `direct auth use` > 1Password/Bitwarden refs. Explicit `--profile` is isolated and does not fall back to base `.env` login. See `direct_cli/auth.py` (`get_credentials`) and README table for the full chain.
|
|
28
28
|
|
|
29
|
-
**Credentials priority (tests):**
|
|
29
|
+
**Credentials priority (tests):** env vars/current working directory `.env` > active profile > skip. Tests must not silently hit production when a developer has an active `direct auth` profile, so env vars take precedence over the profile (see `tests/test_v4_live_contracts.py::_credentials`).
|
|
30
30
|
|
|
31
31
|
**Shared utilities** (`utils.py`): `parse_ids`, `parse_json`, `build_selection_criteria`, `build_common_params`, `get_default_fields`, `COMMON_FIELDS` dict. All command modules import from here — don't duplicate.
|
|
32
32
|
|
|
@@ -106,7 +106,7 @@ Builds dist artifacts, runs twine checks, uploads to TestPyPI + PyPI. Does **not
|
|
|
106
106
|
|
|
107
107
|
- **Unit** (`test_cli.py`, `test_comprehensive.py`) — no API calls, no token needed.
|
|
108
108
|
- **Integration** (`test_integration.py`, `@pytest.mark.integration`) — require `.env` with `YANDEX_DIRECT_TOKEN` and `YANDEX_DIRECT_LOGIN`. Auto-skip if absent.
|
|
109
|
-
- **Credential resolution in tests:** env vars first, then active `direct auth` profile, then skip. This
|
|
109
|
+
- **Credential resolution in tests:** env vars/current working directory `.env` first, then active `direct auth` profile, then skip. This matches the safe CLI default for base env vs. active profile: a developer machine with an active profile must not silently hit production on a plain `pytest`.
|
|
110
110
|
|
|
111
111
|
## Dangerous Commands — Never Auto-Test
|
|
112
112
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: direct-cli
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Command-line interface for Yandex Direct API
|
|
5
5
|
Author: axisrow
|
|
6
6
|
License: MIT
|
|
@@ -106,6 +106,9 @@ Notes:
|
|
|
106
106
|
- If the first non-interactive step includes `--client-secret`, the secret is remembered for the matching completion step.
|
|
107
107
|
- If a profile already stores a confidential OAuth client, `direct auth login --code CODE --profile NAME` reuses the saved `client_id` and `client_secret`.
|
|
108
108
|
- `direct auth login --oauth-token TOKEN` is a manual access-token import and does not auto-refresh.
|
|
109
|
+
- After a successful interactive login, Direct CLI asks whether to save the
|
|
110
|
+
access token and login to the current working directory `.env`; non-interactive
|
|
111
|
+
login flows do not prompt.
|
|
109
112
|
- Alias `auth_login` is not supported.
|
|
110
113
|
|
|
111
114
|
Credential resolution priority:
|
|
@@ -113,22 +116,23 @@ Credential resolution priority:
|
|
|
113
116
|
| Priority | Source | Example |
|
|
114
117
|
|----------|--------|---------|
|
|
115
118
|
| 1 | Explicit CLI options | `direct --token TOKEN --login LOGIN campaigns get` |
|
|
116
|
-
| 2 |
|
|
117
|
-
| 3 |
|
|
118
|
-
| 4 |
|
|
119
|
+
| 2 | Explicit profile credentials | `direct --profile agency1 campaigns get` |
|
|
120
|
+
| 3 | Base env vars or current working directory `.env` | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
|
|
121
|
+
| 4 | Active profile credentials | `direct auth use --profile agency1` |
|
|
119
122
|
| 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
|
|
120
123
|
| 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
|
|
121
124
|
|
|
122
125
|
Direct CLI automatically loads only the `.env` file from the current working
|
|
123
126
|
directory, i.e. the directory where you run `direct`. It does not search for
|
|
124
|
-
`.env` from the installed package or source-code location.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
`.env` from the installed package or source-code location. Without an explicit
|
|
128
|
+
`--profile`, base `YANDEX_DIRECT_TOKEN` / `YANDEX_DIRECT_LOGIN` from env or cwd
|
|
129
|
+
`.env` win over the active OAuth profile. With explicit `--profile`, Direct CLI
|
|
130
|
+
uses only that profile's OAuth/profile-env credentials and does not fall back to
|
|
131
|
+
base `YANDEX_DIRECT_LOGIN`; this prevents mixing accounts. `direct auth status`
|
|
132
|
+
without `--profile` reports the effective credential source; with `--profile` it
|
|
133
|
+
reports that profile.
|
|
130
134
|
|
|
131
|
-
> **Tests
|
|
135
|
+
> **Tests follow the safe credential order.** Live-API test suites (e.g. `tests/test_v4_live_contracts.py`) read `YANDEX_DIRECT_TOKEN` / `YANDEX_DIRECT_LOGIN` from the environment first, only then fall back to the active `direct auth` profile, and skip the test if neither is set. This prevents a developer machine with an active profile from silently hitting production on a plain `pytest` invocation. See `CLAUDE.md` for the contract.
|
|
132
136
|
|
|
133
137
|
Install with `pip install direct-cli`, then run commands with `direct`.
|
|
134
138
|
Invoking the deprecated `direct-cli` entrypoint exits with
|
|
@@ -539,6 +543,7 @@ direct ads add --adgroup-id 12345 --type MOBILE_APP_IMAGE_AD --image-hash abcdef
|
|
|
539
543
|
direct ads add --adgroup-id 12345 --type SMART_AD_BUILDER_AD --logo-extension-hash logoabcdefghijklmnop --dry-run
|
|
540
544
|
direct ads update --id 99999 --type TEXT_AD --title "New Title" --text "New text" --href "https://example.com"
|
|
541
545
|
direct ads update --id 99999 --type TEXT_AD --image-hash abcdefghijklmnopqrst
|
|
546
|
+
direct ads update --id 99999 --type TEXT_AD --clear-image-hash # remove the image (AdImageHash: null; TEXT_AD / DYNAMIC_TEXT_AD / MOBILE_APP_AD only)
|
|
542
547
|
direct ads update --id 99999 --type TEXT_AD --title2 "New second headline" --vcard-id 222
|
|
543
548
|
direct ads update --id 99999 --type TEXT_AD --callouts-add "111,222" --callouts-remove "333"
|
|
544
549
|
direct ads update --id 99999 --type TEXT_AD --callouts-set "444,555"
|
|
@@ -557,7 +562,10 @@ direct ads delete --id 99999
|
|
|
557
562
|
```
|
|
558
563
|
|
|
559
564
|
Available TEXT_AD typed flags for `ads add` / `ads update`: `--title`, `--text`,
|
|
560
|
-
`--href`, `--image-hash`, `--
|
|
565
|
+
`--href`, `--image-hash`, `--clear-image-hash` (update only — sets
|
|
566
|
+
`AdImageHash: null`; TEXT_AD / DYNAMIC_TEXT_AD / MOBILE_APP_AD only, since
|
|
567
|
+
TEXT_IMAGE_AD / MOBILE_APP_IMAGE_AD have a non-nillable `AdImageHash`),
|
|
568
|
+
`--title2`, `--display-url-path`, `--vcard-id`,
|
|
561
569
|
`--sitelink-set-id`, `--turbo-page-id`, `--final-url`,
|
|
562
570
|
`--video-extension-creative-id`, `--price-extension-*`, `--business-id`,
|
|
563
571
|
`--prefer-vcard-over-business`, and `--erir-ad-description`. For `ads add`,
|
|
@@ -704,6 +712,9 @@ direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
|
704
712
|
|
|
705
713
|
# Canonical multiword groups
|
|
706
714
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
715
|
+
# audiencetargets get always needs a filter — the API rejects an empty
|
|
716
|
+
# SelectionCriteria, so there is no whole-account paging. To sweep the account,
|
|
717
|
+
# run `campaigns get` first, then page audiencetargets get in batches of campaign ids.
|
|
707
718
|
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
708
719
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
709
720
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
@@ -1065,27 +1076,32 @@ direct --profile agency1 campaigns get
|
|
|
1065
1076
|
- Если первый non-interactive шаг включает `--client-secret`, secret запоминается для последующего completion step.
|
|
1066
1077
|
- Если profile уже хранит confidential OAuth client, `direct auth login --code CODE --profile NAME` использует сохраненные `client_id` и `client_secret`.
|
|
1067
1078
|
- `direct auth login --oauth-token TOKEN` импортирует access token вручную и не включает auto-refresh.
|
|
1079
|
+
- После успешного интерактивного входа Direct CLI спрашивает, сохранить ли
|
|
1080
|
+
access token и login в `.env` текущей рабочей папки; non-interactive вход этот
|
|
1081
|
+
вопрос не задаёт.
|
|
1068
1082
|
|
|
1069
1083
|
Порядок выбора credentials:
|
|
1070
1084
|
|
|
1071
1085
|
| Приоритет | Источник | Пример |
|
|
1072
1086
|
|-----------|----------|--------|
|
|
1073
1087
|
| 1 | Явные CLI-опции | `direct --token TOKEN --login LOGIN campaigns get` |
|
|
1074
|
-
| 2 |
|
|
1075
|
-
| 3 |
|
|
1076
|
-
| 4 |
|
|
1088
|
+
| 2 | Явно выбранный profile | `direct --profile agency1 campaigns get` |
|
|
1089
|
+
| 3 | Базовые env vars или `.env` из папки запуска | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
|
|
1090
|
+
| 4 | Активный profile | `direct auth use --profile agency1` |
|
|
1077
1091
|
| 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
|
|
1078
1092
|
| 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
|
|
1079
1093
|
|
|
1080
1094
|
Direct CLI автоматически читает только `.env` из текущей рабочей папки, то есть
|
|
1081
1095
|
из папки, где запущена команда `direct`. Он не ищет `.env` от папки
|
|
1082
|
-
установленного пакета или исходного кода.
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1096
|
+
установленного пакета или исходного кода. Без явного `--profile` базовые
|
|
1097
|
+
`YANDEX_DIRECT_TOKEN` / `YANDEX_DIRECT_LOGIN` из окружения или cwd `.env`
|
|
1098
|
+
побеждают активный OAuth profile. С явным `--profile` Direct CLI использует
|
|
1099
|
+
только OAuth/profile-env credentials этого профиля и не подставляет base
|
|
1100
|
+
`YANDEX_DIRECT_LOGIN`; это защищает от смешивания аккаунтов. `direct auth status`
|
|
1101
|
+
без `--profile` показывает реально выбранный источник credentials, а с
|
|
1102
|
+
`--profile` показывает этот профиль.
|
|
1087
1103
|
|
|
1088
|
-
>
|
|
1104
|
+
> **Тесты используют безопасный порядок credentials.** Live-API тесты (например `tests/test_v4_live_contracts.py`) сначала читают `YANDEX_DIRECT_TOKEN` / `YANDEX_DIRECT_LOGIN` из окружения, затем падают на активный профиль `direct auth`, и скипают тест если ни того ни другого нет. Это защищает от случайного обращения к production API на машине разработчика с активным profile. Контракт зафиксирован в `CLAUDE.md`.
|
|
1089
1105
|
|
|
1090
1106
|
Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
|
|
1091
1107
|
через `direct`. Вызов deprecated entrypoint `direct-cli` завершается ошибкой с
|
|
@@ -1362,6 +1378,7 @@ direct ads add --adgroup-id 12345 --type MOBILE_APP_IMAGE_AD --image-hash abcdef
|
|
|
1362
1378
|
direct ads add --adgroup-id 12345 --type SMART_AD_BUILDER_AD --logo-extension-hash logoabcdefghijklmnop --dry-run
|
|
1363
1379
|
direct ads update --id 99999 --type TEXT_AD --title "Новый заголовок" --text "Новый текст" --href "https://example.com"
|
|
1364
1380
|
direct ads update --id 99999 --type TEXT_AD --image-hash abcdefghijklmnopqrst
|
|
1381
|
+
direct ads update --id 99999 --type TEXT_AD --clear-image-hash # удалить изображение (AdImageHash: null; только TEXT_AD / DYNAMIC_TEXT_AD / MOBILE_APP_AD)
|
|
1365
1382
|
direct ads update --id 99999 --type TEXT_AD --title2 "Новый второй заголовок" --vcard-id 222
|
|
1366
1383
|
direct ads update --id 99999 --type TEXT_AD --callouts-add "111,222" --callouts-remove "333"
|
|
1367
1384
|
direct ads update --id 99999 --type TEXT_AD --callouts-set "444,555"
|
|
@@ -1380,7 +1397,10 @@ direct ads delete --id 99999
|
|
|
1380
1397
|
```
|
|
1381
1398
|
|
|
1382
1399
|
Доступные типизированные флаги TEXT_AD для `ads add` / `ads update`:
|
|
1383
|
-
`--title`, `--text`, `--href`, `--image-hash`, `--
|
|
1400
|
+
`--title`, `--text`, `--href`, `--image-hash`, `--clear-image-hash`
|
|
1401
|
+
(только update — устанавливает `AdImageHash: null`; только TEXT_AD /
|
|
1402
|
+
DYNAMIC_TEXT_AD / MOBILE_APP_AD, так как у TEXT_IMAGE_AD / MOBILE_APP_IMAGE_AD
|
|
1403
|
+
поле `AdImageHash` не nillable), `--title2`, `--display-url-path`,
|
|
1384
1404
|
`--vcard-id`, `--sitelink-set-id`, `--turbo-page-id`, `--final-url`,
|
|
1385
1405
|
`--video-extension-creative-id`, `--price-extension-*`, `--business-id`,
|
|
1386
1406
|
`--prefer-vcard-over-business` и `--erir-ad-description`. Для `ads add`
|
|
@@ -1529,6 +1549,9 @@ direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
|
1529
1549
|
|
|
1530
1550
|
# Канонические многословные группы
|
|
1531
1551
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
1552
|
+
# audiencetargets get всегда требует фильтр — API отклоняет пустой
|
|
1553
|
+
# SelectionCriteria, поэтому обхода всего аккаунта нет. Чтобы собрать аккаунт,
|
|
1554
|
+
# сначала выполните `campaigns get`, затем запрашивайте audiencetargets get батчами campaign id.
|
|
1532
1555
|
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
1533
1556
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
1534
1557
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
@@ -63,6 +63,9 @@ Notes:
|
|
|
63
63
|
- If the first non-interactive step includes `--client-secret`, the secret is remembered for the matching completion step.
|
|
64
64
|
- If a profile already stores a confidential OAuth client, `direct auth login --code CODE --profile NAME` reuses the saved `client_id` and `client_secret`.
|
|
65
65
|
- `direct auth login --oauth-token TOKEN` is a manual access-token import and does not auto-refresh.
|
|
66
|
+
- After a successful interactive login, Direct CLI asks whether to save the
|
|
67
|
+
access token and login to the current working directory `.env`; non-interactive
|
|
68
|
+
login flows do not prompt.
|
|
66
69
|
- Alias `auth_login` is not supported.
|
|
67
70
|
|
|
68
71
|
Credential resolution priority:
|
|
@@ -70,22 +73,23 @@ Credential resolution priority:
|
|
|
70
73
|
| Priority | Source | Example |
|
|
71
74
|
|----------|--------|---------|
|
|
72
75
|
| 1 | Explicit CLI options | `direct --token TOKEN --login LOGIN campaigns get` |
|
|
73
|
-
| 2 |
|
|
74
|
-
| 3 |
|
|
75
|
-
| 4 |
|
|
76
|
+
| 2 | Explicit profile credentials | `direct --profile agency1 campaigns get` |
|
|
77
|
+
| 3 | Base env vars or current working directory `.env` | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
|
|
78
|
+
| 4 | Active profile credentials | `direct auth use --profile agency1` |
|
|
76
79
|
| 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
|
|
77
80
|
| 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
|
|
78
81
|
|
|
79
82
|
Direct CLI automatically loads only the `.env` file from the current working
|
|
80
83
|
directory, i.e. the directory where you run `direct`. It does not search for
|
|
81
|
-
`.env` from the installed package or source-code location.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
`.env` from the installed package or source-code location. Without an explicit
|
|
85
|
+
`--profile`, base `YANDEX_DIRECT_TOKEN` / `YANDEX_DIRECT_LOGIN` from env or cwd
|
|
86
|
+
`.env` win over the active OAuth profile. With explicit `--profile`, Direct CLI
|
|
87
|
+
uses only that profile's OAuth/profile-env credentials and does not fall back to
|
|
88
|
+
base `YANDEX_DIRECT_LOGIN`; this prevents mixing accounts. `direct auth status`
|
|
89
|
+
without `--profile` reports the effective credential source; with `--profile` it
|
|
90
|
+
reports that profile.
|
|
87
91
|
|
|
88
|
-
> **Tests
|
|
92
|
+
> **Tests follow the safe credential order.** Live-API test suites (e.g. `tests/test_v4_live_contracts.py`) read `YANDEX_DIRECT_TOKEN` / `YANDEX_DIRECT_LOGIN` from the environment first, only then fall back to the active `direct auth` profile, and skip the test if neither is set. This prevents a developer machine with an active profile from silently hitting production on a plain `pytest` invocation. See `CLAUDE.md` for the contract.
|
|
89
93
|
|
|
90
94
|
Install with `pip install direct-cli`, then run commands with `direct`.
|
|
91
95
|
Invoking the deprecated `direct-cli` entrypoint exits with
|
|
@@ -496,6 +500,7 @@ direct ads add --adgroup-id 12345 --type MOBILE_APP_IMAGE_AD --image-hash abcdef
|
|
|
496
500
|
direct ads add --adgroup-id 12345 --type SMART_AD_BUILDER_AD --logo-extension-hash logoabcdefghijklmnop --dry-run
|
|
497
501
|
direct ads update --id 99999 --type TEXT_AD --title "New Title" --text "New text" --href "https://example.com"
|
|
498
502
|
direct ads update --id 99999 --type TEXT_AD --image-hash abcdefghijklmnopqrst
|
|
503
|
+
direct ads update --id 99999 --type TEXT_AD --clear-image-hash # remove the image (AdImageHash: null; TEXT_AD / DYNAMIC_TEXT_AD / MOBILE_APP_AD only)
|
|
499
504
|
direct ads update --id 99999 --type TEXT_AD --title2 "New second headline" --vcard-id 222
|
|
500
505
|
direct ads update --id 99999 --type TEXT_AD --callouts-add "111,222" --callouts-remove "333"
|
|
501
506
|
direct ads update --id 99999 --type TEXT_AD --callouts-set "444,555"
|
|
@@ -514,7 +519,10 @@ direct ads delete --id 99999
|
|
|
514
519
|
```
|
|
515
520
|
|
|
516
521
|
Available TEXT_AD typed flags for `ads add` / `ads update`: `--title`, `--text`,
|
|
517
|
-
`--href`, `--image-hash`, `--
|
|
522
|
+
`--href`, `--image-hash`, `--clear-image-hash` (update only — sets
|
|
523
|
+
`AdImageHash: null`; TEXT_AD / DYNAMIC_TEXT_AD / MOBILE_APP_AD only, since
|
|
524
|
+
TEXT_IMAGE_AD / MOBILE_APP_IMAGE_AD have a non-nillable `AdImageHash`),
|
|
525
|
+
`--title2`, `--display-url-path`, `--vcard-id`,
|
|
518
526
|
`--sitelink-set-id`, `--turbo-page-id`, `--final-url`,
|
|
519
527
|
`--video-extension-creative-id`, `--price-extension-*`, `--business-id`,
|
|
520
528
|
`--prefer-vcard-over-business`, and `--erir-ad-description`. For `ads add`,
|
|
@@ -661,6 +669,9 @@ direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
|
661
669
|
|
|
662
670
|
# Canonical multiword groups
|
|
663
671
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
672
|
+
# audiencetargets get always needs a filter — the API rejects an empty
|
|
673
|
+
# SelectionCriteria, so there is no whole-account paging. To sweep the account,
|
|
674
|
+
# run `campaigns get` first, then page audiencetargets get in batches of campaign ids.
|
|
664
675
|
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
665
676
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
666
677
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
@@ -1022,27 +1033,32 @@ direct --profile agency1 campaigns get
|
|
|
1022
1033
|
- Если первый non-interactive шаг включает `--client-secret`, secret запоминается для последующего completion step.
|
|
1023
1034
|
- Если profile уже хранит confidential OAuth client, `direct auth login --code CODE --profile NAME` использует сохраненные `client_id` и `client_secret`.
|
|
1024
1035
|
- `direct auth login --oauth-token TOKEN` импортирует access token вручную и не включает auto-refresh.
|
|
1036
|
+
- После успешного интерактивного входа Direct CLI спрашивает, сохранить ли
|
|
1037
|
+
access token и login в `.env` текущей рабочей папки; non-interactive вход этот
|
|
1038
|
+
вопрос не задаёт.
|
|
1025
1039
|
|
|
1026
1040
|
Порядок выбора credentials:
|
|
1027
1041
|
|
|
1028
1042
|
| Приоритет | Источник | Пример |
|
|
1029
1043
|
|-----------|----------|--------|
|
|
1030
1044
|
| 1 | Явные CLI-опции | `direct --token TOKEN --login LOGIN campaigns get` |
|
|
1031
|
-
| 2 |
|
|
1032
|
-
| 3 |
|
|
1033
|
-
| 4 |
|
|
1045
|
+
| 2 | Явно выбранный profile | `direct --profile agency1 campaigns get` |
|
|
1046
|
+
| 3 | Базовые env vars или `.env` из папки запуска | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
|
|
1047
|
+
| 4 | Активный profile | `direct auth use --profile agency1` |
|
|
1034
1048
|
| 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
|
|
1035
1049
|
| 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
|
|
1036
1050
|
|
|
1037
1051
|
Direct CLI автоматически читает только `.env` из текущей рабочей папки, то есть
|
|
1038
1052
|
из папки, где запущена команда `direct`. Он не ищет `.env` от папки
|
|
1039
|
-
установленного пакета или исходного кода.
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1053
|
+
установленного пакета или исходного кода. Без явного `--profile` базовые
|
|
1054
|
+
`YANDEX_DIRECT_TOKEN` / `YANDEX_DIRECT_LOGIN` из окружения или cwd `.env`
|
|
1055
|
+
побеждают активный OAuth profile. С явным `--profile` Direct CLI использует
|
|
1056
|
+
только OAuth/profile-env credentials этого профиля и не подставляет base
|
|
1057
|
+
`YANDEX_DIRECT_LOGIN`; это защищает от смешивания аккаунтов. `direct auth status`
|
|
1058
|
+
без `--profile` показывает реально выбранный источник credentials, а с
|
|
1059
|
+
`--profile` показывает этот профиль.
|
|
1044
1060
|
|
|
1045
|
-
>
|
|
1061
|
+
> **Тесты используют безопасный порядок credentials.** Live-API тесты (например `tests/test_v4_live_contracts.py`) сначала читают `YANDEX_DIRECT_TOKEN` / `YANDEX_DIRECT_LOGIN` из окружения, затем падают на активный профиль `direct auth`, и скипают тест если ни того ни другого нет. Это защищает от случайного обращения к production API на машине разработчика с активным profile. Контракт зафиксирован в `CLAUDE.md`.
|
|
1046
1062
|
|
|
1047
1063
|
Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
|
|
1048
1064
|
через `direct`. Вызов deprecated entrypoint `direct-cli` завершается ошибкой с
|
|
@@ -1319,6 +1335,7 @@ direct ads add --adgroup-id 12345 --type MOBILE_APP_IMAGE_AD --image-hash abcdef
|
|
|
1319
1335
|
direct ads add --adgroup-id 12345 --type SMART_AD_BUILDER_AD --logo-extension-hash logoabcdefghijklmnop --dry-run
|
|
1320
1336
|
direct ads update --id 99999 --type TEXT_AD --title "Новый заголовок" --text "Новый текст" --href "https://example.com"
|
|
1321
1337
|
direct ads update --id 99999 --type TEXT_AD --image-hash abcdefghijklmnopqrst
|
|
1338
|
+
direct ads update --id 99999 --type TEXT_AD --clear-image-hash # удалить изображение (AdImageHash: null; только TEXT_AD / DYNAMIC_TEXT_AD / MOBILE_APP_AD)
|
|
1322
1339
|
direct ads update --id 99999 --type TEXT_AD --title2 "Новый второй заголовок" --vcard-id 222
|
|
1323
1340
|
direct ads update --id 99999 --type TEXT_AD --callouts-add "111,222" --callouts-remove "333"
|
|
1324
1341
|
direct ads update --id 99999 --type TEXT_AD --callouts-set "444,555"
|
|
@@ -1337,7 +1354,10 @@ direct ads delete --id 99999
|
|
|
1337
1354
|
```
|
|
1338
1355
|
|
|
1339
1356
|
Доступные типизированные флаги TEXT_AD для `ads add` / `ads update`:
|
|
1340
|
-
`--title`, `--text`, `--href`, `--image-hash`, `--
|
|
1357
|
+
`--title`, `--text`, `--href`, `--image-hash`, `--clear-image-hash`
|
|
1358
|
+
(только update — устанавливает `AdImageHash: null`; только TEXT_AD /
|
|
1359
|
+
DYNAMIC_TEXT_AD / MOBILE_APP_AD, так как у TEXT_IMAGE_AD / MOBILE_APP_IMAGE_AD
|
|
1360
|
+
поле `AdImageHash` не nillable), `--title2`, `--display-url-path`,
|
|
1341
1361
|
`--vcard-id`, `--sitelink-set-id`, `--turbo-page-id`, `--final-url`,
|
|
1342
1362
|
`--video-extension-creative-id`, `--price-extension-*`, `--business-id`,
|
|
1343
1363
|
`--prefer-vcard-over-business` и `--erir-ad-description`. Для `ads add`
|
|
@@ -1486,6 +1506,9 @@ direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
|
1486
1506
|
|
|
1487
1507
|
# Канонические многословные группы
|
|
1488
1508
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
1509
|
+
# audiencetargets get всегда требует фильтр — API отклоняет пустой
|
|
1510
|
+
# SelectionCriteria, поэтому обхода всего аккаунта нет. Чтобы собрать аккаунт,
|
|
1511
|
+
# сначала выполните `campaigns get`, затем запрашивайте audiencetargets get батчами campaign id.
|
|
1489
1512
|
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
1490
1513
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
1491
1514
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|