direct-cli 0.2.8__tar.gz → 0.2.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {direct_cli-0.2.8 → direct_cli-0.2.9}/.github/workflows/api-coverage.yml +12 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/PKG-INFO +133 -21
- {direct_cli-0.2.8 → direct_cli-0.2.9}/README.md +129 -19
- direct_cli-0.2.9/direct_cli/_vendor/__init__.py +0 -0
- direct_cli-0.2.9/direct_cli/_vendor/tapi_yandex_direct/__init__.py +8 -0
- direct_cli-0.2.9/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +78 -0
- direct_cli-0.2.9/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +127 -0
- direct_cli-0.2.9/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +387 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/api.py +8 -2
- direct_cli-0.2.9/direct_cli/auth.py +450 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/cli.py +28 -4
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/advideos.py +14 -10
- direct_cli-0.2.9/direct_cli/commands/auth.py +125 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/creatives.py +2 -5
- direct_cli-0.2.9/direct_cli/commands/dynamicfeedadtargets.py +280 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/keywords.py +35 -11
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/keywordsresearch.py +2 -2
- direct_cli-0.2.9/direct_cli/commands/strategies.py +307 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/wsdl_coverage.py +22 -1
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli.egg-info/PKG-INFO +133 -21
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli.egg-info/SOURCES.txt +39 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli.egg-info/requires.txt +3 -1
- direct_cli-0.2.9/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +85 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/pyproject.toml +9 -3
- direct_cli-0.2.9/scripts/anonymize_cassettes.py +155 -0
- direct_cli-0.2.9/scripts/build_api_coverage_report.py +236 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/scripts/release_pypi.sh +3 -0
- direct_cli-0.2.9/scripts/update_vendor.sh +50 -0
- direct_cli-0.2.9/tests/API_COVERAGE.md +92 -0
- direct_cli-0.2.9/tests/API_ISSUE_AUDIT.md +60 -0
- direct_cli-0.2.9/tests/MANUAL_COVERAGE.md +75 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_adgroups_add_update_delete.yaml +374 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_adimages_add_get_delete.yaml +68 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_ads_add_update_delete.yaml +502 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_ads_suspend_resume_archive_unarchive.yaml +628 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_advideos_add_get.yaml +126 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_add_delete.yaml +313 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_suspend_resume.yaml +313 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_bids_set.yaml +437 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_campaign_create_get_delete.yaml +250 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_creatives_chain_advideo_to_creative.yaml +189 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_add_delete.yaml +67 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_suspend_resume.yaml +67 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_keywordbids_set.yaml +439 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_keywords_add_update_delete.yaml +439 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_keywords_suspend_resume.yaml +499 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_sitelinks_add_get_delete.yaml +191 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_add_update_delete.yaml +191 -0
- direct_cli-0.2.9/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_suspend_resume.yaml +191 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +11 -11
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +27 -27
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +6 -6
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +27 -27
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +38 -38
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +22 -22
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +18 -18
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +27 -27
- direct_cli-0.2.9/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +218 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +33 -33
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +4 -4
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +16 -16
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +27 -27
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +27 -27
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +17 -17
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +10 -10
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +5 -5
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +15 -15
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +23 -23
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/conftest.py +26 -1
- direct_cli-0.2.9/tests/fixtures/test-video.mp4 +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/test_api_coverage.py +183 -43
- direct_cli-0.2.9/tests/test_auth_oauth.py +206 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/test_cli.py +20 -3
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/test_comprehensive.py +3 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/test_dry_run.py +124 -3
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/test_integration.py +150 -30
- direct_cli-0.2.9/tests/test_integration_live_write.py +1252 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/test_integration_write.py +369 -130
- direct_cli-0.2.9/tests/test_transport_contract.py +23 -0
- direct_cli-0.2.9/tests/wsdl_cache/dynamicfeedadtargets.xml +328 -0
- direct_cli-0.2.9/tests/wsdl_cache/strategies.xml +1100 -0
- direct_cli-0.2.8/direct_cli/auth.py +0 -167
- direct_cli-0.2.8/scripts/build_api_coverage_report.py +0 -108
- {direct_cli-0.2.8 → direct_cli-0.2.9}/.env.example +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/.github/copilot-instructions.md +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/.github/workflows/claude-code-review.yml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/.github/workflows/claude.yml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/.gitignore +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/AGENTS.md +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/CLAUDE.md +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/MANIFEST.in +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/__init__.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/_deprecated.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/__init__.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/adextensions.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/adgroups.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/adimages.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/ads.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/agencyclients.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/audiencetargets.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/bidmodifiers.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/bids.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/businesses.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/campaigns.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/changes.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/clients.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/dictionaries.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/dynamicads.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/feeds.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/keywordbids.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/leads.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/negativekeywordsharedsets.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/reports.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/retargeting.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/sitelinks.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/smartadtargets.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/turbopages.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/commands/vcards.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/output.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/reports_coverage.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli/utils.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli.egg-info/dependency_links.txt +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli.egg-info/entry_points.txt +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/direct_cli.egg-info/top_level.txt +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/scripts/check_reports_drift.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/scripts/check_wsdl_drift.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/scripts/refresh_reports_cache.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/scripts/refresh_wsdl_cache.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/setup.cfg +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/setup.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/__init__.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/reports_cache/raw/fields-list.html +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/reports_cache/raw/headers.html +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/reports_cache/raw/spec.html +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/reports_cache/raw/type.html +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/reports_cache/spec.json +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/test_auth_bw.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/test_auth_op.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/test_reports_drift.py +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/adextensions.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/adgroups.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/adimages.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/ads.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/advideos.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/agencyclients.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/audiencetargets.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/bidmodifiers.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/bids.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/businesses.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/campaigns.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/changes.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/clients.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/creatives.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/dictionaries.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/feeds.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/keywordbids.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/keywords.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/keywordsresearch.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/leads.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/retargetinglists.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/sitelinks.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/smartadtargets.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/turbopages.xml +0 -0
- {direct_cli-0.2.8 → direct_cli-0.2.9}/tests/wsdl_cache/vcards.xml +0 -0
|
@@ -45,12 +45,24 @@ jobs:
|
|
|
45
45
|
|
|
46
46
|
report = json.loads(Path("api_coverage_report.json").read_text())
|
|
47
47
|
summary = report["summary"]
|
|
48
|
+
model_gaps = report["model_gaps"]
|
|
48
49
|
print("## API coverage summary")
|
|
49
50
|
print()
|
|
50
51
|
print(f"- Services checked: {summary['services_checked']}")
|
|
51
52
|
print(f"- Missing methods: {summary['missing_service_methods']}")
|
|
52
53
|
print(f"- Unexpected methods: {summary['unexpected_service_methods']}")
|
|
53
54
|
print(f"- Strict parity OK: {summary['strict_parity_ok']}")
|
|
55
|
+
print(f"- Live model parity OK: {summary['live_model_parity_ok']}")
|
|
56
|
+
print(f"- Declared WSDL services: {model_gaps['declared_wsdl_services_count']}")
|
|
57
|
+
print(f"- Declared WSDL methods: {model_gaps['declared_wsdl_methods_count']}")
|
|
58
|
+
print(f"- Live-discovered services: {model_gaps['live_discovered_services_count']}")
|
|
59
|
+
print(f"- Total known methods: {model_gaps['total_known_methods_count']}")
|
|
60
|
+
print(f"- Model gaps: {model_gaps['live_model_gap_count']}")
|
|
61
|
+
for item in model_gaps["live_discovered_missing_services"][:10]:
|
|
62
|
+
methods = ", ".join(item["api_methods"])
|
|
63
|
+
print(f"- Missing service: {item['api_service']} ({methods})")
|
|
64
|
+
for item in model_gaps["live_discovery_errors"][:10]:
|
|
65
|
+
print(f"- Live discovery error: {item['api_service']}: {item['error']}")
|
|
54
66
|
print(f"- Non-WSDL services: {len(report['non_wsdl_services'])}")
|
|
55
67
|
print(f"- CLI helpers: {len(report['cli_helpers'])}")
|
|
56
68
|
PY
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: direct-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: Command-line interface for Yandex Direct API
|
|
5
5
|
Author: axisrow
|
|
6
6
|
License: MIT
|
|
@@ -18,7 +18,9 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
19
|
Requires-Python: >=3.9
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
|
-
Requires-Dist:
|
|
21
|
+
Requires-Dist: orjson
|
|
22
|
+
Requires-Dist: requests
|
|
23
|
+
Requires-Dist: tapi-wrapper2
|
|
22
24
|
Requires-Dist: click>=8.0.0
|
|
23
25
|
Requires-Dist: python-dotenv>=0.19.0
|
|
24
26
|
Requires-Dist: tabulate>=0.8.0
|
|
@@ -66,6 +68,35 @@ Or pass credentials directly per command:
|
|
|
66
68
|
direct --token YOUR_TOKEN --login YOUR_LOGIN campaigns get
|
|
67
69
|
```
|
|
68
70
|
|
|
71
|
+
Use profile-specific credentials from `.env`:
|
|
72
|
+
|
|
73
|
+
```env
|
|
74
|
+
YANDEX_DIRECT_TOKEN_AGENCY1=token-1
|
|
75
|
+
YANDEX_DIRECT_LOGIN_AGENCY1=client-login-1
|
|
76
|
+
YANDEX_DIRECT_TOKEN_AGENCY2=token-2
|
|
77
|
+
YANDEX_DIRECT_LOGIN_AGENCY2=client-login-2
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
OAuth and profile commands:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
direct auth login
|
|
84
|
+
direct auth login --profile agency1
|
|
85
|
+
direct auth login --code abc123 --profile agency1
|
|
86
|
+
direct auth login --oauth-token y0_example --profile agency1
|
|
87
|
+
direct auth list
|
|
88
|
+
direct auth use --profile agency1
|
|
89
|
+
direct auth status --profile agency1
|
|
90
|
+
direct --profile agency1 campaigns get
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Notes:
|
|
94
|
+
- Legacy profile environment variable is not used.
|
|
95
|
+
- Select credentials with `--profile`.
|
|
96
|
+
- `--login` remains Direct client login.
|
|
97
|
+
- Authorization is performed via `direct auth login`.
|
|
98
|
+
- Alias `auth_login` is not supported.
|
|
99
|
+
|
|
69
100
|
Install with `pip install direct-cli`, then run commands with `direct`.
|
|
70
101
|
Invoking the deprecated `direct-cli` entrypoint exits with
|
|
71
102
|
`use direct instead of direct-cli`.
|
|
@@ -75,7 +106,8 @@ Invoking the deprecated `direct-cli` entrypoint exits with
|
|
|
75
106
|
| Option | Description |
|
|
76
107
|
|--------|-------------|
|
|
77
108
|
| `--token` | API access token |
|
|
78
|
-
| `--login` |
|
|
109
|
+
| `--login` | Direct client login |
|
|
110
|
+
| `--profile` | Credential profile name |
|
|
79
111
|
| `--sandbox` | Use sandbox API |
|
|
80
112
|
|
|
81
113
|
### CLI Convention
|
|
@@ -255,7 +287,7 @@ direct ads delete --id 99999
|
|
|
255
287
|
```bash
|
|
256
288
|
direct keywords get --campaign-ids 1,2,3
|
|
257
289
|
direct keywords add --adgroup-id 12345 --keyword "buy laptop" --bid 10.50 --context-bid 5.25 --user-param-1 segment-a --user-param-2 segment-b --dry-run
|
|
258
|
-
direct keywords update --id 88888 --
|
|
290
|
+
direct keywords update --id 88888 --keyword "updated keyword text"
|
|
259
291
|
direct keywords delete --id 88888
|
|
260
292
|
```
|
|
261
293
|
|
|
@@ -309,6 +341,17 @@ direct smartadtargets update --id 456 --priority HIGH
|
|
|
309
341
|
direct smartadtargets set-bids --id 456 --average-cpc 10.5 --average-cpa 15 --priority HIGH
|
|
310
342
|
direct dynamicads set-bids --id 789 --bid 12.5 --context-bid 9 --priority HIGH
|
|
311
343
|
|
|
344
|
+
# Shared bidding strategies
|
|
345
|
+
direct strategies get --limit 5
|
|
346
|
+
direct strategies add --name "Shared Clicks" --type WbMaximumClicks --params '{"SpendLimit":1000000000,"AverageCpc":30000000}' --dry-run
|
|
347
|
+
direct strategies update --id 42 --params '{"AverageCpc":35000000}' --dry-run
|
|
348
|
+
direct strategies archive --id 42 --dry-run
|
|
349
|
+
|
|
350
|
+
# Dynamic feed ad targets
|
|
351
|
+
direct dynamicfeedadtargets get --adgroup-ids 123 --limit 5
|
|
352
|
+
direct dynamicfeedadtargets add --adgroup-id 33 --name "Feed slice A" --condition "CATEGORY:EQUALS:shoes" --bid 5 --dry-run
|
|
353
|
+
direct dynamicfeedadtargets set-bids --id 789 --bid 6.5 --context-bid 4 --dry-run
|
|
354
|
+
|
|
312
355
|
# Extensions, assets, feeds, and clients
|
|
313
356
|
direct sitelinks add --sitelink "Docs|https://example.com/docs" --sitelink "Help|https://example.com/help|Desk" --dry-run
|
|
314
357
|
direct vcards add --campaign-id 555 --country "Russia" --city "Moscow" --company-name "Acme" --work-time 1#5#9#0#18#0 --phone-country-code +7 --phone-city-code 495 --phone-number 1234567 --dry-run
|
|
@@ -324,12 +367,12 @@ direct agencyclients add-passport-organization-member --passport-organization-lo
|
|
|
324
367
|
direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
|
|
325
368
|
```
|
|
326
369
|
|
|
327
|
-
### Known
|
|
370
|
+
### Known Unsupported API Operation
|
|
328
371
|
|
|
329
|
-
`dynamicads update` is
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
372
|
+
`dynamicads update` is unsupported by API. The Yandex Direct
|
|
373
|
+
`dynamictextadtargets` service exposes `add`, `get`, `delete`, `suspend`,
|
|
374
|
+
`resume`, and `setBids`, but no `update` operation. Do not add or rely on
|
|
375
|
+
`direct dynamicads update` unless Yandex exposes a real API method.
|
|
333
376
|
|
|
334
377
|
### Output Formats
|
|
335
378
|
|
|
@@ -378,19 +421,22 @@ direct campaigns add --name "Test" --start-date 2024-01-01 --dry-run
|
|
|
378
421
|
|
|
379
422
|
### Testing
|
|
380
423
|
|
|
381
|
-
|
|
424
|
+
Four tiers of tests live under `tests/`:
|
|
382
425
|
|
|
383
426
|
| Tier | Marker | Network | Token required |
|
|
384
427
|
|---|---|---|---|
|
|
385
428
|
| Unit / CLI wiring / dry-run | *(none)* | No | No |
|
|
386
429
|
| Read-only integration | `-m integration` | Yes (production API, read-only) | Yes |
|
|
387
430
|
| Write integration | `-m integration_write` | No (replays VCR cassettes) | No |
|
|
431
|
+
| Live draft write integration | `-m integration_live_write` | Yes when recording, otherwise VCR replay | Yes + `YANDEX_DIRECT_LIVE_WRITE=1` |
|
|
388
432
|
|
|
389
433
|
```bash
|
|
390
434
|
pip install -e ".[dev]"
|
|
391
435
|
pytest # fast tier — no token
|
|
392
436
|
pytest -m integration -v # read-only integration tests (needs token)
|
|
393
437
|
pytest -m integration_write -v # write cassette replay (no token needed)
|
|
438
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v # live draft cassette replay
|
|
439
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rewrite # re-record live draft cassette
|
|
394
440
|
```
|
|
395
441
|
|
|
396
442
|
### API Coverage And Drift Monitoring
|
|
@@ -400,13 +446,16 @@ The project now distinguishes four surfaces:
|
|
|
400
446
|
| Surface | Coverage strategy |
|
|
401
447
|
|---|---|
|
|
402
448
|
| Canonical WSDL-backed SOAP services | `tests/test_api_coverage.py` verifies strict service/method parity and dry-run request-schema coverage or explicit exclusions |
|
|
449
|
+
| Live-discovered WSDL model gaps | `scripts/build_api_coverage_report.py` reports services seen in the audited live API surface but not yet declared in the CLI coverage model |
|
|
403
450
|
| Non-WSDL services (`reports`) | Explicit contract tests |
|
|
404
451
|
| Historical aliases retained by exception | None currently retained |
|
|
405
452
|
| Intentional CLI-only helpers | Explicitly allowlisted with reasons in `direct_cli/wsdl_coverage.py` |
|
|
406
453
|
|
|
407
454
|
`100% coverage` in this project means full coverage of the supported
|
|
408
|
-
**canonical API surface**.
|
|
409
|
-
|
|
455
|
+
**declared canonical API surface**. The API coverage report also includes a
|
|
456
|
+
`model_gaps` section for live-discovered Yandex Direct services that are not
|
|
457
|
+
yet part of that declared model. Alias groups and CLI-only helpers remain
|
|
458
|
+
supported, but they are tracked outside the strict parity metric.
|
|
410
459
|
|
|
411
460
|
Useful maintenance commands:
|
|
412
461
|
|
|
@@ -418,7 +467,8 @@ python scripts/check_wsdl_drift.py
|
|
|
418
467
|
|
|
419
468
|
CI runs a scheduled API coverage workflow that:
|
|
420
469
|
- runs the fast coverage suites;
|
|
421
|
-
- uploads a machine-readable API coverage report artifact
|
|
470
|
+
- uploads a machine-readable API coverage report artifact, including declared
|
|
471
|
+
parity and live-discovered model gap counts;
|
|
422
472
|
- checks the cached WSDL files against the live Yandex Direct API on schedule.
|
|
423
473
|
|
|
424
474
|
#### Re-recording write cassettes
|
|
@@ -449,6 +499,29 @@ The VCR config in `tests/conftest.py` already strips `Authorization`,
|
|
|
449
499
|
`Client-Login`, cookies and any response header containing the substring
|
|
450
500
|
`login`, but manual verification is mandatory before committing.
|
|
451
501
|
|
|
502
|
+
#### Live draft write tests
|
|
503
|
+
|
|
504
|
+
The `integration_live_write` tier is manual-only and intentionally separate
|
|
505
|
+
from sandbox cassette tests. In rewrite mode it runs against the production
|
|
506
|
+
Yandex Direct API, but it may only create disposable draft resources and
|
|
507
|
+
delete the exact IDs it created in the same test run. Current coverage is
|
|
508
|
+
limited to a guarded campaign draft create -> get -> delete check.
|
|
509
|
+
|
|
510
|
+
Replay the checked-in cassette:
|
|
511
|
+
|
|
512
|
+
```bash
|
|
513
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Re-record it only when you intentionally want to verify live draft behavior:
|
|
517
|
+
|
|
518
|
+
```bash
|
|
519
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rewrite
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Do not add tests to this tier that accept external IDs, resume/suspend/archive
|
|
523
|
+
existing resources, mutate bids, or touch serving campaigns.
|
|
524
|
+
|
|
452
525
|
### Release Process
|
|
453
526
|
|
|
454
527
|
Build, validate and upload to PyPI:
|
|
@@ -519,7 +592,7 @@ direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
|
|
|
519
592
|
| Опция | Описание |
|
|
520
593
|
|-------|----------|
|
|
521
594
|
| `--token` | OAuth-токен доступа к API |
|
|
522
|
-
| `--login` |
|
|
595
|
+
| `--login` | Direct client login |
|
|
523
596
|
| `--sandbox` | Использовать тестовое API (песочница) |
|
|
524
597
|
|
|
525
598
|
### Использование
|
|
@@ -740,7 +813,7 @@ direct ads delete --id 99999
|
|
|
740
813
|
```bash
|
|
741
814
|
direct keywords get --campaign-ids 1,2,3
|
|
742
815
|
direct keywords add --adgroup-id 12345 --keyword "купить ноутбук" --bid 10.50 --context-bid 5.25 --user-param-1 segment-a --user-param-2 segment-b --dry-run
|
|
743
|
-
direct keywords update --id 88888 --
|
|
816
|
+
direct keywords update --id 88888 --keyword "updated keyword text"
|
|
744
817
|
direct keywords delete --id 88888
|
|
745
818
|
```
|
|
746
819
|
|
|
@@ -794,6 +867,17 @@ direct smartadtargets update --id 456 --priority HIGH
|
|
|
794
867
|
direct smartadtargets set-bids --id 456 --average-cpc 10.5 --average-cpa 15 --priority HIGH
|
|
795
868
|
direct dynamicads set-bids --id 789 --bid 12.5 --context-bid 9 --priority HIGH
|
|
796
869
|
|
|
870
|
+
# Общие стратегии ставок
|
|
871
|
+
direct strategies get --limit 5
|
|
872
|
+
direct strategies add --name "Общая стратегия" --type WbMaximumClicks --params '{"SpendLimit":1000000000,"AverageCpc":30000000}' --dry-run
|
|
873
|
+
direct strategies update --id 42 --params '{"AverageCpc":35000000}' --dry-run
|
|
874
|
+
direct strategies archive --id 42 --dry-run
|
|
875
|
+
|
|
876
|
+
# Динамические таргеты по фиду
|
|
877
|
+
direct dynamicfeedadtargets get --adgroup-ids 123 --limit 5
|
|
878
|
+
direct dynamicfeedadtargets add --adgroup-id 33 --name "Срез фида А" --condition "CATEGORY:EQUALS:shoes" --bid 5 --dry-run
|
|
879
|
+
direct dynamicfeedadtargets set-bids --id 789 --bid 6.5 --context-bid 4 --dry-run
|
|
880
|
+
|
|
797
881
|
# Расширения, ассеты, фиды и клиенты
|
|
798
882
|
direct sitelinks add --sitelink "Docs|https://example.com/docs" --sitelink "Help|https://example.com/help|Desk" --dry-run
|
|
799
883
|
direct vcards add --campaign-id 555 --country "Россия" --city "Москва" --company-name "Acme" --work-time 1#5#9#0#18#0 --phone-country-code +7 --phone-city-code 495 --phone-number 1234567 --dry-run
|
|
@@ -809,12 +893,13 @@ direct agencyclients add-passport-organization-member --passport-organization-lo
|
|
|
809
893
|
direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
|
|
810
894
|
```
|
|
811
895
|
|
|
812
|
-
###
|
|
896
|
+
### Известная неподдерживаемая API-операция
|
|
813
897
|
|
|
814
|
-
`dynamicads update`
|
|
815
|
-
|
|
816
|
-
экспортирует `
|
|
817
|
-
|
|
898
|
+
`dynamicads update` unsupported by API. Сервис Яндекс Директа
|
|
899
|
+
`dynamictextadtargets` экспортирует `add`, `get`, `delete`, `suspend`,
|
|
900
|
+
`resume` и `setBids`, но не экспортирует `update`. Не добавляйте и не
|
|
901
|
+
используйте `direct dynamicads update`, пока Яндекс не предоставит реальный
|
|
902
|
+
API-метод.
|
|
818
903
|
|
|
819
904
|
### Форматы вывода
|
|
820
905
|
|
|
@@ -863,19 +948,22 @@ direct campaigns add --name "Тест" --start-date 2024-01-01 --dry-run
|
|
|
863
948
|
|
|
864
949
|
### Тестирование
|
|
865
950
|
|
|
866
|
-
В `tests/`
|
|
951
|
+
В `tests/` четыре уровня тестов:
|
|
867
952
|
|
|
868
953
|
| Уровень | Маркер | Сеть | Нужен токен |
|
|
869
954
|
|---|---|---|---|
|
|
870
955
|
| Юнит / CLI / dry-run | *(без маркера)* | Нет | Нет |
|
|
871
956
|
| Read-only интеграция | `-m integration` | Да (prod API, только чтение) | Да |
|
|
872
957
|
| Write интеграция | `-m integration_write` | Нет (replay VCR-кассет) | Нет |
|
|
958
|
+
| Live draft write интеграция | `-m integration_live_write` | Да при записи, иначе VCR replay | Да + `YANDEX_DIRECT_LIVE_WRITE=1` |
|
|
873
959
|
|
|
874
960
|
```bash
|
|
875
961
|
pip install -e ".[dev]"
|
|
876
962
|
pytest # быстрый уровень — без токена
|
|
877
963
|
pytest -m integration -v # read-only интеграция (нужен токен)
|
|
878
964
|
pytest -m integration_write -v # replay write-кассет (токен не нужен)
|
|
965
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v # replay live draft-кассеты
|
|
966
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rewrite # перезапись live draft-кассеты
|
|
879
967
|
```
|
|
880
968
|
|
|
881
969
|
#### Перезапись write-кассет
|
|
@@ -906,6 +994,30 @@ VCR-конфиг в `tests/conftest.py` уже стрипает `Authorization`,
|
|
|
906
994
|
куки и любые response-заголовки с подстрокой `login`, но ручная проверка
|
|
907
995
|
перед коммитом обязательна.
|
|
908
996
|
|
|
997
|
+
#### Live write только на черновиках
|
|
998
|
+
|
|
999
|
+
Уровень `integration_live_write` запускается только вручную и отделен от
|
|
1000
|
+
sandbox/VCR-тестов. В rewrite-режиме он ходит в production API Яндекс Директа,
|
|
1001
|
+
но может только создавать одноразовые черновики и удалять ровно те ID, которые
|
|
1002
|
+
были созданы в этом же тестовом прогоне. Текущее покрытие: guarded create ->
|
|
1003
|
+
get -> delete для draft-кампании.
|
|
1004
|
+
|
|
1005
|
+
Replay закоммиченной кассеты:
|
|
1006
|
+
|
|
1007
|
+
```bash
|
|
1008
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
Перезапись после явного решения проверить live draft-поведение:
|
|
1012
|
+
|
|
1013
|
+
```bash
|
|
1014
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rewrite
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
В этот уровень нельзя добавлять тесты, которые принимают внешние ID,
|
|
1018
|
+
возобновляют/останавливают/архивируют существующие ресурсы, меняют ставки или
|
|
1019
|
+
трогают кампании, которые могут показываться.
|
|
1020
|
+
|
|
909
1021
|
### Публикация на PyPI
|
|
910
1022
|
|
|
911
1023
|
Сборка, проверка и загрузка на PyPI:
|
|
@@ -29,6 +29,35 @@ Or pass credentials directly per command:
|
|
|
29
29
|
direct --token YOUR_TOKEN --login YOUR_LOGIN campaigns get
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
Use profile-specific credentials from `.env`:
|
|
33
|
+
|
|
34
|
+
```env
|
|
35
|
+
YANDEX_DIRECT_TOKEN_AGENCY1=token-1
|
|
36
|
+
YANDEX_DIRECT_LOGIN_AGENCY1=client-login-1
|
|
37
|
+
YANDEX_DIRECT_TOKEN_AGENCY2=token-2
|
|
38
|
+
YANDEX_DIRECT_LOGIN_AGENCY2=client-login-2
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
OAuth and profile commands:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
direct auth login
|
|
45
|
+
direct auth login --profile agency1
|
|
46
|
+
direct auth login --code abc123 --profile agency1
|
|
47
|
+
direct auth login --oauth-token y0_example --profile agency1
|
|
48
|
+
direct auth list
|
|
49
|
+
direct auth use --profile agency1
|
|
50
|
+
direct auth status --profile agency1
|
|
51
|
+
direct --profile agency1 campaigns get
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Notes:
|
|
55
|
+
- Legacy profile environment variable is not used.
|
|
56
|
+
- Select credentials with `--profile`.
|
|
57
|
+
- `--login` remains Direct client login.
|
|
58
|
+
- Authorization is performed via `direct auth login`.
|
|
59
|
+
- Alias `auth_login` is not supported.
|
|
60
|
+
|
|
32
61
|
Install with `pip install direct-cli`, then run commands with `direct`.
|
|
33
62
|
Invoking the deprecated `direct-cli` entrypoint exits with
|
|
34
63
|
`use direct instead of direct-cli`.
|
|
@@ -38,7 +67,8 @@ Invoking the deprecated `direct-cli` entrypoint exits with
|
|
|
38
67
|
| Option | Description |
|
|
39
68
|
|--------|-------------|
|
|
40
69
|
| `--token` | API access token |
|
|
41
|
-
| `--login` |
|
|
70
|
+
| `--login` | Direct client login |
|
|
71
|
+
| `--profile` | Credential profile name |
|
|
42
72
|
| `--sandbox` | Use sandbox API |
|
|
43
73
|
|
|
44
74
|
### CLI Convention
|
|
@@ -218,7 +248,7 @@ direct ads delete --id 99999
|
|
|
218
248
|
```bash
|
|
219
249
|
direct keywords get --campaign-ids 1,2,3
|
|
220
250
|
direct keywords add --adgroup-id 12345 --keyword "buy laptop" --bid 10.50 --context-bid 5.25 --user-param-1 segment-a --user-param-2 segment-b --dry-run
|
|
221
|
-
direct keywords update --id 88888 --
|
|
251
|
+
direct keywords update --id 88888 --keyword "updated keyword text"
|
|
222
252
|
direct keywords delete --id 88888
|
|
223
253
|
```
|
|
224
254
|
|
|
@@ -272,6 +302,17 @@ direct smartadtargets update --id 456 --priority HIGH
|
|
|
272
302
|
direct smartadtargets set-bids --id 456 --average-cpc 10.5 --average-cpa 15 --priority HIGH
|
|
273
303
|
direct dynamicads set-bids --id 789 --bid 12.5 --context-bid 9 --priority HIGH
|
|
274
304
|
|
|
305
|
+
# Shared bidding strategies
|
|
306
|
+
direct strategies get --limit 5
|
|
307
|
+
direct strategies add --name "Shared Clicks" --type WbMaximumClicks --params '{"SpendLimit":1000000000,"AverageCpc":30000000}' --dry-run
|
|
308
|
+
direct strategies update --id 42 --params '{"AverageCpc":35000000}' --dry-run
|
|
309
|
+
direct strategies archive --id 42 --dry-run
|
|
310
|
+
|
|
311
|
+
# Dynamic feed ad targets
|
|
312
|
+
direct dynamicfeedadtargets get --adgroup-ids 123 --limit 5
|
|
313
|
+
direct dynamicfeedadtargets add --adgroup-id 33 --name "Feed slice A" --condition "CATEGORY:EQUALS:shoes" --bid 5 --dry-run
|
|
314
|
+
direct dynamicfeedadtargets set-bids --id 789 --bid 6.5 --context-bid 4 --dry-run
|
|
315
|
+
|
|
275
316
|
# Extensions, assets, feeds, and clients
|
|
276
317
|
direct sitelinks add --sitelink "Docs|https://example.com/docs" --sitelink "Help|https://example.com/help|Desk" --dry-run
|
|
277
318
|
direct vcards add --campaign-id 555 --country "Russia" --city "Moscow" --company-name "Acme" --work-time 1#5#9#0#18#0 --phone-country-code +7 --phone-city-code 495 --phone-number 1234567 --dry-run
|
|
@@ -287,12 +328,12 @@ direct agencyclients add-passport-organization-member --passport-organization-lo
|
|
|
287
328
|
direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
|
|
288
329
|
```
|
|
289
330
|
|
|
290
|
-
### Known
|
|
331
|
+
### Known Unsupported API Operation
|
|
291
332
|
|
|
292
|
-
`dynamicads update` is
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
333
|
+
`dynamicads update` is unsupported by API. The Yandex Direct
|
|
334
|
+
`dynamictextadtargets` service exposes `add`, `get`, `delete`, `suspend`,
|
|
335
|
+
`resume`, and `setBids`, but no `update` operation. Do not add or rely on
|
|
336
|
+
`direct dynamicads update` unless Yandex exposes a real API method.
|
|
296
337
|
|
|
297
338
|
### Output Formats
|
|
298
339
|
|
|
@@ -341,19 +382,22 @@ direct campaigns add --name "Test" --start-date 2024-01-01 --dry-run
|
|
|
341
382
|
|
|
342
383
|
### Testing
|
|
343
384
|
|
|
344
|
-
|
|
385
|
+
Four tiers of tests live under `tests/`:
|
|
345
386
|
|
|
346
387
|
| Tier | Marker | Network | Token required |
|
|
347
388
|
|---|---|---|---|
|
|
348
389
|
| Unit / CLI wiring / dry-run | *(none)* | No | No |
|
|
349
390
|
| Read-only integration | `-m integration` | Yes (production API, read-only) | Yes |
|
|
350
391
|
| Write integration | `-m integration_write` | No (replays VCR cassettes) | No |
|
|
392
|
+
| Live draft write integration | `-m integration_live_write` | Yes when recording, otherwise VCR replay | Yes + `YANDEX_DIRECT_LIVE_WRITE=1` |
|
|
351
393
|
|
|
352
394
|
```bash
|
|
353
395
|
pip install -e ".[dev]"
|
|
354
396
|
pytest # fast tier — no token
|
|
355
397
|
pytest -m integration -v # read-only integration tests (needs token)
|
|
356
398
|
pytest -m integration_write -v # write cassette replay (no token needed)
|
|
399
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v # live draft cassette replay
|
|
400
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rewrite # re-record live draft cassette
|
|
357
401
|
```
|
|
358
402
|
|
|
359
403
|
### API Coverage And Drift Monitoring
|
|
@@ -363,13 +407,16 @@ The project now distinguishes four surfaces:
|
|
|
363
407
|
| Surface | Coverage strategy |
|
|
364
408
|
|---|---|
|
|
365
409
|
| Canonical WSDL-backed SOAP services | `tests/test_api_coverage.py` verifies strict service/method parity and dry-run request-schema coverage or explicit exclusions |
|
|
410
|
+
| Live-discovered WSDL model gaps | `scripts/build_api_coverage_report.py` reports services seen in the audited live API surface but not yet declared in the CLI coverage model |
|
|
366
411
|
| Non-WSDL services (`reports`) | Explicit contract tests |
|
|
367
412
|
| Historical aliases retained by exception | None currently retained |
|
|
368
413
|
| Intentional CLI-only helpers | Explicitly allowlisted with reasons in `direct_cli/wsdl_coverage.py` |
|
|
369
414
|
|
|
370
415
|
`100% coverage` in this project means full coverage of the supported
|
|
371
|
-
**canonical API surface**.
|
|
372
|
-
|
|
416
|
+
**declared canonical API surface**. The API coverage report also includes a
|
|
417
|
+
`model_gaps` section for live-discovered Yandex Direct services that are not
|
|
418
|
+
yet part of that declared model. Alias groups and CLI-only helpers remain
|
|
419
|
+
supported, but they are tracked outside the strict parity metric.
|
|
373
420
|
|
|
374
421
|
Useful maintenance commands:
|
|
375
422
|
|
|
@@ -381,7 +428,8 @@ python scripts/check_wsdl_drift.py
|
|
|
381
428
|
|
|
382
429
|
CI runs a scheduled API coverage workflow that:
|
|
383
430
|
- runs the fast coverage suites;
|
|
384
|
-
- uploads a machine-readable API coverage report artifact
|
|
431
|
+
- uploads a machine-readable API coverage report artifact, including declared
|
|
432
|
+
parity and live-discovered model gap counts;
|
|
385
433
|
- checks the cached WSDL files against the live Yandex Direct API on schedule.
|
|
386
434
|
|
|
387
435
|
#### Re-recording write cassettes
|
|
@@ -412,6 +460,29 @@ The VCR config in `tests/conftest.py` already strips `Authorization`,
|
|
|
412
460
|
`Client-Login`, cookies and any response header containing the substring
|
|
413
461
|
`login`, but manual verification is mandatory before committing.
|
|
414
462
|
|
|
463
|
+
#### Live draft write tests
|
|
464
|
+
|
|
465
|
+
The `integration_live_write` tier is manual-only and intentionally separate
|
|
466
|
+
from sandbox cassette tests. In rewrite mode it runs against the production
|
|
467
|
+
Yandex Direct API, but it may only create disposable draft resources and
|
|
468
|
+
delete the exact IDs it created in the same test run. Current coverage is
|
|
469
|
+
limited to a guarded campaign draft create -> get -> delete check.
|
|
470
|
+
|
|
471
|
+
Replay the checked-in cassette:
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
Re-record it only when you intentionally want to verify live draft behavior:
|
|
478
|
+
|
|
479
|
+
```bash
|
|
480
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rewrite
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
Do not add tests to this tier that accept external IDs, resume/suspend/archive
|
|
484
|
+
existing resources, mutate bids, or touch serving campaigns.
|
|
485
|
+
|
|
415
486
|
### Release Process
|
|
416
487
|
|
|
417
488
|
Build, validate and upload to PyPI:
|
|
@@ -482,7 +553,7 @@ direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
|
|
|
482
553
|
| Опция | Описание |
|
|
483
554
|
|-------|----------|
|
|
484
555
|
| `--token` | OAuth-токен доступа к API |
|
|
485
|
-
| `--login` |
|
|
556
|
+
| `--login` | Direct client login |
|
|
486
557
|
| `--sandbox` | Использовать тестовое API (песочница) |
|
|
487
558
|
|
|
488
559
|
### Использование
|
|
@@ -703,7 +774,7 @@ direct ads delete --id 99999
|
|
|
703
774
|
```bash
|
|
704
775
|
direct keywords get --campaign-ids 1,2,3
|
|
705
776
|
direct keywords add --adgroup-id 12345 --keyword "купить ноутбук" --bid 10.50 --context-bid 5.25 --user-param-1 segment-a --user-param-2 segment-b --dry-run
|
|
706
|
-
direct keywords update --id 88888 --
|
|
777
|
+
direct keywords update --id 88888 --keyword "updated keyword text"
|
|
707
778
|
direct keywords delete --id 88888
|
|
708
779
|
```
|
|
709
780
|
|
|
@@ -757,6 +828,17 @@ direct smartadtargets update --id 456 --priority HIGH
|
|
|
757
828
|
direct smartadtargets set-bids --id 456 --average-cpc 10.5 --average-cpa 15 --priority HIGH
|
|
758
829
|
direct dynamicads set-bids --id 789 --bid 12.5 --context-bid 9 --priority HIGH
|
|
759
830
|
|
|
831
|
+
# Общие стратегии ставок
|
|
832
|
+
direct strategies get --limit 5
|
|
833
|
+
direct strategies add --name "Общая стратегия" --type WbMaximumClicks --params '{"SpendLimit":1000000000,"AverageCpc":30000000}' --dry-run
|
|
834
|
+
direct strategies update --id 42 --params '{"AverageCpc":35000000}' --dry-run
|
|
835
|
+
direct strategies archive --id 42 --dry-run
|
|
836
|
+
|
|
837
|
+
# Динамические таргеты по фиду
|
|
838
|
+
direct dynamicfeedadtargets get --adgroup-ids 123 --limit 5
|
|
839
|
+
direct dynamicfeedadtargets add --adgroup-id 33 --name "Срез фида А" --condition "CATEGORY:EQUALS:shoes" --bid 5 --dry-run
|
|
840
|
+
direct dynamicfeedadtargets set-bids --id 789 --bid 6.5 --context-bid 4 --dry-run
|
|
841
|
+
|
|
760
842
|
# Расширения, ассеты, фиды и клиенты
|
|
761
843
|
direct sitelinks add --sitelink "Docs|https://example.com/docs" --sitelink "Help|https://example.com/help|Desk" --dry-run
|
|
762
844
|
direct vcards add --campaign-id 555 --country "Россия" --city "Москва" --company-name "Acme" --work-time 1#5#9#0#18#0 --phone-country-code +7 --phone-city-code 495 --phone-number 1234567 --dry-run
|
|
@@ -772,12 +854,13 @@ direct agencyclients add-passport-organization-member --passport-organization-lo
|
|
|
772
854
|
direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
|
|
773
855
|
```
|
|
774
856
|
|
|
775
|
-
###
|
|
857
|
+
### Известная неподдерживаемая API-операция
|
|
776
858
|
|
|
777
|
-
`dynamicads update`
|
|
778
|
-
|
|
779
|
-
экспортирует `
|
|
780
|
-
|
|
859
|
+
`dynamicads update` unsupported by API. Сервис Яндекс Директа
|
|
860
|
+
`dynamictextadtargets` экспортирует `add`, `get`, `delete`, `suspend`,
|
|
861
|
+
`resume` и `setBids`, но не экспортирует `update`. Не добавляйте и не
|
|
862
|
+
используйте `direct dynamicads update`, пока Яндекс не предоставит реальный
|
|
863
|
+
API-метод.
|
|
781
864
|
|
|
782
865
|
### Форматы вывода
|
|
783
866
|
|
|
@@ -826,19 +909,22 @@ direct campaigns add --name "Тест" --start-date 2024-01-01 --dry-run
|
|
|
826
909
|
|
|
827
910
|
### Тестирование
|
|
828
911
|
|
|
829
|
-
В `tests/`
|
|
912
|
+
В `tests/` четыре уровня тестов:
|
|
830
913
|
|
|
831
914
|
| Уровень | Маркер | Сеть | Нужен токен |
|
|
832
915
|
|---|---|---|---|
|
|
833
916
|
| Юнит / CLI / dry-run | *(без маркера)* | Нет | Нет |
|
|
834
917
|
| Read-only интеграция | `-m integration` | Да (prod API, только чтение) | Да |
|
|
835
918
|
| Write интеграция | `-m integration_write` | Нет (replay VCR-кассет) | Нет |
|
|
919
|
+
| Live draft write интеграция | `-m integration_live_write` | Да при записи, иначе VCR replay | Да + `YANDEX_DIRECT_LIVE_WRITE=1` |
|
|
836
920
|
|
|
837
921
|
```bash
|
|
838
922
|
pip install -e ".[dev]"
|
|
839
923
|
pytest # быстрый уровень — без токена
|
|
840
924
|
pytest -m integration -v # read-only интеграция (нужен токен)
|
|
841
925
|
pytest -m integration_write -v # replay write-кассет (токен не нужен)
|
|
926
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v # replay live draft-кассеты
|
|
927
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rewrite # перезапись live draft-кассеты
|
|
842
928
|
```
|
|
843
929
|
|
|
844
930
|
#### Перезапись write-кассет
|
|
@@ -869,6 +955,30 @@ VCR-конфиг в `tests/conftest.py` уже стрипает `Authorization`,
|
|
|
869
955
|
куки и любые response-заголовки с подстрокой `login`, но ручная проверка
|
|
870
956
|
перед коммитом обязательна.
|
|
871
957
|
|
|
958
|
+
#### Live write только на черновиках
|
|
959
|
+
|
|
960
|
+
Уровень `integration_live_write` запускается только вручную и отделен от
|
|
961
|
+
sandbox/VCR-тестов. В rewrite-режиме он ходит в production API Яндекс Директа,
|
|
962
|
+
но может только создавать одноразовые черновики и удалять ровно те ID, которые
|
|
963
|
+
были созданы в этом же тестовом прогоне. Текущее покрытие: guarded create ->
|
|
964
|
+
get -> delete для draft-кампании.
|
|
965
|
+
|
|
966
|
+
Replay закоммиченной кассеты:
|
|
967
|
+
|
|
968
|
+
```bash
|
|
969
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
Перезапись после явного решения проверить live draft-поведение:
|
|
973
|
+
|
|
974
|
+
```bash
|
|
975
|
+
YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rewrite
|
|
976
|
+
```
|
|
977
|
+
|
|
978
|
+
В этот уровень нельзя добавлять тесты, которые принимают внешние ID,
|
|
979
|
+
возобновляют/останавливают/архивируют существующие ресурсы, меняют ставки или
|
|
980
|
+
трогают кампании, которые могут показываться.
|
|
981
|
+
|
|
872
982
|
### Публикация на PyPI
|
|
873
983
|
|
|
874
984
|
Сборка, проверка и загрузка на PyPI:
|
|
File without changes
|