direct-cli 0.3.5__tar.gz → 0.3.7__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.3.5 → direct_cli-0.3.7}/PKG-INFO +44 -13
- {direct_cli-0.3.5 → direct_cli-0.3.7}/README.md +43 -12
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/cli.py +4 -1
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/auth.py +13 -2
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/campaigns.py +106 -1
- direct_cli-0.3.7/direct_cli/commands/v4forecast.py +168 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/v4shells.py +0 -5
- direct_cli-0.3.7/direct_cli/commands/v4tags.py +263 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/smoke_matrix.py +8 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/v4_contracts.py +86 -24
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli.egg-info/PKG-INFO +44 -13
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli.egg-info/SOURCES.txt +4 -1
- {direct_cli-0.3.5 → direct_cli-0.3.7}/pyproject.toml +1 -1
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/sandbox_write_live.py +60 -3
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/test_safe_commands.sh +12 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/API_COVERAGE.md +3 -3
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/api_coverage_payloads.py +8 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_auth_oauth.py +97 -7
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_cli_contract.py +1 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_comprehensive.py +1 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_dry_run.py +124 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_smoke_matrix.py +75 -4
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_v4_contracts.py +86 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_v4_foundation.py +2 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_v4_safety.py +14 -0
- direct_cli-0.3.7/tests/test_v4forecast.py +238 -0
- direct_cli-0.3.7/tests/test_v4tags.py +321 -0
- direct_cli-0.3.5/.github/workflows/claude-code-review.yml +0 -44
- {direct_cli-0.3.5 → direct_cli-0.3.7}/.env.example +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/.github/copilot-instructions.md +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/.github/workflows/api-coverage.yml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/.github/workflows/claude.yml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/.github/workflows/quality.yml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/.gitignore +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/AGENTS.md +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/CHANGELOG.md +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/CLAUDE.md +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/MANIFEST.in +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/__init__.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_deprecated.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_smoke_probes.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_vendor/__init__.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_vendor/tapi_yandex_direct/endpoints.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/api.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/auth.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/__init__.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/adextensions.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/adgroups.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/adimages.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/ads.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/advideos.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/agencyclients.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/audiencetargets.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/balance.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/bidmodifiers.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/bids.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/businesses.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/changes.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/clients.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/creatives.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/dictionaries.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/dynamicads.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/dynamicfeedadtargets.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/feeds.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/keywordbids.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/keywords.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/keywordsresearch.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/leads.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/negativekeywordsharedsets.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/reports.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/retargeting.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/sitelinks.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/smartadtargets.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/strategies.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/turbopages.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/v4account.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/v4events.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/v4finance.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/v4goals.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/v4wordstat.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/commands/vcards.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/output.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/reports_coverage.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/utils.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/v4/__init__.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/v4/money.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli/wsdl_coverage.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli.egg-info/dependency_links.txt +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli.egg-info/entry_points.txt +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli.egg-info/requires.txt +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/direct_cli.egg-info/top_level.txt +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/anonymize_cassettes.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/build_api_coverage_checklist.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/build_api_coverage_report.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/check_reports_drift.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/check_wsdl_drift.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/patch_vendor_imports.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/refresh_reports_cache.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/refresh_wsdl_cache.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/release_pypi.sh +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/test_dangerous_commands.sh +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/test_sandbox_write.sh +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/scripts/update_vendor.sh +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/setup.cfg +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/setup.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/API_ISSUE_AUDIT.md +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/MANUAL_COVERAGE.md +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/__init__.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_adgroups_add_update_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_adimages_add_get_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_ads_add_update_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_ads_suspend_resume_archive_unarchive.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_advideos_add_get.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_add_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_suspend_resume.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_bids_set.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_campaign_create_get_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_creatives_chain_advideo_to_creative.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_add_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_suspend_resume.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_keywordbids_set.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_add_update_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_suspend_resume.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_sitelinks_add_get_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_add_update_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_suspend_resume.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/conftest.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/fixtures/test-video.mp4 +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/reports_cache/raw/fields-list.html +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/reports_cache/raw/headers.html +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/reports_cache/raw/period.html +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/reports_cache/raw/spec.html +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/reports_cache/raw/type.html +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/reports_cache/spec.json +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_api_coverage.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_auth_bw.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_auth_op.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_balance.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_cli.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_integration.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_integration_live_write.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_integration_write.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_low_coverage_payloads.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_reports_drift.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_reports_parsing.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_transport_contract.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_v4_live_contracts.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_v4account.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_v4events.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_v4finance_money.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_v4finance_read.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_v4goals.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_v4wordstat.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/test_vendor_imports.py +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/adextensions.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/adgroups.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/adimages.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/ads.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/advideos.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/agencyclients.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/audiencetargets.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/bidmodifiers.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/bids.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/businesses.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/campaigns.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/changes.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/clients.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/creatives.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/dictionaries.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/feeds.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/imports/adextensiontypes.xsd +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/imports/general.xsd +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/imports/generalclients.xsd +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/keywordbids.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/keywords.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/keywordsresearch.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/leads.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/retargetinglists.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/sitelinks.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/smartadtargets.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/strategies.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/turbopages.xml +0 -0
- {direct_cli-0.3.5 → direct_cli-0.3.7}/tests/wsdl_cache/vcards.xml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: direct-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: Command-line interface for Yandex Direct API
|
|
5
5
|
Author: axisrow
|
|
6
6
|
License: MIT
|
|
@@ -88,7 +88,7 @@ direct auth login
|
|
|
88
88
|
direct auth login --profile agency1
|
|
89
89
|
direct auth login --profile agency1 --format json
|
|
90
90
|
direct auth login --code abc123 --profile agency1
|
|
91
|
-
printf '%s\n' abc123 | direct auth login --code-
|
|
91
|
+
printf '%s\n' abc123 | direct auth login --code - --profile agency1
|
|
92
92
|
direct auth list
|
|
93
93
|
direct auth use --profile agency1
|
|
94
94
|
direct auth status --profile agency1
|
|
@@ -101,8 +101,8 @@ Notes:
|
|
|
101
101
|
- `--login` remains Direct client login.
|
|
102
102
|
- Authorization is performed via `direct auth login`.
|
|
103
103
|
- OAuth profiles store refresh tokens and refresh access tokens automatically.
|
|
104
|
-
- In a non-interactive shell, run `direct auth login --profile NAME` first, then finish with `direct auth login --code-
|
|
105
|
-
- `direct auth login --code CODE --profile NAME` remains supported for compatibility, but `--code
|
|
104
|
+
- In a non-interactive shell, run `direct auth login --profile NAME` first, then finish with `direct auth login --code - --profile NAME` and pass the browser code on stdin.
|
|
105
|
+
- `direct auth login --code CODE --profile NAME` remains supported for compatibility, but automation should use `--code -` to avoid exposing the code in process arguments.
|
|
106
106
|
- If the first non-interactive step includes `--client-secret`, the secret is remembered for the matching completion step.
|
|
107
107
|
- If a profile already stores a confidential OAuth client, `direct auth login --code CODE --profile NAME` reuses the saved `client_id` and `client_secret`.
|
|
108
108
|
- `direct auth login --oauth-token TOKEN` is a manual access-token import and does not auto-refresh.
|
|
@@ -158,6 +158,24 @@ direct v4goals get-retargeting-goals --campaign-ids 123,456 --format table
|
|
|
158
158
|
direct v4goals get-stat-goals --campaign-ids 123 --dry-run
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
+
### V4 Live Tags
|
|
162
|
+
|
|
163
|
+
Campaign tags are managed as `{TagID, Tag}` pairs. Use `TagID=0` to create a
|
|
164
|
+
new campaign tag. Banner/ad tags are assigned by campaign tag IDs. Update
|
|
165
|
+
methods replace the full tag list for the target campaign or banner, so pass
|
|
166
|
+
existing tags again if they must remain assigned. Ad group tags are filter-only
|
|
167
|
+
through `direct adgroups get --tag-ids/--tags`; this release does not add ad
|
|
168
|
+
group tag mutation commands.
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
direct v4tags get-campaigns --campaign-ids 3193279,1634563
|
|
172
|
+
direct v4tags get-banners --banner-ids 2571700,2571745
|
|
173
|
+
direct v4tags get-banners --campaign-ids 3193279
|
|
174
|
+
direct v4tags update-campaigns --campaign-id 3193279 --tag 0=akapulko --tag 16590=orange --dry-run
|
|
175
|
+
direct v4tags update-banners --banner-ids 2571700,2571745 --tag-ids 16590,16734 --dry-run
|
|
176
|
+
direct v4tags update-banners --banner-ids 2571700 --clear-tags --dry-run
|
|
177
|
+
```
|
|
178
|
+
|
|
161
179
|
### V4 Live Events
|
|
162
180
|
|
|
163
181
|
```bash
|
|
@@ -178,6 +196,19 @@ direct v4wordstat get-report --report-id 123 --format table
|
|
|
178
196
|
direct v4wordstat delete-report --report-id 123
|
|
179
197
|
```
|
|
180
198
|
|
|
199
|
+
### V4 Live Budget Forecasts
|
|
200
|
+
|
|
201
|
+
Budget forecasts are asynchronous. Direct CLI makes exactly one API call per
|
|
202
|
+
command and does not poll automatically; repeat `list` or `get` yourself until
|
|
203
|
+
the forecast is ready.
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
direct v4forecast create --phrases "buy laptop,buy desktop" --geo-ids 213 --currency RUB
|
|
207
|
+
direct v4forecast list --format table
|
|
208
|
+
direct v4forecast get --forecast-id 123 --format table
|
|
209
|
+
direct v4forecast delete --forecast-id 123
|
|
210
|
+
```
|
|
211
|
+
|
|
181
212
|
### V4 Live Finance
|
|
182
213
|
|
|
183
214
|
Finance methods require an extra financial token for money operations. In the
|
|
@@ -562,9 +593,9 @@ Current command surface:
|
|
|
562
593
|
| WSDL-backed API services | 29 |
|
|
563
594
|
| Supported API services including Reports | 30 |
|
|
564
595
|
| WSDL operations | 112 |
|
|
565
|
-
| CLI groups including `auth` |
|
|
566
|
-
| CLI subcommands including `auth` |
|
|
567
|
-
| API CLI subcommands excluding `auth` |
|
|
596
|
+
| CLI groups including `auth` | 40 |
|
|
597
|
+
| CLI subcommands including `auth` | 144 |
|
|
598
|
+
| API CLI subcommands excluding `auth` | 140 |
|
|
568
599
|
|
|
569
600
|
### API Coverage And Drift Monitoring
|
|
570
601
|
|
|
@@ -750,7 +781,7 @@ direct auth login
|
|
|
750
781
|
direct auth login --profile agency1
|
|
751
782
|
direct auth login --profile agency1 --format json
|
|
752
783
|
direct auth login --code abc123 --profile agency1
|
|
753
|
-
printf '%s\n' abc123 | direct auth login --code-
|
|
784
|
+
printf '%s\n' abc123 | direct auth login --code - --profile agency1
|
|
754
785
|
direct auth list
|
|
755
786
|
direct auth use --profile agency1
|
|
756
787
|
direct auth status --profile agency1
|
|
@@ -759,8 +790,8 @@ direct --profile agency1 campaigns get
|
|
|
759
790
|
|
|
760
791
|
Примечания:
|
|
761
792
|
- OAuth profiles сохраняют refresh token и автоматически обновляют access token.
|
|
762
|
-
- В non-interactive shell сначала выполните `direct auth login --profile NAME`, затем завершите через `direct auth login --code-
|
|
763
|
-
- `direct auth login --code CODE --profile NAME` сохраняется для совместимости, но `--code
|
|
793
|
+
- В non-interactive shell сначала выполните `direct auth login --profile NAME`, затем завершите через `direct auth login --code - --profile NAME` и передайте browser code через stdin.
|
|
794
|
+
- `direct auth login --code CODE --profile NAME` сохраняется для совместимости, но автоматизация должна использовать `--code -`, чтобы не раскрывать код в process arguments.
|
|
764
795
|
- Если первый non-interactive шаг включает `--client-secret`, secret запоминается для последующего completion step.
|
|
765
796
|
- Если profile уже хранит confidential OAuth client, `direct auth login --code CODE --profile NAME` использует сохраненные `client_id` и `client_secret`.
|
|
766
797
|
- `direct auth login --oauth-token TOKEN` импортирует access token вручную и не включает auto-refresh.
|
|
@@ -1183,9 +1214,9 @@ YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rew
|
|
|
1183
1214
|
| WSDL-backed API services | 29 |
|
|
1184
1215
|
| API services с учётом Reports | 30 |
|
|
1185
1216
|
| WSDL operations | 112 |
|
|
1186
|
-
| CLI groups с `auth` |
|
|
1187
|
-
| CLI subcommands с `auth` |
|
|
1188
|
-
| API CLI subcommands без `auth` |
|
|
1217
|
+
| CLI groups с `auth` | 40 |
|
|
1218
|
+
| CLI subcommands с `auth` | 144 |
|
|
1219
|
+
| API CLI subcommands без `auth` | 140 |
|
|
1189
1220
|
|
|
1190
1221
|
#### Live sandbox write smoke
|
|
1191
1222
|
|
|
@@ -45,7 +45,7 @@ direct auth login
|
|
|
45
45
|
direct auth login --profile agency1
|
|
46
46
|
direct auth login --profile agency1 --format json
|
|
47
47
|
direct auth login --code abc123 --profile agency1
|
|
48
|
-
printf '%s\n' abc123 | direct auth login --code-
|
|
48
|
+
printf '%s\n' abc123 | direct auth login --code - --profile agency1
|
|
49
49
|
direct auth list
|
|
50
50
|
direct auth use --profile agency1
|
|
51
51
|
direct auth status --profile agency1
|
|
@@ -58,8 +58,8 @@ Notes:
|
|
|
58
58
|
- `--login` remains Direct client login.
|
|
59
59
|
- Authorization is performed via `direct auth login`.
|
|
60
60
|
- OAuth profiles store refresh tokens and refresh access tokens automatically.
|
|
61
|
-
- In a non-interactive shell, run `direct auth login --profile NAME` first, then finish with `direct auth login --code-
|
|
62
|
-
- `direct auth login --code CODE --profile NAME` remains supported for compatibility, but `--code
|
|
61
|
+
- In a non-interactive shell, run `direct auth login --profile NAME` first, then finish with `direct auth login --code - --profile NAME` and pass the browser code on stdin.
|
|
62
|
+
- `direct auth login --code CODE --profile NAME` remains supported for compatibility, but automation should use `--code -` to avoid exposing the code in process arguments.
|
|
63
63
|
- If the first non-interactive step includes `--client-secret`, the secret is remembered for the matching completion step.
|
|
64
64
|
- If a profile already stores a confidential OAuth client, `direct auth login --code CODE --profile NAME` reuses the saved `client_id` and `client_secret`.
|
|
65
65
|
- `direct auth login --oauth-token TOKEN` is a manual access-token import and does not auto-refresh.
|
|
@@ -115,6 +115,24 @@ direct v4goals get-retargeting-goals --campaign-ids 123,456 --format table
|
|
|
115
115
|
direct v4goals get-stat-goals --campaign-ids 123 --dry-run
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
+
### V4 Live Tags
|
|
119
|
+
|
|
120
|
+
Campaign tags are managed as `{TagID, Tag}` pairs. Use `TagID=0` to create a
|
|
121
|
+
new campaign tag. Banner/ad tags are assigned by campaign tag IDs. Update
|
|
122
|
+
methods replace the full tag list for the target campaign or banner, so pass
|
|
123
|
+
existing tags again if they must remain assigned. Ad group tags are filter-only
|
|
124
|
+
through `direct adgroups get --tag-ids/--tags`; this release does not add ad
|
|
125
|
+
group tag mutation commands.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
direct v4tags get-campaigns --campaign-ids 3193279,1634563
|
|
129
|
+
direct v4tags get-banners --banner-ids 2571700,2571745
|
|
130
|
+
direct v4tags get-banners --campaign-ids 3193279
|
|
131
|
+
direct v4tags update-campaigns --campaign-id 3193279 --tag 0=akapulko --tag 16590=orange --dry-run
|
|
132
|
+
direct v4tags update-banners --banner-ids 2571700,2571745 --tag-ids 16590,16734 --dry-run
|
|
133
|
+
direct v4tags update-banners --banner-ids 2571700 --clear-tags --dry-run
|
|
134
|
+
```
|
|
135
|
+
|
|
118
136
|
### V4 Live Events
|
|
119
137
|
|
|
120
138
|
```bash
|
|
@@ -135,6 +153,19 @@ direct v4wordstat get-report --report-id 123 --format table
|
|
|
135
153
|
direct v4wordstat delete-report --report-id 123
|
|
136
154
|
```
|
|
137
155
|
|
|
156
|
+
### V4 Live Budget Forecasts
|
|
157
|
+
|
|
158
|
+
Budget forecasts are asynchronous. Direct CLI makes exactly one API call per
|
|
159
|
+
command and does not poll automatically; repeat `list` or `get` yourself until
|
|
160
|
+
the forecast is ready.
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
direct v4forecast create --phrases "buy laptop,buy desktop" --geo-ids 213 --currency RUB
|
|
164
|
+
direct v4forecast list --format table
|
|
165
|
+
direct v4forecast get --forecast-id 123 --format table
|
|
166
|
+
direct v4forecast delete --forecast-id 123
|
|
167
|
+
```
|
|
168
|
+
|
|
138
169
|
### V4 Live Finance
|
|
139
170
|
|
|
140
171
|
Finance methods require an extra financial token for money operations. In the
|
|
@@ -519,9 +550,9 @@ Current command surface:
|
|
|
519
550
|
| WSDL-backed API services | 29 |
|
|
520
551
|
| Supported API services including Reports | 30 |
|
|
521
552
|
| WSDL operations | 112 |
|
|
522
|
-
| CLI groups including `auth` |
|
|
523
|
-
| CLI subcommands including `auth` |
|
|
524
|
-
| API CLI subcommands excluding `auth` |
|
|
553
|
+
| CLI groups including `auth` | 40 |
|
|
554
|
+
| CLI subcommands including `auth` | 144 |
|
|
555
|
+
| API CLI subcommands excluding `auth` | 140 |
|
|
525
556
|
|
|
526
557
|
### API Coverage And Drift Monitoring
|
|
527
558
|
|
|
@@ -707,7 +738,7 @@ direct auth login
|
|
|
707
738
|
direct auth login --profile agency1
|
|
708
739
|
direct auth login --profile agency1 --format json
|
|
709
740
|
direct auth login --code abc123 --profile agency1
|
|
710
|
-
printf '%s\n' abc123 | direct auth login --code-
|
|
741
|
+
printf '%s\n' abc123 | direct auth login --code - --profile agency1
|
|
711
742
|
direct auth list
|
|
712
743
|
direct auth use --profile agency1
|
|
713
744
|
direct auth status --profile agency1
|
|
@@ -716,8 +747,8 @@ direct --profile agency1 campaigns get
|
|
|
716
747
|
|
|
717
748
|
Примечания:
|
|
718
749
|
- OAuth profiles сохраняют refresh token и автоматически обновляют access token.
|
|
719
|
-
- В non-interactive shell сначала выполните `direct auth login --profile NAME`, затем завершите через `direct auth login --code-
|
|
720
|
-
- `direct auth login --code CODE --profile NAME` сохраняется для совместимости, но `--code
|
|
750
|
+
- В non-interactive shell сначала выполните `direct auth login --profile NAME`, затем завершите через `direct auth login --code - --profile NAME` и передайте browser code через stdin.
|
|
751
|
+
- `direct auth login --code CODE --profile NAME` сохраняется для совместимости, но автоматизация должна использовать `--code -`, чтобы не раскрывать код в process arguments.
|
|
721
752
|
- Если первый non-interactive шаг включает `--client-secret`, secret запоминается для последующего completion step.
|
|
722
753
|
- Если profile уже хранит confidential OAuth client, `direct auth login --code CODE --profile NAME` использует сохраненные `client_id` и `client_secret`.
|
|
723
754
|
- `direct auth login --oauth-token TOKEN` импортирует access token вручную и не включает auto-refresh.
|
|
@@ -1140,9 +1171,9 @@ YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rew
|
|
|
1140
1171
|
| WSDL-backed API services | 29 |
|
|
1141
1172
|
| API services с учётом Reports | 30 |
|
|
1142
1173
|
| WSDL operations | 112 |
|
|
1143
|
-
| CLI groups с `auth` |
|
|
1144
|
-
| CLI subcommands с `auth` |
|
|
1145
|
-
| API CLI subcommands без `auth` |
|
|
1174
|
+
| CLI groups с `auth` | 40 |
|
|
1175
|
+
| CLI subcommands с `auth` | 144 |
|
|
1176
|
+
| API CLI subcommands без `auth` | 140 |
|
|
1146
1177
|
|
|
1147
1178
|
#### Live sandbox write smoke
|
|
1148
1179
|
|
|
@@ -43,10 +43,12 @@ from .commands.strategies import strategies
|
|
|
43
43
|
from .commands.auth import auth
|
|
44
44
|
from .commands.balance import balance
|
|
45
45
|
from .commands.v4events import v4events
|
|
46
|
+
from .commands.v4forecast import v4forecast
|
|
46
47
|
from .commands.v4finance import v4finance
|
|
47
48
|
from .commands.v4account import v4account
|
|
48
|
-
from .commands.v4shells import
|
|
49
|
+
from .commands.v4shells import v4meta
|
|
49
50
|
from .commands.v4goals import v4goals
|
|
51
|
+
from .commands.v4tags import v4tags
|
|
50
52
|
from .commands.v4wordstat import v4wordstat
|
|
51
53
|
|
|
52
54
|
# Load .env file
|
|
@@ -186,6 +188,7 @@ for command in (
|
|
|
186
188
|
v4goals,
|
|
187
189
|
v4events,
|
|
188
190
|
v4wordstat,
|
|
191
|
+
v4tags,
|
|
189
192
|
v4forecast,
|
|
190
193
|
v4meta,
|
|
191
194
|
auth,
|
|
@@ -35,10 +35,14 @@ def auth():
|
|
|
35
35
|
|
|
36
36
|
@auth.command()
|
|
37
37
|
@click.option("--profile", default="default", show_default=True, help="Profile name")
|
|
38
|
-
@click.option(
|
|
38
|
+
@click.option(
|
|
39
|
+
"--code",
|
|
40
|
+
help="OAuth authorization code; use '-' to read from stdin for automation",
|
|
41
|
+
)
|
|
39
42
|
@click.option(
|
|
40
43
|
"--code-stdin",
|
|
41
44
|
is_flag=True,
|
|
45
|
+
hidden=True,
|
|
42
46
|
help="Read OAuth authorization code from stdin",
|
|
43
47
|
)
|
|
44
48
|
@click.option("--oauth-token", help="Ready OAuth access token")
|
|
@@ -78,9 +82,16 @@ def login(
|
|
|
78
82
|
"--code-stdin cannot be combined with --code, "
|
|
79
83
|
"--oauth-token, or --start-pkce."
|
|
80
84
|
)
|
|
85
|
+
code = "-"
|
|
86
|
+
|
|
87
|
+
if code == "-":
|
|
88
|
+
if oauth_token or start_pkce:
|
|
89
|
+
raise click.ClickException(
|
|
90
|
+
"--code - cannot be combined with --oauth-token or --start-pkce."
|
|
91
|
+
)
|
|
81
92
|
code = sys.stdin.read().strip()
|
|
82
93
|
if not code:
|
|
83
|
-
raise click.ClickException("--code-
|
|
94
|
+
raise click.ClickException("--code - requires a code on stdin.")
|
|
84
95
|
|
|
85
96
|
if start_pkce:
|
|
86
97
|
if code or oauth_token or client_secret:
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Campaigns commands
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
5
7
|
import click
|
|
6
8
|
|
|
7
9
|
from ..api import create_client
|
|
@@ -13,6 +15,7 @@ from ..utils import (
|
|
|
13
15
|
get_default_fields,
|
|
14
16
|
MICRO_RUBLES,
|
|
15
17
|
parse_ids,
|
|
18
|
+
parse_csv_strings,
|
|
16
19
|
parse_setting_specs,
|
|
17
20
|
)
|
|
18
21
|
|
|
@@ -22,6 +25,14 @@ def campaigns():
|
|
|
22
25
|
"""Manage campaigns"""
|
|
23
26
|
|
|
24
27
|
|
|
28
|
+
def _parse_csv_option(option_name: str, value: Optional[str]) -> Optional[List[str]]:
|
|
29
|
+
"""Parse a CSV option and reject explicitly empty input."""
|
|
30
|
+
parsed = parse_csv_strings(value)
|
|
31
|
+
if value is not None and not parsed:
|
|
32
|
+
raise click.UsageError(f"{option_name} must contain at least one value")
|
|
33
|
+
return parsed
|
|
34
|
+
|
|
35
|
+
|
|
25
36
|
@campaigns.command()
|
|
26
37
|
@click.option("--ids", help="Comma-separated campaign IDs")
|
|
27
38
|
@click.option("--status", help="Filter by status (ACTIVE, SUSPENDED, etc.)")
|
|
@@ -41,6 +52,40 @@ def campaigns():
|
|
|
41
52
|
@click.option(
|
|
42
53
|
"--fields", help="Comma-separated field names (default: all common fields)"
|
|
43
54
|
)
|
|
55
|
+
@click.option("--text-campaign-fields", help="Comma-separated TextCampaignFieldNames")
|
|
56
|
+
@click.option(
|
|
57
|
+
"--text-campaign-search-strategy-placement-types-fields",
|
|
58
|
+
help="Comma-separated TextCampaignSearchStrategyPlacementTypesFieldNames",
|
|
59
|
+
)
|
|
60
|
+
@click.option(
|
|
61
|
+
"--mobile-app-campaign-fields",
|
|
62
|
+
help="Comma-separated MobileAppCampaignFieldNames",
|
|
63
|
+
)
|
|
64
|
+
@click.option(
|
|
65
|
+
"--dynamic-text-campaign-fields",
|
|
66
|
+
help="Comma-separated DynamicTextCampaignFieldNames",
|
|
67
|
+
)
|
|
68
|
+
@click.option(
|
|
69
|
+
"--dynamic-text-campaign-search-strategy-placement-types-fields",
|
|
70
|
+
help="Comma-separated DynamicTextCampaignSearchStrategyPlacementTypesFieldNames",
|
|
71
|
+
)
|
|
72
|
+
@click.option(
|
|
73
|
+
"--cpm-banner-campaign-fields",
|
|
74
|
+
help="Comma-separated CpmBannerCampaignFieldNames",
|
|
75
|
+
)
|
|
76
|
+
@click.option("--smart-campaign-fields", help="Comma-separated SmartCampaignFieldNames")
|
|
77
|
+
@click.option(
|
|
78
|
+
"--unified-campaign-fields",
|
|
79
|
+
help="Comma-separated UnifiedCampaignFieldNames",
|
|
80
|
+
)
|
|
81
|
+
@click.option(
|
|
82
|
+
"--unified-campaign-search-strategy-placement-types-fields",
|
|
83
|
+
help="Comma-separated UnifiedCampaignSearchStrategyPlacementTypesFieldNames",
|
|
84
|
+
)
|
|
85
|
+
@click.option(
|
|
86
|
+
"--unified-campaign-package-bidding-strategy-platforms-fields",
|
|
87
|
+
help="Comma-separated UnifiedCampaignPackageBiddingStrategyPlatformsFieldNames",
|
|
88
|
+
)
|
|
44
89
|
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
45
90
|
@click.pass_context
|
|
46
91
|
def get(
|
|
@@ -56,6 +101,16 @@ def get(
|
|
|
56
101
|
output_format,
|
|
57
102
|
output,
|
|
58
103
|
fields,
|
|
104
|
+
text_campaign_fields,
|
|
105
|
+
text_campaign_search_strategy_placement_types_fields,
|
|
106
|
+
mobile_app_campaign_fields,
|
|
107
|
+
dynamic_text_campaign_fields,
|
|
108
|
+
dynamic_text_campaign_search_strategy_placement_types_fields,
|
|
109
|
+
cpm_banner_campaign_fields,
|
|
110
|
+
smart_campaign_fields,
|
|
111
|
+
unified_campaign_fields,
|
|
112
|
+
unified_campaign_search_strategy_placement_types_fields,
|
|
113
|
+
unified_campaign_package_bidding_strategy_platforms_fields,
|
|
59
114
|
dry_run,
|
|
60
115
|
):
|
|
61
116
|
"""Get campaigns"""
|
|
@@ -70,7 +125,11 @@ def get(
|
|
|
70
125
|
)
|
|
71
126
|
|
|
72
127
|
# Parse field names
|
|
73
|
-
field_names =
|
|
128
|
+
field_names = (
|
|
129
|
+
_parse_csv_option("--fields", fields)
|
|
130
|
+
if fields is not None
|
|
131
|
+
else get_default_fields("campaigns")
|
|
132
|
+
)
|
|
74
133
|
|
|
75
134
|
# Build selection criteria
|
|
76
135
|
criteria = build_selection_criteria(
|
|
@@ -86,6 +145,52 @@ def get(
|
|
|
86
145
|
params = build_common_params(
|
|
87
146
|
criteria=criteria, field_names=field_names, limit=limit
|
|
88
147
|
)
|
|
148
|
+
selector_options = {
|
|
149
|
+
"TextCampaignFieldNames": (
|
|
150
|
+
"--text-campaign-fields",
|
|
151
|
+
text_campaign_fields,
|
|
152
|
+
),
|
|
153
|
+
"TextCampaignSearchStrategyPlacementTypesFieldNames": (
|
|
154
|
+
"--text-campaign-search-strategy-placement-types-fields",
|
|
155
|
+
text_campaign_search_strategy_placement_types_fields,
|
|
156
|
+
),
|
|
157
|
+
"MobileAppCampaignFieldNames": (
|
|
158
|
+
"--mobile-app-campaign-fields",
|
|
159
|
+
mobile_app_campaign_fields,
|
|
160
|
+
),
|
|
161
|
+
"DynamicTextCampaignFieldNames": (
|
|
162
|
+
"--dynamic-text-campaign-fields",
|
|
163
|
+
dynamic_text_campaign_fields,
|
|
164
|
+
),
|
|
165
|
+
"DynamicTextCampaignSearchStrategyPlacementTypesFieldNames": (
|
|
166
|
+
"--dynamic-text-campaign-search-strategy-placement-types-fields",
|
|
167
|
+
dynamic_text_campaign_search_strategy_placement_types_fields,
|
|
168
|
+
),
|
|
169
|
+
"CpmBannerCampaignFieldNames": (
|
|
170
|
+
"--cpm-banner-campaign-fields",
|
|
171
|
+
cpm_banner_campaign_fields,
|
|
172
|
+
),
|
|
173
|
+
"SmartCampaignFieldNames": (
|
|
174
|
+
"--smart-campaign-fields",
|
|
175
|
+
smart_campaign_fields,
|
|
176
|
+
),
|
|
177
|
+
"UnifiedCampaignFieldNames": (
|
|
178
|
+
"--unified-campaign-fields",
|
|
179
|
+
unified_campaign_fields,
|
|
180
|
+
),
|
|
181
|
+
"UnifiedCampaignSearchStrategyPlacementTypesFieldNames": (
|
|
182
|
+
"--unified-campaign-search-strategy-placement-types-fields",
|
|
183
|
+
unified_campaign_search_strategy_placement_types_fields,
|
|
184
|
+
),
|
|
185
|
+
"UnifiedCampaignPackageBiddingStrategyPlatformsFieldNames": (
|
|
186
|
+
"--unified-campaign-package-bidding-strategy-platforms-fields",
|
|
187
|
+
unified_campaign_package_bidding_strategy_platforms_fields,
|
|
188
|
+
),
|
|
189
|
+
}
|
|
190
|
+
for request_key, (option_name, value) in selector_options.items():
|
|
191
|
+
parsed = _parse_csv_option(option_name, value)
|
|
192
|
+
if parsed:
|
|
193
|
+
params[request_key] = parsed
|
|
89
194
|
|
|
90
195
|
body = {"method": "get", "params": params}
|
|
91
196
|
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""Yandex Direct v4 Live budget forecast commands."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from ..api import create_v4_client
|
|
8
|
+
from ..output import format_output, print_error
|
|
9
|
+
from ..utils import parse_csv_strings, parse_ids
|
|
10
|
+
from ..v4 import build_v4_body, call_v4
|
|
11
|
+
from ..v4_contracts import v4_method_contract
|
|
12
|
+
from .v4shells import V4_EPILOG
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _forecast_param(
|
|
16
|
+
phrases: str, geo_ids: Optional[str], currency: str
|
|
17
|
+
) -> dict[str, object]:
|
|
18
|
+
"""Build the v4 Live CreateNewForecast parameter."""
|
|
19
|
+
phrase_list = parse_csv_strings(phrases)
|
|
20
|
+
if not phrase_list:
|
|
21
|
+
raise click.UsageError("--phrases must not be empty")
|
|
22
|
+
if len(phrase_list) > 100:
|
|
23
|
+
raise click.UsageError("--phrases accepts at most 100 phrases")
|
|
24
|
+
|
|
25
|
+
param: dict[str, object] = {
|
|
26
|
+
"Phrases": phrase_list,
|
|
27
|
+
"Currency": currency,
|
|
28
|
+
}
|
|
29
|
+
if geo_ids:
|
|
30
|
+
try:
|
|
31
|
+
parsed_geo_ids = parse_ids(geo_ids)
|
|
32
|
+
except ValueError as exc:
|
|
33
|
+
raise click.UsageError(str(exc)) from exc
|
|
34
|
+
if parsed_geo_ids:
|
|
35
|
+
param["GeoID"] = parsed_geo_ids
|
|
36
|
+
return param
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _call_forecast(
|
|
40
|
+
ctx,
|
|
41
|
+
method: str,
|
|
42
|
+
param,
|
|
43
|
+
output_format: str,
|
|
44
|
+
output: Optional[str],
|
|
45
|
+
) -> None:
|
|
46
|
+
"""Call one v4 Live budget forecast method and print formatted output."""
|
|
47
|
+
try:
|
|
48
|
+
client = create_v4_client(
|
|
49
|
+
token=ctx.obj.get("token"),
|
|
50
|
+
login=ctx.obj.get("login"),
|
|
51
|
+
profile=ctx.obj.get("profile"),
|
|
52
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
53
|
+
)
|
|
54
|
+
data = call_v4(client, method, param)
|
|
55
|
+
format_output(data, output_format, output)
|
|
56
|
+
except Exception as e:
|
|
57
|
+
print_error(str(e))
|
|
58
|
+
raise click.Abort()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@click.group(epilog=V4_EPILOG)
|
|
62
|
+
def v4forecast():
|
|
63
|
+
"""Yandex Direct v4 Live budget forecast commands."""
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@v4_method_contract("CreateNewForecast")
|
|
67
|
+
@v4forecast.command()
|
|
68
|
+
@click.option("--phrases", required=True, help="Comma-separated phrases, up to 100")
|
|
69
|
+
@click.option("--geo-ids", help="Comma-separated geo region IDs")
|
|
70
|
+
@click.option(
|
|
71
|
+
"--currency",
|
|
72
|
+
default="RUB",
|
|
73
|
+
show_default=True,
|
|
74
|
+
help="Forecast currency",
|
|
75
|
+
)
|
|
76
|
+
@click.option(
|
|
77
|
+
"--format",
|
|
78
|
+
"output_format",
|
|
79
|
+
default="json",
|
|
80
|
+
type=click.Choice(["json", "table", "csv", "tsv"]),
|
|
81
|
+
help="Output format",
|
|
82
|
+
)
|
|
83
|
+
@click.option("--output", help="Output file")
|
|
84
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
85
|
+
@click.pass_context
|
|
86
|
+
def create(ctx, phrases, geo_ids, currency, output_format, output, dry_run):
|
|
87
|
+
"""Create a v4 Live budget forecast."""
|
|
88
|
+
param = _forecast_param(phrases, geo_ids, currency)
|
|
89
|
+
if dry_run:
|
|
90
|
+
format_output(build_v4_body("CreateNewForecast", param), "json", None)
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
_call_forecast(ctx, "CreateNewForecast", param, output_format, output)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@v4_method_contract("GetForecastList")
|
|
97
|
+
@v4forecast.command(name="list")
|
|
98
|
+
@click.option(
|
|
99
|
+
"--format",
|
|
100
|
+
"output_format",
|
|
101
|
+
default="json",
|
|
102
|
+
type=click.Choice(["json", "table", "csv", "tsv"]),
|
|
103
|
+
help="Output format",
|
|
104
|
+
)
|
|
105
|
+
@click.option("--output", help="Output file")
|
|
106
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
107
|
+
@click.pass_context
|
|
108
|
+
def list_forecasts(ctx, output_format, output, dry_run):
|
|
109
|
+
"""List v4 Live budget forecasts."""
|
|
110
|
+
if dry_run:
|
|
111
|
+
format_output(build_v4_body("GetForecastList"), "json", None)
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
_call_forecast(ctx, "GetForecastList", None, output_format, output)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@v4_method_contract("GetForecast")
|
|
118
|
+
@v4forecast.command()
|
|
119
|
+
@click.option(
|
|
120
|
+
"--forecast-id",
|
|
121
|
+
required=True,
|
|
122
|
+
type=click.IntRange(min=1),
|
|
123
|
+
help="Forecast ID",
|
|
124
|
+
)
|
|
125
|
+
@click.option(
|
|
126
|
+
"--format",
|
|
127
|
+
"output_format",
|
|
128
|
+
default="json",
|
|
129
|
+
type=click.Choice(["json", "table", "csv", "tsv"]),
|
|
130
|
+
help="Output format",
|
|
131
|
+
)
|
|
132
|
+
@click.option("--output", help="Output file")
|
|
133
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
134
|
+
@click.pass_context
|
|
135
|
+
def get(ctx, forecast_id, output_format, output, dry_run):
|
|
136
|
+
"""Get a ready v4 Live budget forecast."""
|
|
137
|
+
if dry_run:
|
|
138
|
+
format_output(build_v4_body("GetForecast", forecast_id), "json", None)
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
_call_forecast(ctx, "GetForecast", forecast_id, output_format, output)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@v4_method_contract("DeleteForecastReport")
|
|
145
|
+
@v4forecast.command()
|
|
146
|
+
@click.option(
|
|
147
|
+
"--forecast-id",
|
|
148
|
+
required=True,
|
|
149
|
+
type=click.IntRange(min=1),
|
|
150
|
+
help="Forecast ID",
|
|
151
|
+
)
|
|
152
|
+
@click.option(
|
|
153
|
+
"--format",
|
|
154
|
+
"output_format",
|
|
155
|
+
default="json",
|
|
156
|
+
type=click.Choice(["json", "table", "csv", "tsv"]),
|
|
157
|
+
help="Output format",
|
|
158
|
+
)
|
|
159
|
+
@click.option("--output", help="Output file")
|
|
160
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
161
|
+
@click.pass_context
|
|
162
|
+
def delete(ctx, forecast_id, output_format, output, dry_run):
|
|
163
|
+
"""Delete a v4 Live budget forecast."""
|
|
164
|
+
if dry_run:
|
|
165
|
+
format_output(build_v4_body("DeleteForecastReport", forecast_id), "json", None)
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
_call_forecast(ctx, "DeleteForecastReport", forecast_id, output_format, output)
|
|
@@ -15,11 +15,6 @@ def v4wordstat():
|
|
|
15
15
|
"""Yandex Direct v4 Live wordstat commands."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
@click.group(epilog=V4_EPILOG)
|
|
19
|
-
def v4forecast():
|
|
20
|
-
"""Yandex Direct v4 Live forecast commands."""
|
|
21
|
-
|
|
22
|
-
|
|
23
18
|
@click.group(epilog=V4_EPILOG)
|
|
24
19
|
def v4meta():
|
|
25
20
|
"""Yandex Direct v4 Live metadata commands."""
|