direct-cli 0.2.11__tar.gz → 0.3.1__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.1}/CLAUDE.md +11 -1
- {direct_cli-0.2.11 → direct_cli-0.3.1}/PKG-INFO +39 -9
- {direct_cli-0.2.11 → direct_cli-0.3.1}/README.md +38 -8
- direct_cli-0.3.1/direct_cli/_smoke_probes.py +94 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +2 -1
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +43 -0
- direct_cli-0.3.1/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +163 -0
- direct_cli-0.3.1/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +9 -0
- direct_cli-0.3.1/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +221 -0
- direct_cli-0.3.1/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +54 -0
- direct_cli-0.3.1/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +66 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/api.py +53 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/cli.py +18 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/adextensions.py +4 -2
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/ads.py +3 -5
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/agencyclients.py +70 -13
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/audiencetargets.py +30 -17
- direct_cli-0.3.1/direct_cli/commands/balance.py +55 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/bidmodifiers.py +15 -3
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/bids.py +15 -3
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/businesses.py +2 -2
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/changes.py +14 -7
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/clients.py +51 -16
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/creatives.py +2 -4
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/dynamicads.py +18 -9
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/dynamicfeedadtargets.py +2 -4
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/keywordbids.py +7 -11
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/keywordsresearch.py +2 -2
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/leads.py +2 -6
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/negativekeywordsharedsets.py +4 -2
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/sitelinks.py +2 -2
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/smartadtargets.py +21 -10
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/strategies.py +8 -6
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/turbopages.py +2 -2
- direct_cli-0.3.1/direct_cli/commands/v4goals.py +103 -0
- direct_cli-0.3.1/direct_cli/commands/v4shells.py +40 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/vcards.py +2 -6
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/smoke_matrix.py +14 -5
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/utils.py +229 -10
- direct_cli-0.3.1/direct_cli/v4.py +17 -0
- direct_cli-0.3.1/direct_cli/v4_contracts.py +433 -0
- direct_cli-0.3.1/direct_cli/wsdl_coverage.py +581 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli.egg-info/PKG-INFO +39 -9
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli.egg-info/SOURCES.txt +21 -1
- {direct_cli-0.2.11 → direct_cli-0.3.1}/pyproject.toml +2 -1
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/build_api_coverage_checklist.py +48 -34
- direct_cli-0.3.1/scripts/build_api_coverage_report.py +1040 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/check_wsdl_drift.py +49 -2
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/patch_vendor_imports.py +40 -9
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/test_safe_commands.sh +73 -14
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/update_vendor.sh +5 -6
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/API_COVERAGE.md +11 -1
- direct_cli-0.3.1/tests/api_coverage_payloads.py +450 -0
- direct_cli-0.3.1/tests/test_api_coverage.py +1765 -0
- direct_cli-0.3.1/tests/test_balance.py +137 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_comprehensive.py +8 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_dry_run.py +348 -138
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_integration.py +5 -55
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_smoke_matrix.py +31 -8
- direct_cli-0.3.1/tests/test_v4_contracts.py +141 -0
- direct_cli-0.3.1/tests/test_v4_foundation.py +91 -0
- direct_cli-0.3.1/tests/test_v4_live_contracts.py +79 -0
- direct_cli-0.3.1/tests/test_v4goals.py +190 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_vendor_imports.py +34 -12
- direct_cli-0.3.1/tests/wsdl_cache/imports/adextensiontypes.xsd +60 -0
- direct_cli-0.3.1/tests/wsdl_cache/imports/general.xsd +444 -0
- direct_cli-0.3.1/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.1}/.env.example +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/.github/copilot-instructions.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/.github/workflows/api-coverage.yml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/.github/workflows/claude-code-review.yml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/.github/workflows/claude.yml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/.gitignore +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/AGENTS.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/MANIFEST.in +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/__init__.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/_deprecated.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/_vendor/__init__.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/auth.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/__init__.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/adgroups.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/adimages.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/advideos.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/auth.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/campaigns.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/dictionaries.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/feeds.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/keywords.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/reports.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/commands/retargeting.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/output.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli/reports_coverage.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli.egg-info/dependency_links.txt +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli.egg-info/entry_points.txt +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli.egg-info/requires.txt +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/direct_cli.egg-info/top_level.txt +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/anonymize_cassettes.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/check_reports_drift.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/refresh_reports_cache.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/refresh_wsdl_cache.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/release_pypi.sh +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/sandbox_write_live.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/test_dangerous_commands.sh +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/scripts/test_sandbox_write.sh +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/setup.cfg +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/setup.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/API_ISSUE_AUDIT.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/MANUAL_COVERAGE.md +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/__init__.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/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.1}/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.1}/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.1}/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.1}/tests/cassettes/test_integration_live_write/test_live_draft_advideos_add_get.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_suspend_resume.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_bids_set.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/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.1}/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.1}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_suspend_resume.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_keywordbids_set.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/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.1}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_suspend_resume.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/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.1}/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.1}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_suspend_resume.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/conftest.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/fixtures/test-video.mp4 +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/reports_cache/raw/fields-list.html +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/reports_cache/raw/headers.html +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/reports_cache/raw/spec.html +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/reports_cache/raw/type.html +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/reports_cache/spec.json +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_auth_bw.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_auth_oauth.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_auth_op.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_cli.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_integration_live_write.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_integration_write.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_reports_drift.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/test_transport_contract.py +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/adextensions.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/adgroups.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/adimages.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/ads.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/advideos.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/agencyclients.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/audiencetargets.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/bidmodifiers.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/bids.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/businesses.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/campaigns.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/changes.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/clients.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/creatives.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/dictionaries.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/feeds.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/keywordbids.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/keywords.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/keywordsresearch.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/leads.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/retargetinglists.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/sitelinks.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/smartadtargets.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/strategies.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/tests/wsdl_cache/turbopages.xml +0 -0
- {direct_cli-0.2.11 → direct_cli-0.3.1}/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.1
|
|
4
4
|
Summary: Command-line interface for Yandex Direct API
|
|
5
5
|
Author: axisrow
|
|
6
6
|
License: MIT
|
|
@@ -118,6 +118,18 @@ Install with `pip install direct-cli`, then run commands with `direct`.
|
|
|
118
118
|
Invoking the deprecated `direct-cli` entrypoint exits with
|
|
119
119
|
`use direct instead of direct-cli`.
|
|
120
120
|
|
|
121
|
+
### Quick Start: Check Balance
|
|
122
|
+
|
|
123
|
+
Yandex removed the legacy v4 `GetBalance` method. Direct CLI uses the v4 Live
|
|
124
|
+
`AccountManagement` method with `Action=Get` for `direct balance`, returning
|
|
125
|
+
money fields such as `Amount`, `AmountAvailableForTransfer`, and `Currency`.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
direct balance
|
|
129
|
+
direct balance --logins client-login,other-client --format table
|
|
130
|
+
direct balance --logins client-login --dry-run
|
|
131
|
+
```
|
|
132
|
+
|
|
121
133
|
### Global Options
|
|
122
134
|
|
|
123
135
|
| Option | Description |
|
|
@@ -127,6 +139,14 @@ Invoking the deprecated `direct-cli` entrypoint exits with
|
|
|
127
139
|
| `--profile` | Credential profile name |
|
|
128
140
|
| `--sandbox` | Use sandbox API |
|
|
129
141
|
|
|
142
|
+
### V4 Live Goals
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
direct v4goals get-stat-goals --campaign-ids 123,456
|
|
146
|
+
direct v4goals get-retargeting-goals --campaign-ids 123,456 --format table
|
|
147
|
+
direct v4goals get-stat-goals --campaign-ids 123 --dry-run
|
|
148
|
+
```
|
|
149
|
+
|
|
130
150
|
### CLI Convention
|
|
131
151
|
|
|
132
152
|
The current CLI convention is defined as follows.
|
|
@@ -342,7 +362,7 @@ direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-n
|
|
|
342
362
|
direct clients get --fields ClientId,Login,Currency
|
|
343
363
|
|
|
344
364
|
# Changes
|
|
345
|
-
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
365
|
+
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
|
|
346
366
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
347
367
|
direct changes check-dictionaries
|
|
348
368
|
|
|
@@ -352,15 +372,18 @@ direct retargeting add --name "List A" --type AUDIENCE --rule "ALL:12345:30|6789
|
|
|
352
372
|
direct retargeting update --id 55 --name "Renamed" --rule "ANY:12345:30" --dry-run
|
|
353
373
|
|
|
354
374
|
# Bids and modifiers
|
|
375
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
355
376
|
direct bids set --keyword-id 123 --bid 15000000
|
|
356
377
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
357
378
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
358
379
|
direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
|
|
380
|
+
direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
|
|
359
381
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
360
382
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
361
383
|
|
|
362
384
|
# Canonical multiword groups
|
|
363
385
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
386
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
364
387
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
365
388
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
366
389
|
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 +411,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
388
411
|
direct creatives add --video-id video-id --dry-run
|
|
389
412
|
direct feeds add --name "Feed A" --url "https://example.com/feed.xml" --dry-run
|
|
390
413
|
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
|
|
414
|
+
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
|
|
415
|
+
direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
|
|
393
416
|
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
417
|
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
|
|
418
|
+
direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
|
|
396
419
|
```
|
|
397
420
|
|
|
421
|
+
`direct agencyclients add` is runtime-deprecated by Yandex Direct and is blocked by the CLI. Use `direct agencyclients add-passport-organization` instead.
|
|
422
|
+
|
|
398
423
|
### Known Unsupported API Operation
|
|
399
424
|
|
|
400
425
|
`dynamicads update` is unsupported by API. The Yandex Direct
|
|
@@ -959,7 +984,7 @@ direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --e
|
|
|
959
984
|
direct clients get --fields ClientId,Login,Currency
|
|
960
985
|
|
|
961
986
|
# Изменения
|
|
962
|
-
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
987
|
+
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
|
|
963
988
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
964
989
|
direct changes check-dictionaries
|
|
965
990
|
|
|
@@ -969,15 +994,18 @@ direct retargeting add --name "Список A" --type AUDIENCE --rule "ALL:12345
|
|
|
969
994
|
direct retargeting update --id 55 --name "Переименованный список" --rule "ANY:12345:30" --dry-run
|
|
970
995
|
|
|
971
996
|
# Ставки и модификаторы
|
|
997
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
972
998
|
direct bids set --keyword-id 123 --bid 15000000
|
|
973
999
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
974
1000
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
975
1001
|
direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
|
|
1002
|
+
direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
|
|
976
1003
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
977
1004
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
978
1005
|
|
|
979
1006
|
# Канонические многословные группы
|
|
980
1007
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
1008
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
981
1009
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
982
1010
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
983
1011
|
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 +1033,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
1005
1033
|
direct creatives add --video-id video-id --dry-run
|
|
1006
1034
|
direct feeds add --name "Фид A" --url "https://example.com/feed.xml" --dry-run
|
|
1007
1035
|
direct feeds update --id 18 --name "Фид A v2" --url "https://example.com/feed-v2.xml" --dry-run
|
|
1008
|
-
direct clients update --client-
|
|
1009
|
-
direct
|
|
1036
|
+
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
|
|
1037
|
+
direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
|
|
1010
1038
|
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
1039
|
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
|
|
1040
|
+
direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
|
|
1013
1041
|
```
|
|
1014
1042
|
|
|
1043
|
+
`direct agencyclients add` runtime-deprecated в Yandex Direct и блокируется CLI. Используйте `direct agencyclients add-passport-organization`.
|
|
1044
|
+
|
|
1015
1045
|
### Известная неподдерживаемая API-операция
|
|
1016
1046
|
|
|
1017
1047
|
`dynamicads update` unsupported by API. Сервис Яндекс Директа
|
|
@@ -79,6 +79,18 @@ Install with `pip install direct-cli`, then run commands with `direct`.
|
|
|
79
79
|
Invoking the deprecated `direct-cli` entrypoint exits with
|
|
80
80
|
`use direct instead of direct-cli`.
|
|
81
81
|
|
|
82
|
+
### Quick Start: Check Balance
|
|
83
|
+
|
|
84
|
+
Yandex removed the legacy v4 `GetBalance` method. Direct CLI uses the v4 Live
|
|
85
|
+
`AccountManagement` method with `Action=Get` for `direct balance`, returning
|
|
86
|
+
money fields such as `Amount`, `AmountAvailableForTransfer`, and `Currency`.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
direct balance
|
|
90
|
+
direct balance --logins client-login,other-client --format table
|
|
91
|
+
direct balance --logins client-login --dry-run
|
|
92
|
+
```
|
|
93
|
+
|
|
82
94
|
### Global Options
|
|
83
95
|
|
|
84
96
|
| Option | Description |
|
|
@@ -88,6 +100,14 @@ Invoking the deprecated `direct-cli` entrypoint exits with
|
|
|
88
100
|
| `--profile` | Credential profile name |
|
|
89
101
|
| `--sandbox` | Use sandbox API |
|
|
90
102
|
|
|
103
|
+
### V4 Live Goals
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
direct v4goals get-stat-goals --campaign-ids 123,456
|
|
107
|
+
direct v4goals get-retargeting-goals --campaign-ids 123,456 --format table
|
|
108
|
+
direct v4goals get-stat-goals --campaign-ids 123 --dry-run
|
|
109
|
+
```
|
|
110
|
+
|
|
91
111
|
### CLI Convention
|
|
92
112
|
|
|
93
113
|
The current CLI convention is defined as follows.
|
|
@@ -303,7 +323,7 @@ direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-n
|
|
|
303
323
|
direct clients get --fields ClientId,Login,Currency
|
|
304
324
|
|
|
305
325
|
# Changes
|
|
306
|
-
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
326
|
+
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
|
|
307
327
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
308
328
|
direct changes check-dictionaries
|
|
309
329
|
|
|
@@ -313,15 +333,18 @@ direct retargeting add --name "List A" --type AUDIENCE --rule "ALL:12345:30|6789
|
|
|
313
333
|
direct retargeting update --id 55 --name "Renamed" --rule "ANY:12345:30" --dry-run
|
|
314
334
|
|
|
315
335
|
# Bids and modifiers
|
|
336
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
316
337
|
direct bids set --keyword-id 123 --bid 15000000
|
|
317
338
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
318
339
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
319
340
|
direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
|
|
341
|
+
direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
|
|
320
342
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
321
343
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
322
344
|
|
|
323
345
|
# Canonical multiword groups
|
|
324
346
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
347
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
325
348
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
326
349
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
327
350
|
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 +372,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
349
372
|
direct creatives add --video-id video-id --dry-run
|
|
350
373
|
direct feeds add --name "Feed A" --url "https://example.com/feed.xml" --dry-run
|
|
351
374
|
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
|
|
375
|
+
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
|
|
376
|
+
direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
|
|
354
377
|
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
378
|
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
|
|
379
|
+
direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
|
|
357
380
|
```
|
|
358
381
|
|
|
382
|
+
`direct agencyclients add` is runtime-deprecated by Yandex Direct and is blocked by the CLI. Use `direct agencyclients add-passport-organization` instead.
|
|
383
|
+
|
|
359
384
|
### Known Unsupported API Operation
|
|
360
385
|
|
|
361
386
|
`dynamicads update` is unsupported by API. The Yandex Direct
|
|
@@ -920,7 +945,7 @@ direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --e
|
|
|
920
945
|
direct clients get --fields ClientId,Login,Currency
|
|
921
946
|
|
|
922
947
|
# Изменения
|
|
923
|
-
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
948
|
+
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
|
|
924
949
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
925
950
|
direct changes check-dictionaries
|
|
926
951
|
|
|
@@ -930,15 +955,18 @@ direct retargeting add --name "Список A" --type AUDIENCE --rule "ALL:12345
|
|
|
930
955
|
direct retargeting update --id 55 --name "Переименованный список" --rule "ANY:12345:30" --dry-run
|
|
931
956
|
|
|
932
957
|
# Ставки и модификаторы
|
|
958
|
+
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
933
959
|
direct bids set --keyword-id 123 --bid 15000000
|
|
934
960
|
direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
|
|
935
961
|
direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
|
|
936
962
|
direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
|
|
963
|
+
direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
|
|
937
964
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
938
965
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
939
966
|
|
|
940
967
|
# Канонические многословные группы
|
|
941
968
|
direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
|
|
969
|
+
direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
|
|
942
970
|
direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
|
|
943
971
|
direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
|
|
944
972
|
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 +994,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
|
|
|
966
994
|
direct creatives add --video-id video-id --dry-run
|
|
967
995
|
direct feeds add --name "Фид A" --url "https://example.com/feed.xml" --dry-run
|
|
968
996
|
direct feeds update --id 18 --name "Фид A v2" --url "https://example.com/feed-v2.xml" --dry-run
|
|
969
|
-
direct clients update --client-
|
|
970
|
-
direct
|
|
997
|
+
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
|
|
998
|
+
direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
|
|
971
999
|
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
1000
|
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
|
|
1001
|
+
direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
|
|
974
1002
|
```
|
|
975
1003
|
|
|
1004
|
+
`direct agencyclients add` runtime-deprecated в Yandex Direct и блокируется CLI. Используйте `direct agencyclients add-passport-organization`.
|
|
1005
|
+
|
|
976
1006
|
### Известная неподдерживаемая API-операция
|
|
977
1007
|
|
|
978
1008
|
`dynamicads update` unsupported by API. Сервис Яндекс Директа
|
|
@@ -0,0 +1,94 @@
|
|
|
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 = {
|
|
12
|
+
"VIDEO_EXTENSION_CREATIVE",
|
|
13
|
+
"CPM_VIDEO_CREATIVE",
|
|
14
|
+
"CPC_VIDEO_CREATIVE",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _extract_items(response: Any) -> list[dict[str, Any]]:
|
|
19
|
+
"""Return a normalized list from a tapi response object."""
|
|
20
|
+
data = response().extract()
|
|
21
|
+
return data if isinstance(data, list) else []
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _advideo_get_accepts(client: Any, candidate: str) -> bool:
|
|
25
|
+
"""Return whether advideos.get accepts the candidate ID."""
|
|
26
|
+
body = {
|
|
27
|
+
"method": "get",
|
|
28
|
+
"params": {
|
|
29
|
+
"SelectionCriteria": {"Ids": [candidate]},
|
|
30
|
+
"FieldNames": ["Id", "Status"],
|
|
31
|
+
"Page": {"Limit": 1},
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
try:
|
|
35
|
+
_extract_items(client.advideos().post(data=body))
|
|
36
|
+
return True
|
|
37
|
+
except Exception:
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def advideo_probe_id() -> Optional[str]:
|
|
42
|
+
"""Return an AdVideos ID accepted by ``advideos.get``, or ``None``.
|
|
43
|
+
|
|
44
|
+
Returns ``None`` (never raises) on auth failure, missing credentials,
|
|
45
|
+
or any network/API error — smoke scripts use this in a context where a
|
|
46
|
+
failed probe should be a benign skip, not a fatal error.
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
client = create_client()
|
|
50
|
+
except Exception:
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
env_id = os.getenv("YANDEX_DIRECT_TEST_ADVIDEO_ID")
|
|
54
|
+
if env_id and _advideo_get_accepts(client, env_id):
|
|
55
|
+
return env_id
|
|
56
|
+
|
|
57
|
+
body = {
|
|
58
|
+
"method": "get",
|
|
59
|
+
"params": {
|
|
60
|
+
"SelectionCriteria": {},
|
|
61
|
+
"FieldNames": ["Id", "Name", "Type"],
|
|
62
|
+
"Page": {"Limit": 20},
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
try:
|
|
66
|
+
creatives = _extract_items(client.creatives().post(data=body))
|
|
67
|
+
except Exception:
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
for creative in creatives:
|
|
71
|
+
if creative.get("Type") not in VIDEO_CREATIVE_TYPES:
|
|
72
|
+
continue
|
|
73
|
+
candidate = creative.get("Id")
|
|
74
|
+
if candidate and _advideo_get_accepts(client, str(candidate)):
|
|
75
|
+
return str(candidate)
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def main(argv: list[str] | None = None) -> int:
|
|
80
|
+
"""CLI entry point for smoke probes."""
|
|
81
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
82
|
+
if argv != ["advideo"]:
|
|
83
|
+
print("Usage: python3 -m direct_cli._smoke_probes advideo", file=sys.stderr)
|
|
84
|
+
return 2
|
|
85
|
+
|
|
86
|
+
probe_id = advideo_probe_id()
|
|
87
|
+
if not probe_id:
|
|
88
|
+
return 1
|
|
89
|
+
print(probe_id)
|
|
90
|
+
return 0
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
if __name__ == "__main__":
|
|
94
|
+
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
|
+
]
|