direct-cli 0.2.10__tar.gz → 0.3.0__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.
Files changed (187) hide show
  1. {direct_cli-0.2.10 → direct_cli-0.3.0}/CLAUDE.md +11 -1
  2. {direct_cli-0.2.10 → direct_cli-0.3.0}/PKG-INFO +76 -9
  3. {direct_cli-0.2.10 → direct_cli-0.3.0}/README.md +75 -8
  4. direct_cli-0.3.0/direct_cli/_smoke_probes.py +89 -0
  5. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +2 -1
  6. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +43 -0
  7. direct_cli-0.3.0/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +163 -0
  8. direct_cli-0.3.0/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +9 -0
  9. direct_cli-0.3.0/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +219 -0
  10. direct_cli-0.3.0/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +54 -0
  11. direct_cli-0.3.0/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +66 -0
  12. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/cli.py +46 -31
  13. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/adextensions.py +4 -2
  14. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/ads.py +3 -5
  15. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/agencyclients.py +101 -26
  16. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/audiencetargets.py +30 -17
  17. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/bidmodifiers.py +15 -3
  18. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/bids.py +15 -3
  19. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/businesses.py +2 -2
  20. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/changes.py +14 -7
  21. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/clients.py +51 -16
  22. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/creatives.py +2 -4
  23. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/dynamicads.py +18 -9
  24. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/dynamicfeedadtargets.py +2 -4
  25. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/keywordbids.py +7 -11
  26. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/keywordsresearch.py +2 -2
  27. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/leads.py +2 -6
  28. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/negativekeywordsharedsets.py +4 -2
  29. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/sitelinks.py +2 -2
  30. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/smartadtargets.py +21 -10
  31. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/strategies.py +8 -6
  32. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/turbopages.py +2 -2
  33. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/vcards.py +2 -6
  34. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/reports_coverage.py +15 -5
  35. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/smoke_matrix.py +3 -0
  36. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/utils.py +236 -10
  37. direct_cli-0.3.0/direct_cli/wsdl_coverage.py +581 -0
  38. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/PKG-INFO +76 -9
  39. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/SOURCES.txt +11 -1
  40. {direct_cli-0.2.10 → direct_cli-0.3.0}/pyproject.toml +1 -1
  41. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/build_api_coverage_checklist.py +48 -34
  42. direct_cli-0.3.0/scripts/build_api_coverage_report.py +1040 -0
  43. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/check_wsdl_drift.py +49 -2
  44. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/patch_vendor_imports.py +40 -9
  45. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/test_safe_commands.sh +69 -15
  46. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/update_vendor.sh +5 -6
  47. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/API_COVERAGE.md +25 -1
  48. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/MANUAL_COVERAGE.md +7 -4
  49. direct_cli-0.3.0/tests/api_coverage_payloads.py +448 -0
  50. direct_cli-0.3.0/tests/test_api_coverage.py +1765 -0
  51. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_cli.py +24 -1
  52. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_dry_run.py +350 -136
  53. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_integration.py +159 -16
  54. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_integration_write.py +4 -0
  55. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_smoke_matrix.py +10 -0
  56. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_vendor_imports.py +34 -12
  57. direct_cli-0.3.0/tests/wsdl_cache/imports/adextensiontypes.xsd +60 -0
  58. direct_cli-0.3.0/tests/wsdl_cache/imports/general.xsd +444 -0
  59. direct_cli-0.3.0/tests/wsdl_cache/imports/generalclients.xsd +396 -0
  60. direct_cli-0.2.10/direct_cli/wsdl_coverage.py +0 -346
  61. direct_cli-0.2.10/scripts/build_api_coverage_report.py +0 -236
  62. direct_cli-0.2.10/tests/test_api_coverage.py +0 -1357
  63. {direct_cli-0.2.10 → direct_cli-0.3.0}/.env.example +0 -0
  64. {direct_cli-0.2.10 → direct_cli-0.3.0}/.github/copilot-instructions.md +0 -0
  65. {direct_cli-0.2.10 → direct_cli-0.3.0}/.github/workflows/api-coverage.yml +0 -0
  66. {direct_cli-0.2.10 → direct_cli-0.3.0}/.github/workflows/claude-code-review.yml +0 -0
  67. {direct_cli-0.2.10 → direct_cli-0.3.0}/.github/workflows/claude.yml +0 -0
  68. {direct_cli-0.2.10 → direct_cli-0.3.0}/.gitignore +0 -0
  69. {direct_cli-0.2.10 → direct_cli-0.3.0}/AGENTS.md +0 -0
  70. {direct_cli-0.2.10 → direct_cli-0.3.0}/MANIFEST.in +0 -0
  71. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/__init__.py +0 -0
  72. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_deprecated.py +0 -0
  73. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_vendor/__init__.py +0 -0
  74. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
  75. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +0 -0
  76. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/api.py +0 -0
  77. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/auth.py +0 -0
  78. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/__init__.py +0 -0
  79. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/adgroups.py +0 -0
  80. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/adimages.py +0 -0
  81. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/advideos.py +0 -0
  82. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/auth.py +0 -0
  83. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/campaigns.py +0 -0
  84. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/dictionaries.py +0 -0
  85. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/feeds.py +0 -0
  86. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/keywords.py +0 -0
  87. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/reports.py +0 -0
  88. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/commands/retargeting.py +0 -0
  89. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli/output.py +0 -0
  90. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/dependency_links.txt +0 -0
  91. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/entry_points.txt +0 -0
  92. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/requires.txt +0 -0
  93. {direct_cli-0.2.10 → direct_cli-0.3.0}/direct_cli.egg-info/top_level.txt +0 -0
  94. {direct_cli-0.2.10 → direct_cli-0.3.0}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
  95. {direct_cli-0.2.10 → direct_cli-0.3.0}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
  96. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/anonymize_cassettes.py +0 -0
  97. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/check_reports_drift.py +0 -0
  98. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/refresh_reports_cache.py +0 -0
  99. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/refresh_wsdl_cache.py +0 -0
  100. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/release_pypi.sh +0 -0
  101. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/sandbox_write_live.py +0 -0
  102. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/test_dangerous_commands.sh +0 -0
  103. {direct_cli-0.2.10 → direct_cli-0.3.0}/scripts/test_sandbox_write.sh +0 -0
  104. {direct_cli-0.2.10 → direct_cli-0.3.0}/setup.cfg +0 -0
  105. {direct_cli-0.2.10 → direct_cli-0.3.0}/setup.py +0 -0
  106. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/API_ISSUE_AUDIT.md +0 -0
  107. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/__init__.py +0 -0
  108. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_adgroups_add_update_delete.yaml +0 -0
  109. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_adimages_add_get_delete.yaml +0 -0
  110. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_ads_add_update_delete.yaml +0 -0
  111. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_ads_suspend_resume_archive_unarchive.yaml +0 -0
  112. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_advideos_add_get.yaml +0 -0
  113. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_add_delete.yaml +0 -0
  114. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_suspend_resume.yaml +0 -0
  115. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_bids_set.yaml +0 -0
  116. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_campaign_create_get_delete.yaml +0 -0
  117. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_creatives_chain_advideo_to_creative.yaml +0 -0
  118. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_add_delete.yaml +0 -0
  119. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_suspend_resume.yaml +0 -0
  120. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_keywordbids_set.yaml +0 -0
  121. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_add_update_delete.yaml +0 -0
  122. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_suspend_resume.yaml +0 -0
  123. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_sitelinks_add_get_delete.yaml +0 -0
  124. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_add_update_delete.yaml +0 -0
  125. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_suspend_resume.yaml +0 -0
  126. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
  127. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
  128. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
  129. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
  130. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
  131. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
  132. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
  133. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
  134. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
  135. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
  136. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
  137. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
  138. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
  139. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
  140. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
  141. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
  142. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
  143. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
  144. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
  145. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/conftest.py +0 -0
  146. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/fixtures/test-video.mp4 +0 -0
  147. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/reports_cache/raw/fields-list.html +0 -0
  148. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/reports_cache/raw/headers.html +0 -0
  149. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/reports_cache/raw/spec.html +0 -0
  150. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/reports_cache/raw/type.html +0 -0
  151. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/reports_cache/spec.json +0 -0
  152. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_auth_bw.py +0 -0
  153. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_auth_oauth.py +0 -0
  154. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_auth_op.py +0 -0
  155. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_comprehensive.py +0 -0
  156. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_integration_live_write.py +0 -0
  157. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_reports_drift.py +0 -0
  158. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/test_transport_contract.py +0 -0
  159. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/adextensions.xml +0 -0
  160. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/adgroups.xml +0 -0
  161. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/adimages.xml +0 -0
  162. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/ads.xml +0 -0
  163. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/advideos.xml +0 -0
  164. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/agencyclients.xml +0 -0
  165. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/audiencetargets.xml +0 -0
  166. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/bidmodifiers.xml +0 -0
  167. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/bids.xml +0 -0
  168. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/businesses.xml +0 -0
  169. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/campaigns.xml +0 -0
  170. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/changes.xml +0 -0
  171. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/clients.xml +0 -0
  172. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/creatives.xml +0 -0
  173. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/dictionaries.xml +0 -0
  174. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
  175. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
  176. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/feeds.xml +0 -0
  177. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/keywordbids.xml +0 -0
  178. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/keywords.xml +0 -0
  179. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/keywordsresearch.xml +0 -0
  180. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/leads.xml +0 -0
  181. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
  182. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/retargetinglists.xml +0 -0
  183. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/sitelinks.xml +0 -0
  184. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/smartadtargets.xml +0 -0
  185. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/strategies.xml +0 -0
  186. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/turbopages.xml +0 -0
  187. {direct_cli-0.2.10 → direct_cli-0.3.0}/tests/wsdl_cache/vcards.xml +0 -0
