direct-cli 0.2.10__tar.gz → 0.3.0__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.2.10 → direct_cli-0.3.0}/CLAUDE.md +11 -1
- {direct_cli-0.2.10 → direct_cli-0.3.0}/PKG-INFO +76 -9
- {direct_cli-0.2.10 → direct_cli-0.3.0}/README.md +75 -8
- direct_cli-0.3.0/direct_cli/_smoke_probes.py +89 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +2 -1
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +43 -0
- direct_cli-0.3.0/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +163 -0
- direct_cli-0.3.0/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +9 -0
- direct_cli-0.3.0/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +219 -0
- direct_cli-0.3.0/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +54 -0
- direct_cli-0.3.0/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +66 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/cli.py +46 -31
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/adextensions.py +4 -2
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/ads.py +3 -5
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/agencyclients.py +101 -26
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/audiencetargets.py +30 -17
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/bidmodifiers.py +15 -3
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/bids.py +15 -3
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/businesses.py +2 -2
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/changes.py +14 -7
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/clients.py +51 -16
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/creatives.py +2 -4
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/dynamicads.py +18 -9
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/dynamicfeedadtargets.py +2 -4
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/keywordbids.py +7 -11
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/keywordsresearch.py +2 -2
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/leads.py +2 -6
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/negativekeywordsharedsets.py +4 -2
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/sitelinks.py +2 -2
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/smartadtargets.py +21 -10
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/strategies.py +8 -6
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/turbopages.py +2 -2
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/vcards.py +2 -6
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/reports_coverage.py +15 -5
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/smoke_matrix.py +3 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/utils.py +236 -10
- direct_cli-0.3.0/direct_cli/wsdl_coverage.py +581 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/PKG-INFO +76 -9
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/SOURCES.txt +11 -1
- {direct_cli-0.2.10 → direct_cli-0.3.0}/pyproject.toml +1 -1
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/build_api_coverage_checklist.py +48 -34
- direct_cli-0.3.0/scripts/build_api_coverage_report.py +1040 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/check_wsdl_drift.py +49 -2
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/patch_vendor_imports.py +40 -9
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/test_safe_commands.sh +69 -15
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/update_vendor.sh +5 -6
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/API_COVERAGE.md +25 -1
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/MANUAL_COVERAGE.md +7 -4
- direct_cli-0.3.0/tests/api_coverage_payloads.py +448 -0
- direct_cli-0.3.0/tests/test_api_coverage.py +1765 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_cli.py +24 -1
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_dry_run.py +350 -136
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_integration.py +159 -16
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_integration_write.py +4 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_smoke_matrix.py +10 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_vendor_imports.py +34 -12
- direct_cli-0.3.0/tests/wsdl_cache/imports/adextensiontypes.xsd +60 -0
- direct_cli-0.3.0/tests/wsdl_cache/imports/general.xsd +444 -0
- direct_cli-0.3.0/tests/wsdl_cache/imports/generalclients.xsd +396 -0
- direct_cli-0.2.10/direct_cli/wsdl_coverage.py +0 -346
- direct_cli-0.2.10/scripts/build_api_coverage_report.py +0 -236
- direct_cli-0.2.10/tests/test_api_coverage.py +0 -1357
- {direct_cli-0.2.10 → direct_cli-0.3.0}/.env.example +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/.github/copilot-instructions.md +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/.github/workflows/api-coverage.yml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/.github/workflows/claude-code-review.yml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/.github/workflows/claude.yml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/.gitignore +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/AGENTS.md +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/MANIFEST.in +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/__init__.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_deprecated.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_vendor/__init__.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/api.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/auth.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/__init__.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/adgroups.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/adimages.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/advideos.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/auth.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/campaigns.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/dictionaries.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/feeds.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/keywords.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/reports.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/retargeting.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/output.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/dependency_links.txt +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/entry_points.txt +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/requires.txt +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/top_level.txt +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/anonymize_cassettes.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/check_reports_drift.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/refresh_reports_cache.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/refresh_wsdl_cache.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/release_pypi.sh +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/sandbox_write_live.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/test_dangerous_commands.sh +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/test_sandbox_write.sh +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/setup.cfg +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/setup.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/API_ISSUE_AUDIT.md +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/__init__.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_adgroups_add_update_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_adimages_add_get_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_ads_add_update_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_ads_suspend_resume_archive_unarchive.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_advideos_add_get.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_add_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_suspend_resume.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_bids_set.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_campaign_create_get_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_creatives_chain_advideo_to_creative.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_add_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_suspend_resume.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_keywordbids_set.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_add_update_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_suspend_resume.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_sitelinks_add_get_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_add_update_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_suspend_resume.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/conftest.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/fixtures/test-video.mp4 +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/reports_cache/raw/fields-list.html +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/reports_cache/raw/headers.html +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/reports_cache/raw/spec.html +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/reports_cache/raw/type.html +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/reports_cache/spec.json +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_auth_bw.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_auth_oauth.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_auth_op.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_comprehensive.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_integration_live_write.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_reports_drift.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_transport_contract.py +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/adextensions.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/adgroups.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/adimages.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/ads.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/advideos.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/agencyclients.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/audiencetargets.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/bidmodifiers.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/bids.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/businesses.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/campaigns.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/changes.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/clients.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/creatives.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/dictionaries.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/feeds.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/keywordbids.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/keywords.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/keywordsresearch.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/leads.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/retargetinglists.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/sitelinks.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/smartadtargets.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/strategies.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/turbopages.xml +0 -0
- {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/vcards.xml +0 -0
|
@@ -39,11 +39,17 @@ Click group-of-groups. Each Yandex Direct API resource = one file in `direct_cli
|
|
|
39
39
|
|
|
40
40
|
**`--dry-run`:** `add`/`update` commands print request JSON without calling the API. Use as test seam.
|
|
41
41
|
|
|
42
|
+
**Runtime-deprecated methods:** WSDL-visible methods that Yandex rejects at runtime belong in `RUNTIME_DEPRECATED_METHODS` (`direct_cli/wsdl_coverage.py`) and must fail with `click.UsageError` before request construction. `agencyclients add` is blocked this way; use `agencyclients add-passport-organization`.
|
|
43
|
+
|
|
42
44
|
**SelectionCriteria:** Resources like `adgroups`, `ads`, `keywords` require at least one of `Ids`, `CampaignIds`, or `AdGroupIds` — otherwise API error 4001.
|
|
43
45
|
|
|
44
46
|
**Error handling:** All commands wrap API calls in `try/except Exception` → `print_error(str(e))` + `raise click.Abort()`.
|
|
45
47
|
|
|
46
|
-
**Default fields:** `COMMON_FIELDS` in `utils.py` maps resource names to
|
|
48
|
+
**Default fields:** `COMMON_FIELDS` in `utils.py` maps resource names to default `*FieldNames`. Most entries are `list[str]`; multi-`*FieldNames` resources use `dict[str, list[str]]` keyed by WSDL request param (for example `FieldNames`, `TextAdFieldNames`, `SearchFieldNames`). Not all fields are valid for all resources (e.g., `adimages` uses `AdImageHash`, not `Id`).
|
|
49
|
+
|
|
50
|
+
**WSDL imports:** Imported schemas used by request validation are cached in `tests/wsdl_cache/imports/` and registered in `IMPORTED_XSD_REGISTRY`. Keep imported nested types resolved; empty `item_fields` for registered imports is coverage drift.
|
|
51
|
+
|
|
52
|
+
**Smoke probes:** Live ID discovery for safe-smoke and integration tests lives in `direct_cli/_smoke_probes.py`. Functions like `advideo_probe_id()` query the live API to find a real resource ID (env override `YANDEX_DIRECT_TEST_ADVIDEO_ID`, fallback through `creatives.get`) and return `None` on any failure — smoke scripts treat `None` as a benign skip, not a fatal error. CLI entry: `python3 -m direct_cli._smoke_probes advideo`.
|
|
47
53
|
|
|
48
54
|
## Tests
|
|
49
55
|
|
|
@@ -66,3 +72,7 @@ subcommand belongs to exactly one category:
|
|
|
66
72
|
Never auto-test production mutations: agency client changes, live bid changes,
|
|
67
73
|
moderation, lifecycle operations, `clients update`, or any `delete` without
|
|
68
74
|
`--sandbox`.
|
|
75
|
+
|
|
76
|
+
Client update payloads (`clients update` and `agencyclients update`) must use
|
|
77
|
+
the shared typed helpers in `direct_cli/utils.py`; do not expose raw JSON for
|
|
78
|
+
general client update fields or nested client update payloads.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: direct-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Command-line interface for Yandex Direct API
|
|
5
5
|
Author: axisrow
|
|
6
6
|
License: MIT
|
|
@@ -97,6 +97,23 @@ Notes:
|
|
|
97
97
|
- Authorization is performed via `direct auth login`.
|
|
98
98
|
- Alias `auth_login` is not supported.
|
|
99
99
|
|
|
100
|
+
Credential resolution priority:
|
|
101
|
+
|
|
102
|
+
| Priority | Source | Example |
|
|
103
|
+
|----------|--------|---------|
|
|
104
|
+
| 1 | Explicit CLI options | `direct --token TOKEN --login LOGIN campaigns get` |
|
|
105
|
+
| 2 | OAuth profile storage | `direct --profile agency1 campaigns get` |
|
|
106
|
+
| 3 | Profile-specific env vars | `YANDEX_DIRECT_TOKEN_AGENCY1`, `YANDEX_DIRECT_LOGIN_AGENCY1` |
|
|
107
|
+
| 4 | Base env vars or project `.env` | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
|
|
108
|
+
| 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
|
|
109
|
+
| 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
|
|
110
|
+
|
|
111
|
+
The project `.env` file is loaded automatically. If a profile is selected
|
|
112
|
+
with `--profile` or `direct auth use --profile NAME`, Direct CLI does not
|
|
113
|
+
fall back to base `YANDEX_DIRECT_LOGIN`; this prevents mixing a profile token
|
|
114
|
+
with a login from the project `.env`. For multi-account setups, prefer OAuth
|
|
115
|
+
profiles or profile-specific env vars instead of base credentials.
|
|
116
|
+
|
|
100
117
|
Install with `pip install direct-cli`, then run commands with `direct`.
|
|
101
118
|
Invoking the deprecated `direct-cli` entrypoint exits with
|
|
102
119
|
`use direct instead of direct-cli`.
|
|
@@ -325,7 +342,7 @@ direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-n
|
|
|
325
342
|
direct clients get --fields ClientId,Login,Currency
|
|
326
343
|
|
|
327
344
|
# Changes
|
|
328
|
-
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
345
|
+
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
|
|
329
346
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
330
347
|
direct changes check-dictionaries
|
|
331
348
|
|
|
@@ -335,15 +352,18 @@ direct retargeting add --name "List A" --type AUDIENCE --rule "ALL:12345:30|6789
|
|
|
335
352
|
direct retargeting update --id 55 --name "Renamed" --rule "ANY:12345:30" --dry-run
|
|
336
353
|
|
|
337
354
|
# Bids and modifiers
|
|
355
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
338
356
|
direct bids set --keyword-id 123 --bid 15000000
|
|
339
357
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
340
358
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
341
359
|
direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
|
|
360
|
+
direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
|
|
342
361
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
343
362
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
344
363
|
|
|
345
364
|
# Canonical multiword groups
|
|
346
365
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
366
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
347
367
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
348
368
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
349
369
|
direct dynamicads add --adgroup-id 33 --name "Webpage A" --condition "URL:CONTAINS_ANY:test|shop" --condition "PAGE_CONTENT:CONTAINS:baz" --bid 3000000 --context-bid 2000000 --priority HIGH --dry-run
|
|
@@ -371,13 +391,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
371
391
|
direct creatives add --video-id video-id --dry-run
|
|
372
392
|
direct feeds add --name "Feed A" --url "https://example.com/feed.xml" --dry-run
|
|
373
393
|
direct feeds update --id 18 --name "Feed A v2" --url "https://example.com/feed-v2.xml" --dry-run
|
|
374
|
-
direct clients update --client-
|
|
375
|
-
direct
|
|
394
|
+
direct clients update --client-info "Priority client" --phone +70000000000 --notification-email user@example.com --notification-lang EN --email-subscription RECEIVE_RECOMMENDATIONS=YES --setting DISPLAY_STORE_RATING=NO --dry-run
|
|
395
|
+
direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
|
|
376
396
|
direct agencyclients add-passport-organization --name "Org" --currency RUB --notification-email ops@example.com --notification-lang EN --no-send-account-news --send-warnings --dry-run
|
|
377
397
|
direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
|
|
378
|
-
direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
|
|
398
|
+
direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
|
|
379
399
|
```
|
|
380
400
|
|
|
401
|
+
`direct agencyclients add` is runtime-deprecated by Yandex Direct and is blocked by the CLI. Use `direct agencyclients add-passport-organization` instead.
|
|
402
|
+
|
|
381
403
|
### Known Unsupported API Operation
|
|
382
404
|
|
|
383
405
|
`dynamicads update` is unsupported by API. The Yandex Direct
|
|
@@ -634,6 +656,45 @@ YANDEX_DIRECT_LOGIN=ваш_логин_на_яндексе
|
|
|
634
656
|
direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
|
|
635
657
|
```
|
|
636
658
|
|
|
659
|
+
Используйте профильные credentials из `.env`:
|
|
660
|
+
|
|
661
|
+
```env
|
|
662
|
+
YANDEX_DIRECT_TOKEN_AGENCY1=token-1
|
|
663
|
+
YANDEX_DIRECT_LOGIN_AGENCY1=client-login-1
|
|
664
|
+
YANDEX_DIRECT_TOKEN_AGENCY2=token-2
|
|
665
|
+
YANDEX_DIRECT_LOGIN_AGENCY2=client-login-2
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
OAuth и profile-команды:
|
|
669
|
+
|
|
670
|
+
```bash
|
|
671
|
+
direct auth login
|
|
672
|
+
direct auth login --profile agency1
|
|
673
|
+
direct auth login --code abc123 --profile agency1
|
|
674
|
+
direct auth login --oauth-token y0_example --profile agency1
|
|
675
|
+
direct auth list
|
|
676
|
+
direct auth use --profile agency1
|
|
677
|
+
direct auth status --profile agency1
|
|
678
|
+
direct --profile agency1 campaigns get
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
Порядок выбора credentials:
|
|
682
|
+
|
|
683
|
+
| Приоритет | Источник | Пример |
|
|
684
|
+
|-----------|----------|--------|
|
|
685
|
+
| 1 | Явные CLI-опции | `direct --token TOKEN --login LOGIN campaigns get` |
|
|
686
|
+
| 2 | OAuth profile storage | `direct --profile agency1 campaigns get` |
|
|
687
|
+
| 3 | Профильные env vars | `YANDEX_DIRECT_TOKEN_AGENCY1`, `YANDEX_DIRECT_LOGIN_AGENCY1` |
|
|
688
|
+
| 4 | Базовые env vars или project `.env` | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
|
|
689
|
+
| 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
|
|
690
|
+
| 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
|
|
691
|
+
|
|
692
|
+
Файл `.env` в проекте загружается автоматически. Если профиль выбран через
|
|
693
|
+
`--profile` или `direct auth use --profile NAME`, Direct CLI не подставляет
|
|
694
|
+
base `YANDEX_DIRECT_LOGIN`; это защищает от смешивания токена из профиля с
|
|
695
|
+
логином из project `.env`. Для нескольких аккаунтов используйте OAuth profiles
|
|
696
|
+
или профильные env vars, а не базовые credentials.
|
|
697
|
+
|
|
637
698
|
Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
|
|
638
699
|
через `direct`. Вызов deprecated entrypoint `direct-cli` завершается ошибкой с
|
|
639
700
|
подсказкой `use direct instead of direct-cli`.
|
|
@@ -644,6 +705,7 @@ direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
|
|
|
644
705
|
|-------|----------|
|
|
645
706
|
| `--token` | OAuth-токен доступа к API |
|
|
646
707
|
| `--login` | Direct client login |
|
|
708
|
+
| `--profile` | Имя credential profile |
|
|
647
709
|
| `--sandbox` | Использовать тестовое API (песочница) |
|
|
648
710
|
|
|
649
711
|
### Использование
|
|
@@ -902,7 +964,7 @@ direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --e
|
|
|
902
964
|
direct clients get --fields ClientId,Login,Currency
|
|
903
965
|
|
|
904
966
|
# Изменения
|
|
905
|
-
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
967
|
+
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
|
|
906
968
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
907
969
|
direct changes check-dictionaries
|
|
908
970
|
|
|
@@ -912,15 +974,18 @@ direct retargeting add --name "Список A" --type AUDIENCE --rule "ALL:12345
|
|
|
912
974
|
direct retargeting update --id 55 --name "Переименованный список" --rule "ANY:12345:30" --dry-run
|
|
913
975
|
|
|
914
976
|
# Ставки и модификаторы
|
|
977
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
915
978
|
direct bids set --keyword-id 123 --bid 15000000
|
|
916
979
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
917
980
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
918
981
|
direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
|
|
982
|
+
direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
|
|
919
983
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
920
984
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
921
985
|
|
|
922
986
|
# Канонические многословные группы
|
|
923
987
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
988
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
924
989
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
925
990
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
926
991
|
direct dynamicads add --adgroup-id 33 --name "Webpage A" --condition "URL:CONTAINS_ANY:test|shop" --condition "PAGE_CONTENT:CONTAINS:baz" --bid 3000000 --context-bid 2000000 --priority HIGH --dry-run
|
|
@@ -948,13 +1013,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
948
1013
|
direct creatives add --video-id video-id --dry-run
|
|
949
1014
|
direct feeds add --name "Фид A" --url "https://example.com/feed.xml" --dry-run
|
|
950
1015
|
direct feeds update --id 18 --name "Фид A v2" --url "https://example.com/feed-v2.xml" --dry-run
|
|
951
|
-
direct clients update --client-
|
|
952
|
-
direct
|
|
1016
|
+
direct clients update --client-info "Приоритетный клиент" --phone +70000000000 --notification-email user@example.com --notification-lang EN --email-subscription RECEIVE_RECOMMENDATIONS=YES --setting DISPLAY_STORE_RATING=NO --dry-run
|
|
1017
|
+
direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
|
|
953
1018
|
direct agencyclients add-passport-organization --name "Org" --currency RUB --notification-email ops@example.com --notification-lang EN --no-send-account-news --send-warnings --dry-run
|
|
954
1019
|
direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
|
|
955
|
-
direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
|
|
1020
|
+
direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
|
|
956
1021
|
```
|
|
957
1022
|
|
|
1023
|
+
`direct agencyclients add` runtime-deprecated в Yandex Direct и блокируется CLI. Используйте `direct agencyclients add-passport-organization`.
|
|
1024
|
+
|
|
958
1025
|
### Известная неподдерживаемая API-операция
|
|
959
1026
|
|
|
960
1027
|
`dynamicads update` unsupported by API. Сервис Яндекс Директа
|
|
@@ -58,6 +58,23 @@ Notes:
|
|
|
58
58
|
- Authorization is performed via `direct auth login`.
|
|
59
59
|
- Alias `auth_login` is not supported.
|
|
60
60
|
|
|
61
|
+
Credential resolution priority:
|
|
62
|
+
|
|
63
|
+
| Priority | Source | Example |
|
|
64
|
+
|----------|--------|---------|
|
|
65
|
+
| 1 | Explicit CLI options | `direct --token TOKEN --login LOGIN campaigns get` |
|
|
66
|
+
| 2 | OAuth profile storage | `direct --profile agency1 campaigns get` |
|
|
67
|
+
| 3 | Profile-specific env vars | `YANDEX_DIRECT_TOKEN_AGENCY1`, `YANDEX_DIRECT_LOGIN_AGENCY1` |
|
|
68
|
+
| 4 | Base env vars or project `.env` | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
|
|
69
|
+
| 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
|
|
70
|
+
| 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
|
|
71
|
+
|
|
72
|
+
The project `.env` file is loaded automatically. If a profile is selected
|
|
73
|
+
with `--profile` or `direct auth use --profile NAME`, Direct CLI does not
|
|
74
|
+
fall back to base `YANDEX_DIRECT_LOGIN`; this prevents mixing a profile token
|
|
75
|
+
with a login from the project `.env`. For multi-account setups, prefer OAuth
|
|
76
|
+
profiles or profile-specific env vars instead of base credentials.
|
|
77
|
+
|
|
61
78
|
Install with `pip install direct-cli`, then run commands with `direct`.
|
|
62
79
|
Invoking the deprecated `direct-cli` entrypoint exits with
|
|
63
80
|
`use direct instead of direct-cli`.
|
|
@@ -286,7 +303,7 @@ direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-n
|
|
|
286
303
|
direct clients get --fields ClientId,Login,Currency
|
|
287
304
|
|
|
288
305
|
# Changes
|
|
289
|
-
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
306
|
+
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
|
|
290
307
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
291
308
|
direct changes check-dictionaries
|
|
292
309
|
|
|
@@ -296,15 +313,18 @@ direct retargeting add --name "List A" --type AUDIENCE --rule "ALL:12345:30|6789
|
|
|
296
313
|
direct retargeting update --id 55 --name "Renamed" --rule "ANY:12345:30" --dry-run
|
|
297
314
|
|
|
298
315
|
# Bids and modifiers
|
|
316
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
299
317
|
direct bids set --keyword-id 123 --bid 15000000
|
|
300
318
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
301
319
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
302
320
|
direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
|
|
321
|
+
direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
|
|
303
322
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
304
323
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
305
324
|
|
|
306
325
|
# Canonical multiword groups
|
|
307
326
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
327
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
308
328
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
309
329
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
310
330
|
direct dynamicads add --adgroup-id 33 --name "Webpage A" --condition "URL:CONTAINS_ANY:test|shop" --condition "PAGE_CONTENT:CONTAINS:baz" --bid 3000000 --context-bid 2000000 --priority HIGH --dry-run
|
|
@@ -332,13 +352,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
332
352
|
direct creatives add --video-id video-id --dry-run
|
|
333
353
|
direct feeds add --name "Feed A" --url "https://example.com/feed.xml" --dry-run
|
|
334
354
|
direct feeds update --id 18 --name "Feed A v2" --url "https://example.com/feed-v2.xml" --dry-run
|
|
335
|
-
direct clients update --client-
|
|
336
|
-
direct
|
|
355
|
+
direct clients update --client-info "Priority client" --phone +70000000000 --notification-email user@example.com --notification-lang EN --email-subscription RECEIVE_RECOMMENDATIONS=YES --setting DISPLAY_STORE_RATING=NO --dry-run
|
|
356
|
+
direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
|
|
337
357
|
direct agencyclients add-passport-organization --name "Org" --currency RUB --notification-email ops@example.com --notification-lang EN --no-send-account-news --send-warnings --dry-run
|
|
338
358
|
direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
|
|
339
|
-
direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
|
|
359
|
+
direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
|
|
340
360
|
```
|
|
341
361
|
|
|
362
|
+
`direct agencyclients add` is runtime-deprecated by Yandex Direct and is blocked by the CLI. Use `direct agencyclients add-passport-organization` instead.
|
|
363
|
+
|
|
342
364
|
### Known Unsupported API Operation
|
|
343
365
|
|
|
344
366
|
`dynamicads update` is unsupported by API. The Yandex Direct
|
|
@@ -595,6 +617,45 @@ YANDEX_DIRECT_LOGIN=ваш_логин_на_яндексе
|
|
|
595
617
|
direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
|
|
596
618
|
```
|
|
597
619
|
|
|
620
|
+
Используйте профильные credentials из `.env`:
|
|
621
|
+
|
|
622
|
+
```env
|
|
623
|
+
YANDEX_DIRECT_TOKEN_AGENCY1=token-1
|
|
624
|
+
YANDEX_DIRECT_LOGIN_AGENCY1=client-login-1
|
|
625
|
+
YANDEX_DIRECT_TOKEN_AGENCY2=token-2
|
|
626
|
+
YANDEX_DIRECT_LOGIN_AGENCY2=client-login-2
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
OAuth и profile-команды:
|
|
630
|
+
|
|
631
|
+
```bash
|
|
632
|
+
direct auth login
|
|
633
|
+
direct auth login --profile agency1
|
|
634
|
+
direct auth login --code abc123 --profile agency1
|
|
635
|
+
direct auth login --oauth-token y0_example --profile agency1
|
|
636
|
+
direct auth list
|
|
637
|
+
direct auth use --profile agency1
|
|
638
|
+
direct auth status --profile agency1
|
|
639
|
+
direct --profile agency1 campaigns get
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
Порядок выбора credentials:
|
|
643
|
+
|
|
644
|
+
| Приоритет | Источник | Пример |
|
|
645
|
+
|-----------|----------|--------|
|
|
646
|
+
| 1 | Явные CLI-опции | `direct --token TOKEN --login LOGIN campaigns get` |
|
|
647
|
+
| 2 | OAuth profile storage | `direct --profile agency1 campaigns get` |
|
|
648
|
+
| 3 | Профильные env vars | `YANDEX_DIRECT_TOKEN_AGENCY1`, `YANDEX_DIRECT_LOGIN_AGENCY1` |
|
|
649
|
+
| 4 | Базовые env vars или project `.env` | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
|
|
650
|
+
| 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
|
|
651
|
+
| 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
|
|
652
|
+
|
|
653
|
+
Файл `.env` в проекте загружается автоматически. Если профиль выбран через
|
|
654
|
+
`--profile` или `direct auth use --profile NAME`, Direct CLI не подставляет
|
|
655
|
+
base `YANDEX_DIRECT_LOGIN`; это защищает от смешивания токена из профиля с
|
|
656
|
+
логином из project `.env`. Для нескольких аккаунтов используйте OAuth profiles
|
|
657
|
+
или профильные env vars, а не базовые credentials.
|
|
658
|
+
|
|
598
659
|
Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
|
|
599
660
|
через `direct`. Вызов deprecated entrypoint `direct-cli` завершается ошибкой с
|
|
600
661
|
подсказкой `use direct instead of direct-cli`.
|
|
@@ -605,6 +666,7 @@ direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
|
|
|
605
666
|
|-------|----------|
|
|
606
667
|
| `--token` | OAuth-токен доступа к API |
|
|
607
668
|
| `--login` | Direct client login |
|
|
669
|
+
| `--profile` | Имя credential profile |
|
|
608
670
|
| `--sandbox` | Использовать тестовое API (песочница) |
|
|
609
671
|
|
|
610
672
|
### Использование
|
|
@@ -863,7 +925,7 @@ direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --e
|
|
|
863
925
|
direct clients get --fields ClientId,Login,Currency
|
|
864
926
|
|
|
865
927
|
# Изменения
|
|
866
|
-
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
928
|
+
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
|
|
867
929
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
868
930
|
direct changes check-dictionaries
|
|
869
931
|
|
|
@@ -873,15 +935,18 @@ direct retargeting add --name "Список A" --type AUDIENCE --rule "ALL:12345
|
|
|
873
935
|
direct retargeting update --id 55 --name "Переименованный список" --rule "ANY:12345:30" --dry-run
|
|
874
936
|
|
|
875
937
|
# Ставки и модификаторы
|
|
938
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
876
939
|
direct bids set --keyword-id 123 --bid 15000000
|
|
877
940
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
878
941
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
879
942
|
direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
|
|
943
|
+
direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
|
|
880
944
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
881
945
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
882
946
|
|
|
883
947
|
# Канонические многословные группы
|
|
884
948
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
949
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
885
950
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
886
951
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
887
952
|
direct dynamicads add --adgroup-id 33 --name "Webpage A" --condition "URL:CONTAINS_ANY:test|shop" --condition "PAGE_CONTENT:CONTAINS:baz" --bid 3000000 --context-bid 2000000 --priority HIGH --dry-run
|
|
@@ -909,13 +974,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
909
974
|
direct creatives add --video-id video-id --dry-run
|
|
910
975
|
direct feeds add --name "Фид A" --url "https://example.com/feed.xml" --dry-run
|
|
911
976
|
direct feeds update --id 18 --name "Фид A v2" --url "https://example.com/feed-v2.xml" --dry-run
|
|
912
|
-
direct clients update --client-
|
|
913
|
-
direct
|
|
977
|
+
direct clients update --client-info "Приоритетный клиент" --phone +70000000000 --notification-email user@example.com --notification-lang EN --email-subscription RECEIVE_RECOMMENDATIONS=YES --setting DISPLAY_STORE_RATING=NO --dry-run
|
|
978
|
+
direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
|
|
914
979
|
direct agencyclients add-passport-organization --name "Org" --currency RUB --notification-email ops@example.com --notification-lang EN --no-send-account-news --send-warnings --dry-run
|
|
915
980
|
direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
|
|
916
|
-
direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
|
|
981
|
+
direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
|
|
917
982
|
```
|
|
918
983
|
|
|
984
|
+
`direct agencyclients add` runtime-deprecated в Yandex Direct и блокируется CLI. Используйте `direct agencyclients add-passport-organization`.
|
|
985
|
+
|
|
919
986
|
### Известная неподдерживаемая API-операция
|
|
920
987
|
|
|
921
988
|
`dynamicads update` unsupported by API. Сервис Яндекс Директа
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Live smoke-test probes for IDs that cannot be hardcoded safely."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from typing import Any, Optional
|
|
8
|
+
|
|
9
|
+
from .api import create_client
|
|
10
|
+
|
|
11
|
+
VIDEO_CREATIVE_TYPES = {"VIDEO_EXTENSION_CREATIVE", "CPM_VIDEO_CREATIVE"}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _extract_items(response: Any) -> list[dict[str, Any]]:
|
|
15
|
+
"""Return a normalized list from a tapi response object."""
|
|
16
|
+
data = response().extract()
|
|
17
|
+
return data if isinstance(data, list) else []
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _advideo_get_accepts(client: Any, candidate: str) -> bool:
|
|
21
|
+
"""Return whether advideos.get accepts and returns the candidate ID."""
|
|
22
|
+
body = {
|
|
23
|
+
"method": "get",
|
|
24
|
+
"params": {
|
|
25
|
+
"SelectionCriteria": {"Ids": [candidate]},
|
|
26
|
+
"FieldNames": ["Id", "Status"],
|
|
27
|
+
"Page": {"Limit": 1},
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
try:
|
|
31
|
+
return bool(_extract_items(client.advideos().post(data=body)))
|
|
32
|
+
except Exception:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def advideo_probe_id() -> Optional[str]:
|
|
37
|
+
"""Return an AdVideos ID accepted by ``advideos.get``, or ``None``.
|
|
38
|
+
|
|
39
|
+
Returns ``None`` (never raises) on auth failure, missing credentials,
|
|
40
|
+
or any network/API error — smoke scripts use this in a context where a
|
|
41
|
+
failed probe should be a benign skip, not a fatal error.
|
|
42
|
+
"""
|
|
43
|
+
try:
|
|
44
|
+
client = create_client()
|
|
45
|
+
except Exception:
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
env_id = os.getenv("YANDEX_DIRECT_TEST_ADVIDEO_ID")
|
|
49
|
+
if env_id and _advideo_get_accepts(client, env_id):
|
|
50
|
+
return env_id
|
|
51
|
+
|
|
52
|
+
body = {
|
|
53
|
+
"method": "get",
|
|
54
|
+
"params": {
|
|
55
|
+
"SelectionCriteria": {},
|
|
56
|
+
"FieldNames": ["Id", "Name", "Type"],
|
|
57
|
+
"Page": {"Limit": 20},
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
try:
|
|
61
|
+
creatives = _extract_items(client.creatives().post(data=body))
|
|
62
|
+
except Exception:
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
for creative in creatives:
|
|
66
|
+
if creative.get("Type") not in VIDEO_CREATIVE_TYPES:
|
|
67
|
+
continue
|
|
68
|
+
candidate = creative.get("Id")
|
|
69
|
+
if candidate and _advideo_get_accepts(client, str(candidate)):
|
|
70
|
+
return str(candidate)
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def main(argv: list[str] | None = None) -> int:
|
|
75
|
+
"""CLI entry point for smoke probes."""
|
|
76
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
77
|
+
if argv != ["advideo"]:
|
|
78
|
+
print("Usage: python3 -m direct_cli._smoke_probes advideo", file=sys.stderr)
|
|
79
|
+
return 2
|
|
80
|
+
|
|
81
|
+
probe_id = advideo_probe_id()
|
|
82
|
+
if not probe_id:
|
|
83
|
+
return 1
|
|
84
|
+
print(probe_id)
|
|
85
|
+
return 0
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
raise SystemExit(main())
|
|
@@ -65,6 +65,49 @@ class YandexDirectRequestsLimitError(YandexDirectClientError):
|
|
|
65
65
|
super().__init__(*args, **kwargs)
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
class V4LiveError(YandexDirectApiError):
|
|
69
|
+
"""Base exception for v4 Live API errors (error_code != 0).
|
|
70
|
+
|
|
71
|
+
v4 Live error payload differs from v5: integer ``error_code``, ``error_str``
|
|
72
|
+
instead of ``error_string``, no ``request_id``. Errors are returned with
|
|
73
|
+
HTTP 200 — they are detected from the response body, not the status code.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def __init__(
|
|
77
|
+
self,
|
|
78
|
+
response: Response,
|
|
79
|
+
message: Union[str, dict],
|
|
80
|
+
client: TapiClient,
|
|
81
|
+
*args,
|
|
82
|
+
**kwargs,
|
|
83
|
+
):
|
|
84
|
+
if isinstance(message, dict):
|
|
85
|
+
try:
|
|
86
|
+
self.error_code = int(message.get("error_code", 0))
|
|
87
|
+
except (TypeError, ValueError):
|
|
88
|
+
self.error_code = 0
|
|
89
|
+
self.error_str = message.get("error_str", "")
|
|
90
|
+
self.error_detail = message.get("error_detail", "")
|
|
91
|
+
else:
|
|
92
|
+
self.error_code = 0
|
|
93
|
+
self.error_str = str(message)
|
|
94
|
+
self.error_detail = ""
|
|
95
|
+
super().__init__(response, message, client, *args, **kwargs)
|
|
96
|
+
|
|
97
|
+
def __str__(self):
|
|
98
|
+
return "v4 Live error_code={}, error_str={}, error_detail={}".format(
|
|
99
|
+
self.error_code, self.error_str, self.error_detail
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class V4LiveTokenError(V4LiveError):
|
|
104
|
+
"""v4 Live error_code=53 — invalid or missing OAuth token."""
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class V4LiveRequestsLimitError(V4LiveError):
|
|
108
|
+
"""v4 Live error_code in (54, 55, 56) — rate / method limit exceeded."""
|
|
109
|
+
|
|
110
|
+
|
|
68
111
|
class BackwardCompatibilityError(Exception):
|
|
69
112
|
def __init__(self, name):
|
|
70
113
|
self.name = name
|