direct-cli 0.2.7__tar.gz → 0.2.8__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.7 → direct_cli-0.2.8}/AGENTS.md +1 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/PKG-INFO +34 -14
- {direct_cli-0.2.7 → direct_cli-0.2.8}/README.md +33 -13
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/__init__.py +4 -3
- direct_cli-0.2.8/direct_cli/_deprecated.py +11 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/cli.py +2 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/bidmodifiers.py +0 -61
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/wsdl_coverage.py +1 -4
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli.egg-info/PKG-INFO +34 -14
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli.egg-info/SOURCES.txt +1 -0
- direct_cli-0.2.8/direct_cli.egg-info/entry_points.txt +3 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/pyproject.toml +2 -2
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/test_api_coverage.py +1 -2
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/test_cli.py +26 -1
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/test_dry_run.py +1 -24
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/test_integration_write.py +0 -67
- direct_cli-0.2.7/direct_cli.egg-info/entry_points.txt +0 -3
- {direct_cli-0.2.7 → direct_cli-0.2.8}/.env.example +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/.github/copilot-instructions.md +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/.github/workflows/api-coverage.yml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/.github/workflows/claude-code-review.yml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/.github/workflows/claude.yml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/.gitignore +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/CLAUDE.md +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/MANIFEST.in +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/api.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/auth.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/__init__.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/adextensions.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/adgroups.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/adimages.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/ads.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/advideos.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/agencyclients.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/audiencetargets.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/bids.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/businesses.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/campaigns.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/changes.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/clients.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/creatives.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/dictionaries.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/dynamicads.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/feeds.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/keywordbids.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/keywords.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/keywordsresearch.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/leads.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/negativekeywordsharedsets.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/reports.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/retargeting.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/sitelinks.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/smartadtargets.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/turbopages.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/commands/vcards.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/output.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/reports_coverage.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli/utils.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli.egg-info/dependency_links.txt +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli.egg-info/requires.txt +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/direct_cli.egg-info/top_level.txt +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/scripts/build_api_coverage_report.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/scripts/check_reports_drift.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/scripts/check_wsdl_drift.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/scripts/refresh_reports_cache.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/scripts/refresh_wsdl_cache.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/scripts/release_pypi.sh +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/setup.cfg +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/setup.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/__init__.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/conftest.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/reports_cache/raw/fields-list.html +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/reports_cache/raw/headers.html +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/reports_cache/raw/spec.html +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/reports_cache/raw/type.html +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/reports_cache/spec.json +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/test_auth_bw.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/test_auth_op.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/test_comprehensive.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/test_integration.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/test_reports_drift.py +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/adextensions.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/adgroups.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/adimages.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/ads.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/advideos.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/agencyclients.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/audiencetargets.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/bidmodifiers.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/bids.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/businesses.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/campaigns.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/changes.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/clients.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/creatives.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/dictionaries.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/feeds.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/keywordbids.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/keywords.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/keywordsresearch.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/leads.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/retargetinglists.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/sitelinks.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/smartadtargets.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/turbopages.xml +0 -0
- {direct_cli-0.2.7 → direct_cli-0.2.8}/tests/wsdl_cache/vcards.xml +0 -0
|
@@ -106,6 +106,7 @@ Valid canonical examples:
|
|
|
106
106
|
direct campaigns get --ids 1,2,3
|
|
107
107
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
108
108
|
direct keywordsresearch has-search-volume --keywords "buy laptop,buy desktop"
|
|
109
|
+
direct smartadtargets update --id 456 --priority HIGH
|
|
109
110
|
direct dynamicads set-bids --id 789 --bid 12.5
|
|
110
111
|
direct dictionaries get-geo-regions --region-ids 225 --fields GeoRegionId,GeoRegionName
|
|
111
112
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: direct-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: Command-line interface for Yandex Direct API
|
|
5
5
|
Author: axisrow
|
|
6
6
|
License: MIT
|
|
@@ -67,6 +67,8 @@ direct --token YOUR_TOKEN --login YOUR_LOGIN campaigns get
|
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
Install with `pip install direct-cli`, then run commands with `direct`.
|
|
70
|
+
Invoking the deprecated `direct-cli` entrypoint exits with
|
|
71
|
+
`use direct instead of direct-cli`.
|
|
70
72
|
|
|
71
73
|
### Global Options
|
|
72
74
|
|
|
@@ -101,9 +103,10 @@ Naming rules:
|
|
|
101
103
|
- multiword commands use kebab-case
|
|
102
104
|
- examples: `get`, `set-bids`, `check-campaigns`, `has-search-volume`
|
|
103
105
|
|
|
104
|
-
direct
|
|
105
|
-
|
|
106
|
-
names.
|
|
106
|
+
The `direct` executable defines the public naming contract. The
|
|
107
|
+
`direct-cli` package name and deprecated shim do not define canonical CLI
|
|
108
|
+
names. `tapi-yandex-direct` may influence the internal transport layer, but it
|
|
109
|
+
does not define canonical CLI names.
|
|
107
110
|
|
|
108
111
|
The current policy is canonical-only. Historical aliases are not preserved in
|
|
109
112
|
the runtime CLI by default. If compatibility is ever needed, an alias must be
|
|
@@ -120,6 +123,7 @@ be supported.
|
|
|
120
123
|
- If the API requires a complex object, the CLI must expose explicit flags or subcommands instead of forwarding raw JSON.
|
|
121
124
|
|
|
122
125
|
#### Command Formatting Rules
|
|
126
|
+
|
|
123
127
|
- Every canonical CLI command must be written strictly on a single line.
|
|
124
128
|
- Multi-line command formatting is not allowed.
|
|
125
129
|
- Shell line continuation using `\` is forbidden in canonical documentation, help text, tests, and examples.
|
|
@@ -184,6 +188,7 @@ Valid canonical examples:
|
|
|
184
188
|
direct campaigns get --ids 1,2,3
|
|
185
189
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
186
190
|
direct keywordsresearch has-search-volume --keywords "buy laptop,buy desktop"
|
|
191
|
+
direct smartadtargets update --id 456 --priority HIGH
|
|
187
192
|
direct dynamicads set-bids --id 789 --bid 12.5 --context-bid 9 --priority HIGH
|
|
188
193
|
direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-names Москва,Санкт-Петербург --fields GeoRegionId,GeoRegionName
|
|
189
194
|
```
|
|
@@ -272,10 +277,14 @@ Available report types: `CAMPAIGN_PERFORMANCE_REPORT`, `ADGROUP_PERFORMANCE_REPO
|
|
|
272
277
|
# Reference dictionaries and changes
|
|
273
278
|
direct dictionaries get --names Currencies,GeoRegions
|
|
274
279
|
direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-names Москва,Санкт-Петербург --fields GeoRegionId,GeoRegionName
|
|
280
|
+
|
|
281
|
+
# Client info
|
|
282
|
+
direct clients get --fields ClientId,Login,Currency
|
|
283
|
+
|
|
284
|
+
# Changes
|
|
275
285
|
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
276
286
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
277
287
|
direct changes check-dictionaries
|
|
278
|
-
direct clients get --fields ClientId,Login,Currency
|
|
279
288
|
|
|
280
289
|
# Keyword research and retargeting
|
|
281
290
|
direct keywordsresearch has-search-volume --keywords "buy laptop,buy desktop"
|
|
@@ -501,7 +510,9 @@ YANDEX_DIRECT_LOGIN=ваш_логин_на_яндексе
|
|
|
501
510
|
direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
|
|
502
511
|
```
|
|
503
512
|
|
|
504
|
-
Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
|
|
513
|
+
Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
|
|
514
|
+
через `direct`. Вызов deprecated entrypoint `direct-cli` завершается ошибкой с
|
|
515
|
+
подсказкой `use direct instead of direct-cli`.
|
|
505
516
|
|
|
506
517
|
### Глобальные опции
|
|
507
518
|
|
|
@@ -530,17 +541,20 @@ Command naming rules:
|
|
|
530
541
|
- в документации и примерах каноническими считаются `get`,
|
|
531
542
|
`check-dictionaries` и `has-search-volume`
|
|
532
543
|
|
|
533
|
-
|
|
534
|
-
|
|
544
|
+
Публичный naming contract задаёт исполняемый файл `direct`. Имя пакета
|
|
545
|
+
`direct-cli` и deprecated shim не определяют канонические CLI-имена.
|
|
546
|
+
`tapi-yandex-direct` может влиять на внутренний transport layer, но не
|
|
547
|
+
определяет канонические CLI-имена.
|
|
535
548
|
|
|
536
549
|
Текущая политика — canonical-only. Исторические aliases по умолчанию не
|
|
537
550
|
сохраняются в runtime CLI. Если совместимость когда-нибудь понадобится, alias
|
|
538
551
|
должен быть добавлен как явное exception-правило с конкретным legacy syntax из
|
|
539
552
|
`tapi-yandex-direct`, который действительно нужно поддержать.
|
|
540
553
|
|
|
541
|
-
`direct
|
|
542
|
-
имена CLI-групп следуют
|
|
543
|
-
`tapi-yandex-direct`, а имена подкоманд —
|
|
554
|
+
`direct` — это канонический transport entrypoint над API Яндекс Директа,
|
|
555
|
+
устанавливаемый пакетом `direct-cli`. Канонические имена CLI-групп следуют
|
|
556
|
+
нормализованным Python-именам из `tapi-yandex-direct`, а имена подкоманд —
|
|
557
|
+
это kebab-case проекции API-методов.
|
|
544
558
|
|
|
545
559
|
Базовые соответствия:
|
|
546
560
|
|
|
@@ -575,8 +589,10 @@ Naming rules:
|
|
|
575
589
|
- multiword commands use kebab-case
|
|
576
590
|
- examples: `get`, `set-bids`, `check-campaigns`, `has-search-volume`
|
|
577
591
|
|
|
578
|
-
|
|
579
|
-
|
|
592
|
+
Публичный naming contract задаёт исполняемый файл `direct`. Имя пакета
|
|
593
|
+
`direct-cli` и deprecated shim не определяют канонические CLI-имена.
|
|
594
|
+
`tapi-yandex-direct` может влиять на внутренний transport layer, но не
|
|
595
|
+
определяет канонические CLI-имена.
|
|
580
596
|
|
|
581
597
|
Текущая политика — canonical-only. Исторические aliases по умолчанию не
|
|
582
598
|
сохраняются в runtime CLI. Если совместимость когда-нибудь понадобится, alias
|
|
@@ -746,10 +762,14 @@ direct reports list-types
|
|
|
746
762
|
# Справочники и изменения
|
|
747
763
|
direct dictionaries get --names Currencies,GeoRegions
|
|
748
764
|
direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --exact-names Москва,Санкт-Петербург --fields GeoRegionId,GeoRegionName
|
|
765
|
+
|
|
766
|
+
# Информация о клиенте
|
|
767
|
+
direct clients get --fields ClientId,Login,Currency
|
|
768
|
+
|
|
769
|
+
# Изменения
|
|
749
770
|
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
750
771
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
751
772
|
direct changes check-dictionaries
|
|
752
|
-
direct clients get --fields ClientId,Login,Currency
|
|
753
773
|
|
|
754
774
|
# Исследование ключевых слов и ретаргетинг
|
|
755
775
|
direct keywordsresearch has-search-volume --keywords "купить ноутбук,купить компьютер"
|
|
@@ -30,6 +30,8 @@ direct --token YOUR_TOKEN --login YOUR_LOGIN campaigns get
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
Install with `pip install direct-cli`, then run commands with `direct`.
|
|
33
|
+
Invoking the deprecated `direct-cli` entrypoint exits with
|
|
34
|
+
`use direct instead of direct-cli`.
|
|
33
35
|
|
|
34
36
|
### Global Options
|
|
35
37
|
|
|
@@ -64,9 +66,10 @@ Naming rules:
|
|
|
64
66
|
- multiword commands use kebab-case
|
|
65
67
|
- examples: `get`, `set-bids`, `check-campaigns`, `has-search-volume`
|
|
66
68
|
|
|
67
|
-
direct
|
|
68
|
-
|
|
69
|
-
names.
|
|
69
|
+
The `direct` executable defines the public naming contract. The
|
|
70
|
+
`direct-cli` package name and deprecated shim do not define canonical CLI
|
|
71
|
+
names. `tapi-yandex-direct` may influence the internal transport layer, but it
|
|
72
|
+
does not define canonical CLI names.
|
|
70
73
|
|
|
71
74
|
The current policy is canonical-only. Historical aliases are not preserved in
|
|
72
75
|
the runtime CLI by default. If compatibility is ever needed, an alias must be
|
|
@@ -83,6 +86,7 @@ be supported.
|
|
|
83
86
|
- If the API requires a complex object, the CLI must expose explicit flags or subcommands instead of forwarding raw JSON.
|
|
84
87
|
|
|
85
88
|
#### Command Formatting Rules
|
|
89
|
+
|
|
86
90
|
- Every canonical CLI command must be written strictly on a single line.
|
|
87
91
|
- Multi-line command formatting is not allowed.
|
|
88
92
|
- Shell line continuation using `\` is forbidden in canonical documentation, help text, tests, and examples.
|
|
@@ -147,6 +151,7 @@ Valid canonical examples:
|
|
|
147
151
|
direct campaigns get --ids 1,2,3
|
|
148
152
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
149
153
|
direct keywordsresearch has-search-volume --keywords "buy laptop,buy desktop"
|
|
154
|
+
direct smartadtargets update --id 456 --priority HIGH
|
|
150
155
|
direct dynamicads set-bids --id 789 --bid 12.5 --context-bid 9 --priority HIGH
|
|
151
156
|
direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-names Москва,Санкт-Петербург --fields GeoRegionId,GeoRegionName
|
|
152
157
|
```
|
|
@@ -235,10 +240,14 @@ Available report types: `CAMPAIGN_PERFORMANCE_REPORT`, `ADGROUP_PERFORMANCE_REPO
|
|
|
235
240
|
# Reference dictionaries and changes
|
|
236
241
|
direct dictionaries get --names Currencies,GeoRegions
|
|
237
242
|
direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-names Москва,Санкт-Петербург --fields GeoRegionId,GeoRegionName
|
|
243
|
+
|
|
244
|
+
# Client info
|
|
245
|
+
direct clients get --fields ClientId,Login,Currency
|
|
246
|
+
|
|
247
|
+
# Changes
|
|
238
248
|
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
239
249
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
240
250
|
direct changes check-dictionaries
|
|
241
|
-
direct clients get --fields ClientId,Login,Currency
|
|
242
251
|
|
|
243
252
|
# Keyword research and retargeting
|
|
244
253
|
direct keywordsresearch has-search-volume --keywords "buy laptop,buy desktop"
|
|
@@ -464,7 +473,9 @@ YANDEX_DIRECT_LOGIN=ваш_логин_на_яндексе
|
|
|
464
473
|
direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
|
|
465
474
|
```
|
|
466
475
|
|
|
467
|
-
Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
|
|
476
|
+
Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
|
|
477
|
+
через `direct`. Вызов deprecated entrypoint `direct-cli` завершается ошибкой с
|
|
478
|
+
подсказкой `use direct instead of direct-cli`.
|
|
468
479
|
|
|
469
480
|
### Глобальные опции
|
|
470
481
|
|
|
@@ -493,17 +504,20 @@ Command naming rules:
|
|
|
493
504
|
- в документации и примерах каноническими считаются `get`,
|
|
494
505
|
`check-dictionaries` и `has-search-volume`
|
|
495
506
|
|
|
496
|
-
|
|
497
|
-
|
|
507
|
+
Публичный naming contract задаёт исполняемый файл `direct`. Имя пакета
|
|
508
|
+
`direct-cli` и deprecated shim не определяют канонические CLI-имена.
|
|
509
|
+
`tapi-yandex-direct` может влиять на внутренний transport layer, но не
|
|
510
|
+
определяет канонические CLI-имена.
|
|
498
511
|
|
|
499
512
|
Текущая политика — canonical-only. Исторические aliases по умолчанию не
|
|
500
513
|
сохраняются в runtime CLI. Если совместимость когда-нибудь понадобится, alias
|
|
501
514
|
должен быть добавлен как явное exception-правило с конкретным legacy syntax из
|
|
502
515
|
`tapi-yandex-direct`, который действительно нужно поддержать.
|
|
503
516
|
|
|
504
|
-
`direct
|
|
505
|
-
имена CLI-групп следуют
|
|
506
|
-
`tapi-yandex-direct`, а имена подкоманд —
|
|
517
|
+
`direct` — это канонический transport entrypoint над API Яндекс Директа,
|
|
518
|
+
устанавливаемый пакетом `direct-cli`. Канонические имена CLI-групп следуют
|
|
519
|
+
нормализованным Python-именам из `tapi-yandex-direct`, а имена подкоманд —
|
|
520
|
+
это kebab-case проекции API-методов.
|
|
507
521
|
|
|
508
522
|
Базовые соответствия:
|
|
509
523
|
|
|
@@ -538,8 +552,10 @@ Naming rules:
|
|
|
538
552
|
- multiword commands use kebab-case
|
|
539
553
|
- examples: `get`, `set-bids`, `check-campaigns`, `has-search-volume`
|
|
540
554
|
|
|
541
|
-
|
|
542
|
-
|
|
555
|
+
Публичный naming contract задаёт исполняемый файл `direct`. Имя пакета
|
|
556
|
+
`direct-cli` и deprecated shim не определяют канонические CLI-имена.
|
|
557
|
+
`tapi-yandex-direct` может влиять на внутренний transport layer, но не
|
|
558
|
+
определяет канонические CLI-имена.
|
|
543
559
|
|
|
544
560
|
Текущая политика — canonical-only. Исторические aliases по умолчанию не
|
|
545
561
|
сохраняются в runtime CLI. Если совместимость когда-нибудь понадобится, alias
|
|
@@ -709,10 +725,14 @@ direct reports list-types
|
|
|
709
725
|
# Справочники и изменения
|
|
710
726
|
direct dictionaries get --names Currencies,GeoRegions
|
|
711
727
|
direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --exact-names Москва,Санкт-Петербург --fields GeoRegionId,GeoRegionName
|
|
728
|
+
|
|
729
|
+
# Информация о клиенте
|
|
730
|
+
direct clients get --fields ClientId,Login,Currency
|
|
731
|
+
|
|
732
|
+
# Изменения
|
|
712
733
|
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
713
734
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
714
735
|
direct changes check-dictionaries
|
|
715
|
-
direct clients get --fields ClientId,Login,Currency
|
|
716
736
|
|
|
717
737
|
# Исследование ключевых слов и ретаргетинг
|
|
718
738
|
direct keywordsresearch has-search-volume --keywords "купить ноутбук,купить компьютер"
|
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
Direct CLI - Command-line interface for Yandex Direct API
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
6
|
+
|
|
5
7
|
__author__ = "Pavel Maksimov"
|
|
6
8
|
__email__ = "vur21@ya.ru"
|
|
7
9
|
|
|
8
|
-
# Version will be set by setuptools_scm
|
|
9
10
|
try:
|
|
10
|
-
|
|
11
|
-
except
|
|
11
|
+
__version__ = version("direct-cli")
|
|
12
|
+
except PackageNotFoundError:
|
|
12
13
|
__version__ = "unknown"
|
|
13
14
|
|
|
14
15
|
__all__ = ["__version__", "__author__", "__email__"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
DEPRECATED_ENTRYPOINT_MESSAGE = (
|
|
4
|
+
"direct-cli is deprecated; use direct instead of direct-cli."
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def deprecated_main() -> None:
|
|
9
|
+
"""Fail fast for the deprecated `direct-cli` entrypoint."""
|
|
10
|
+
click.echo(f"Error: {DEPRECATED_ENTRYPOINT_MESSAGE}", err=True)
|
|
11
|
+
raise SystemExit(2)
|
|
@@ -6,6 +6,7 @@ Direct CLI - Command-line interface for Yandex Direct API
|
|
|
6
6
|
import click
|
|
7
7
|
from dotenv import load_dotenv
|
|
8
8
|
|
|
9
|
+
from . import __version__
|
|
9
10
|
from .auth import get_credentials
|
|
10
11
|
|
|
11
12
|
from .commands.campaigns import campaigns
|
|
@@ -42,6 +43,7 @@ load_dotenv()
|
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
@click.group(name="direct")
|
|
46
|
+
@click.version_option(__version__, prog_name="direct")
|
|
45
47
|
@click.option("--token", envvar="YANDEX_DIRECT_TOKEN", help="API access token")
|
|
46
48
|
@click.option("--login", envvar="YANDEX_DIRECT_LOGIN", help="Client login")
|
|
47
49
|
@click.option("--sandbox", is_flag=True, help="Use sandbox API")
|
|
@@ -337,67 +337,6 @@ def set(ctx, modifier_id, campaign_id, modifier_type, value, dry_run):
|
|
|
337
337
|
raise click.Abort()
|
|
338
338
|
|
|
339
339
|
|
|
340
|
-
@bidmodifiers.command()
|
|
341
|
-
@click.option("--campaign-id", type=int, help="Campaign ID (mutually exclusive with --adgroup-id)")
|
|
342
|
-
@click.option("--adgroup-id", type=int, help="Ad group ID (mutually exclusive with --campaign-id)")
|
|
343
|
-
@click.option(
|
|
344
|
-
"--type",
|
|
345
|
-
"modifier_type",
|
|
346
|
-
required=True,
|
|
347
|
-
type=click.Choice([
|
|
348
|
-
"DEMOGRAPHICS_ADJUSTMENT",
|
|
349
|
-
"RETARGETING_ADJUSTMENT",
|
|
350
|
-
"REGIONAL_ADJUSTMENT",
|
|
351
|
-
"SERP_LAYOUT_ADJUSTMENT",
|
|
352
|
-
"INCOME_GRADE_ADJUSTMENT",
|
|
353
|
-
], case_sensitive=False),
|
|
354
|
-
help="Adjustment type to toggle",
|
|
355
|
-
)
|
|
356
|
-
@click.option("--enabled/--disabled", "enabled", default=True, help="Enable or disable")
|
|
357
|
-
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
358
|
-
@click.pass_context
|
|
359
|
-
def toggle(ctx, campaign_id, adgroup_id, modifier_type, enabled, dry_run):
|
|
360
|
-
"""Toggle bid modifier state (enable/disable by type)"""
|
|
361
|
-
try:
|
|
362
|
-
if not campaign_id and not adgroup_id:
|
|
363
|
-
raise click.UsageError("Either --campaign-id or --adgroup-id is required.")
|
|
364
|
-
if campaign_id and adgroup_id:
|
|
365
|
-
raise click.UsageError("Use either --campaign-id or --adgroup-id, not both.")
|
|
366
|
-
|
|
367
|
-
item = {
|
|
368
|
-
"Type": modifier_type.upper(),
|
|
369
|
-
"Enabled": "YES" if enabled else "NO",
|
|
370
|
-
}
|
|
371
|
-
if campaign_id:
|
|
372
|
-
item["CampaignId"] = campaign_id
|
|
373
|
-
else:
|
|
374
|
-
item["AdGroupId"] = adgroup_id
|
|
375
|
-
|
|
376
|
-
body = {
|
|
377
|
-
"method": "toggle",
|
|
378
|
-
"params": {"BidModifierToggleItems": [item]},
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
if dry_run:
|
|
382
|
-
format_output(body, "json", None)
|
|
383
|
-
return
|
|
384
|
-
|
|
385
|
-
client = create_client(
|
|
386
|
-
token=ctx.obj.get("token"),
|
|
387
|
-
login=ctx.obj.get("login"),
|
|
388
|
-
sandbox=ctx.obj.get("sandbox"),
|
|
389
|
-
)
|
|
390
|
-
|
|
391
|
-
result = client.bidmodifiers().post(data=body)
|
|
392
|
-
format_output(result().extract(), "json", None)
|
|
393
|
-
|
|
394
|
-
except click.UsageError:
|
|
395
|
-
raise
|
|
396
|
-
except Exception as e:
|
|
397
|
-
print_error(str(e))
|
|
398
|
-
raise click.Abort()
|
|
399
|
-
|
|
400
|
-
|
|
401
340
|
@bidmodifiers.command()
|
|
402
341
|
@click.option("--id", "modifier_id", required=True, type=int, help="Modifier ID")
|
|
403
342
|
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
@@ -109,10 +109,7 @@ INTENTIONAL_EXTRA_METHODS = {
|
|
|
109
109
|
"CLI guard command: the Yandex Direct API does not support deleting "
|
|
110
110
|
"agency clients, so the command aborts with an explicit message."
|
|
111
111
|
),
|
|
112
|
-
|
|
113
|
-
"JSON-only helper command; no matching SOAP/WSDL operation exists."
|
|
114
|
-
),
|
|
115
|
-
("keywords", "archive"): (
|
|
112
|
+
("keywords", "archive"): (
|
|
116
113
|
"Legacy lifecycle command preserved for compatibility with existing CLI users."
|
|
117
114
|
),
|
|
118
115
|
("keywords", "unarchive"): (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: direct-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: Command-line interface for Yandex Direct API
|
|
5
5
|
Author: axisrow
|
|
6
6
|
License: MIT
|
|
@@ -67,6 +67,8 @@ direct --token YOUR_TOKEN --login YOUR_LOGIN campaigns get
|
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
Install with `pip install direct-cli`, then run commands with `direct`.
|
|
70
|
+
Invoking the deprecated `direct-cli` entrypoint exits with
|
|
71
|
+
`use direct instead of direct-cli`.
|
|
70
72
|
|
|
71
73
|
### Global Options
|
|
72
74
|
|
|
@@ -101,9 +103,10 @@ Naming rules:
|
|
|
101
103
|
- multiword commands use kebab-case
|
|
102
104
|
- examples: `get`, `set-bids`, `check-campaigns`, `has-search-volume`
|
|
103
105
|
|
|
104
|
-
direct
|
|
105
|
-
|
|
106
|
-
names.
|
|
106
|
+
The `direct` executable defines the public naming contract. The
|
|
107
|
+
`direct-cli` package name and deprecated shim do not define canonical CLI
|
|
108
|
+
names. `tapi-yandex-direct` may influence the internal transport layer, but it
|
|
109
|
+
does not define canonical CLI names.
|
|
107
110
|
|
|
108
111
|
The current policy is canonical-only. Historical aliases are not preserved in
|
|
109
112
|
the runtime CLI by default. If compatibility is ever needed, an alias must be
|
|
@@ -120,6 +123,7 @@ be supported.
|
|
|
120
123
|
- If the API requires a complex object, the CLI must expose explicit flags or subcommands instead of forwarding raw JSON.
|
|
121
124
|
|
|
122
125
|
#### Command Formatting Rules
|
|
126
|
+
|
|
123
127
|
- Every canonical CLI command must be written strictly on a single line.
|
|
124
128
|
- Multi-line command formatting is not allowed.
|
|
125
129
|
- Shell line continuation using `\` is forbidden in canonical documentation, help text, tests, and examples.
|
|
@@ -184,6 +188,7 @@ Valid canonical examples:
|
|
|
184
188
|
direct campaigns get --ids 1,2,3
|
|
185
189
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
186
190
|
direct keywordsresearch has-search-volume --keywords "buy laptop,buy desktop"
|
|
191
|
+
direct smartadtargets update --id 456 --priority HIGH
|
|
187
192
|
direct dynamicads set-bids --id 789 --bid 12.5 --context-bid 9 --priority HIGH
|
|
188
193
|
direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-names Москва,Санкт-Петербург --fields GeoRegionId,GeoRegionName
|
|
189
194
|
```
|
|
@@ -272,10 +277,14 @@ Available report types: `CAMPAIGN_PERFORMANCE_REPORT`, `ADGROUP_PERFORMANCE_REPO
|
|
|
272
277
|
# Reference dictionaries and changes
|
|
273
278
|
direct dictionaries get --names Currencies,GeoRegions
|
|
274
279
|
direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-names Москва,Санкт-Петербург --fields GeoRegionId,GeoRegionName
|
|
280
|
+
|
|
281
|
+
# Client info
|
|
282
|
+
direct clients get --fields ClientId,Login,Currency
|
|
283
|
+
|
|
284
|
+
# Changes
|
|
275
285
|
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
276
286
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
277
287
|
direct changes check-dictionaries
|
|
278
|
-
direct clients get --fields ClientId,Login,Currency
|
|
279
288
|
|
|
280
289
|
# Keyword research and retargeting
|
|
281
290
|
direct keywordsresearch has-search-volume --keywords "buy laptop,buy desktop"
|
|
@@ -501,7 +510,9 @@ YANDEX_DIRECT_LOGIN=ваш_логин_на_яндексе
|
|
|
501
510
|
direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
|
|
502
511
|
```
|
|
503
512
|
|
|
504
|
-
Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
|
|
513
|
+
Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
|
|
514
|
+
через `direct`. Вызов deprecated entrypoint `direct-cli` завершается ошибкой с
|
|
515
|
+
подсказкой `use direct instead of direct-cli`.
|
|
505
516
|
|
|
506
517
|
### Глобальные опции
|
|
507
518
|
|
|
@@ -530,17 +541,20 @@ Command naming rules:
|
|
|
530
541
|
- в документации и примерах каноническими считаются `get`,
|
|
531
542
|
`check-dictionaries` и `has-search-volume`
|
|
532
543
|
|
|
533
|
-
|
|
534
|
-
|
|
544
|
+
Публичный naming contract задаёт исполняемый файл `direct`. Имя пакета
|
|
545
|
+
`direct-cli` и deprecated shim не определяют канонические CLI-имена.
|
|
546
|
+
`tapi-yandex-direct` может влиять на внутренний transport layer, но не
|
|
547
|
+
определяет канонические CLI-имена.
|
|
535
548
|
|
|
536
549
|
Текущая политика — canonical-only. Исторические aliases по умолчанию не
|
|
537
550
|
сохраняются в runtime CLI. Если совместимость когда-нибудь понадобится, alias
|
|
538
551
|
должен быть добавлен как явное exception-правило с конкретным legacy syntax из
|
|
539
552
|
`tapi-yandex-direct`, который действительно нужно поддержать.
|
|
540
553
|
|
|
541
|
-
`direct
|
|
542
|
-
имена CLI-групп следуют
|
|
543
|
-
`tapi-yandex-direct`, а имена подкоманд —
|
|
554
|
+
`direct` — это канонический transport entrypoint над API Яндекс Директа,
|
|
555
|
+
устанавливаемый пакетом `direct-cli`. Канонические имена CLI-групп следуют
|
|
556
|
+
нормализованным Python-именам из `tapi-yandex-direct`, а имена подкоманд —
|
|
557
|
+
это kebab-case проекции API-методов.
|
|
544
558
|
|
|
545
559
|
Базовые соответствия:
|
|
546
560
|
|
|
@@ -575,8 +589,10 @@ Naming rules:
|
|
|
575
589
|
- multiword commands use kebab-case
|
|
576
590
|
- examples: `get`, `set-bids`, `check-campaigns`, `has-search-volume`
|
|
577
591
|
|
|
578
|
-
|
|
579
|
-
|
|
592
|
+
Публичный naming contract задаёт исполняемый файл `direct`. Имя пакета
|
|
593
|
+
`direct-cli` и deprecated shim не определяют канонические CLI-имена.
|
|
594
|
+
`tapi-yandex-direct` может влиять на внутренний transport layer, но не
|
|
595
|
+
определяет канонические CLI-имена.
|
|
580
596
|
|
|
581
597
|
Текущая политика — canonical-only. Исторические aliases по умолчанию не
|
|
582
598
|
сохраняются в runtime CLI. Если совместимость когда-нибудь понадобится, alias
|
|
@@ -746,10 +762,14 @@ direct reports list-types
|
|
|
746
762
|
# Справочники и изменения
|
|
747
763
|
direct dictionaries get --names Currencies,GeoRegions
|
|
748
764
|
direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --exact-names Москва,Санкт-Петербург --fields GeoRegionId,GeoRegionName
|
|
765
|
+
|
|
766
|
+
# Информация о клиенте
|
|
767
|
+
direct clients get --fields ClientId,Login,Currency
|
|
768
|
+
|
|
769
|
+
# Изменения
|
|
749
770
|
direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
|
|
750
771
|
direct changes check-campaigns --timestamp 2026-04-14T00:00:00
|
|
751
772
|
direct changes check-dictionaries
|
|
752
|
-
direct clients get --fields ClientId,Login,Currency
|
|
753
773
|
|
|
754
774
|
# Исследование ключевых слов и ретаргетинг
|
|
755
775
|
direct keywordsresearch has-search-volume --keywords "купить ноутбук,купить компьютер"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "direct-cli"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.8"
|
|
8
8
|
description = "Command-line interface for Yandex Direct API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -48,7 +48,7 @@ dev = [
|
|
|
48
48
|
|
|
49
49
|
[project.scripts]
|
|
50
50
|
direct = "direct_cli.cli:cli"
|
|
51
|
-
direct-cli = "direct_cli.
|
|
51
|
+
direct-cli = "direct_cli._deprecated:deprecated_main"
|
|
52
52
|
|
|
53
53
|
[project.urls]
|
|
54
54
|
Homepage = "https://github.com/axisrow/direct-cli"
|
|
@@ -49,8 +49,7 @@ DRY_RUN_PAYLOAD_EXCLUSIONS = {
|
|
|
49
49
|
"bidmodifiers.add": "Requires modifier-type-specific typed flag fixtures.",
|
|
50
50
|
"bidmodifiers.delete": "Helper/legacy surface; not part of strict WSDL parity claim.",
|
|
51
51
|
"bidmodifiers.set": "Requires modifier-type-specific typed flag fixtures.",
|
|
52
|
-
|
|
53
|
-
"campaigns.add": "Requires campaign-type-specific typed payload variants; covered by focused dry-run tests.",
|
|
52
|
+
"campaigns.add": "Requires campaign-type-specific typed payload variants; covered by focused dry-run tests.",
|
|
54
53
|
"campaigns.suspend": "Same lifecycle payload family as covered campaigns.delete/archive/resume.",
|
|
55
54
|
"campaigns.unarchive": "Same lifecycle payload family as covered campaigns.delete/archive/resume.",
|
|
56
55
|
"campaigns.update": "Requires typed budget/date/status variants; covered by focused dry-run tests.",
|
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
Tests for Direct CLI
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import io
|
|
5
6
|
import os
|
|
6
7
|
import unittest
|
|
8
|
+
from contextlib import redirect_stderr
|
|
9
|
+
from importlib.metadata import version
|
|
7
10
|
from pathlib import Path
|
|
8
11
|
from unittest.mock import patch
|
|
12
|
+
|
|
9
13
|
from click.testing import CliRunner
|
|
14
|
+
|
|
10
15
|
from direct_cli.cli import cli
|
|
16
|
+
from direct_cli._deprecated import DEPRECATED_ENTRYPOINT_MESSAGE, deprecated_main
|
|
11
17
|
|
|
12
18
|
|
|
13
19
|
class TestCLI(unittest.TestCase):
|
|
@@ -23,6 +29,13 @@ class TestCLI(unittest.TestCase):
|
|
|
23
29
|
self.assertIn("Command-line interface for Yandex Direct API", result.output)
|
|
24
30
|
self.assertIn("Usage: direct", result.output)
|
|
25
31
|
|
|
32
|
+
def test_cli_version(self):
|
|
33
|
+
"""Test CLI version command"""
|
|
34
|
+
result = self.runner.invoke(cli, ["--version"])
|
|
35
|
+
self.assertEqual(result.exit_code, 0)
|
|
36
|
+
expected = f"direct, version {version('direct-cli')}"
|
|
37
|
+
self.assertEqual(result.output.strip(), expected)
|
|
38
|
+
|
|
26
39
|
def test_campaigns_help(self):
|
|
27
40
|
"""Test campaigns help"""
|
|
28
41
|
result = self.runner.invoke(cli, ["campaigns", "--help"])
|
|
@@ -112,6 +125,14 @@ class TestCLI(unittest.TestCase):
|
|
|
112
125
|
self.assertNotIn("--notification-json", result.output)
|
|
113
126
|
self.assertNotIn("--send-invite-to-json", result.output)
|
|
114
127
|
|
|
128
|
+
def test_deprecated_direct_cli_entrypoint_exits_with_hint(self):
|
|
129
|
+
stderr = io.StringIO()
|
|
130
|
+
with self.assertRaises(SystemExit) as context:
|
|
131
|
+
with redirect_stderr(stderr):
|
|
132
|
+
deprecated_main()
|
|
133
|
+
self.assertEqual(context.exception.code, 2)
|
|
134
|
+
self.assertIn(DEPRECATED_ENTRYPOINT_MESSAGE, stderr.getvalue())
|
|
135
|
+
|
|
115
136
|
|
|
116
137
|
class TestAuth(unittest.TestCase):
|
|
117
138
|
"""Test authentication"""
|
|
@@ -146,7 +167,11 @@ class TestReadmeContract(unittest.TestCase):
|
|
|
146
167
|
self.assertIn("direct <group> <command> [flags]", self.content)
|
|
147
168
|
self.assertIn("Group naming rules", self.content)
|
|
148
169
|
self.assertIn("Command naming rules", self.content)
|
|
149
|
-
self.assertIn(
|
|
170
|
+
self.assertIn(
|
|
171
|
+
"The `direct` executable defines the public naming contract",
|
|
172
|
+
self.content,
|
|
173
|
+
)
|
|
174
|
+
self.assertIn("use direct instead of direct-cli", self.content)
|
|
150
175
|
|
|
151
176
|
def test_readme_contains_canonical_command_examples(self):
|
|
152
177
|
"""README must include canonical examples for renamed commands."""
|
|
@@ -39,7 +39,7 @@ Coverage scope
|
|
|
39
39
|
--------------
|
|
40
40
|
|
|
41
41
|
The suite covers both payload-building write commands (``add``,
|
|
42
|
-
``update``, ``set
|
|
42
|
+
``update``, ``set``) and the main single-action lifecycle
|
|
43
43
|
commands that now expose ``--dry-run`` (``delete``, ``archive``,
|
|
44
44
|
``unarchive``, ``suspend``, ``resume``, ``moderate``) so that trivial
|
|
45
45
|
``SelectionCriteria`` regressions are also caught in CI.
|
|
@@ -726,29 +726,6 @@ def test_bidmodifiers_set_without_any_key_errors():
|
|
|
726
726
|
assert "--id" in combined or "--campaign-id" in combined
|
|
727
727
|
|
|
728
728
|
|
|
729
|
-
def test_bidmodifiers_toggle_enable():
|
|
730
|
-
body = _dry_run(
|
|
731
|
-
"bidmodifiers", "toggle",
|
|
732
|
-
"--campaign-id", "777",
|
|
733
|
-
"--type", "DEMOGRAPHICS_ADJUSTMENT",
|
|
734
|
-
"--enabled",
|
|
735
|
-
)
|
|
736
|
-
assert body["method"] == "toggle"
|
|
737
|
-
item = body["params"]["BidModifierToggleItems"][0]
|
|
738
|
-
assert item == {"CampaignId": 777, "Type": "DEMOGRAPHICS_ADJUSTMENT", "Enabled": "YES"}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
def test_bidmodifiers_toggle_disable():
|
|
742
|
-
body = _dry_run(
|
|
743
|
-
"bidmodifiers", "toggle",
|
|
744
|
-
"--campaign-id", "777",
|
|
745
|
-
"--type", "DEMOGRAPHICS_ADJUSTMENT",
|
|
746
|
-
"--disabled",
|
|
747
|
-
)
|
|
748
|
-
item = body["params"]["BidModifierToggleItems"][0]
|
|
749
|
-
assert item == {"CampaignId": 777, "Type": "DEMOGRAPHICS_ADJUSTMENT", "Enabled": "NO"}
|
|
750
|
-
|
|
751
|
-
|
|
752
729
|
def test_bidmodifiers_add_mobile_uses_nested_object():
|
|
753
730
|
body = _dry_run(
|
|
754
731
|
"bidmodifiers",
|
|
@@ -394,73 +394,6 @@ class TestWriteBidModifiersSet:
|
|
|
394
394
|
)
|
|
395
395
|
|
|
396
396
|
|
|
397
|
-
@pytest.mark.integration_write
|
|
398
|
-
@pytest.mark.vcr
|
|
399
|
-
@pytest.mark.skip(
|
|
400
|
-
reason=(
|
|
401
|
-
"No stable VCR cassette for bidmodifiers toggle. "
|
|
402
|
-
"Replay mode fails without a recording and live sandbox rewrite is not stable. "
|
|
403
|
-
"Toggle request shape remains covered by dry-run tests."
|
|
404
|
-
)
|
|
405
|
-
)
|
|
406
|
-
@pytest.mark.sandbox_limitation(
|
|
407
|
-
reason=(
|
|
408
|
-
"Sandbox/VCR coverage for bidmodifiers toggle is unstable and may require "
|
|
409
|
-
"existing DEMOGRAPHICS_ADJUSTMENT state"
|
|
410
|
-
)
|
|
411
|
-
)
|
|
412
|
-
class TestWriteBidModifiers:
|
|
413
|
-
def test_toggle_existing(self, sandbox_campaign):
|
|
414
|
-
"""Toggle a supported bid modifier type off and back on."""
|
|
415
|
-
cid = sandbox_campaign
|
|
416
|
-
|
|
417
|
-
r = _invoke(
|
|
418
|
-
"bidmodifiers", "toggle",
|
|
419
|
-
"--campaign-id", str(cid),
|
|
420
|
-
"--type", "DEMOGRAPHICS_ADJUSTMENT",
|
|
421
|
-
"--disabled",
|
|
422
|
-
)
|
|
423
|
-
if r.exit_code != 0:
|
|
424
|
-
if _is_sandbox_error(r.output):
|
|
425
|
-
pytest.skip(
|
|
426
|
-
f"bidmodifiers toggle not supported (sandbox): {r.output[:200]}"
|
|
427
|
-
)
|
|
428
|
-
pytest.fail(
|
|
429
|
-
f"bidmodifiers toggle --disabled failed: {r.output[:500]}"
|
|
430
|
-
)
|
|
431
|
-
|
|
432
|
-
if _has_result_errors(r.output, "ToggleResults"):
|
|
433
|
-
if _is_sandbox_error(r.output):
|
|
434
|
-
pytest.skip(
|
|
435
|
-
f"bidmodifiers toggle rejected by sandbox: {r.output[:200]}"
|
|
436
|
-
)
|
|
437
|
-
pytest.fail(
|
|
438
|
-
f"bidmodifiers toggle --disabled returned errors: {r.output[:500]}"
|
|
439
|
-
)
|
|
440
|
-
|
|
441
|
-
r = _invoke(
|
|
442
|
-
"bidmodifiers", "toggle",
|
|
443
|
-
"--campaign-id", str(cid),
|
|
444
|
-
"--type", "DEMOGRAPHICS_ADJUSTMENT",
|
|
445
|
-
"--enabled",
|
|
446
|
-
)
|
|
447
|
-
if r.exit_code != 0:
|
|
448
|
-
if _is_sandbox_error(r.output):
|
|
449
|
-
pytest.skip(
|
|
450
|
-
f"bidmodifiers toggle on not supported (sandbox): {r.output[:200]}"
|
|
451
|
-
)
|
|
452
|
-
pytest.fail(f"bidmodifiers toggle --enabled failed: {r.output[:500]}")
|
|
453
|
-
|
|
454
|
-
if _has_result_errors(r.output, "ToggleResults"):
|
|
455
|
-
if _is_sandbox_error(r.output):
|
|
456
|
-
pytest.skip(
|
|
457
|
-
f"bidmodifiers toggle rejected by sandbox: {r.output[:200]}"
|
|
458
|
-
)
|
|
459
|
-
pytest.fail(
|
|
460
|
-
f"bidmodifiers toggle --enabled returned errors: {r.output[:500]}"
|
|
461
|
-
)
|
|
462
|
-
|
|
463
|
-
|
|
464
397
|
# ── feeds ────────────────────────────────────────────────────────────────
|
|
465
398
|
|
|
466
399
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{direct_cli-0.2.7 → direct_cli-0.2.8}/docs/superpowers/plans/2026-04-12-issue-32-completion.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|