direct-cli 0.2.11__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.11 → direct_cli-0.3.0}/CLAUDE.md +11 -1
  2. {direct_cli-0.2.11 → direct_cli-0.3.0}/PKG-INFO +19 -9
  3. {direct_cli-0.2.11 → direct_cli-0.3.0}/README.md +18 -8
  4. direct_cli-0.3.0/direct_cli/_smoke_probes.py +89 -0
  5. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +2 -1
  6. {direct_cli-0.2.11 → 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.11 → direct_cli-0.3.0}/direct_cli/commands/adextensions.py +4 -2
  13. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/ads.py +3 -5
  14. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/agencyclients.py +70 -13
  15. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/audiencetargets.py +30 -17
  16. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/bidmodifiers.py +15 -3
  17. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/bids.py +15 -3
  18. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/businesses.py +2 -2
  19. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/changes.py +14 -7
  20. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/clients.py +51 -16
  21. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/creatives.py +2 -4
  22. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/dynamicads.py +18 -9
  23. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/dynamicfeedadtargets.py +2 -4
  24. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/keywordbids.py +7 -11
  25. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/keywordsresearch.py +2 -2
  26. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/leads.py +2 -6
  27. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/negativekeywordsharedsets.py +4 -2
  28. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/sitelinks.py +2 -2
  29. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/smartadtargets.py +21 -10
  30. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/strategies.py +8 -6
  31. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/turbopages.py +2 -2
  32. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/vcards.py +2 -6
  33. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/smoke_matrix.py +3 -0
  34. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/utils.py +229 -10
  35. direct_cli-0.3.0/direct_cli/wsdl_coverage.py +581 -0
  36. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/PKG-INFO +19 -9
  37. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/SOURCES.txt +11 -1
  38. {direct_cli-0.2.11 → direct_cli-0.3.0}/pyproject.toml +1 -1
  39. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/build_api_coverage_checklist.py +48 -34
  40. direct_cli-0.3.0/scripts/build_api_coverage_report.py +1040 -0
  41. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/check_wsdl_drift.py +49 -2
  42. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/patch_vendor_imports.py +40 -9
  43. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/test_safe_commands.sh +69 -13
  44. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/update_vendor.sh +5 -6
  45. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/API_COVERAGE.md +11 -1
  46. direct_cli-0.3.0/tests/api_coverage_payloads.py +448 -0
  47. direct_cli-0.3.0/tests/test_api_coverage.py +1765 -0
  48. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_dry_run.py +346 -136
  49. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_integration.py +2 -51
  50. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_smoke_matrix.py +10 -0
  51. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_vendor_imports.py +34 -12
  52. direct_cli-0.3.0/tests/wsdl_cache/imports/adextensiontypes.xsd +60 -0
  53. direct_cli-0.3.0/tests/wsdl_cache/imports/general.xsd +444 -0
  54. direct_cli-0.3.0/tests/wsdl_cache/imports/generalclients.xsd +396 -0
  55. direct_cli-0.2.11/direct_cli/wsdl_coverage.py +0 -346
  56. direct_cli-0.2.11/scripts/build_api_coverage_report.py +0 -236
  57. direct_cli-0.2.11/tests/test_api_coverage.py +0 -1373
  58. {direct_cli-0.2.11 → direct_cli-0.3.0}/.env.example +0 -0
  59. {direct_cli-0.2.11 → direct_cli-0.3.0}/.github/copilot-instructions.md +0 -0
  60. {direct_cli-0.2.11 → direct_cli-0.3.0}/.github/workflows/api-coverage.yml +0 -0
  61. {direct_cli-0.2.11 → direct_cli-0.3.0}/.github/workflows/claude-code-review.yml +0 -0
  62. {direct_cli-0.2.11 → direct_cli-0.3.0}/.github/workflows/claude.yml +0 -0
  63. {direct_cli-0.2.11 → direct_cli-0.3.0}/.gitignore +0 -0
  64. {direct_cli-0.2.11 → direct_cli-0.3.0}/AGENTS.md +0 -0
  65. {direct_cli-0.2.11 → direct_cli-0.3.0}/MANIFEST.in +0 -0
  66. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/__init__.py +0 -0
  67. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/_deprecated.py +0 -0
  68. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/_vendor/__init__.py +0 -0
  69. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
  70. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +0 -0
  71. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/api.py +0 -0
  72. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/auth.py +0 -0
  73. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/cli.py +0 -0
  74. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/__init__.py +0 -0
  75. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/adgroups.py +0 -0
  76. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/adimages.py +0 -0
  77. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/advideos.py +0 -0
  78. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/auth.py +0 -0
  79. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/campaigns.py +0 -0
  80. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/dictionaries.py +0 -0
  81. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/feeds.py +0 -0
  82. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/keywords.py +0 -0
  83. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/reports.py +0 -0
  84. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/commands/retargeting.py +0 -0
  85. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/output.py +0 -0
  86. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli/reports_coverage.py +0 -0
  87. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/dependency_links.txt +0 -0
  88. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/entry_points.txt +0 -0
  89. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/requires.txt +0 -0
  90. {direct_cli-0.2.11 → direct_cli-0.3.0}/direct_cli.egg-info/top_level.txt +0 -0
  91. {direct_cli-0.2.11 → direct_cli-0.3.0}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
  92. {direct_cli-0.2.11 → direct_cli-0.3.0}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
  93. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/anonymize_cassettes.py +0 -0
  94. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/check_reports_drift.py +0 -0
  95. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/refresh_reports_cache.py +0 -0
  96. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/refresh_wsdl_cache.py +0 -0
  97. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/release_pypi.sh +0 -0
  98. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/sandbox_write_live.py +0 -0
  99. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/test_dangerous_commands.sh +0 -0
  100. {direct_cli-0.2.11 → direct_cli-0.3.0}/scripts/test_sandbox_write.sh +0 -0
  101. {direct_cli-0.2.11 → direct_cli-0.3.0}/setup.cfg +0 -0
  102. {direct_cli-0.2.11 → direct_cli-0.3.0}/setup.py +0 -0
  103. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/API_ISSUE_AUDIT.md +0 -0
  104. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/MANUAL_COVERAGE.md +0 -0
  105. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/__init__.py +0 -0
  106. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_adgroups_add_update_delete.yaml +0 -0
  107. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_adimages_add_get_delete.yaml +0 -0
  108. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_ads_add_update_delete.yaml +0 -0
  109. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_ads_suspend_resume_archive_unarchive.yaml +0 -0
  110. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_advideos_add_get.yaml +0 -0
  111. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_add_delete.yaml +0 -0
  112. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_suspend_resume.yaml +0 -0
  113. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_bids_set.yaml +0 -0
  114. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_campaign_create_get_delete.yaml +0 -0
  115. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_creatives_chain_advideo_to_creative.yaml +0 -0
  116. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_add_delete.yaml +0 -0
  117. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_suspend_resume.yaml +0 -0
  118. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_keywordbids_set.yaml +0 -0
  119. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_add_update_delete.yaml +0 -0
  120. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_suspend_resume.yaml +0 -0
  121. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_sitelinks_add_get_delete.yaml +0 -0
  122. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_add_update_delete.yaml +0 -0
  123. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_suspend_resume.yaml +0 -0
  124. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
  125. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
  126. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
  127. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
  128. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
  129. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
  130. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
  131. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
  132. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
  133. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
  134. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
  135. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
  136. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
  137. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
  138. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
  139. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
  140. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
  141. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
  142. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
  143. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/conftest.py +0 -0
  144. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/fixtures/test-video.mp4 +0 -0
  145. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/reports_cache/raw/fields-list.html +0 -0
  146. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/reports_cache/raw/headers.html +0 -0
  147. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/reports_cache/raw/spec.html +0 -0
  148. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/reports_cache/raw/type.html +0 -0
  149. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/reports_cache/spec.json +0 -0
  150. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_auth_bw.py +0 -0
  151. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_auth_oauth.py +0 -0
  152. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_auth_op.py +0 -0
  153. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_cli.py +0 -0
  154. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_comprehensive.py +0 -0
  155. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_integration_live_write.py +0 -0
  156. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_integration_write.py +0 -0
  157. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_reports_drift.py +0 -0
  158. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/test_transport_contract.py +0 -0
  159. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/adextensions.xml +0 -0
  160. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/adgroups.xml +0 -0
  161. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/adimages.xml +0 -0
  162. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/ads.xml +0 -0
  163. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/advideos.xml +0 -0
  164. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/agencyclients.xml +0 -0
  165. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/audiencetargets.xml +0 -0
  166. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/bidmodifiers.xml +0 -0
  167. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/bids.xml +0 -0
  168. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/businesses.xml +0 -0
  169. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/campaigns.xml +0 -0
  170. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/changes.xml +0 -0
  171. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/clients.xml +0 -0
  172. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/creatives.xml +0 -0
  173. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/dictionaries.xml +0 -0
  174. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
  175. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
  176. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/feeds.xml +0 -0
  177. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/keywordbids.xml +0 -0
  178. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/keywords.xml +0 -0
  179. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/keywordsresearch.xml +0 -0
  180. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/leads.xml +0 -0
  181. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
  182. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/retargetinglists.xml +0 -0
  183. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/sitelinks.xml +0 -0
  184. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/smartadtargets.xml +0 -0
  185. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/strategies.xml +0 -0
  186. {direct_cli-0.2.11 → direct_cli-0.3.0}/tests/wsdl_cache/turbopages.xml +0 -0
  187. {direct_cli-0.2.11 → 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.11
3
+ Version: 0.3.0
4
4
  Summary: Command-line interface for Yandex Direct API
5
5
  Author: axisrow
6
6
  License: MIT
@@ -342,7 +342,7 @@ direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-n
342
342
  direct clients get --fields ClientId,Login,Currency
343
343
 
344
344
  # Changes
345
- 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
346
346
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
347
347
  direct changes check-dictionaries
348
348
 
@@ -352,15 +352,18 @@ direct retargeting add --name "List A" --type AUDIENCE --rule "ALL:12345:30|6789
352
352
  direct retargeting update --id 55 --name "Renamed" --rule "ANY:12345:30" --dry-run
353
353
 
354
354
  # Bids and modifiers
355
+ direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
355
356
  direct bids set --keyword-id 123 --bid 15000000
356
357
  direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
357
358
  direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
358
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
359
361
  direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
360
362
  direct bidmodifiers set --id 99 --value 130 --dry-run
361
363
 
362
364
  # Canonical multiword groups
363
365
  direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
366
+ direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
364
367
  direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
365
368
  direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
366
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
@@ -388,13 +391,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
388
391
  direct creatives add --video-id video-id --dry-run
389
392
  direct feeds add --name "Feed A" --url "https://example.com/feed.xml" --dry-run
390
393
  direct feeds update --id 18 --name "Feed A v2" --url "https://example.com/feed-v2.xml" --dry-run
391
- direct clients update --client-id 999 --phone +70000000000 --fax +70000000001 --email user@example.com --city Moscow --dry-run
392
- 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
393
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
394
397
  direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
395
- 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
396
399
  ```
397
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
+
398
403
  ### Known Unsupported API Operation
399
404
 
400
405
  `dynamicads update` is unsupported by API. The Yandex Direct
@@ -959,7 +964,7 @@ direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --e
959
964
  direct clients get --fields ClientId,Login,Currency
960
965
 
961
966
  # Изменения
962
- 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
963
968
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
964
969
  direct changes check-dictionaries
965
970
 
@@ -969,15 +974,18 @@ direct retargeting add --name "Список A" --type AUDIENCE --rule "ALL:12345
969
974
  direct retargeting update --id 55 --name "Переименованный список" --rule "ANY:12345:30" --dry-run
970
975
 
971
976
  # Ставки и модификаторы
977
+ direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
972
978
  direct bids set --keyword-id 123 --bid 15000000
973
979
  direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
974
980
  direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
975
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
976
983
  direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
977
984
  direct bidmodifiers set --id 99 --value 130 --dry-run
978
985
 
979
986
  # Канонические многословные группы
980
987
  direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
988
+ direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
981
989
  direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
982
990
  direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
983
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
@@ -1005,13 +1013,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
1005
1013
  direct creatives add --video-id video-id --dry-run
1006
1014
  direct feeds add --name "Фид A" --url "https://example.com/feed.xml" --dry-run
1007
1015
  direct feeds update --id 18 --name "Фид A v2" --url "https://example.com/feed-v2.xml" --dry-run
1008
- direct clients update --client-id 999 --phone +70000000000 --fax +70000000001 --email user@example.com --city Moscow --dry-run
1009
- 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
1010
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
1011
1019
  direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
1012
- 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
1013
1021
  ```
1014
1022
 
1023
+ `direct agencyclients add` runtime-deprecated в Yandex Direct и блокируется CLI. Используйте `direct agencyclients add-passport-organization`.
1024
+
1015
1025
  ### Известная неподдерживаемая API-операция
1016
1026
 
1017
1027
  `dynamicads update` unsupported by API. Сервис Яндекс Директа
@@ -303,7 +303,7 @@ direct dictionaries get-geo-regions --name Moscow --region-ids 225,187 --exact-n
303
303
  direct clients get --fields ClientId,Login,Currency
304
304
 
305
305
  # Changes
306
- 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
307
307
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
308
308
  direct changes check-dictionaries
309
309
 
@@ -313,15 +313,18 @@ direct retargeting add --name "List A" --type AUDIENCE --rule "ALL:12345:30|6789
313
313
  direct retargeting update --id 55 --name "Renamed" --rule "ANY:12345:30" --dry-run
314
314
 
315
315
  # Bids and modifiers
316
+ direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
316
317
  direct bids set --keyword-id 123 --bid 15000000
317
318
  direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
318
319
  direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
319
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
320
322
  direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
321
323
  direct bidmodifiers set --id 99 --value 130 --dry-run
322
324
 
323
325
  # Canonical multiword groups
324
326
  direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
327
+ direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
325
328
  direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
326
329
  direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
327
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
@@ -349,13 +352,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
349
352
  direct creatives add --video-id video-id --dry-run
350
353
  direct feeds add --name "Feed A" --url "https://example.com/feed.xml" --dry-run
351
354
  direct feeds update --id 18 --name "Feed A v2" --url "https://example.com/feed-v2.xml" --dry-run
352
- direct clients update --client-id 999 --phone +70000000000 --fax +70000000001 --email user@example.com --city Moscow --dry-run
353
- 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
354
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
355
358
  direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
356
- 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
357
360
  ```
358
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
+
359
364
  ### Known Unsupported API Operation
360
365
 
361
366
  `dynamicads update` is unsupported by API. The Yandex Direct
@@ -920,7 +925,7 @@ direct dictionaries get-geo-regions --name Москва --region-ids 225,187 --e
920
925
  direct clients get --fields ClientId,Login,Currency
921
926
 
922
927
  # Изменения
923
- 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
924
929
  direct changes check-campaigns --timestamp 2026-04-14T00:00:00
925
930
  direct changes check-dictionaries
926
931
 
@@ -930,15 +935,18 @@ direct retargeting add --name "Список A" --type AUDIENCE --rule "ALL:12345
930
935
  direct retargeting update --id 55 --name "Переименованный список" --rule "ANY:12345:30" --dry-run
931
936
 
932
937
  # Ставки и модификаторы
938
+ direct bids get --campaign-ids 123 --fields CampaignId,AdGroupId,KeywordId,Bid
933
939
  direct bids set --keyword-id 123 --bid 15000000
934
940
  direct bids set-auto --keyword-id 123 --max-bid 20000000 --position PREMIUMBLOCK --scope SEARCH --dry-run
935
941
  direct keywordbids set --keyword-id 321 --search-bid 8000000 --network-bid 3000000
936
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
937
944
  direct bidmodifiers add --campaign-id 123 --type DEMOGRAPHICS_ADJUSTMENT --value 150 --gender GENDER_MALE --age AGE_25_34 --dry-run
938
945
  direct bidmodifiers set --id 99 --value 130 --dry-run
939
946
 
940
947
  # Канонические многословные группы
941
948
  direct negativekeywordsharedsets update --id 123 --keywords "foo,bar"
949
+ direct audiencetargets get --campaign-ids 123 --fields Id,AdGroupId,RetargetingListId,State,ContextBid
942
950
  direct audiencetargets add --adgroup-id 100 --retargeting-list-id 200 --bid 12000000 --priority HIGH --dry-run
943
951
  direct audiencetargets set-bids --id 101 --context-bid 7000000 --priority LOW --dry-run
944
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
@@ -966,13 +974,15 @@ direct adimages add --name banner.png --image-data BASE64DATA --type ICON --dry-
966
974
  direct creatives add --video-id video-id --dry-run
967
975
  direct feeds add --name "Фид A" --url "https://example.com/feed.xml" --dry-run
968
976
  direct feeds update --id 18 --name "Фид A v2" --url "https://example.com/feed-v2.xml" --dry-run
969
- direct clients update --client-id 999 --phone +70000000000 --fax +70000000001 --email user@example.com --city Moscow --dry-run
970
- 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
971
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
972
980
  direct agencyclients add-passport-organization-member --passport-organization-login org-login --role CHIEF --invite-email user@example.com --dry-run
973
- 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
974
982
  ```
975
983
 
984
+ `direct agencyclients add` runtime-deprecated в Yandex Direct и блокируется CLI. Используйте `direct agencyclients add-passport-organization`.
985
+
976
986
  ### Известная неподдерживаемая API-операция
977
987
 
978
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
@@ -0,0 +1,163 @@
1
+ from typing import List, Iterator, Union
2
+
3
+ from requests import Response
4
+
5
+ class YandexDirectBaseMethodsClientResponse:
6
+ @property
7
+ def data(self) -> dict: ...
8
+ @property
9
+ def request_kwargs(self) -> dict: ...
10
+ @property
11
+ def response(self) -> Response: ...
12
+ @property
13
+ def status_code(self) -> int: ...
14
+ def __getitem__(self, item) -> Union[dict, list]: ...
15
+ def __iter__(self) -> Iterator: ...
16
+
17
+ # Yandex Direct management.
18
+ class YandexDirectClientResponse(YandexDirectBaseMethodsClientResponse):
19
+ def pages(
20
+ self, *, max_pages: int = None
21
+ ) -> Iterator["YandexDirectPageIteratorExecutor"]: ...
22
+ def items(self, *, max_items: int = None) -> Iterator[dict]: ...
23
+ def iter_items(
24
+ self, *, max_pages: int = None, max_items: int = None
25
+ ) -> Iterator[dict]: ...
26
+ def extract(self) -> List[dict]: ...
27
+
28
+ class YandexDirectClientExecutorResponse(YandexDirectBaseMethodsClientResponse):
29
+ def __call__(self) -> YandexDirectClientResponse: ...
30
+
31
+ class YandexDirectClientExecutor:
32
+ def open_docs(self) -> YandexDirectClientExecutor:
33
+ """Open API official docs of resource in browser."""
34
+ def open_in_browser(self) -> YandexDirectClientExecutor:
35
+ """Send a request in the browser."""
36
+ def help(self) -> YandexDirectClientExecutor:
37
+ """Print docs of resource."""
38
+ def get(
39
+ self, *, params: dict = None, data: dict = None, headers: dict = None
40
+ ) -> YandexDirectClientExecutorResponse:
41
+ """
42
+ Send HTTP 'GET' request.
43
+
44
+ :param params: querystring arguments in the URL
45
+ :param data: send data in the body of the request
46
+ """
47
+ def post(
48
+ self, *, params: dict = None, data: dict = None, headers: dict = None
49
+ ) -> YandexDirectClientExecutorResponse:
50
+ """
51
+ Send HTTP 'POST' request.
52
+
53
+ :param params: querystring arguments in the URL
54
+ :param data: send data in the body of the request
55
+ """
56
+
57
+ class YandexDirectPageIteratorResponse(YandexDirectBaseMethodsClientResponse):
58
+ def items(self, *, max_items: int = None) -> Iterator[dict]: ...
59
+
60
+ class YandexDirectPageIteratorExecutor(YandexDirectBaseMethodsClientResponse):
61
+ def __call__(self) -> YandexDirectPageIteratorResponse: ...
62
+
63
+ # Yandex Direct reports.
64
+ class YandexDirectClientReportResponse(YandexDirectBaseMethodsClientResponse):
65
+ def iter_lines(self) -> Iterator[str]: ...
66
+ def iter_values(self) -> Iterator[list]: ...
67
+ def iter_dicts(self) -> Iterator[dict]: ...
68
+ def to_lines(self) -> List[str]: ...
69
+ def to_values(self) -> List[list]: ...
70
+ def to_columns(self) -> List[list]: ...
71
+ def to_dicts(self) -> List[dict]: ...
72
+
73
+ class YandexDirectClientReportExecutorResponse(YandexDirectBaseMethodsClientResponse):
74
+ def __call__(self) -> YandexDirectClientReportResponse: ...
75
+ @property
76
+ def columns(self) -> List[str]: ...
77
+
78
+ class YandexDirectClientReportExecutor:
79
+ def open_docs(self) -> YandexDirectClientReportExecutor:
80
+ """Open API official docs of resource in browser."""
81
+ def open_in_browser(self) -> YandexDirectClientReportExecutor:
82
+ """Send a request in the browser."""
83
+ def help(self) -> YandexDirectClientReportExecutor:
84
+ """Print docs of resource."""
85
+ def post(
86
+ self, *, params: dict = None, data: dict = None, headers: dict = None
87
+ ) -> YandexDirectClientReportExecutorResponse:
88
+ """
89
+ Send HTTP 'POST' request.
90
+
91
+ :param params: querystring arguments in the URL
92
+ :param data: send data in the body of the request
93
+ """
94
+
95
+ # Main.
96
+ class YandexDirect:
97
+ def __init__(
98
+ self,
99
+ *,
100
+ access_token: str,
101
+ login: str = None,
102
+ is_sandbox: bool = False,
103
+ retry_if_not_enough_units: bool = False,
104
+ retry_if_exceeded_limit: bool = True,
105
+ retries_if_server_error: int = 5,
106
+ language: str = None,
107
+ processing_mode: str = "offline",
108
+ wait_report: bool = True,
109
+ return_money_in_micros: bool = False,
110
+ skip_report_header: bool = True,
111
+ skip_column_header: bool = False,
112
+ skip_report_summary: bool = True,
113
+ ):
114
+ """
115
+ Official documentation of the reports resource: https://yandex.ru/dev/direct/doc/ref-v5/concepts/about.html
116
+ Official documentation of other resources: https://yandex.ru/dev/direct/doc/reports/how-to.html
117
+
118
+ :param access_token: Access token.
119
+ :param login: If you are making inquiries from an agent account, you must be sure to specify the account login.
120
+ :param is_sandbox: Enable sandbox.
121
+ :param retry_if_not_enough_units: Repeat request when units run out
122
+ :param retry_if_exceeded_limit: Repeat the request if the limits on the number of reports or requests are exceeded.
123
+ :param retries_if_server_error: Number of retries when server errors occur.
124
+ :param language: The language in which the data for directories and errors will be returned.
125
+
126
+ :param processing_mode: (report resource) Report generation mode: online, offline or auto.
127
+ :param wait_report: (report resource) When requesting a report, it will wait until the report is prepared and download it.
128
+ :param return_money_in_micros: (report resource) Monetary values in the report are returned in currency with an accuracy of two decimal places.
129
+ :param skip_report_header: (report resource) Do not display a line with the report name and date range in the report.
130
+ :param skip_column_header: (report resource) Do not display a line with field names in the report.
131
+ :param skip_report_summary: (report resource) Do not display a line with the number of statistics lines in the report.
132
+ """
133
+ def reports(self) -> YandexDirectClientReportExecutor: ...
134
+ def adextensions(self) -> YandexDirectClientExecutor: ...
135
+ def adgroups(self) -> YandexDirectClientExecutor: ...
136
+ def adimages(self) -> YandexDirectClientExecutor: ...
137
+ def advideos(self) -> YandexDirectClientExecutor: ...
138
+ def ads(self) -> YandexDirectClientExecutor: ...
139
+ def agencyclients(self) -> YandexDirectClientExecutor: ...
140
+ def audiencetargets(self) -> YandexDirectClientExecutor: ...
141
+ def bidmodifiers(self) -> YandexDirectClientExecutor: ...
142
+ def bids(self) -> YandexDirectClientExecutor: ...
143
+ def businesses(self) -> YandexDirectClientExecutor: ...
144
+ def campaigns(self) -> YandexDirectClientExecutor: ...
145
+ def changes(self) -> YandexDirectClientExecutor: ...
146
+ def clients(self) -> YandexDirectClientExecutor: ...
147
+ def creatives(self) -> YandexDirectClientExecutor: ...
148
+ def debugtoken(self, *, client_id: str) -> YandexDirectClientExecutor: ...
149
+ def dictionaries(self) -> YandexDirectClientExecutor: ...
150
+ def dynamicads(self) -> YandexDirectClientExecutor: ...
151
+ def dynamicfeedadtargets(self) -> YandexDirectClientExecutor: ...
152
+ def feeds(self) -> YandexDirectClientExecutor: ...
153
+ def keywordbids(self) -> YandexDirectClientExecutor: ...
154
+ def keywords(self) -> YandexDirectClientExecutor: ...
155
+ def keywordsresearch(self) -> YandexDirectClientExecutor: ...
156
+ def leads(self) -> YandexDirectClientExecutor: ...
157
+ def negativekeywordsharedsets(self) -> YandexDirectClientExecutor: ...
158
+ def retargeting(self) -> YandexDirectClientExecutor: ...
159
+ def sitelinks(self) -> YandexDirectClientExecutor: ...
160
+ def smartadtargets(self) -> YandexDirectClientExecutor: ...
161
+ def strategies(self) -> YandexDirectClientExecutor: ...
162
+ def turbopages(self) -> YandexDirectClientExecutor: ...
163
+ def vcards(self) -> YandexDirectClientExecutor: ...
@@ -0,0 +1,9 @@
1
+ from .adapter import V4LiveClientAdapter, YandexDirectV4Live
2
+ from .resource_mapping import RESOURCE_MAPPING_V4_LIVE, SUPPORTED_V4_METHODS
3
+
4
+ __all__ = [
5
+ "V4LiveClientAdapter",
6
+ "YandexDirectV4Live",
7
+ "RESOURCE_MAPPING_V4_LIVE",
8
+ "SUPPORTED_V4_METHODS",
9
+ ]