direct-cli 0.5.3__tar.gz → 0.5.4__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.5.3 → direct_cli-0.5.4}/AGENTS.md +21 -1
- {direct_cli-0.5.3 → direct_cli-0.5.4}/CHANGELOG.md +208 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/PKG-INFO +149 -49
- {direct_cli-0.5.3 → direct_cli-0.5.4}/README.md +147 -47
- {direct_cli-0.5.3 → direct_cli-0.5.4}/README_ru.md +84 -38
- direct_cli-0.5.4/direct_cli/_auth_hints.py +21 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +10 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +6 -1
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/api.py +72 -1
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/auth.py +124 -17
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/_chrome_crypto.py +27 -5
- direct_cli-0.5.4/direct_cli/browser/ad_elements.py +376 -0
- direct_cli-0.5.4/direct_cli/browser/auth.py +114 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/diagnostics.py +63 -86
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/masters.py +169 -102
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/session.py +25 -44
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/store.py +16 -4
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/cli.py +82 -6
- direct_cli-0.5.4/direct_cli/commands/ad_elements.py +69 -0
- direct_cli-0.5.4/direct_cli/commands/auth.py +1400 -0
- direct_cli-0.5.4/direct_cli/commands/browser_session.py +48 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/history.py +2 -3
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/masters.py +118 -463
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/reports.py +38 -7
- direct_cli-0.5.4/direct_cli/optional_output.py +107 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/output.py +8 -1
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/smoke_matrix.py +16 -2
- direct_cli-0.5.4/direct_cli/translations/auth.json +98 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/reports.json +4 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/PKG-INFO +149 -49
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/SOURCES.txt +11 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/requires.txt +1 -1
- {direct_cli-0.5.3 → direct_cli-0.5.4}/pyproject.toml +13 -4
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/build_api_coverage_report.py +7 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/test_dangerous_commands.sh +3 -2
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/test_safe_commands.sh +4 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/conftest.py +40 -1
- direct_cli-0.5.4/tests/fixtures/ad_elements_payloads.json +1254 -0
- direct_cli-0.5.4/tests/test_ad_elements.py +326 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_api_coverage.py +56 -2
- direct_cli-0.5.4/tests/test_api_retry.py +189 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_auth_bw.py +5 -3
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_auth_oauth.py +34 -28
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_auth_op.py +5 -3
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_chrome_crypto.py +19 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_comprehensive.py +50 -0
- direct_cli-0.5.4/tests/test_credential_provenance.py +394 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_common.py +73 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_masters.py +363 -207
- direct_cli-0.5.4/tests/test_optional_output.py +191 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_playwright_session.py +96 -31
- direct_cli-0.5.4/tests/test_unified_auth.py +763 -0
- direct_cli-0.5.3/direct_cli/commands/auth.py +0 -564
- direct_cli-0.5.3/direct_cli/commands/browser_session.py +0 -180
- direct_cli-0.5.3/direct_cli/translations/auth.json +0 -25
- {direct_cli-0.5.3 → direct_cli-0.5.4}/.env.example +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/.github/copilot-instructions.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/.github/workflows/api-coverage.yml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/.github/workflows/claude.yml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/.github/workflows/quality.yml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/.gitignore +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/.mcp.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/CLAUDE.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/MANIFEST.in +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/__init__.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_autotargeting.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_bidding_strategy.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_captcha.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_deprecated.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_flag_validation.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_smoke_probes.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/__init__.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/endpoints.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/__init__.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/_clock.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/browser/change_history.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/__init__.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_batch.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_base.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_cpm_banner.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_dynamic.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_mobile_app.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_smart.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_text.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_campaigns_unified.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_execute.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_get.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_lifecycle.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/_set_bids.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/adextensions.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/adgroups.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/adimages.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/__init__.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/_cli.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/base.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/batch.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/builder.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/mobile_app.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/objects.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/responsive.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/shopping.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/ads/text.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/advideos.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/agencyclients.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/audiencetargets.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/balance.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/bidmodifiers.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/bids.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/businesses.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/campaigns.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/changes.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/clients.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/creatives.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/dictionaries.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/dynamicads.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/dynamicfeedadtargets.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/feeds.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/keywordbids.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/keywords.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/keywordsresearch.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/leads.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/negativekeywordsharedsets.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/retargeting.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/sitelinks.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/smartadtargets.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/strategies.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/trackingparams.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/turbopages.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4account.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4adimage.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4events.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4finance.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4forecast.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4goals.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4keywords.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4shells.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4tags.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/v4wordstat.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/commands/vcards.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/i18n.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/reports_coverage.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/tracking_params.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/adextensions.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/adgroups.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/adimages.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/ads.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/advideos.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/agencyclients.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/audiencetargets.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/balance.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/bidmodifiers.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/bids.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/businesses.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/campaigns.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/changes.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/clients.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/common.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/creatives.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/dictionaries.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/dynamicads.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/dynamicfeedadtargets.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/feeds.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/keywordbids.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/keywords.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/keywordsresearch.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/leads.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/negativekeywordsharedsets.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/retargeting.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/sitelinks.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/smartadtargets.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/strategies.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/turbopages.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4account.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4adimage.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4events.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4finance.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4forecast.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4goals.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4keywords.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4shells.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4tags.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/v4wordstat.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/translations/vcards.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/utils.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/v4/__init__.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/v4/emit.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/v4/money.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/v4/parse.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/v4_contracts.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli/wsdl_coverage.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/dependency_links.txt +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/entry_points.txt +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/direct_cli.egg-info/top_level.txt +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/audits/API_COVERAGE.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/audits/PROJECT_WIRE_SHAPE_AUDIT_2026-05-30.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/audits/WIRE_SHAPE_TRIAGE_2026-05-30.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/audits/issue-198-mutating-wsdl-audit.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/audits/wire_shape.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/anonymize_cassettes.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/audit_wire_shape.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/build_api_coverage_checklist.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/build_wsdl_optional_field_audit.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/check_all_docs_urls.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/check_reports_drift.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/check_wsdl_drift.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/measure_criteria_limits.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/patch_vendor_imports.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/preflight_check.sh +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/probe_drift_urls.sh +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/recon_761_utm_split.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/recon_774_audit_saved_utm.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/recon_774_utm_reorder.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/recon_812_video_upload.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/recon_871_bidmodifiers_enum.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/refresh_reports_cache.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/refresh_wsdl_cache.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/release_pypi.sh +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/sandbox_write_audit.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/sandbox_write_live.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/test_sandbox_write.sh +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/scripts/update_vendor.sh +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/setup.cfg +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/setup.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/API_COVERAGE.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/API_ISSUE_AUDIT.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/MANUAL_COVERAGE.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/WSDL_OPTIONAL_FIELD_AUDIT.md +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/__init__.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/_cli_tree.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/_orphan_store.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/api_coverage_payloads.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteBidsRead.test_bids_get.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteBidsRead.test_bids_set_auto.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteRetargetingUpdate.test_retargeting_update.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteStrategies.test_strategies_lifecycle.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_balance_get_no_shared_account.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[adextensions_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[adgroups_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[adimages_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[ads_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[advideos_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[audiencetargets_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[bidmodifiers_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[bids_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[businesses_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[campaigns_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[changes_check].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[changes_check_campaigns].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[changes_check_dictionaries].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[clients_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[creatives_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[dictionaries_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[dynamicads_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[dynamicfeedadtargets_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[feeds_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[keywordbids_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[keywords_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[keywordsresearch_deduplicate].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[keywordsresearch_has_search_volume].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[leads_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[negativekeywordsharedsets_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[reports_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[retargeting_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[sitelinks_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[smartadtargets_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[strategies_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[turbopages_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4adimage_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4events_get_events_log].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4finance_get_clients_units].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4forecast_list].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4goals_get_stat_goals].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4tags_get_campaigns].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[v4wordstat_list_reports].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_read_command[vcards_get].yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4account_get_accounts_no_shared_account.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4finance_check_payment_unknown_transaction.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4forecast_get_unknown_forecast.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4goals_get_retargeting_goals_server_error.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4tags_get_banners_server_error.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_read_cassettes/test_v4wordstat_get_report_unknown_report.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_adgroups_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_adimages_add_get_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_ads_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_ads_suspend_resume_archive_unarchive.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_advideos_add_get.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_audiencetargets_add_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_audiencetargets_suspend_resume.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_bids_set.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_campaign_create_get_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_creatives_chain_advideo_to_creative.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_dynamicads_add_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_dynamicads_suspend_resume.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_feeds_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywordbids_set.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywords_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywords_suspend_resume.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_retargeting_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_sitelinks_add_get_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_smartadtargets_add_update_delete.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_smartadtargets_suspend_resume.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/cassettes/test_v5_live_write/test_v5_live_draft_strategies_add_update_archive_unarchive.yaml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_grid_campaigns.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_create.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_draft_overview.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_edit_moderation.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_edit_name.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_edit_stage_a.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_edit_stage_b.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_edit_stage_d.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/masters_wizard_overview.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/test-video.mp4 +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/fixtures/user_action_log.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/raw/fields-list.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/raw/headers.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/raw/period.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/raw/spec.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/raw/type.html +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/reports_cache/spec.json +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_adgroups_build_adgroup_object.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_adgroups_build_adgroup_update_object.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_ads_build_ad_object.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_ads_build_ad_update_object.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_audit_wire_shape.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_auth_write_json.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_autotargeting.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_balance.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_bidding_strategy_constants.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_cassette_integrity.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_change_history.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_changes.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_check_all_docs_urls.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_cli.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_cli_contract.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_adgroups.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_ads.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_bids.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_campaigns.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_clients.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_extensions.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_keywords.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_shared.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_strategies.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_strategy_smart.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_strategy_text.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_strategy_unified.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_dry_run_targets.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_env_loading.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_field_names_option.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_flag_validation.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_handle_api_errors.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_i18n.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_integration.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_integration_write.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_low_coverage_payloads.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_read_cassettes.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_reference_output.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_reports_drift.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_reports_parsing.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_sandbox_write_audit.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_smoke_matrix.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_transport_contract.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_unknown_option_hints.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_contracts.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_exit_codes.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_foundation.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_live_contracts.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_output_options.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_runtime_shape.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4_safety.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4account.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4adimage.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4events.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4finance_money.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4finance_read.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4forecast.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4goals.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4keywords.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4meta.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4tags.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v4wordstat.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_v5_live_write.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_vendor_imports.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/test_wsdl_parity_gate.py +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/adextensions.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/adgroups.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/adimages.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/ads.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/advideos.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/agencyclients.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/audiencetargets.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/bidmodifiers.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/bids.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/businesses.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/campaigns.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/changes.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/clients.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/creatives.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/dictionaries.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/feeds.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/imports/adextensiontypes.xsd +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/imports/general.xsd +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/imports/generalclients.xsd +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/keywordbids.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/keywords.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/keywordsresearch.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/leads.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/retargetinglists.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/sitelinks.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/smartadtargets.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/strategies.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/turbopages.xml +0 -0
- {direct_cli-0.5.3 → direct_cli-0.5.4}/tests/wsdl_cache/vcards.xml +0 -0
|
@@ -35,13 +35,33 @@ Naming rules:
|
|
|
35
35
|
|
|
36
36
|
### Input Rules
|
|
37
37
|
|
|
38
|
-
-
|
|
38
|
+
- In default headless mode, all user-facing input must be passed only through typed CLI flags.
|
|
39
|
+
- Authentication input prompts require explicit `direct auth login --interactive`.
|
|
39
40
|
- `--json` is not part of the public CLI contract.
|
|
40
41
|
- User-facing parameters must not be passed through `--json`.
|
|
41
42
|
- The CLI must not accept `SelectionCriteria`, nested payloads, update payloads, bidding rules, or any other user-facing command input through `--json`.
|
|
42
43
|
- Typed flags and JSON blobs must not be mixed as part of one public command contract.
|
|
43
44
|
- If the API requires a complex object, the CLI must expose explicit flags or subcommands instead of forwarding raw JSON.
|
|
44
45
|
|
|
46
|
+
### Authorization Execution Mode
|
|
47
|
+
|
|
48
|
+
- Authorization is headless and non-interactive by default, including when stdin and stdout are terminals. TTY detection must never enable login dialogs or browser UI by itself.
|
|
49
|
+
- `direct auth login` defaults to the headless API flow: print the authorization URL and accept the completion code later through typed flags or explicit stdin input.
|
|
50
|
+
- Login menus and OAuth code prompts require `direct auth login --interactive`.
|
|
51
|
+
- Manual browser login requires explicit `--interactive` or `--headful`. `--allow-no-tty` only overrides the terminal check; it does not authorize browser UI by itself.
|
|
52
|
+
- Chrome import is headless by default. Failed headless verification must not retry in a visible browser automatically.
|
|
53
|
+
- Missing or expired credentials in ordinary commands produce an actionable error, never an implicit login.
|
|
54
|
+
- Saving credentials into an existing profile requires explicit `--force`; the headless completion and token import refuse to overwrite otherwise.
|
|
55
|
+
|
|
56
|
+
### Data Safety — No Silent Overwrites
|
|
57
|
+
|
|
58
|
+
- Stored user data (auth profiles, credentials, folder bindings, browser sessions) is never replaced silently.
|
|
59
|
+
- A write is either the command's declared purpose (the command then reports what was replaced) or requires an explicit confirmation flag (`--force`). Ordinary commands never write stored user data as a side effect.
|
|
60
|
+
- Overwriting an existing auth profile requires explicit `--force` on the CLI layer and `overwrite=True` on the helper layer; the refusal names the current owner's login.
|
|
61
|
+
- Replacing an existing `YANDEX_DIRECT_TOKEN` in the folder `.env` prints a warning naming the previous owner.
|
|
62
|
+
- New write paths for stored user data must go through the guarded helpers (`save_oauth_profile`, `save_env_credentials`); bypassing the guard is a contract violation.
|
|
63
|
+
- Production API mutations are always explicit commands, classified SAFE / WRITE_SANDBOX / DANGEROUS in `direct_cli/smoke_matrix.py`.
|
|
64
|
+
|
|
45
65
|
### Command Formatting Rules
|
|
46
66
|
|
|
47
67
|
- Every canonical CLI command must be written strictly on a single line.
|
|
@@ -1,5 +1,213 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
### BREAKING CHANGES
|
|
6
|
+
|
|
7
|
+
**`auth login`/`auth status`/`auth logout` use `api|browser` subcommands; `--method`, `--interactive` and `--headful` are removed without aliases (#924).**
|
|
8
|
+
|
|
9
|
+
The two authorization domains — the Direct API OAuth token and the browser
|
|
10
|
+
session used by `masters`/`history` — now have explicit names:
|
|
11
|
+
|
|
12
|
+
- `direct auth login api` — OAuth login for API/v4 commands (what bare
|
|
13
|
+
`direct auth login` did and still does: the owner-decided default is the
|
|
14
|
+
API domain, and the old "Choose login method" menu is gone).
|
|
15
|
+
- `direct auth login browser` — manual login in a visible window for browser
|
|
16
|
+
commands (`masters`, `history`, ...); visibility needs no flag anymore.
|
|
17
|
+
`--source chrome` keeps importing an existing Chrome session headless;
|
|
18
|
+
`--allow-no-tty` is the only surviving special flag — it lets a script
|
|
19
|
+
open the login window without a terminal.
|
|
20
|
+
- `direct auth status api|browser` selects a domain; **bare `direct auth
|
|
21
|
+
status` now reports both domains** (an `API:` and a `Browser:` block,
|
|
22
|
+
previously the API-only default — parse the new `Browser:` section or use
|
|
23
|
+
`auth status api` for the old behavior; combined JSON is unchanged:
|
|
24
|
+
`{"api": ..., "browser": ...}`).
|
|
25
|
+
- `direct auth logout api --profile NAME` / `direct auth logout browser`
|
|
26
|
+
(bare `auth logout` asks for a domain).
|
|
27
|
+
- `--profile` is valid in both domains; in the browser domain it is accepted
|
|
28
|
+
and reported as ignored (browser sessions are shared). `--profile-dir`/
|
|
29
|
+
`--chrome-profile` live only in the browser domain.
|
|
30
|
+
- In the API domain a terminal is now the interactive default: the login
|
|
31
|
+
prints the URL, opens the browser, reads the code and binds the folder's
|
|
32
|
+
`.env`. `--format json`, `--start-pkce` and `--code -` stay headless —
|
|
33
|
+
unattended scripts are unaffected.
|
|
34
|
+
|
|
35
|
+
Every removed flag fails with `click.UsageError` naming the exact
|
|
36
|
+
replacement from `direct_cli/_auth_hints.py` — the same pointer the live
|
|
37
|
+
auth errors advise. Deprecated aliases (`playwright login`,
|
|
38
|
+
`masters login`/`logout`/`status`) keep their stdout formats; their
|
|
39
|
+
replacement notices now point at the new subcommand surface.
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- **Optional diagnostics output is now env-switched and hidden by default
|
|
44
|
+
(#925).** Successful v5 API calls no longer print anything extra: the API
|
|
45
|
+
Units points line is opt-in via `DIRECT_SHOW_UNITS=1`, which prints one
|
|
46
|
+
stderr line per successful call — `API units: <spent>/<rest>/<daily limit>`
|
|
47
|
+
(e.g. `API units: 10/20828/64000`), plus ` (used-login: <login>)` when the
|
|
48
|
+
API returned `Units-Used-Login` (agency accounts). The v4 Live API returns
|
|
49
|
+
no Units headers, so v4 commands stay silent under this switch. stdout is
|
|
50
|
+
never touched,
|
|
51
|
+
so pipes and `--format json` parsing are unaffected. `DIRECT_QUIET=0`
|
|
52
|
+
restores the legacy behaviour for channels that had one (Units had none).
|
|
53
|
+
Safety output — inherited-credential warnings (#909), sandbox notices, API
|
|
54
|
+
warnings — is never suppressed. The switch registry
|
|
55
|
+
(`direct_cli/optional_output.py`) is extensible: future optional channels
|
|
56
|
+
(Reports `retryIn`/`reportsInQueue`) are added as one entry. Supported by a
|
|
57
|
+
success-response hook in the vendored `tapi_yandex_direct` client, mirrored
|
|
58
|
+
on `master` of the axisrow fork (axisrow/tapi-yandex-direct#28, merged) so
|
|
59
|
+
`update_vendor.sh` keeps it (#634).
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
|
|
63
|
+
- **One canonical login pointer in every authorization error (#924, part 1 —
|
|
64
|
+
non-breaking).** A new leaf module `direct_cli/_auth_hints.py` defines the
|
|
65
|
+
canonical pointers — `direct auth login api`, `direct auth login browser`,
|
|
66
|
+
`direct auth login browser --source chrome` — and every auth error and
|
|
67
|
+
deprecated-command notice now advises exactly one domain-appropriate pointer.
|
|
68
|
+
Previously a stale `masters list` session printed four contradictory
|
|
69
|
+
suggestions, and a deprecated command's warning recommended different flags
|
|
70
|
+
than the error of the same command. Commands and flags are unchanged; the
|
|
71
|
+
`auth login api|browser` subcommand restructuring lands separately. An AST
|
|
72
|
+
guard in `tests/test_unified_auth.py` bans literal login-command strings
|
|
73
|
+
outside `_auth_hints.py`, so a second hint source fails CI.
|
|
74
|
+
|
|
75
|
+
### Fixed
|
|
76
|
+
|
|
77
|
+
- **`reports get`: API error 56 (method rate limit) now retries with
|
|
78
|
+
exponential backoff (#918).** Yandex allows only 1 request per 10 seconds
|
|
79
|
+
per method; with several `direct`/MCP clients sharing one account, each
|
|
80
|
+
keeps consuming the other's window and the first 56 used to kill the
|
|
81
|
+
command (the vendored client's own retry branches read the error code from
|
|
82
|
+
the wrong payload key and never fire). Now the reports POST is retried up
|
|
83
|
+
to 5 attempts, waiting 10/20/40/80s plus up to 50% jitter; each attempt
|
|
84
|
+
logs `attempt N/5 … retrying in Xs` to stderr so a waiting CLI is
|
|
85
|
+
distinguishable from a dead one. If the limit still doesn't clear, the
|
|
86
|
+
final error names the likely cause — another client or session working
|
|
87
|
+
with the same Yandex Direct account. Any other error code (53, 152, 506,
|
|
88
|
+
9000, …) fails immediately as before.
|
|
89
|
+
- **`reports get`: `--from`/`--to` are bound to `--date-range-type
|
|
90
|
+
CUSTOM_DATE` (#898).** Relative periods (`TODAY`, `YESTERDAY`, `LAST_*`,
|
|
91
|
+
`ALL_TIME`, `AUTO`) no longer require the flags and build requests without
|
|
92
|
+
`DateFrom`/`DateTo`, per the Reports spec ("required at CUSTOM_DATE and
|
|
93
|
+
forbidden with other values"). Explicit dates alongside a relative period,
|
|
94
|
+
and `CUSTOM_DATE` with either date missing, fail with a usage error instead
|
|
95
|
+
of silently sending a forbidden combination.
|
|
96
|
+
- **`--format csv`/`--format tsv`: export no longer fails when later records
|
|
97
|
+
carry optional fields missing from the first record (#900).** The column set
|
|
98
|
+
is now the union of keys across all records (in first-seen order) instead of
|
|
99
|
+
the first record's keys alone, so a record with an extra optional field
|
|
100
|
+
(e.g. `TextAd` present only on `TEXT_AD` rows) gets its own column and rows
|
|
101
|
+
missing a field export an empty cell — success no longer depends on row
|
|
102
|
+
order. Explicitly passed `headers` still define the columns exactly as
|
|
103
|
+
before.
|
|
104
|
+
|
|
105
|
+
- **`masters list`: intermittent grid-load timeout now retries internally
|
|
106
|
+
(#912).** The campaigns grid's `GridCampaigns` data request is observed
|
|
107
|
+
across two attempts — 30s, then 60s, with a fresh page load per attempt —
|
|
108
|
+
before the command fails, so an ordinary slow page load no longer surfaces
|
|
109
|
+
as a terminal error requiring a manual retry. The exhausted-attempts error
|
|
110
|
+
is worded purely as the retryable timeout it is (the old text's "Yandex may
|
|
111
|
+
have changed the grid's internal API" clause is gone); an unrecognized
|
|
112
|
+
response structure keeps its separate, API-change message. New
|
|
113
|
+
`masters list --timeout SECONDS` scales both per-attempt budgets for slow
|
|
114
|
+
connections.
|
|
115
|
+
- **`masters targetactions get`: a populated goals table is no longer
|
|
116
|
+
reported as empty (#910).** The "Целевые действия" table goes through a
|
|
117
|
+
genuine, non-throwing EMPTY interval mid-hydration (the same race
|
|
118
|
+
#750/#756 documented for the save guard), and the command answered with a
|
|
119
|
+
single immediate read — landing in that dip silently returned
|
|
120
|
+
`{"TargetActions": [], "Count": 0}` for a campaign whose table is
|
|
121
|
+
populated, indistinguishable from genuinely empty (the audit over 28
|
|
122
|
+
campaigns produced 2 false violations this way). The read is now the same
|
|
123
|
+
settled, failure-aware snapshot the `--preserve-target-actions` guard
|
|
124
|
+
uses: rows are reported only once their `{GoalId: Price}` identity is
|
|
125
|
+
stable, and a rendered section whose rows never settle into a readable
|
|
126
|
+
snapshot fails with an error instead of printing `Count: 0`. A genuinely
|
|
127
|
+
empty table still answers `Count: 0`, and so does a max-clicks campaign
|
|
128
|
+
(no section rendered) — the latter now pays the settle deadline (~20 s)
|
|
129
|
+
before that answer, same as the guard path, because the same dips briefly
|
|
130
|
+
unmount the section and its absence is only meaningful after settling had
|
|
131
|
+
its chance.
|
|
132
|
+
|
|
133
|
+
## 0.5.4 — 2026-10-24
|
|
134
|
+
|
|
135
|
+
### Unified authorization
|
|
136
|
+
|
|
137
|
+
- **Existing profiles are never overwritten silently.** `direct auth login`
|
|
138
|
+
refuses to write credentials into an existing profile (including the default
|
|
139
|
+
`default`) without explicit `--force`; a fresh profile name is unaffected.
|
|
140
|
+
Previously a headless completion replaced the profile's token, refresh token
|
|
141
|
+
and OAuth client without warning. The refusal names the current owner's
|
|
142
|
+
login, and replacing an existing `YANDEX_DIRECT_TOKEN` in the folder `.env`
|
|
143
|
+
prints a warning.
|
|
144
|
+
- Authorization is headless and non-interactive by default, including in a
|
|
145
|
+
terminal. Login dialogs require `--interactive`; manual browser login also
|
|
146
|
+
accepts explicit `--headful`. TTY detection never selects an interactive mode.
|
|
147
|
+
- Chrome import no longer retries failed headless verification with a visible
|
|
148
|
+
browser. Legacy browser login paths also require an explicit UI flag.
|
|
149
|
+
|
|
150
|
+
- Canonical API/browser login, status, logout and browser diagnostics now live
|
|
151
|
+
under `direct auth`. Existing explicit login paths and JSON remain supported
|
|
152
|
+
through deprecated adapters; credentials and browser storage are not migrated.
|
|
153
|
+
- Resource commands use saved browser sessions only. Missing, expired or rejected
|
|
154
|
+
sessions fail with a login hint, without Chrome cookie import, Keychain access
|
|
155
|
+
or retrying an operation. Move resource Chrome flags to explicit
|
|
156
|
+
`direct auth login --method browser --source chrome`.
|
|
157
|
+
- API logout removes the selected local profile and this folder's binding;
|
|
158
|
+
browser logout removes both CLI browser sessions. Source Chrome is untouched.
|
|
159
|
+
- Browser diagnostics skip Keychain and cookie decryption, preserving check names.
|
|
160
|
+
|
|
161
|
+
### BREAKING CHANGES
|
|
162
|
+
|
|
163
|
+
**A folder with no bound credentials has no credentials — the global active
|
|
164
|
+
profile is no longer inherited silently (#904).**
|
|
165
|
+
|
|
166
|
+
Since #489 a folder with no explicit credential binding (no cwd `.env`, no
|
|
167
|
+
`--profile`, no base env) silently resolved credentials from the global
|
|
168
|
+
active profile in `~/.direct-cli/auth.json` — every new project started
|
|
169
|
+
billing the last logged-in account, and `direct auth status` reported an
|
|
170
|
+
indistinguishable `source=oauth`. Now an unbound folder has no credentials:
|
|
171
|
+
|
|
172
|
+
- **Non-interactive sessions** (scripts, sub-processes — including the
|
|
173
|
+
Yandex Direct MCP plugin): every API command fails with `UsageError` and
|
|
174
|
+
binding hints until the folder is bound. New: `direct auth write --profile
|
|
175
|
+
<name>` binds a folder without any prompts — it writes the profile's
|
|
176
|
+
credentials to the cwd `.env` (merge, `0600`, the token is never printed);
|
|
177
|
+
`--profile` is required, nothing is bound implicitly.
|
|
178
|
+
- **Terminal sessions** also fail without opening a login dialog. Explicit
|
|
179
|
+
`direct auth login --interactive` offers API or browser authorization. The API menu
|
|
180
|
+
binds a saved or newly authorized profile to the cwd `.env` immediately;
|
|
181
|
+
a newly named profile does not change the global active profile.
|
|
182
|
+
`--dry-run` still needs no credentials and stays silent.
|
|
183
|
+
- **`direct auth status`** in an unbound folder reports
|
|
184
|
+
`source=null`/`has_token=false` plus a note about the global profile
|
|
185
|
+
(`global_profile`/`global_login` in JSON) — the global profile exists, but
|
|
186
|
+
it is not presented as this folder's credentials.
|
|
187
|
+
- **Opt-in**: `YANDEX_DIRECT_INHERIT_GLOBAL=1` restores the #489 behavior —
|
|
188
|
+
the global active profile is inherited silently again, and `auth status`
|
|
189
|
+
labels it `source=global-profile-inherited`.
|
|
190
|
+
|
|
191
|
+
Explicit bindings are unchanged and still win: `--token`, `--profile`,
|
|
192
|
+
base env, cwd `.env`. `--sandbox` does not bypass the gate — the sandbox
|
|
193
|
+
authenticates under the same profile login, so a wrong inherited account is
|
|
194
|
+
the same mistake there. A folder with only a partial credential ref (e.g.
|
|
195
|
+
an exported `YANDEX_DIRECT_LOGIN` and no token) no longer silently inherits
|
|
196
|
+
the global active profile either — the bind gate applies there too.
|
|
197
|
+
|
|
198
|
+
Migration: bind the folders you use via a `.env` file (`direct auth write`,
|
|
199
|
+
or run `direct auth login --method api` once per folder), pass `--profile`, or set
|
|
200
|
+
`YANDEX_DIRECT_INHERIT_GLOBAL=1` where inheritance is intended.
|
|
201
|
+
|
|
202
|
+
Offline tests are insulated from the same nondeterminism: the suite now
|
|
203
|
+
points `AUTH_STORE_PATH` at a per-test file by default (autouse fixture;
|
|
204
|
+
live tiers keep the real store so their profile fallback still works) and
|
|
205
|
+
runs under the inheritance opt-in, so offline tests no longer change
|
|
206
|
+
behavior with the developer's active `direct auth` profile. The `ruff` dev
|
|
207
|
+
pin moves to `>=0.16,<0.17` with the pre-0.16 default rule set pinned
|
|
208
|
+
explicitly in `[tool.ruff.lint] select`, so lint behavior no longer drifts
|
|
209
|
+
with the ruff version.
|
|
210
|
+
|
|
3
211
|
## 0.5.3 — 2026-10-07
|
|
4
212
|
|
|
5
213
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: direct-cli
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4
|
|
4
4
|
Summary: Command-line interface for Yandex Direct API
|
|
5
5
|
Author: axisrow
|
|
6
6
|
License: MIT
|
|
@@ -37,7 +37,7 @@ Requires-Dist: black>=22.0; extra == "dev"
|
|
|
37
37
|
Requires-Dist: flake8>=4.0; extra == "dev"
|
|
38
38
|
Requires-Dist: mypy>=1.8; extra == "dev"
|
|
39
39
|
Requires-Dist: pyright>=1.1.400; extra == "dev"
|
|
40
|
-
Requires-Dist: ruff<0.
|
|
40
|
+
Requires-Dist: ruff<0.17,>=0.16; extra == "dev"
|
|
41
41
|
Requires-Dist: requests>=2.0; extra == "dev"
|
|
42
42
|
Requires-Dist: beautifulsoup4>=4.12; extra == "dev"
|
|
43
43
|
Requires-Dist: lxml>=4.9; extra == "dev"
|
|
@@ -66,18 +66,16 @@ pip install direct-cli
|
|
|
66
66
|
Мастер кампаний has **no Yandex Direct API surface at all** — it only exists
|
|
67
67
|
in the web interface, and must not be confused with `UNIFIED_CAMPAIGN` (an
|
|
68
68
|
unrelated v5 API campaign type already supported by `campaigns add/get --type
|
|
69
|
-
unified_campaign`).
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
system permission dialog — click Allow. Linux is supported when Chrome uses
|
|
75
|
-
its basic (non-keyring) password store; Windows isn't supported yet. Requires
|
|
76
|
-
the optional `browser` extra:
|
|
69
|
+
unified_campaign`). Browser-backed commands use a saved browser session,
|
|
70
|
+
independent of the API token. Set it up explicitly with
|
|
71
|
+
`direct auth login browser`. This opens a CLI-owned Chromium window
|
|
72
|
+
and works on macOS/Linux/Windows without reading Chrome or Keychain.
|
|
73
|
+
Requires the optional `browser` extra:
|
|
77
74
|
|
|
78
75
|
```bash
|
|
79
76
|
pip install "direct-cli[browser]"
|
|
80
77
|
playwright install chromium
|
|
78
|
+
direct auth login browser
|
|
81
79
|
direct masters list
|
|
82
80
|
direct masters list --status archived
|
|
83
81
|
direct masters get 72349978
|
|
@@ -245,18 +243,18 @@ never a silent skip, and the whole plan (including that local image/video
|
|
|
245
243
|
files exist) is validated before the first save.
|
|
246
244
|
|
|
247
245
|
A campaign that fails is reported with an `Error` and does not stop the rest;
|
|
248
|
-
the command exits non-zero afterwards. If
|
|
249
|
-
|
|
250
|
-
|
|
246
|
+
the command exits non-zero afterwards. If browser authorization fails mid-plan,
|
|
247
|
+
the run stops with a login hint. It never imports cookies or repeats the
|
|
248
|
+
operation under another session.
|
|
251
249
|
`--pacing-ms` (default 1000) controls the pause between campaigns,
|
|
252
250
|
`--moderation-statuses` additionally reads each campaign's current moderation
|
|
253
251
|
statuses after its save (a snapshot — moderation usually has not run yet at
|
|
254
252
|
that point, so a rejection can still appear later), and `--dry-run` prints
|
|
255
253
|
what would be applied without opening a browser.
|
|
256
254
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
255
|
+
To import an existing Chrome session instead, run
|
|
256
|
+
`direct auth login browser --source chrome --chrome-profile "Profile 1"`.
|
|
257
|
+
Chrome profile flags belong to explicit login, not resource commands.
|
|
260
258
|
|
|
261
259
|
Since this data has no API contract, the parser degrades per-section (a
|
|
262
260
|
warning, not a hard failure) if Yandex changes the page markup, rather than
|
|
@@ -334,33 +332,26 @@ running it twice creates a SECOND copy, not an update to the first. By
|
|
|
334
332
|
default the copy is saved as a draft (`--draft`); pass `--launch` to launch
|
|
335
333
|
it immediately in production instead. Same no-`--sandbox` caveat as `add`.
|
|
336
334
|
|
|
337
|
-
**Browser
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
profile and revoke the on-disk session (a no-op warning, not an error, if
|
|
358
|
-
none exists).
|
|
359
|
-
|
|
360
|
-
Run `direct masters status` to check which of these two sessions `masters`
|
|
361
|
-
commands would currently use — which tier is active, the persistent
|
|
362
|
-
profile's path, and the saved session's expiry — without any network call
|
|
363
|
-
or side effect (no browser launch, unlike every other `masters` command).
|
|
335
|
+
**Browser authorization:** `direct auth login browser` opens the
|
|
336
|
+
CLI's persistent Chromium profile (`~/.direct-cli/chrome-profile/`) and waits
|
|
337
|
+
up to `--timeout` seconds (default 300) for manual login. It requires a
|
|
338
|
+
terminal unless `--allow-no-tty` is explicitly supplied.
|
|
339
|
+
|
|
340
|
+
Alternatively, `direct auth login browser --source chrome` imports
|
|
341
|
+
Chrome cookies into `~/.direct-cli/playwright/session.json` (`0600`). Only
|
|
342
|
+
this explicit import may request Keychain access. `--profile-dir` selects the
|
|
343
|
+
source directory and `--chrome-profile` the Chrome profile subdirectory.
|
|
344
|
+
|
|
345
|
+
Commands prefer an existing persistent Chromium session over an imported
|
|
346
|
+
session. `direct auth status browser` inspects both without opening
|
|
347
|
+
a browser; it reports saved state, not proof of current server-side validity.
|
|
348
|
+
`direct auth doctor` diagnoses dependencies and saved session metadata;
|
|
349
|
+
cookie decryption checks are skipped. Missing or rejected sessions produce
|
|
350
|
+
a login hint; commands never start login or import cookies automatically.
|
|
351
|
+
|
|
352
|
+
`direct auth logout browser` removes both CLI-owned browser sessions.
|
|
353
|
+
It does not touch the original Chrome profile. Old browser-auth commands
|
|
354
|
+
remain deprecated compatibility aliases; their stdout formats are preserved.
|
|
364
355
|
|
|
365
356
|
### История изменений (change history) — browser-only
|
|
366
357
|
|
|
@@ -370,8 +361,8 @@ changed IDs, and Live v4's `GetEventsLog` logs *system* events
|
|
|
370
361
|
(`BannerModerated`, `MoneyOut`, …) — none of them can answer "who changed
|
|
371
362
|
this field, when, and from what to what". That history exists only in the web
|
|
372
363
|
interface's «История изменений» section, so `direct history` reads it through
|
|
373
|
-
the same browser session `direct masters` uses (same `--headful
|
|
374
|
-
|
|
364
|
+
the same saved browser session `direct masters` uses (same `--headful`
|
|
365
|
+
option and no-`--login` rule):
|
|
375
366
|
|
|
376
367
|
```bash
|
|
377
368
|
direct history get
|
|
@@ -399,6 +390,63 @@ A bare `--date-from`/`--date-to` date covers the whole day; pass
|
|
|
399
390
|
`YYYY-MM-DDTHH:MM:SS` for an exact window. Without them, the period the
|
|
400
391
|
section itself defaults to is used.
|
|
401
392
|
|
|
393
|
+
### Authorization
|
|
394
|
+
|
|
395
|
+
`auth login` has two explicit domains: `direct auth login api` (an OAuth
|
|
396
|
+
token for API/v4 commands, saved in an auth profile) and
|
|
397
|
+
`direct auth login browser` (a browser session for browser commands:
|
|
398
|
+
`masters`, `history`, ...). Bare `direct auth login` is the API login.
|
|
399
|
+
|
|
400
|
+
In a terminal the API login is interactive by default: it prints the
|
|
401
|
+
authorize URL, opens the browser, reads the code, and binds the credentials
|
|
402
|
+
to this folder's `.env`. In a non-interactive shell it prints the API
|
|
403
|
+
authorization URL without opening a browser or asking questions. Complete
|
|
404
|
+
the two-step flow with `--code` or `--code -` and bind a saved profile with
|
|
405
|
+
`direct auth write --profile NAME`. Saving into an existing profile
|
|
406
|
+
(including the default `default`) requires explicit `--force`; without it
|
|
407
|
+
the save refuses to overwrite stored credentials. The CLI never replaces
|
|
408
|
+
stored credentials, profiles or browser sessions silently: a replacement is
|
|
409
|
+
either the command's declared purpose (and it reports what was replaced) or
|
|
410
|
+
requires explicit `--force`.
|
|
411
|
+
|
|
412
|
+
The API login in a terminal first offers to reuse a saved profile (bound to
|
|
413
|
+
this folder's `.env` on the spot); otherwise a new profile name comes from
|
|
414
|
+
the account login and gets a numeric suffix when the name is taken.
|
|
415
|
+
API credentials and browser cookies stay separate and may belong to
|
|
416
|
+
different accounts.
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
direct auth login # = direct auth login api
|
|
420
|
+
direct auth login api
|
|
421
|
+
direct auth login browser # manual login in a visible window
|
|
422
|
+
direct auth login browser --source chrome
|
|
423
|
+
direct auth status # both domains
|
|
424
|
+
direct auth status api
|
|
425
|
+
direct auth status browser
|
|
426
|
+
direct auth doctor
|
|
427
|
+
direct auth logout api --profile agency1
|
|
428
|
+
direct auth logout browser
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Manual browser login is visible by definition; `--allow-no-tty` only
|
|
432
|
+
overrides the terminal check for scripts that open the window on purpose.
|
|
433
|
+
Chrome import stays headless, including when verification fails: there is no
|
|
434
|
+
automatic headful retry. All resource commands fail with
|
|
435
|
+
a helpful error when authorization is missing, including in a terminal.
|
|
436
|
+
`direct` without arguments still shows help. API logout removes the named
|
|
437
|
+
local profile and this folder's API binding, preserving other `.env` settings.
|
|
438
|
+
The binding includes local token/login values, secret-manager references and
|
|
439
|
+
the folder's global-profile inheritance setting.
|
|
440
|
+
It does not revoke token copies in other folders, external environments, or
|
|
441
|
+
secret managers. Browser logout removes both saved CLI sessions.
|
|
442
|
+
|
|
443
|
+
`auth status` reports both domains (an `API:` and a `Browser:` block);
|
|
444
|
+
combined JSON has `api` and `browser` sections. `auth status api` and
|
|
445
|
+
`auth status browser` select one domain. Existing API flags and two-step
|
|
446
|
+
PKCE/stdin login remain supported in unattended workflows. The old
|
|
447
|
+
`--method`/`--interactive`/`--headful` flags were removed without aliases:
|
|
448
|
+
each old form fails with the exact replacement command.
|
|
449
|
+
|
|
402
450
|
### Configuration
|
|
403
451
|
|
|
404
452
|
Create a `.env` file in your working directory:
|
|
@@ -446,11 +494,12 @@ Notes:
|
|
|
446
494
|
- 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.
|
|
447
495
|
- `direct auth login --code CODE --profile NAME` remains supported for compatibility, but automation should use `--code -` to avoid exposing the code in process arguments.
|
|
448
496
|
- If the first non-interactive step includes `--client-secret`, the secret is remembered for the matching completion step.
|
|
449
|
-
- If a profile already stores a confidential OAuth client, `direct auth login --code CODE --profile NAME` reuses the saved `client_id` and `client_secret`.
|
|
497
|
+
- If a profile already stores a confidential OAuth client, `direct auth login --code CODE --profile NAME` reuses the saved `client_id` and `client_secret`. Re-logging into an existing profile requires `--force`.
|
|
450
498
|
- `direct auth login --oauth-token TOKEN` is a manual access-token import and does not auto-refresh.
|
|
451
|
-
-
|
|
452
|
-
|
|
453
|
-
|
|
499
|
+
- In a terminal, the interactive API login saves the selected API profile
|
|
500
|
+
directly to the current folder's `.env`. Headless flows never ask for save
|
|
501
|
+
confirmation; use `direct auth write --profile NAME` to bind the folder
|
|
502
|
+
explicitly.
|
|
454
503
|
- Alias `auth_login` is not supported.
|
|
455
504
|
|
|
456
505
|
Credential resolution priority:
|
|
@@ -474,6 +523,44 @@ base `YANDEX_DIRECT_LOGIN`; this prevents mixing accounts. `direct auth status`
|
|
|
474
523
|
without `--profile` reports the effective credential source; with `--profile` it
|
|
475
524
|
reports that profile.
|
|
476
525
|
|
|
526
|
+
**An unbound folder has no credentials (#904).** When credentials would come
|
|
527
|
+
from the active profile fallback (priority 4) — e.g. a brand-new folder with
|
|
528
|
+
no `.env` — the CLI no longer inherits them silently:
|
|
529
|
+
|
|
530
|
+
- Non-interactive sessions (scripts, sub-processes): API commands fail with
|
|
531
|
+
`UsageError` and binding hints until the folder is bound. Bind a folder
|
|
532
|
+
without prompts via `direct auth write --profile <name>` — it writes the
|
|
533
|
+
profile's credentials to the cwd `.env` (merge, `0600`, token never
|
|
534
|
+
printed); `--profile` is required, nothing is bound implicitly.
|
|
535
|
+
- Terminal sessions follow the same rule: an ordinary command never opens a
|
|
536
|
+
login dialog. Run `direct auth login api` to choose or
|
|
537
|
+
authorize a profile and bind it to this folder. A profile created through
|
|
538
|
+
the menu does not change the global active profile.
|
|
539
|
+
- `direct auth status` in an unbound folder reports
|
|
540
|
+
`source=null`/`has_token=false` and notes the global profile
|
|
541
|
+
(`global_profile`/`global_login` in JSON) without presenting it as this
|
|
542
|
+
folder's credentials.
|
|
543
|
+
- `--dry-run` needs no credentials and stays silent; `--sandbox` does not
|
|
544
|
+
bypass the gate — the sandbox authenticates under the same profile login.
|
|
545
|
+
- Set `YANDEX_DIRECT_INHERIT_GLOBAL=1` to restore the former silent
|
|
546
|
+
inheritance for unattended workflows (auth status then labels it
|
|
547
|
+
`source=global-profile-inherited`).
|
|
548
|
+
|
|
549
|
+
### Optional diagnostics output (#925)
|
|
550
|
+
|
|
551
|
+
Optional output — data you did not ask for — is hidden by default and printed
|
|
552
|
+
to stderr only, so stdout stays byte-identical for pipes and JSON parsing:
|
|
553
|
+
|
|
554
|
+
| Env var | Effect |
|
|
555
|
+
|---------|--------|
|
|
556
|
+
| `DIRECT_SHOW_UNITS=1` | After each successful v5 API call, one stderr line with the API Units points: `API units: <spent>/<rest>/<daily limit>` (e.g. `API units: 10/20828/64000`), plus ` (used-login: <login>)` for agency accounts (`Units-Used-Login`). The v4 Live API returns no Units headers, so v4 commands (`direct balance`, …) stay silent under this switch |
|
|
557
|
+
| `DIRECT_QUIET=0` | Master switch back to the legacy behaviour for optional output that existed before #925 (Units had none) |
|
|
558
|
+
|
|
559
|
+
`DIRECT_SHOW_UNITS=1` works even with `DIRECT_QUIET=1`; an explicit
|
|
560
|
+
`DIRECT_SHOW_UNITS=0` wins over `DIRECT_QUIET=0`. Safety output — inherited
|
|
561
|
+
credential warnings (#909), sandbox notices, API warnings — is never
|
|
562
|
+
suppressed. Limit errors already include Units in their text (#921).
|
|
563
|
+
|
|
477
564
|
> **Tests follow the safe credential order.** Live-API test suites (e.g. `tests/test_v4_live_contracts.py`) read `YANDEX_DIRECT_TOKEN` / `YANDEX_DIRECT_LOGIN` from the environment first, only then fall back to the active `direct auth` profile, and skip the test if neither is set. This prevents a developer machine with an active profile from silently hitting production on a plain `pytest` invocation. See `CLAUDE.md` for the contract.
|
|
478
565
|
|
|
479
566
|
Install with `pip install direct-cli`, then run commands with `direct`.
|
|
@@ -1065,6 +1152,15 @@ direct dictionaries get-retargeting-goals --ids 19000000660,19000001592
|
|
|
1065
1152
|
> more than one goal `Type` (e.g. `HOST` and `APPLICATION`) for similar names
|
|
1066
1153
|
> — pick the entry with the `Type` your use case needs.
|
|
1067
1154
|
|
|
1155
|
+
> `retargeting get` returns each list's `Scope` (a default field):
|
|
1156
|
+
> `FOR_TARGETS_ONLY` / `FOR_TARGETS_AND_ADJUSTMENTS` /
|
|
1157
|
+
> `FOR_ADJUSTMENTS_ONLY`. There is no `--scope` flag: the WSDL declares
|
|
1158
|
+
> `Scope` only on `RetargetingListGetItem`, so the API assigns it
|
|
1159
|
+
> server-side. Verified live (#890): `retargeting get` returns
|
|
1160
|
+
> every documented scope class present in the account — an empty
|
|
1161
|
+
> adjustment-class section means the account has no such lists, not
|
|
1162
|
+
> server-side filtering.
|
|
1163
|
+
|
|
1068
1164
|
```bash
|
|
1069
1165
|
# Bids and modifiers
|
|
1070
1166
|
direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
|
|
@@ -1076,6 +1172,10 @@ direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --incre
|
|
|
1076
1172
|
direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
|
|
1077
1173
|
direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
|
|
1078
1174
|
direct bidmodifiers add --campaign-id 123 --type MOBILE_ADJUSTMENT --value 120 --operating-system-type IOS --dry-run
|
|
1175
|
+
# RETARGETING_SEARCH_ADJUSTMENT is a live-only type (#871): the payload is
|
|
1176
|
+
# mirrored, but Yandex currently rejects its creation with 5005 on every
|
|
1177
|
+
# documented retargeting-list class (#890) — works once acceptance is enabled.
|
|
1178
|
+
direct bidmodifiers add --campaign-id 123 --type RETARGETING_SEARCH_ADJUSTMENT --retargeting-condition-id 12345 --value 120 --dry-run
|
|
1079
1179
|
direct bidmodifiers set --id 99 --value 130 --dry-run
|
|
1080
1180
|
|
|
1081
1181
|
# Canonical multiword groups
|