@@ -39,11 +39,17 @@ Click group-of-groups. Each Yandex Direct API resource = one file in `direct_cli
39
39
 
40
40
  **`--dry-run`:** `add`/`update` commands print request JSON without calling the API. Use as test seam.
41
41
 
42
+ **Runtime-deprecated methods:** WSDL-visible methods that Yandex rejects at runtime belong in `RUNTIME_DEPRECATED_METHODS` (`direct_cli/wsdl_coverage.py`) and must fail with `click.UsageError` before request construction. `agencyclients add` is blocked this way; use `agencyclients add-passport-organization`.
43
+
42
44
  **SelectionCriteria:** Resources like `adgroups`, `ads`, `keywords` require at least one of `Ids`, `CampaignIds`, or `AdGroupIds` — otherwise API error 4001.
43
45
 
44
46
  **Error handling:** All commands wrap API calls in `try/except Exception` → `print_error(str(e))` + `raise click.Abort()`.
45
47
 
46
- **Default fields:** `COMMON_FIELDS` in `utils.py` maps resource names to `FieldNames`. Not all fields are valid for all resources (e.g., `adimages` uses `AdImageHash`, not `Id`).
48
+ **Default fields:** `COMMON_FIELDS` in `utils.py` maps resource names to default `*FieldNames`. Most entries are `list[str]`; multi-`*FieldNames` resources use `dict[str, list[str]]` keyed by WSDL request param (for example `FieldNames`, `TextAdFieldNames`, `SearchFieldNames`). Not all fields are valid for all resources (e.g., `adimages` uses `AdImageHash`, not `Id`).
49
+
50
+ **WSDL imports:** Imported schemas used by request validation are cached in `tests/wsdl_cache/imports/` and registered in `IMPORTED_XSD_REGISTRY`. Keep imported nested types resolved; empty `item_fields` for registered imports is coverage drift.
51
+
52
+ **Smoke probes:** Live ID discovery for safe-smoke and integration tests lives in `direct_cli/_smoke_probes.py`. Functions like `advideo_probe_id()` query the live API to find a real resource ID (env override `YANDEX_DIRECT_TEST_ADVIDEO_ID`, fallback through `creatives.get`) and return `None` on any failure — smoke scripts treat `None` as a benign skip, not a fatal error. CLI entry: `python3 -m direct_cli._smoke_probes advideo`.
47
53
 
48
54
  ## Tests
49
55
 
@@ -66,3 +72,7 @@ subcommand belongs to exactly one category:
66
72
  Never auto-test production mutations: agency client changes, live bid changes,
67
73
  moderation, lifecycle operations, `clients update`, or any `delete` without
68
74
  `--sandbox`.
75
+
76
+ Client update payloads (`clients update` and `agencyclients update`) must use
77
+ the shared typed helpers in `direct_cli/utils.py`; do not expose raw JSON for
78
+ general client update fields or nested client update payloads.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: direct-cli
3
- Version: 0.2.10
3
+ Version: 0.3.0
4
4
  Summary: Command-line interface for Yandex Direct API
5
5
  Author: axisrow
6
6
  License: MIT
@@ -97,6 +97,23 @@ Notes:
97
97
  - Authorization is performed via `direct auth login`.
98
98
  - Alias `auth_login` is not supported.
99
99
 
100
+ Credential resolution priority:
101
+
102
+ | Priority | Source | Example |
103
+ |----------|--------|---------|
104
+ | 1 | Explicit CLI options | `direct --token TOKEN --login LOGIN campaigns get` |
105
+ | 2 | OAuth profile storage | `direct --profile agency1 campaigns get` |
106
+ | 3 | Profile-specific env vars | `YANDEX_DIRECT_TOKEN_AGENCY1`, `YANDEX_DIRECT_LOGIN_AGENCY1` |
107
+ | 4 | Base env vars or project `.env` | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
108
+ | 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
109
+ | 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
110
+
111
+ The project `.env` file is loaded automatically. If a profile is selected
112
+ with `--profile` or `direct auth use --profile NAME`, Direct CLI does not
113
+ fall back to base `YANDEX_DIRECT_LOGIN`; this prevents mixing a profile token
114
+ with a login from the project `.env`. For multi-account setups, prefer OAuth
115
+ profiles or profile-specific env vars instead of base credentials.
116
+
100
117
  Install with `pip install direct-cli`, then run commands with `direct`.
101
118
  Invoking the deprecated `direct-cli` entrypoint exits with
102
119
  `use direct instead of direct-cli`.
@@ -325,7 +342,7 @@ direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-n
325
342
  direct clients get --fields ClientId,Login,Currency
326
343
 
327
344
  # Changes
328
- direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
345
+ direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
329
346
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
330
347
  direct changes check-dictionaries
331
348
 
@@ -335,15 +352,18 @@ direct retargeting add --name "List A" --type AUDIENCE --rule "ALL:12345:30|6789
335
352
  direct retargeting update --id 55 --name "Renamed" --rule "ANY:12345:30" --dry-run
336
353
 
337
354
  # Bids and modifiers
355
+ direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
338
356
  direct bids set --keyword-id 123 --bid 15000000
339
357
  direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
340
358
  direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
341
359
  direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
360
+ direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
342
361
  direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
343
362
  direct bidmodifiers set --id 99 --value 130 --dry-run
344
363
 
345
364
  # Canonical multiword groups
346
365
  direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
366
+ direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
347
367
  direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
348
368
  direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
349
369
  direct dynamicads add --adgroup-id 33 --name "Webpage A" --condition "URL:CONTAINS_ANY:test|shop" --condition "PAGE_CONTENT:CONTAINS:baz" --bid 3000000 --context-bid 2000000 --priority HIGH --dry-run
@@ -371,13 +391,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
371
391
  direct creatives add --video-id video-id --dry-run
372
392
  direct feeds add --name "Feed A" --url "https://example.com/feed.xml" --dry-run
373
393
  direct feeds update --id 18 --name "Feed A v2" --url "https://example.com/feed-v2.xml" --dry-run
374
- direct clients update --client-id 999 --phone +70000000000 --fax +70000000001 --email user@example.com --city Moscow --dry-run
375
- direct agencyclients add --login client-login --first-name Alice --last-name Smith --currency RUB --notification-email ops@example.com --notification-lang RU --send-account-news --no-send-warnings --dry-run
394
+ direct clients update --client-info "Priority client" --phone +70000000000 --notification-email user@example.com --notification-lang EN --email-subscription RECEIVE_RECOMMENDATIONS=YES --setting DISPLAY_STORE_RATING=NO --dry-run
395
+ direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
376
396
  direct agencyclients add-passport-organization --name "Org" --currency RUB --notification-email ops@example.com --notification-lang EN --no-send-account-news --send-warnings --dry-run
377
397
  direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
378
- direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
398
+ direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
379
399
  ```
