direct-cli 0.3.0__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.3.0 → direct_cli-0.3.1}/PKG-INFO +21 -1
- {direct_cli-0.3.0 → direct_cli-0.3.1}/README.md +20 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_smoke_probes.py +8 -3
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +1 -1
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +7 -5
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/api.py +53 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/cli.py +18 -0
- direct_cli-0.3.1/direct_cli/commands/balance.py +55 -0
- 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.3.0 → direct_cli-0.3.1}/direct_cli/smoke_matrix.py +11 -5
- 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.0 → direct_cli-0.3.1}/direct_cli.egg-info/PKG-INFO +21 -1
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli.egg-info/SOURCES.txt +10 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/pyproject.toml +2 -1
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/test_safe_commands.sh +4 -1
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/api_coverage_payloads.py +2 -0
- direct_cli-0.3.1/tests/test_balance.py +137 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_comprehensive.py +8 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_dry_run.py +2 -2
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_integration.py +3 -4
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_smoke_matrix.py +21 -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.3.0 → direct_cli-0.3.1}/.env.example +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/.github/copilot-instructions.md +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/.github/workflows/api-coverage.yml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/.github/workflows/claude-code-review.yml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/.github/workflows/claude.yml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/.gitignore +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/AGENTS.md +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/CLAUDE.md +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/MANIFEST.in +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/__init__.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_deprecated.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_vendor/__init__.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/auth.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/__init__.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/adextensions.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/adgroups.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/adimages.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/ads.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/advideos.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/agencyclients.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/audiencetargets.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/auth.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/bidmodifiers.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/bids.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/businesses.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/campaigns.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/changes.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/clients.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/creatives.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/dictionaries.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/dynamicads.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/dynamicfeedadtargets.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/feeds.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/keywordbids.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/keywords.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/keywordsresearch.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/leads.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/negativekeywordsharedsets.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/reports.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/retargeting.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/sitelinks.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/smartadtargets.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/strategies.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/turbopages.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/commands/vcards.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/output.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/reports_coverage.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/utils.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli/wsdl_coverage.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli.egg-info/dependency_links.txt +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli.egg-info/entry_points.txt +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli.egg-info/requires.txt +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/direct_cli.egg-info/top_level.txt +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/anonymize_cassettes.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/build_api_coverage_checklist.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/build_api_coverage_report.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/check_reports_drift.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/check_wsdl_drift.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/patch_vendor_imports.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/refresh_reports_cache.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/refresh_wsdl_cache.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/release_pypi.sh +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/sandbox_write_live.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/test_dangerous_commands.sh +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/test_sandbox_write.sh +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/scripts/update_vendor.sh +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/setup.cfg +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/setup.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/API_COVERAGE.md +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/API_ISSUE_AUDIT.md +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/MANUAL_COVERAGE.md +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/__init__.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_adgroups_add_update_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_adimages_add_get_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_ads_add_update_delete.yaml +0 -0
- {direct_cli-0.3.0 → 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.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_advideos_add_get.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_add_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_suspend_resume.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_bids_set.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_campaign_create_get_delete.yaml +0 -0
- {direct_cli-0.3.0 → 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.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_add_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_suspend_resume.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_keywordbids_set.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_add_update_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_suspend_resume.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_sitelinks_add_get_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_add_update_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_suspend_resume.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/conftest.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/fixtures/test-video.mp4 +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/reports_cache/raw/fields-list.html +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/reports_cache/raw/headers.html +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/reports_cache/raw/spec.html +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/reports_cache/raw/type.html +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/reports_cache/spec.json +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_api_coverage.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_auth_bw.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_auth_oauth.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_auth_op.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_cli.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_integration_live_write.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_integration_write.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_reports_drift.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_transport_contract.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/test_vendor_imports.py +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/adextensions.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/adgroups.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/adimages.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/ads.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/advideos.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/agencyclients.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/audiencetargets.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/bidmodifiers.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/bids.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/businesses.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/campaigns.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/changes.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/clients.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/creatives.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/dictionaries.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/feeds.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/imports/adextensiontypes.xsd +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/imports/general.xsd +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/imports/generalclients.xsd +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/keywordbids.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/keywords.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/keywordsresearch.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/leads.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/retargetinglists.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/sitelinks.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/smartadtargets.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/strategies.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/tests/wsdl_cache/turbopages.xml +0 -0
- {direct_cli-0.3.0 → direct_cli-0.3.1}/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.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.
|
|
@@ -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.
|
|
@@ -8,7 +8,11 @@ from typing import Any, Optional
|
|
|
8
8
|
|
|
9
9
|
from .api import create_client
|
|
10
10
|
|
|
11
|
-
VIDEO_CREATIVE_TYPES = {
|
|
11
|
+
VIDEO_CREATIVE_TYPES = {
|
|
12
|
+
"VIDEO_EXTENSION_CREATIVE",
|
|
13
|
+
"CPM_VIDEO_CREATIVE",
|
|
14
|
+
"CPC_VIDEO_CREATIVE",
|
|
15
|
+
}
|
|
12
16
|
|
|
13
17
|
|
|
14
18
|
def _extract_items(response: Any) -> list[dict[str, Any]]:
|
|
@@ -18,7 +22,7 @@ def _extract_items(response: Any) -> list[dict[str, Any]]:
|
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
def _advideo_get_accepts(client: Any, candidate: str) -> bool:
|
|
21
|
-
"""Return whether advideos.get accepts
|
|
25
|
+
"""Return whether advideos.get accepts the candidate ID."""
|
|
22
26
|
body = {
|
|
23
27
|
"method": "get",
|
|
24
28
|
"params": {
|
|
@@ -28,7 +32,8 @@ def _advideo_get_accepts(client: Any, candidate: str) -> bool:
|
|
|
28
32
|
},
|
|
29
33
|
}
|
|
30
34
|
try:
|
|
31
|
-
|
|
35
|
+
_extract_items(client.advideos().post(data=body))
|
|
36
|
+
return True
|
|
32
37
|
except Exception:
|
|
33
38
|
return False
|
|
34
39
|
|
|
@@ -44,9 +44,10 @@ class V4LiveClientAdapter(JSONAdapterMixin, TapiAdapter):
|
|
|
44
44
|
login = api_params.get("login")
|
|
45
45
|
language = api_params.get("language", "en")
|
|
46
46
|
|
|
47
|
-
# Enrich the JSON body with token / locale
|
|
48
|
-
#
|
|
49
|
-
#
|
|
47
|
+
# Enrich the JSON body with token / locale. format_data_to_request does
|
|
48
|
+
# not see api_params, so we do this here, after super() has already
|
|
49
|
+
# serialised the user data. Agency/client selection is transport-level
|
|
50
|
+
# (Client-Login header); method params must stay schema-shaped.
|
|
50
51
|
raw = params.get("data")
|
|
51
52
|
if raw:
|
|
52
53
|
if isinstance(raw, (bytes, bytearray)):
|
|
@@ -66,14 +67,15 @@ class V4LiveClientAdapter(JSONAdapterMixin, TapiAdapter):
|
|
|
66
67
|
body.setdefault("token", token)
|
|
67
68
|
if language:
|
|
68
69
|
body.setdefault("locale", language)
|
|
69
|
-
if login and isinstance(body.get("param"), dict):
|
|
70
|
-
body["param"].setdefault("login", login)
|
|
71
70
|
|
|
72
71
|
params["data"] = orjson.dumps(body)
|
|
73
72
|
|
|
74
73
|
if token:
|
|
75
74
|
params["headers"]["Authorization"] = "Bearer {}".format(token)
|
|
76
75
|
|
|
76
|
+
if login:
|
|
77
|
+
params["headers"]["Client-Login"] = login
|
|
78
|
+
|
|
77
79
|
return params
|
|
78
80
|
|
|
79
81
|
def format_data_to_request(self, data) -> Optional[bytes]:
|
|
@@ -5,6 +5,7 @@ API client wrapper for Direct CLI
|
|
|
5
5
|
from typing import Optional, Dict, Any, List
|
|
6
6
|
|
|
7
7
|
from direct_cli._vendor.tapi_yandex_direct import YandexDirect
|
|
8
|
+
from direct_cli._vendor.tapi_yandex_direct.v4 import YandexDirectV4Live
|
|
8
9
|
from .auth import get_credentials
|
|
9
10
|
|
|
10
11
|
|
|
@@ -67,6 +68,58 @@ def create_client(
|
|
|
67
68
|
)
|
|
68
69
|
|
|
69
70
|
|
|
71
|
+
def create_v4_client(
|
|
72
|
+
token: Optional[str] = None,
|
|
73
|
+
login: Optional[str] = None,
|
|
74
|
+
profile: Optional[str] = None,
|
|
75
|
+
sandbox: bool = False,
|
|
76
|
+
op_token_ref: Optional[str] = None,
|
|
77
|
+
op_login_ref: Optional[str] = None,
|
|
78
|
+
bw_token_ref: Optional[str] = None,
|
|
79
|
+
bw_login_ref: Optional[str] = None,
|
|
80
|
+
language: Optional[str] = None,
|
|
81
|
+
retry_if_exceeded_limit: bool = True,
|
|
82
|
+
retries_if_server_error: int = 5,
|
|
83
|
+
) -> YandexDirectV4Live:
|
|
84
|
+
"""
|
|
85
|
+
Create YandexDirect v4 Live client.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
token: API access token
|
|
89
|
+
login: Client login (for agency accounts)
|
|
90
|
+
profile: Credential profile name
|
|
91
|
+
sandbox: Use sandbox API
|
|
92
|
+
op_token_ref: 1Password secret reference for token
|
|
93
|
+
op_login_ref: 1Password secret reference for login
|
|
94
|
+
bw_token_ref: Bitwarden item name/ID for token
|
|
95
|
+
bw_login_ref: Bitwarden item name/ID for login
|
|
96
|
+
language: API locale
|
|
97
|
+
retry_if_exceeded_limit: Retry when the API limit is exceeded
|
|
98
|
+
retries_if_server_error: Number of retries for server errors
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
YandexDirect v4 Live client instance
|
|
102
|
+
"""
|
|
103
|
+
final_token, final_login = get_credentials(
|
|
104
|
+
token,
|
|
105
|
+
login,
|
|
106
|
+
profile=profile,
|
|
107
|
+
op_token_ref=op_token_ref,
|
|
108
|
+
op_login_ref=op_login_ref,
|
|
109
|
+
bw_token_ref=bw_token_ref,
|
|
110
|
+
bw_login_ref=bw_login_ref,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
return YandexDirectV4Live(
|
|
114
|
+
access_token=final_token,
|
|
115
|
+
login=final_login,
|
|
116
|
+
is_sandbox=sandbox,
|
|
117
|
+
language=language or "en",
|
|
118
|
+
retry_if_exceeded_limit=retry_if_exceeded_limit,
|
|
119
|
+
retries_if_server_error=retries_if_server_error,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
70
123
|
def fetch_all_pages(
|
|
71
124
|
client: YandexDirect,
|
|
72
125
|
resource_name: str,
|
|
@@ -41,6 +41,16 @@ from .commands.advideos import advideos
|
|
|
41
41
|
from .commands.dynamicfeedadtargets import dynamicfeedadtargets
|
|
42
42
|
from .commands.strategies import strategies
|
|
43
43
|
from .commands.auth import auth
|
|
44
|
+
from .commands.balance import balance
|
|
45
|
+
from .commands.v4shells import (
|
|
46
|
+
v4account,
|
|
47
|
+
v4events,
|
|
48
|
+
v4finance,
|
|
49
|
+
v4forecast,
|
|
50
|
+
v4meta,
|
|
51
|
+
v4wordstat,
|
|
52
|
+
)
|
|
53
|
+
from .commands.v4goals import v4goals
|
|
44
54
|
|
|
45
55
|
# Load .env file
|
|
46
56
|
load_dotenv()
|
|
@@ -173,6 +183,14 @@ for command in (
|
|
|
173
183
|
advideos,
|
|
174
184
|
dynamicfeedadtargets,
|
|
175
185
|
strategies,
|
|
186
|
+
balance,
|
|
187
|
+
v4finance,
|
|
188
|
+
v4account,
|
|
189
|
+
v4goals,
|
|
190
|
+
v4events,
|
|
191
|
+
v4wordstat,
|
|
192
|
+
v4forecast,
|
|
193
|
+
v4meta,
|
|
176
194
|
auth,
|
|
177
195
|
):
|
|
178
196
|
_register_command(command)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Money balance command backed by Yandex Direct v4 Live."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from ..api import create_v4_client
|
|
6
|
+
from ..output import format_output, print_error
|
|
7
|
+
from ..utils import parse_csv_strings
|
|
8
|
+
from ..v4 import build_v4_body, call_v4
|
|
9
|
+
from ..v4_contracts import v4_method_contract
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@v4_method_contract("AccountManagement")
|
|
13
|
+
@click.command()
|
|
14
|
+
@click.option("--logins", help="Comma-separated client logins")
|
|
15
|
+
@click.option(
|
|
16
|
+
"--format",
|
|
17
|
+
"output_format",
|
|
18
|
+
default="json",
|
|
19
|
+
type=click.Choice(["json", "table", "csv", "tsv"]),
|
|
20
|
+
help="Output format",
|
|
21
|
+
)
|
|
22
|
+
@click.option("--output", help="Output file")
|
|
23
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
24
|
+
@click.pass_context
|
|
25
|
+
def balance(ctx, logins, output_format, output, dry_run):
|
|
26
|
+
"""Check account money balance."""
|
|
27
|
+
login_list = parse_csv_strings(logins)
|
|
28
|
+
configured_login = ctx.obj.get("login")
|
|
29
|
+
if not login_list and configured_login:
|
|
30
|
+
login_list = [configured_login]
|
|
31
|
+
|
|
32
|
+
param = {
|
|
33
|
+
"Action": "Get",
|
|
34
|
+
}
|
|
35
|
+
if login_list:
|
|
36
|
+
param["SelectionCriteria"] = {"Logins": login_list}
|
|
37
|
+
elif ctx.obj.get("sandbox"):
|
|
38
|
+
raise click.UsageError("Provide --logins or configure YANDEX_DIRECT_LOGIN")
|
|
39
|
+
|
|
40
|
+
if dry_run:
|
|
41
|
+
format_output(build_v4_body("AccountManagement", param), "json", None)
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
client = create_v4_client(
|
|
46
|
+
token=ctx.obj.get("token"),
|
|
47
|
+
login=ctx.obj.get("login"),
|
|
48
|
+
profile=ctx.obj.get("profile"),
|
|
49
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
50
|
+
)
|
|
51
|
+
data = call_v4(client, "AccountManagement", param)
|
|
52
|
+
format_output(data, output_format, output)
|
|
53
|
+
except Exception as e:
|
|
54
|
+
print_error(str(e))
|
|
55
|
+
raise click.Abort()
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Yandex Direct v4 Live goals commands."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from ..api import create_v4_client
|
|
6
|
+
from ..output import format_output, print_error
|
|
7
|
+
from ..utils import parse_ids
|
|
8
|
+
from ..v4 import build_v4_body, call_v4
|
|
9
|
+
from ..v4_contracts import v4_method_contract
|
|
10
|
+
from .v4shells import V4_EPILOG
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _campaign_ids_param(campaign_ids: str) -> dict:
|
|
14
|
+
"""Build the v4 Live CampaignIDInfo parameter."""
|
|
15
|
+
try:
|
|
16
|
+
ids = parse_ids(campaign_ids)
|
|
17
|
+
except ValueError as exc:
|
|
18
|
+
raise click.UsageError(str(exc))
|
|
19
|
+
if not ids:
|
|
20
|
+
raise click.UsageError("--campaign-ids must not be empty")
|
|
21
|
+
return {"CampaignIDS": ids}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _run_goals_command(
|
|
25
|
+
ctx,
|
|
26
|
+
method: str,
|
|
27
|
+
campaign_ids: str,
|
|
28
|
+
output_format: str,
|
|
29
|
+
output: str,
|
|
30
|
+
dry_run: bool,
|
|
31
|
+
) -> None:
|
|
32
|
+
param = _campaign_ids_param(campaign_ids)
|
|
33
|
+
if dry_run:
|
|
34
|
+
format_output(build_v4_body(method, param), "json", None)
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
client = create_v4_client(
|
|
39
|
+
token=ctx.obj.get("token"),
|
|
40
|
+
login=ctx.obj.get("login"),
|
|
41
|
+
profile=ctx.obj.get("profile"),
|
|
42
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
43
|
+
)
|
|
44
|
+
data = call_v4(client, method, param)
|
|
45
|
+
format_output(data, output_format, output)
|
|
46
|
+
except Exception as e:
|
|
47
|
+
print_error(str(e))
|
|
48
|
+
raise click.Abort()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@click.group(epilog=V4_EPILOG)
|
|
52
|
+
def v4goals():
|
|
53
|
+
"""Yandex Direct v4 Live goals commands."""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@v4_method_contract("GetStatGoals")
|
|
57
|
+
@v4goals.command(name="get-stat-goals")
|
|
58
|
+
@click.option("--campaign-ids", required=True, help="Comma-separated campaign IDs")
|
|
59
|
+
@click.option(
|
|
60
|
+
"--format",
|
|
61
|
+
"output_format",
|
|
62
|
+
default="json",
|
|
63
|
+
type=click.Choice(["json", "table", "csv", "tsv"]),
|
|
64
|
+
help="Output format",
|
|
65
|
+
)
|
|
66
|
+
@click.option("--output", help="Output file")
|
|
67
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
68
|
+
@click.pass_context
|
|
69
|
+
def get_stat_goals(ctx, campaign_ids, output_format, output, dry_run):
|
|
70
|
+
"""Get Yandex Metrica goals available for campaigns."""
|
|
71
|
+
_run_goals_command(
|
|
72
|
+
ctx,
|
|
73
|
+
"GetStatGoals",
|
|
74
|
+
campaign_ids,
|
|
75
|
+
output_format,
|
|
76
|
+
output,
|
|
77
|
+
dry_run,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@v4_method_contract("GetRetargetingGoals")
|
|
82
|
+
@v4goals.command(name="get-retargeting-goals")
|
|
83
|
+
@click.option("--campaign-ids", required=True, help="Comma-separated campaign IDs")
|
|
84
|
+
@click.option(
|
|
85
|
+
"--format",
|
|
86
|
+
"output_format",
|
|
87
|
+
default="json",
|
|
88
|
+
type=click.Choice(["json", "table", "csv", "tsv"]),
|
|
89
|
+
help="Output format",
|
|
90
|
+
)
|
|
91
|
+
@click.option("--output", help="Output file")
|
|
92
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
93
|
+
@click.pass_context
|
|
94
|
+
def get_retargeting_goals(ctx, campaign_ids, output_format, output, dry_run):
|
|
95
|
+
"""Get retargeting goals for campaigns."""
|
|
96
|
+
_run_goals_command(
|
|
97
|
+
ctx,
|
|
98
|
+
"GetRetargetingGoals",
|
|
99
|
+
campaign_ids,
|
|
100
|
+
output_format,
|
|
101
|
+
output,
|
|
102
|
+
dry_run,
|
|
103
|
+
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Shell command groups for Yandex Direct v4 Live command families."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
V4_EPILOG = (
|
|
6
|
+
"\b\n"
|
|
7
|
+
"V4 Live commands use typed flags only. Supported methods are listed in "
|
|
8
|
+
"the Yandex Direct v4 Live documentation: "
|
|
9
|
+
"https://yandex.com/dev/direct/doc/dg-v4/en/live/concepts"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group(epilog=V4_EPILOG)
|
|
14
|
+
def v4finance():
|
|
15
|
+
"""Yandex Direct v4 Live finance commands."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@click.group(epilog=V4_EPILOG)
|
|
19
|
+
def v4account():
|
|
20
|
+
"""Yandex Direct v4 Live account commands."""
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@click.group(epilog=V4_EPILOG)
|
|
24
|
+
def v4events():
|
|
25
|
+
"""Yandex Direct v4 Live events commands."""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@click.group(epilog=V4_EPILOG)
|
|
29
|
+
def v4wordstat():
|
|
30
|
+
"""Yandex Direct v4 Live wordstat commands."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@click.group(epilog=V4_EPILOG)
|
|
34
|
+
def v4forecast():
|
|
35
|
+
"""Yandex Direct v4 Live forecast commands."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@click.group(epilog=V4_EPILOG)
|
|
39
|
+
def v4meta():
|
|
40
|
+
"""Yandex Direct v4 Live metadata commands."""
|
|
@@ -19,6 +19,7 @@ DANGEROUS = "DANGEROUS"
|
|
|
19
19
|
|
|
20
20
|
SMOKE_MATRIX = {
|
|
21
21
|
SAFE: [
|
|
22
|
+
"balance",
|
|
22
23
|
"adextensions.get",
|
|
23
24
|
"adgroups.get",
|
|
24
25
|
"adimages.get",
|
|
@@ -56,6 +57,8 @@ SMOKE_MATRIX = {
|
|
|
56
57
|
"smartadtargets.get",
|
|
57
58
|
"strategies.get",
|
|
58
59
|
"turbopages.get",
|
|
60
|
+
"v4goals.get-retargeting-goals",
|
|
61
|
+
"v4goals.get-stat-goals",
|
|
59
62
|
"vcards.get",
|
|
60
63
|
],
|
|
61
64
|
WRITE_SANDBOX: [
|
|
@@ -190,11 +193,14 @@ def commands_for_category(category: str) -> list[str]:
|
|
|
190
193
|
def _registered_cli_commands() -> set[str]:
|
|
191
194
|
from direct_cli.cli import cli
|
|
192
195
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
registered = set()
|
|
197
|
+
for group_name, group in cli.commands.items():
|
|
198
|
+
if hasattr(group, "commands"):
|
|
199
|
+
for command_name in group.commands:
|
|
200
|
+
registered.add(command_key(group_name, command_name))
|
|
201
|
+
else:
|
|
202
|
+
registered.add(group_name)
|
|
203
|
+
return registered
|
|
198
204
|
|
|
199
205
|
|
|
200
206
|
def _wsdl_operations_count() -> int:
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Shared helpers for Yandex Direct v4 Live commands."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def build_v4_body(method: str, param: Optional[Any] = None) -> dict:
|
|
7
|
+
"""Build a v4 Live request body."""
|
|
8
|
+
body = {"method": method}
|
|
9
|
+
if param is not None:
|
|
10
|
+
body["param"] = param
|
|
11
|
+
return body
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def call_v4(client: Any, method: str, param: Optional[Any] = None) -> Any:
|
|
15
|
+
"""Call one v4 Live method and return the extracted response payload."""
|
|
16
|
+
result = client.v4live().post(data=build_v4_body(method, param))
|
|
17
|
+
return result().extract()
|