direct-cli 0.2.11__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.11 → direct_cli-0.3.0}/CLAUDE.md +11 -1
- {direct_cli-0.2.11 → direct_cli-0.3.0}/PKG-INFO +19 -9
- {direct_cli-0.2.11 → direct_cli-0.3.0}/README.md +18 -8
- direct_cli-0.3.0/direct_cli/_smoke_probes.py +89 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +2 -1
- {direct_cli-0.2.11 → 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.11 → direct_cli-0.3.0}/direct_cli/commands/adextensions.py +4 -2
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/ads.py +3 -5
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/agencyclients.py +70 -13
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/audiencetargets.py +30 -17
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/bidmodifiers.py +15 -3
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/bids.py +15 -3
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/businesses.py +2 -2
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/changes.py +14 -7
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/clients.py +51 -16
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/creatives.py +2 -4
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/dynamicads.py +18 -9
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/dynamicfeedadtargets.py +2 -4
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/keywordbids.py +7 -11
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/keywordsresearch.py +2 -2
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/leads.py +2 -6
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/negativekeywordsharedsets.py +4 -2
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/sitelinks.py +2 -2
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/smartadtargets.py +21 -10
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/strategies.py +8 -6
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/turbopages.py +2 -2
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/vcards.py +2 -6
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/smoke_matrix.py +3 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/utils.py +229 -10
- direct_cli-0.3.0/direct_cli/wsdl_coverage.py +581 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/PKG-INFO +19 -9
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/SOURCES.txt +11 -1
- {direct_cli-0.2.11 → direct_cli-0.3.0}/pyproject.toml +1 -1
- {direct_cli-0.2.11 → 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.11 → direct_cli-0.3.0}/scripts/check_wsdl_drift.py +49 -2
- {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/patch_vendor_imports.py +40 -9
- {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/test_safe_commands.sh +69 -13
- {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/update_vendor.sh +5 -6
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/API_COVERAGE.md +11 -1
- 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.11 → direct_cli-0.3.0}/tests/test_dry_run.py +346 -136
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_integration.py +2 -51
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_smoke_matrix.py +10 -0
- {direct_cli-0.2.11 → 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.11/direct_cli/wsdl_coverage.py +0 -346
- direct_cli-0.2.11/scripts/build_api_coverage_report.py +0 -236
- direct_cli-0.2.11/tests/test_api_coverage.py +0 -1373
- {direct_cli-0.2.11 → direct_cli-0.3.0}/.env.example +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/.github/copilot-instructions.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/.github/workflows/api-coverage.yml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/.github/workflows/claude-code-review.yml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/.github/workflows/claude.yml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/.gitignore +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/AGENTS.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/MANIFEST.in +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/__init__.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/_deprecated.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/_vendor/__init__.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/api.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/auth.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/cli.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/__init__.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/adgroups.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/adimages.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/advideos.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/auth.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/campaigns.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/dictionaries.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/feeds.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/keywords.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/reports.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/retargeting.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/output.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/reports_coverage.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/dependency_links.txt +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/entry_points.txt +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/requires.txt +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/top_level.txt +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/anonymize_cassettes.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/check_reports_drift.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/refresh_reports_cache.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/refresh_wsdl_cache.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/release_pypi.sh +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/sandbox_write_live.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/test_dangerous_commands.sh +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/test_sandbox_write.sh +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/setup.cfg +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/setup.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/API_ISSUE_AUDIT.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/MANUAL_COVERAGE.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/__init__.py +0 -0
- {direct_cli-0.2.11 → 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.11 → 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.11 → 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.11 → 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.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_advideos_add_get.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_suspend_resume.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_bids_set.yaml +0 -0
- {direct_cli-0.2.11 → 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.11 → 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.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_suspend_resume.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_keywordbids_set.yaml +0 -0
- {direct_cli-0.2.11 → 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.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_suspend_resume.yaml +0 -0
- {direct_cli-0.2.11 → 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.11 → 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.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_suspend_resume.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/conftest.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/fixtures/test-video.mp4 +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/reports_cache/raw/fields-list.html +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/reports_cache/raw/headers.html +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/reports_cache/raw/spec.html +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/reports_cache/raw/type.html +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/reports_cache/spec.json +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_auth_bw.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_auth_oauth.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_auth_op.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_cli.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_comprehensive.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_integration_live_write.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_integration_write.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_reports_drift.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_transport_contract.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/adextensions.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/adgroups.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/adimages.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/ads.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/advideos.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/agencyclients.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/audiencetargets.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/bidmodifiers.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/bids.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/businesses.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/campaigns.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/changes.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/clients.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/creatives.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/dictionaries.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/feeds.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/keywordbids.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/keywords.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/keywordsresearch.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/leads.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/retargetinglists.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/sitelinks.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/smartadtargets.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/strategies.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/turbopages.xml +0 -0
- {direct_cli-0.2.11 → 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
|
|
@@ -342,7 +342,7 @@ direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-n
|
|
|
342
342
|
direct clients get --fields ClientId,Login,Currency
|
|
343
343
|
|
|
344
344
|
# Changes
|
|
345
|
-
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
|
|
346
346
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
347
347
|
direct changes check-dictionaries
|
|
348
348
|
|
|
@@ -352,15 +352,18 @@ direct retargeting add --name "List A" --type AUDIENCE --rule "ALL:12345:30|6789
|
|
|
352
352
|
direct retargeting update --id 55 --name "Renamed" --rule "ANY:12345:30" --dry-run
|
|
353
353
|
|
|
354
354
|
# Bids and modifiers
|
|
355
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
355
356
|
direct bids set --keyword-id 123 --bid 15000000
|
|
356
357
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
357
358
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
358
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
|
|
359
361
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
360
362
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
361
363
|
|
|
362
364
|
# Canonical multiword groups
|
|
363
365
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
366
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
364
367
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
365
368
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
366
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
|
|
@@ -388,13 +391,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
388
391
|
direct creatives add --video-id video-id --dry-run
|
|
389
392
|
direct feeds add --name "Feed A" --url "https://example.com/feed.xml" --dry-run
|
|
390
393
|
direct feeds update --id 18 --name "Feed A v2" --url "https://example.com/feed-v2.xml" --dry-run
|
|
391
|
-
direct clients update --client-
|
|
392
|
-
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
|
|
393
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
|
|
394
397
|
direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
|
|
395
|
-
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
|
|
396
399
|
```
|
|
397
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
|
+
|
|
398
403
|
### Known Unsupported API Operation
|
|
399
404
|
|
|
400
405
|
`dynamicads update` is unsupported by API. The Yandex Direct
|
|
@@ -959,7 +964,7 @@ direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --e
|
|
|
959
964
|
direct clients get --fields ClientId,Login,Currency
|
|
960
965
|
|
|
961
966
|
# Изменения
|
|
962
|
-
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
|
|
963
968
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
964
969
|
direct changes check-dictionaries
|
|
965
970
|
|
|
@@ -969,15 +974,18 @@ direct retargeting add --name "Список A" --type AUDIENCE --rule "ALL:12345
|
|
|
969
974
|
direct retargeting update --id 55 --name "Переименованный список" --rule "ANY:12345:30" --dry-run
|
|
970
975
|
|
|
971
976
|
# Ставки и модификаторы
|
|
977
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
972
978
|
direct bids set --keyword-id 123 --bid 15000000
|
|
973
979
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
974
980
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
975
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
|
|
976
983
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
977
984
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
978
985
|
|
|
979
986
|
# Канонические многословные группы
|
|
980
987
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
988
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
981
989
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
982
990
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
983
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
|
|
@@ -1005,13 +1013,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
1005
1013
|
direct creatives add --video-id video-id --dry-run
|
|
1006
1014
|
direct feeds add --name "Фид A" --url "https://example.com/feed.xml" --dry-run
|
|
1007
1015
|
direct feeds update --id 18 --name "Фид A v2" --url "https://example.com/feed-v2.xml" --dry-run
|
|
1008
|
-
direct clients update --client-
|
|
1009
|
-
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
|
|
1010
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
|
|
1011
1019
|
direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
|
|
1012
|
-
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
|
|
1013
1021
|
```
|
|
1014
1022
|
|
|
1023
|
+
`direct agencyclients add` runtime-deprecated в Yandex Direct и блокируется CLI. Используйте `direct agencyclients add-passport-organization`.
|
|
1024
|
+
|
|
1015
1025
|
### Известная неподдерживаемая API-операция
|
|
1016
1026
|
|
|
1017
1027
|
`dynamicads update` unsupported by API. Сервис Яндекс Директа
|
|
@@ -303,7 +303,7 @@ direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-n
|
|
|
303
303
|
direct clients get --fields ClientId,Login,Currency
|
|
304
304
|
|
|
305
305
|
# Changes
|
|
306
|
-
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
|
|
307
307
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
308
308
|
direct changes check-dictionaries
|
|
309
309
|
|
|
@@ -313,15 +313,18 @@ direct retargeting add --name "List A" --type AUDIENCE --rule "ALL:12345:30|6789
|
|
|
313
313
|
direct retargeting update --id 55 --name "Renamed" --rule "ANY:12345:30" --dry-run
|
|
314
314
|
|
|
315
315
|
# Bids and modifiers
|
|
316
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
316
317
|
direct bids set --keyword-id 123 --bid 15000000
|
|
317
318
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
318
319
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
319
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
|
|
320
322
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
321
323
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
322
324
|
|
|
323
325
|
# Canonical multiword groups
|
|
324
326
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
327
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
325
328
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
326
329
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
327
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
|
|
@@ -349,13 +352,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
349
352
|
direct creatives add --video-id video-id --dry-run
|
|
350
353
|
direct feeds add --name "Feed A" --url "https://example.com/feed.xml" --dry-run
|
|
351
354
|
direct feeds update --id 18 --name "Feed A v2" --url "https://example.com/feed-v2.xml" --dry-run
|
|
352
|
-
direct clients update --client-
|
|
353
|
-
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
|
|
354
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
|
|
355
358
|
direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
|
|
356
|
-
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
|
|
357
360
|
```
|
|
358
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
|
+
|
|
359
364
|
### Known Unsupported API Operation
|
|
360
365
|
|
|
361
366
|
`dynamicads update` is unsupported by API. The Yandex Direct
|
|
@@ -920,7 +925,7 @@ direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --e
|
|
|
920
925
|
direct clients get --fields ClientId,Login,Currency
|
|
921
926
|
|
|
922
927
|
# Изменения
|
|
923
|
-
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
|
|
924
929
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
925
930
|
direct changes check-dictionaries
|
|
926
931
|
|
|
@@ -930,15 +935,18 @@ direct retargeting add --name "Список A" --type AUDIENCE --rule "ALL:12345
|
|
|
930
935
|
direct retargeting update --id 55 --name "Переименованный список" --rule "ANY:12345:30" --dry-run
|
|
931
936
|
|
|
932
937
|
# Ставки и модификаторы
|
|
938
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
933
939
|
direct bids set --keyword-id 123 --bid 15000000
|
|
934
940
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
935
941
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
936
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
|
|
937
944
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
938
945
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
939
946
|
|
|
940
947
|
# Канонические многословные группы
|
|
941
948
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
949
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
942
950
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
943
951
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
944
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
|
|
@@ -966,13 +974,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
966
974
|
direct creatives add --video-id video-id --dry-run
|
|
967
975
|
direct feeds add --name "Фид A" --url "https://example.com/feed.xml" --dry-run
|
|
968
976
|
direct feeds update --id 18 --name "Фид A v2" --url "https://example.com/feed-v2.xml" --dry-run
|
|
969
|
-
direct clients update --client-
|
|
970
|
-
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
|
|
971
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
|
|
972
980
|
direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
|
|
973
|
-
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
|
|
974
982
|
```
|
|
975
983
|
|
|
984
|
+
`direct agencyclients add` runtime-deprecated в Yandex Direct и блокируется CLI. Используйте `direct agencyclients add-passport-organization`.
|
|
985
|
+
|
|
976
986
|
### Известная неподдерживаемая API-операция
|
|
977
987
|
|
|
978
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
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
from typing import List, Iterator, Union
|
|
2
|
+
|
|
3
|
+
from requests import Response
|
|
4
|
+
|
|
5
|
+
class YandexDirectBaseMethodsClientResponse:
|
|
6
|
+
@property
|
|
7
|
+
def data(self) -> dict: ...
|
|
8
|
+
@property
|
|
9
|
+
def request_kwargs(self) -> dict: ...
|
|
10
|
+
@property
|
|
11
|
+
def response(self) -> Response: ...
|
|
12
|
+
@property
|
|
13
|
+
def status_code(self) -> int: ...
|
|
14
|
+
def __getitem__(self, item) -> Union[dict, list]: ...
|
|
15
|
+
def __iter__(self) -> Iterator: ...
|
|
16
|
+
|
|
17
|
+
# Yandex Direct management.
|
|
18
|
+
class YandexDirectClientResponse(YandexDirectBaseMethodsClientResponse):
|
|
19
|
+
def pages(
|
|
20
|
+
self, *, max_pages: int = None
|
|
21
|
+
) -> Iterator["YandexDirectPageIteratorExecutor"]: ...
|
|
22
|
+
def items(self, *, max_items: int = None) -> Iterator[dict]: ...
|
|
23
|
+
def iter_items(
|
|
24
|
+
self, *, max_pages: int = None, max_items: int = None
|
|
25
|
+
) -> Iterator[dict]: ...
|
|
26
|
+
def extract(self) -> List[dict]: ...
|
|
27
|
+
|
|
28
|
+
class YandexDirectClientExecutorResponse(YandexDirectBaseMethodsClientResponse):
|
|
29
|
+
def __call__(self) -> YandexDirectClientResponse: ...
|
|
30
|
+
|
|
31
|
+
class YandexDirectClientExecutor:
|
|
32
|
+
def open_docs(self) -> YandexDirectClientExecutor:
|
|
33
|
+
"""Open API official docs of resource in browser."""
|
|
34
|
+
def open_in_browser(self) -> YandexDirectClientExecutor:
|
|
35
|
+
"""Send a request in the browser."""
|
|
36
|
+
def help(self) -> YandexDirectClientExecutor:
|
|
37
|
+
"""Print docs of resource."""
|
|
38
|
+
def get(
|
|
39
|
+
self, *, params: dict = None, data: dict = None, headers: dict = None
|
|
40
|
+
) -> YandexDirectClientExecutorResponse:
|
|
41
|
+
"""
|
|
42
|
+
Send HTTP 'GET' request.
|
|
43
|
+
|
|
44
|
+
:param params: querystring arguments in the URL
|
|
45
|
+
:param data: send data in the body of the request
|
|
46
|
+
"""
|
|
47
|
+
def post(
|
|
48
|
+
self, *, params: dict = None, data: dict = None, headers: dict = None
|
|
49
|
+
) -> YandexDirectClientExecutorResponse:
|
|
50
|
+
"""
|
|
51
|
+
Send HTTP 'POST' request.
|
|
52
|
+
|
|
53
|
+
:param params: querystring arguments in the URL
|
|
54
|
+
:param data: send data in the body of the request
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
class YandexDirectPageIteratorResponse(YandexDirectBaseMethodsClientResponse):
|
|
58
|
+
def items(self, *, max_items: int = None) -> Iterator[dict]: ...
|
|
59
|
+
|
|
60
|
+
class YandexDirectPageIteratorExecutor(YandexDirectBaseMethodsClientResponse):
|
|
61
|
+
def __call__(self) -> YandexDirectPageIteratorResponse: ...
|
|
62
|
+
|
|
63
|
+
# Yandex Direct reports.
|
|
64
|
+
class YandexDirectClientReportResponse(YandexDirectBaseMethodsClientResponse):
|
|
65
|
+
def iter_lines(self) -> Iterator[str]: ...
|
|
66
|
+
def iter_values(self) -> Iterator[list]: ...
|
|
67
|
+
def iter_dicts(self) -> Iterator[dict]: ...
|
|
68
|
+
def to_lines(self) -> List[str]: ...
|
|
69
|
+
def to_values(self) -> List[list]: ...
|
|
70
|
+
def to_columns(self) -> List[list]: ...
|
|
71
|
+
def to_dicts(self) -> List[dict]: ...
|
|
72
|
+
|
|
73
|
+
class YandexDirectClientReportExecutorResponse(YandexDirectBaseMethodsClientResponse):
|
|
74
|
+
def __call__(self) -> YandexDirectClientReportResponse: ...
|
|
75
|
+
@property
|
|
76
|
+
def columns(self) -> List[str]: ...
|
|
77
|
+
|
|
78
|
+
class YandexDirectClientReportExecutor:
|
|
79
|
+
def open_docs(self) -> YandexDirectClientReportExecutor:
|
|
80
|
+
"""Open API official docs of resource in browser."""
|
|
81
|
+
def open_in_browser(self) -> YandexDirectClientReportExecutor:
|
|
82
|
+
"""Send a request in the browser."""
|
|
83
|
+
def help(self) -> YandexDirectClientReportExecutor:
|
|
84
|
+
"""Print docs of resource."""
|
|
85
|
+
def post(
|
|
86
|
+
self, *, params: dict = None, data: dict = None, headers: dict = None
|
|
87
|
+
) -> YandexDirectClientReportExecutorResponse:
|
|
88
|
+
"""
|
|
89
|
+
Send HTTP 'POST' request.
|
|
90
|
+
|
|
91
|
+
:param params: querystring arguments in the URL
|
|
92
|
+
:param data: send data in the body of the request
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
# Main.
|
|
96
|
+
class YandexDirect:
|
|
97
|
+
def __init__(
|
|
98
|
+
self,
|
|
99
|
+
*,
|
|
100
|
+
access_token: str,
|
|
101
|
+
login: str = None,
|
|
102
|
+
is_sandbox: bool = False,
|
|
103
|
+
retry_if_not_enough_units: bool = False,
|
|
104
|
+
retry_if_exceeded_limit: bool = True,
|
|
105
|
+
retries_if_server_error: int = 5,
|
|
106
|
+
language: str = None,
|
|
107
|
+
processing_mode: str = "offline",
|
|
108
|
+
wait_report: bool = True,
|
|
109
|
+
return_money_in_micros: bool = False,
|
|
110
|
+
skip_report_header: bool = True,
|
|
111
|
+
skip_column_header: bool = False,
|
|
112
|
+
skip_report_summary: bool = True,
|
|
113
|
+
):
|
|
114
|
+
"""
|
|
115
|
+
Official documentation of the reports resource: https://yandex.ru/dev/direct/doc/ref-v5/concepts/about.html
|
|
116
|
+
Official documentation of other resources: https://yandex.ru/dev/direct/doc/reports/how-to.html
|
|
117
|
+
|
|
118
|
+
:param access_token: Access token.
|
|
119
|
+
:param login: If you are making inquiries from an agent account, you must be sure to specify the account login.
|
|
120
|
+
:param is_sandbox: Enable sandbox.
|
|
121
|
+
:param retry_if_not_enough_units: Repeat request when units run out
|
|
122
|
+
:param retry_if_exceeded_limit: Repeat the request if the limits on the number of reports or requests are exceeded.
|
|
123
|
+
:param retries_if_server_error: Number of retries when server errors occur.
|
|
124
|
+
:param language: The language in which the data for directories and errors will be returned.
|
|
125
|
+
|
|
126
|
+
:param processing_mode: (report resource) Report generation mode: online, offline or auto.
|
|
127
|
+
:param wait_report: (report resource) When requesting a report, it will wait until the report is prepared and download it.
|
|
128
|
+
:param return_money_in_micros: (report resource) Monetary values in the report are returned in currency with an accuracy of two decimal places.
|
|
129
|
+
:param skip_report_header: (report resource) Do not display a line with the report name and date range in the report.
|
|
130
|
+
:param skip_column_header: (report resource) Do not display a line with field names in the report.
|
|
131
|
+
:param skip_report_summary: (report resource) Do not display a line with the number of statistics lines in the report.
|
|
132
|
+
"""
|
|
133
|
+
def reports(self) -> YandexDirectClientReportExecutor: ...
|
|
134
|
+
def adextensions(self) -> YandexDirectClientExecutor: ...
|
|
135
|
+
def adgroups(self) -> YandexDirectClientExecutor: ...
|
|
136
|
+
def adimages(self) -> YandexDirectClientExecutor: ...
|
|
137
|
+
def advideos(self) -> YandexDirectClientExecutor: ...
|
|
138
|
+
def ads(self) -> YandexDirectClientExecutor: ...
|
|
139
|
+
def agencyclients(self) -> YandexDirectClientExecutor: ...
|
|
140
|
+
def audiencetargets(self) -> YandexDirectClientExecutor: ...
|
|
141
|
+
def bidmodifiers(self) -> YandexDirectClientExecutor: ...
|
|
142
|
+
def bids(self) -> YandexDirectClientExecutor: ...
|
|
143
|
+
def businesses(self) -> YandexDirectClientExecutor: ...
|
|
144
|
+
def campaigns(self) -> YandexDirectClientExecutor: ...
|
|
145
|
+
def changes(self) -> YandexDirectClientExecutor: ...
|
|
146
|
+
def clients(self) -> YandexDirectClientExecutor: ...
|
|
147
|
+
def creatives(self) -> YandexDirectClientExecutor: ...
|
|
148
|
+
def debugtoken(self, *, client_id: str) -> YandexDirectClientExecutor: ...
|
|
149
|
+
def dictionaries(self) -> YandexDirectClientExecutor: ...
|
|
150
|
+
def dynamicads(self) -> YandexDirectClientExecutor: ...
|
|
151
|
+
def dynamicfeedadtargets(self) -> YandexDirectClientExecutor: ...
|
|
152
|
+
def feeds(self) -> YandexDirectClientExecutor: ...
|
|
153
|
+
def keywordbids(self) -> YandexDirectClientExecutor: ...
|
|
154
|
+
def keywords(self) -> YandexDirectClientExecutor: ...
|
|
155
|
+
def keywordsresearch(self) -> YandexDirectClientExecutor: ...
|
|
156
|
+
def leads(self) -> YandexDirectClientExecutor: ...
|
|
157
|
+
def negativekeywordsharedsets(self) -> YandexDirectClientExecutor: ...
|
|
158
|
+
def retargeting(self) -> YandexDirectClientExecutor: ...
|
|
159
|
+
def sitelinks(self) -> YandexDirectClientExecutor: ...
|
|
160
|
+
def smartadtargets(self) -> YandexDirectClientExecutor: ...
|
|
161
|
+
def strategies(self) -> YandexDirectClientExecutor: ...
|
|
162
|
+
def turbopages(self) -> YandexDirectClientExecutor: ...
|
|
163
|
+
def vcards(self) -> YandexDirectClientExecutor: ...
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from .adapter import V4LiveClientAdapter, YandexDirectV4Live
|
|
2
|
+
from .resource_mapping import RESOURCE_MAPPING_V4_LIVE, SUPPORTED_V4_METHODS
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"V4LiveClientAdapter",
|
|
6
|
+
"YandexDirectV4Live",
|
|
7
|
+
"RESOURCE_MAPPING_V4_LIVE",
|
|
8
|
+
"SUPPORTED_V4_METHODS",
|
|
9
|
+
]
|