380
400
 
401
+ `direct agencyclients add` is runtime-deprecated by Yandex Direct and is blocked by the CLI. Use `direct agencyclients add-passport-organization` instead.
402
+
381
403
  ### Known Unsupported API Operation
382
404
 
383
405
  `dynamicads update` is unsupported by API. The Yandex Direct
@@ -634,6 +656,45 @@ YANDEX_DIRECT_LOGIN=ваш_логин_на_яндексе
634
656
  direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
635
657
  ```
636
658
 
659
+ Используйте профильные credentials из `.env`:
660
+
661
+ ```env
662
+ YANDEX_DIRECT_TOKEN_AGENCY1=token-1
663
+ YANDEX_DIRECT_LOGIN_AGENCY1=client-login-1
664
+ YANDEX_DIRECT_TOKEN_AGENCY2=token-2
665
+ YANDEX_DIRECT_LOGIN_AGENCY2=client-login-2
666
+ ```
667
+
668
+ OAuth и profile-команды:
669
+
670
+ ```bash
671
+ direct auth login
672
+ direct auth login --profile agency1
673
+ direct auth login --code abc123 --profile agency1
674
+ direct auth login --oauth-token y0_example --profile agency1
675
+ direct auth list
676
+ direct auth use --profile agency1
677
+ direct auth status --profile agency1
678
+ direct --profile agency1 campaigns get
679
+ ```
680
+
681
+ Порядок выбора credentials:
682
+
683
+ | Приоритет | Источник | Пример |
684
+ |-----------|----------|--------|
685
+ | 1 | Явные CLI-опции | `direct --token TOKEN --login LOGIN campaigns get` |
686
+ | 2 | OAuth profile storage | `direct --profile agency1 campaigns get` |
687
+ | 3 | Профильные env vars | `YANDEX_DIRECT_TOKEN_AGENCY1`, `YANDEX_DIRECT_LOGIN_AGENCY1` |
688
+ | 4 | Базовые env vars или project `.env` | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
689
+ | 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
690
+ | 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
691
+
692
+ Файл `.env` в проекте загружается автоматически. Если профиль выбран через
693
+ `--profile` или `direct auth use --profile NAME`, Direct CLI не подставляет
694
+ base `YANDEX_DIRECT_LOGIN`; это защищает от смешивания токена из профиля с
695
+ логином из project `.env`. Для нескольких аккаунтов используйте OAuth profiles
696
+ или профильные env vars, а не базовые credentials.
697
+
637
698
  Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
638
699
  через `direct`. Вызов deprecated entrypoint `direct-cli` завершается ошибкой с
639
700
  подсказкой `use direct instead of direct-cli`.
@@ -644,6 +705,7 @@ direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
644
705
  |-------|----------|
645
706
  | `--token` | OAuth-токен доступа к API |
646
707
  | `--login` | Direct client login |
708
+ | `--profile` | Имя credential profile |
647
709
  | `--sandbox` | Использовать тестовое API (песочница) |
648
710
 
649
711
  ### Использование
@@ -902,7 +964,7 @@ direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --e
902
964
  direct clients get --fields ClientId,Login,Currency
903
965
 
904
966
  # Изменения
905
- direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
967
+ direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
906
968
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
907
969
  direct changes check-dictionaries
908
970
 
@@ -912,15 +974,18 @@ direct retargeting add --name "Список A" --type AUDIENCE --rule "ALL:12345
912
974
  direct retargeting update --id 55 --name "Переименованный список" --rule "ANY:12345:30" --dry-run
913
975
 
914
976
  # Ставки и модификаторы
977
+ direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
915
978
  direct bids set --keyword-id 123 --bid 15000000
916
979
  direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
917
980
  direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
918
981
  direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
982
+ direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
919
983
  direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
920
984
  direct bidmodifiers set --id 99 --value 130 --dry-run
921
985
 
922
986
  # Канонические многословные группы
923
987
  direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
988
+ direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
924
989
  direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
925
990
  direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
926
991
  direct dynamicads add --adgroup-id 33 --name "Webpage A" --condition "URL:CONTAINS_ANY:test|shop" --condition "PAGE_CONTENT:CONTAINS:baz" --bid 3000000 --context-bid 2000000 --priority HIGH --dry-run
@@ -948,13 +1013,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
948
1013
  direct creatives add --video-id video-id --dry-run
949
1014
  direct feeds add --name "Фид A" --url "https://example.com/feed.xml" --dry-run
950
1015
  direct feeds update --id 18 --name "Фид A v2" --url "https://example.com/feed-v2.xml" --dry-run
951
- direct clients update --client-id 999 --phone +70000000000 --fax +70000000001 --email user@example.com --city Moscow --dry-run
952
- direct agencyclients add --login client-login --first-name Alice --last-name Smith --currency RUB --notification-email ops@example.com --notification-lang RU --send-account-news --no-send-warnings --dry-run
1016
+ direct clients update --client-info "Приоритетный клиент" --phone +70000000000 --notification-email user@example.com --notification-lang EN --email-subscription RECEIVE_RECOMMENDATIONS=YES --setting DISPLAY_STORE_RATING=NO --dry-run
1017
+ direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
953
1018
  direct agencyclients add-passport-organization --name "Org" --currency RUB --notification-email ops@example.com --notification-lang EN --no-send-account-news --send-warnings --dry-run
954
1019
  direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
955
- direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
1020
+ direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
956
1021
  ```
957
1022
 
1023
+ `direct agencyclients add` runtime-deprecated в Yandex Direct и блокируется CLI. Используйте `direct agencyclients add-passport-organization`.
1024
+
958
1025
  ### Известная неподдерживаемая API-операция
959
1026
 
960
1027
  `dynamicads update` unsupported by API. Сервис Яндекс Директа
@@ -58,6 +58,23 @@ Notes:
58
58
  - Authorization is performed via `direct auth login`.
59
59
  - Alias `auth_login` is not supported.
60
60
 
61
+ Credential resolution priority:
62
+
63
+ | Priority | Source | Example |
64
+ |----------|--------|---------|
65
+ | 1 | Explicit CLI options | `direct --token TOKEN --login LOGIN campaigns get` |
66
+ | 2 | OAuth profile storage | `direct --profile agency1 campaigns get` |
67
+ | 3 | Profile-specific env vars | `YANDEX_DIRECT_TOKEN_AGENCY1`, `YANDEX_DIRECT_LOGIN_AGENCY1` |
68
+ | 4 | Base env vars or project `.env` | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
69
+ | 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
70
+ | 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
71
+
72
+ The project `.env` file is loaded automatically. If a profile is selected
73
+ with `--profile` or `direct auth use --profile NAME`, Direct CLI does not
74
+ fall back to base `YANDEX_DIRECT_LOGIN`; this prevents mixing a profile token
75
+ with a login from the project `.env`. For multi-account setups, prefer OAuth
76
+ profiles or profile-specific env vars instead of base credentials.
77
+
61
78
  Install with `pip install direct-cli`, then run commands with `direct`.
62
79
  Invoking the deprecated `direct-cli` entrypoint exits with
63
80
  `use direct instead of direct-cli`.
@@ -286,7 +303,7 @@ direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-n
286
303
  direct clients get --fields ClientId,Login,Currency
287
304
 
288
305
  # Changes
289
- direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
306
+ direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
290
307
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
291
308
  direct changes check-dictionaries
292
309
 
@@ -296,15 +313,18 @@ direct retargeting add --name "List A" --type AUDIENCE --rule "ALL:12345:30|6789
296
313
  direct retargeting update --id 55 --name "Renamed" --rule "ANY:12345:30" --dry-run
297
314
 
298
315
  # Bids and modifiers
316
+ direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
299
317
  direct bids set --keyword-id 123 --bid 15000000
300
318
  direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
301
319
  direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
302
320
  direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
321
+ direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
303
322
  direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
304
323
  direct bidmodifiers set --id 99 --value 130 --dry-run
305
324
 
306
325
  # Canonical multiword groups
307
326
  direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
327
+ direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
308
328
  direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
309
329
  direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
310
330
  direct dynamicads add --adgroup-id 33 --name "Webpage A" --condition "URL:CONTAINS_ANY:test|shop" --condition "PAGE_CONTENT:CONTAINS:baz" --bid 3000000 --context-bid 2000000 --priority HIGH --dry-run
@@ -332,13 +352,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
332
352
  direct creatives add --video-id video-id --dry-run
333
353
  direct feeds add --name "Feed A" --url "https://example.com/feed.xml" --dry-run
334
354
  direct feeds update --id 18 --name "Feed A v2" --url "https://example.com/feed-v2.xml" --dry-run
335
- direct clients update --client-id 999 --phone +70000000000 --fax +70000000001 --email user@example.com --city Moscow --dry-run
336
- direct agencyclients add --login client-login --first-name Alice --last-name Smith --currency RUB --notification-email ops@example.com --notification-lang RU --send-account-news --no-send-warnings --dry-run
355
+ direct clients update --client-info "Priority client" --phone +70000000000 --notification-email user@example.com --notification-lang EN --email-subscription RECEIVE_RECOMMENDATIONS=YES --setting DISPLAY_STORE_RATING=NO --dry-run
356
+ direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
337
357
  direct agencyclients add-passport-organization --name "Org" --currency RUB --notification-email ops@example.com --notification-lang EN --no-send-account-news --send-warnings --dry-run
338
358
  direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
339
- direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
359
+ direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
340
360
  ```
341
361
 
362
+ `direct agencyclients add` is runtime-deprecated by Yandex Direct and is blocked by the CLI. Use `direct agencyclients add-passport-organization` instead.
363
+
342
364
  ### Known Unsupported API Operation
343
365
 
344
366
  `dynamicads update` is unsupported by API. The Yandex Direct
@@ -595,6 +617,45 @@ YANDEX_DIRECT_LOGIN=ваш_логин_на_яндексе
595
617
  direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
596
618
  ```
597
619
 
620
+ Используйте профильные credentials из `.env`:
621
+
622
+ ```env
623
+ YANDEX_DIRECT_TOKEN_AGENCY1=token-1
624
+ YANDEX_DIRECT_LOGIN_AGENCY1=client-login-1
625
+ YANDEX_DIRECT_TOKEN_AGENCY2=token-2
626
+ YANDEX_DIRECT_LOGIN_AGENCY2=client-login-2
627
+ ```
628
+
629
+ OAuth и profile-команды:
630
+
631
+ ```bash
632
+ direct auth login
633
+ direct auth login --profile agency1
634
+ direct auth login --code abc123 --profile agency1
635
+ direct auth login --oauth-token y0_example --profile agency1
636
+ direct auth list
637
+ direct auth use --profile agency1
638
+ direct auth status --profile agency1
639
+ direct --profile agency1 campaigns get
640
+ ```
641
+
642
+ Порядок выбора credentials:
643
+
644
+ | Приоритет | Источник | Пример |
645
+ |-----------|----------|--------|
646
+ | 1 | Явные CLI-опции | `direct --token TOKEN --login LOGIN campaigns get` |
647
+ | 2 | OAuth profile storage | `direct --profile agency1 campaigns get` |
648
+ | 3 | Профильные env vars | `YANDEX_DIRECT_TOKEN_AGENCY1`, `YANDEX_DIRECT_LOGIN_AGENCY1` |
649
+ | 4 | Базовые env vars или project `.env` | `YANDEX_DIRECT_TOKEN`, `YANDEX_DIRECT_LOGIN` |
650
+ | 5 | 1Password references | `--op-token-ref`, `YANDEX_DIRECT_OP_TOKEN_REF` |
651
+ | 6 | Bitwarden references | `--bw-token-ref`, `YANDEX_DIRECT_BW_TOKEN_REF` |
652
+
653
+ Файл `.env` в проекте загружается автоматически. Если профиль выбран через
654
+ `--profile` или `direct auth use --profile NAME`, Direct CLI не подставляет
655
+ base `YANDEX_DIRECT_LOGIN`; это защищает от смешивания токена из профиля с
656
+ логином из project `.env`. Для нескольких аккаунтов используйте OAuth profiles
657
+ или профильные env vars, а не базовые credentials.
658
+
598
659
  Установка остаётся через `pip install direct-cli`, а запуск команд теперь идет
599
660
  через `direct`. Вызов deprecated entrypoint `direct-cli` завершается ошибкой с
600
661
  подсказкой `use direct instead of direct-cli`.
@@ -605,6 +666,7 @@ direct --token ВАШ_ТОКЕН --login ВАШ_ЛОГИН campaigns get
605
666
  |-------|----------|
606
667
  | `--token` | OAuth-токен доступа к API |
607
668
  | `--login` | Direct client login |
669
+ | `--profile` | Имя credential profile |
608
670
  | `--sandbox` | Использовать тестовое API (песочница) |
609
671
 
610
672
  ### Использование
@@ -863,7 +925,7 @@ direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --e
863
925
  direct clients get --fields ClientId,Login,Currency
864
926
 
865
927
  # Изменения
866
- direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00
928
+ direct changes check --campaign-ids 1,2,3 --timestamp 2026-04-14T00:00:00 --fields CampaignIds,AdGroupIds,AdIds,CampaignsStat
867
929
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
868
930
  direct changes check-dictionaries
869
931
 
@@ -873,15 +935,18 @@ direct retargeting add --name "Список A" --type AUDIENCE --rule "ALL:12345
873
935
  direct retargeting update --id 55 --name "Переименованный список" --rule "ANY:12345:30" --dry-run
874
936
 
875
937
  # Ставки и модификаторы
938
+ direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
876
939
  direct bids set --keyword-id 123 --bid 15000000
877
940
  direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
878
941
  direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
879
942
  direct keywordbids set-auto --keyword-id 321 --target-traffic-volume 100 --increase-percent 10 --bid-ceiling 12500000 --dry-run
943
+ direct bidmodifiers get --campaign-ids 123 --fields Id,CampaignId,AdGroupId,Level,Type
880
944
  direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
881
945
  direct bidmodifiers set --id 99 --value 130 --dry-run
882
946
 
883
947
  # Канонические многословные группы
884
948
  direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
949
+ direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
885
950
  direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
886
951
  direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
887
952
  direct dynamicads add --adgroup-id 33 --name "Webpage A" --condition "URL:CONTAINS_ANY:test|shop" --condition "PAGE_CONTENT:CONTAINS:baz" --bid 3000000 --context-bid 2000000 --priority HIGH --dry-run
@@ -909,13 +974,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
909
974
  direct creatives add --video-id video-id --dry-run
910
975
  direct feeds add --name "Фид A" --url "https://example.com/feed.xml" --dry-run
911
976
  direct feeds update --id 18 --name "Фид A v2" --url "https://example.com/feed-v2.xml" --dry-run
912
- direct clients update --client-id 999 --phone +70000000000 --fax +70000000001 --email user@example.com --city Moscow --dry-run
913
- direct agencyclients add --login client-login --first-name Alice --last-name Smith --currency RUB --notification-email ops@example.com --notification-lang RU --send-account-news --no-send-warnings --dry-run
977
+ direct clients update --client-info "Приоритетный клиент" --phone +70000000000 --notification-email user@example.com --notification-lang EN --email-subscription RECEIVE_RECOMMENDATIONS=YES --setting DISPLAY_STORE_RATING=NO --dry-run
978
+ direct --login CLIENT_LOGIN clients update --phone +70000000000 --notification-email user@example.com --dry-run
914
979
  direct agencyclients add-passport-organization --name "Org" --currency RUB --notification-email ops@example.com --notification-lang EN --no-send-account-news --send-warnings --dry-run
915
980
  direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
916
- direct agencyclients update --client-id 42 --phone +70000000000 --email user@example.com --grant EDIT_CAMPAIGNS --grant IMPORT_XLS --dry-run
981
+ direct agencyclients update --client-id 42 --phone +70000000000 --notification-email user@example.com --grant EDIT_CAMPAIGNS=YES --grant IMPORT_XLS=NO --dry-run
917
982
  ```
918
983
 
984
+ `direct agencyclients add` runtime-deprecated в Yandex Direct и блокируется CLI. Используйте `direct agencyclients add-passport-organization`.
985
+
919
986
  ### Известная неподдерживаемая API-операция
920
987
 
921
988
  `dynamicads update` unsupported by API. Сервис Яндекс Директа
@@ -0,0 +1,89 @@
1
+ """Live smoke-test probes for IDs that cannot be hardcoded safely."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import sys
7
+ from typing import Any, Optional
8
+
9
+ from .api import create_client
10
+
11
+ VIDEO_CREATIVE_TYPES = {"VIDEO_EXTENSION_CREATIVE", "CPM_VIDEO_CREATIVE"}
12
+
13
+
14
+ def _extract_items(response: Any) -> list[dict[str, Any]]:
15
+ """Return a normalized list from a tapi response object."""
16
+ data = response().extract()
17
+ return data if isinstance(data, list) else []
18
+
19
+
20
+ def _advideo_get_accepts(client: Any, candidate: str) -> bool:
21
+ """Return whether advideos.get accepts and returns the candidate ID."""
22
+ body = {
23
+ "method": "get",
24
+ "params": {
25
+ "SelectionCriteria": {"Ids": [candidate]},
26
+ "FieldNames": ["Id", "Status"],
27
+ "Page": {"Limit": 1},
28
+ },
29
+ }
30
+ try:
31
+ return bool(_extract_items(client.advideos().post(data=body)))
32
+ except Exception:
33
+ return False
34
+
35
+
36
+ def advideo_probe_id() -> Optional[str]:
37
+ """Return an AdVideos ID accepted by ``advideos.get``, or ``None``.
38
+
39
+ Returns ``None`` (never raises) on auth failure, missing credentials,
40
+ or any network/API error — smoke scripts use this in a context where a
41
+ failed probe should be a benign skip, not a fatal error.
42
+ """
43
+ try:
44
+ client = create_client()
45
+ except Exception:
46
+ return None
47
+
48
+ env_id = os.getenv("YANDEX_DIRECT_TEST_ADVIDEO_ID")
49
+ if env_id and _advideo_get_accepts(client, env_id):
50
+ return env_id
51
+
52
+ body = {
53
+ "method": "get",
54
+ "params": {
55
+ "SelectionCriteria": {},
56
+ "FieldNames": ["Id", "Name", "Type"],
57
+ "Page": {"Limit": 20},
58
+ },
59
+ }
60
+ try:
61
+ creatives = _extract_items(client.creatives().post(data=body))
62
+ except Exception:
63
+ return None
64
+
65
+ for creative in creatives:
66
+ if creative.get("Type") not in VIDEO_CREATIVE_TYPES:
67
+ continue
68
+ candidate = creative.get("Id")
69
+ if candidate and _advideo_get_accepts(client, str(candidate)):
70
+ return str(candidate)
71
+ return None
72
+
73
+
74
+ def main(argv: list[str] | None = None) -> int:
75
+ """CLI entry point for smoke probes."""
76
+ argv = list(sys.argv[1:] if argv is None else argv)
77
+ if argv != ["advideo"]:
78
+ print("Usage: python3 -m direct_cli._smoke_probes advideo", file=sys.stderr)
79
+ return 2
80
+
81
+ probe_id = advideo_probe_id()
82
+ if not probe_id:
83
+ return 1
84
+ print(probe_id)
85
+ return 0
86
+
87
+
88
+ if __name__ == "__main__":
89
+ raise SystemExit(main())
@@ -1,8 +1,9 @@
1
1
 
2
2
  __author__ = 'Pavel Maksimov'
3
3
  __email__ = 'vur21@ya.ru'
4
- __version__ = '2026.4.25'
4
+ __version__ = '2026.4.27'
5
5
 
6
6
 
7
7
  from .resource_mapping import *
8
8
  from .tapi_yandex_direct import YandexDirect
9
+ from .v4 import YandexDirectV4Live
@@ -65,6 +65,49 @@ class YandexDirectRequestsLimitError(YandexDirectClientError):
65
65
  super().__init__(*args, **kwargs)
66
66
 
67
67
 
68
+ class V4LiveError(YandexDirectApiError):
69
+ """Base exception for v4 Live API errors (error_code != 0).
70
+
71
+ v4 Live error payload differs from v5: integer ``error_code``, ``error_str``
72
+ instead of ``error_string``, no ``request_id``. Errors are returned with
73
+ HTTP 200 — they are detected from the response body, not the status code.
74
+ """
75
+
76
+ def __init__(
77
+ self,
78
+ response: Response,
79
+ message: Union[str, dict],
80
+ client: TapiClient,
81
+ *args,
82
+ **kwargs,
83
+ ):
84
+ if isinstance(message, dict):
85
+ try:
86
+ self.error_code = int(message.get("error_code", 0))
87
+ except (TypeError, ValueError):
88
+ self.error_code = 0
89
+ self.error_str = message.get("error_str", "")
90
+ self.error_detail = message.get("error_detail", "")
91
+ else:
92
+ self.error_code = 0
93
+ self.error_str = str(message)
94
+ self.error_detail = ""
95
+ super().__init__(response, message, client, *args, **kwargs)
96
+
97
+ def __str__(self):
98
+ return "v4 Live error_code={}, error_str={}, error_detail={}".format(
99
+ self.error_code, self.error_str, self.error_detail
100
+ )
101
+
102
+
103
+ class V4LiveTokenError(V4LiveError):
104
+ """v4 Live error_code=53 — invalid or missing OAuth token."""
105
+
106
+
107
+ class V4LiveRequestsLimitError(V4LiveError):
108
+ """v4 Live error_code in (54, 55, 56) — rate / method limit exceeded."""
109
+
110
+
68
111
  class BackwardCompatibilityError(Exception):
69
112
  def __init__(self, name):
70
113
  self.name = name