direct-cli 0.3.0__tar.gz → 0.3.2__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 (205) hide show
  1. {direct_cli-0.3.0 → direct_cli-0.3.2}/PKG-INFO +62 -7
  2. {direct_cli-0.3.0 → direct_cli-0.3.2}/README.md +61 -6
  3. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_smoke_probes.py +8 -3
  4. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +1 -1
  5. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +15 -6
  6. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +2 -0
  7. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/api.py +59 -0
  8. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/cli.py +18 -0
  9. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/adextensions.py +27 -2
  10. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/adgroups.py +36 -1
  11. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/adimages.py +27 -6
  12. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/ads.py +55 -4
  13. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/advideos.py +11 -6
  14. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/audiencetargets.py +18 -1
  15. direct_cli-0.3.2/direct_cli/commands/balance.py +55 -0
  16. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/bidmodifiers.py +16 -0
  17. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/bids.py +10 -1
  18. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/businesses.py +9 -2
  19. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/campaigns.py +40 -20
  20. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/creatives.py +11 -1
  21. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/dynamicads.py +26 -1
  22. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/dynamicfeedadtargets.py +22 -2
  23. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/feeds.py +9 -2
  24. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/keywordbids.py +18 -2
  25. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/keywords.py +50 -13
  26. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/leads.py +23 -1
  27. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/negativekeywordsharedsets.py +10 -5
  28. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/reports.py +124 -22
  29. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/sitelinks.py +9 -2
  30. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/smartadtargets.py +26 -1
  31. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/turbopages.py +16 -2
  32. direct_cli-0.3.2/direct_cli/commands/v4account.py +218 -0
  33. direct_cli-0.3.2/direct_cli/commands/v4events.py +118 -0
  34. direct_cli-0.3.2/direct_cli/commands/v4finance.py +298 -0
  35. direct_cli-0.3.2/direct_cli/commands/v4goals.py +103 -0
  36. direct_cli-0.3.2/direct_cli/commands/v4shells.py +25 -0
  37. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/vcards.py +13 -3
  38. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/reports_coverage.py +113 -15
  39. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/smoke_matrix.py +18 -5
  40. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/utils.py +25 -0
  41. direct_cli-0.3.2/direct_cli/v4/__init__.py +17 -0
  42. direct_cli-0.3.2/direct_cli/v4/money.py +35 -0
  43. direct_cli-0.3.2/direct_cli/v4_contracts.py +494 -0
  44. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli.egg-info/PKG-INFO +62 -7
  45. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli.egg-info/SOURCES.txt +20 -0
  46. {direct_cli-0.3.0 → direct_cli-0.3.2}/pyproject.toml +2 -1
  47. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/build_api_coverage_report.py +1 -0
  48. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/test_dangerous_commands.sh +4 -0
  49. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/test_safe_commands.sh +34 -1
  50. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/API_COVERAGE.md +22 -2
  51. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/MANUAL_COVERAGE.md +12 -0
  52. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/api_coverage_payloads.py +30 -0
  53. direct_cli-0.3.0/tests/reports_cache/raw/spec.html → direct_cli-0.3.2/tests/reports_cache/raw/period.html +9 -9
  54. direct_cli-0.3.2/tests/reports_cache/raw/spec.html +660 -0
  55. direct_cli-0.3.2/tests/reports_cache/spec.json +1645 -0
  56. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_api_coverage.py +210 -19
  57. direct_cli-0.3.2/tests/test_balance.py +137 -0
  58. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_comprehensive.py +8 -0
  59. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_dry_run.py +318 -2
  60. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_integration.py +3 -4
  61. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_smoke_matrix.py +25 -8
  62. direct_cli-0.3.2/tests/test_v4_contracts.py +292 -0
  63. direct_cli-0.3.2/tests/test_v4_foundation.py +95 -0
  64. direct_cli-0.3.2/tests/test_v4_live_contracts.py +154 -0
  65. direct_cli-0.3.2/tests/test_v4_safety.py +15 -0
  66. direct_cli-0.3.2/tests/test_v4account.py +304 -0
  67. direct_cli-0.3.2/tests/test_v4events.py +162 -0
  68. direct_cli-0.3.2/tests/test_v4finance_money.py +320 -0
  69. direct_cli-0.3.2/tests/test_v4finance_read.py +202 -0
  70. direct_cli-0.3.2/tests/test_v4goals.py +190 -0
  71. direct_cli-0.3.0/tests/reports_cache/spec.json +0 -583
  72. {direct_cli-0.3.0 → direct_cli-0.3.2}/.env.example +0 -0
  73. {direct_cli-0.3.0 → direct_cli-0.3.2}/.github/copilot-instructions.md +0 -0
  74. {direct_cli-0.3.0 → direct_cli-0.3.2}/.github/workflows/api-coverage.yml +0 -0
  75. {direct_cli-0.3.0 → direct_cli-0.3.2}/.github/workflows/claude-code-review.yml +0 -0
  76. {direct_cli-0.3.0 → direct_cli-0.3.2}/.github/workflows/claude.yml +0 -0
  77. {direct_cli-0.3.0 → direct_cli-0.3.2}/.gitignore +0 -0
  78. {direct_cli-0.3.0 → direct_cli-0.3.2}/AGENTS.md +0 -0
  79. {direct_cli-0.3.0 → direct_cli-0.3.2}/CLAUDE.md +0 -0
  80. {direct_cli-0.3.0 → direct_cli-0.3.2}/MANIFEST.in +0 -0
  81. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/__init__.py +0 -0
  82. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_deprecated.py +0 -0
  83. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_vendor/__init__.py +0 -0
  84. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +0 -0
  85. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
  86. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +0 -0
  87. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +0 -0
  88. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +0 -0
  89. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +0 -0
  90. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/auth.py +0 -0
  91. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/__init__.py +0 -0
  92. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/agencyclients.py +0 -0
  93. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/auth.py +0 -0
  94. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/changes.py +0 -0
  95. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/clients.py +0 -0
  96. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/dictionaries.py +0 -0
  97. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/keywordsresearch.py +0 -0
  98. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/retargeting.py +0 -0
  99. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/commands/strategies.py +0 -0
  100. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/output.py +0 -0
  101. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli/wsdl_coverage.py +0 -0
  102. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli.egg-info/dependency_links.txt +0 -0
  103. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli.egg-info/entry_points.txt +0 -0
  104. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli.egg-info/requires.txt +0 -0
  105. {direct_cli-0.3.0 → direct_cli-0.3.2}/direct_cli.egg-info/top_level.txt +0 -0
  106. {direct_cli-0.3.0 → direct_cli-0.3.2}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
  107. {direct_cli-0.3.0 → direct_cli-0.3.2}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
  108. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/anonymize_cassettes.py +0 -0
  109. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/build_api_coverage_checklist.py +0 -0
  110. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/check_reports_drift.py +0 -0
  111. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/check_wsdl_drift.py +0 -0
  112. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/patch_vendor_imports.py +0 -0
  113. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/refresh_reports_cache.py +0 -0
  114. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/refresh_wsdl_cache.py +0 -0
  115. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/release_pypi.sh +0 -0
  116. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/sandbox_write_live.py +0 -0
  117. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/test_sandbox_write.sh +0 -0
  118. {direct_cli-0.3.0 → direct_cli-0.3.2}/scripts/update_vendor.sh +0 -0
  119. {direct_cli-0.3.0 → direct_cli-0.3.2}/setup.cfg +0 -0
  120. {direct_cli-0.3.0 → direct_cli-0.3.2}/setup.py +0 -0
  121. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/API_ISSUE_AUDIT.md +0 -0
  122. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/__init__.py +0 -0
  123. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_adgroups_add_update_delete.yaml +0 -0
  124. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_adimages_add_get_delete.yaml +0 -0
  125. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_ads_add_update_delete.yaml +0 -0
  126. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_ads_suspend_resume_archive_unarchive.yaml +0 -0
  127. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_advideos_add_get.yaml +0 -0
  128. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_add_delete.yaml +0 -0
  129. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_audiencetargets_suspend_resume.yaml +0 -0
  130. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_bids_set.yaml +0 -0
  131. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_campaign_create_get_delete.yaml +0 -0
  132. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_creatives_chain_advideo_to_creative.yaml +0 -0
  133. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_add_delete.yaml +0 -0
  134. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_dynamicads_suspend_resume.yaml +0 -0
  135. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_keywordbids_set.yaml +0 -0
  136. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_add_update_delete.yaml +0 -0
  137. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_keywords_suspend_resume.yaml +0 -0
  138. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_sitelinks_add_get_delete.yaml +0 -0
  139. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_add_update_delete.yaml +0 -0
  140. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_live_write/test_live_draft_smartadtargets_suspend_resume.yaml +0 -0
  141. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
  142. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
  143. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
  144. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
  145. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
  146. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
  147. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
  148. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
  149. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
  150. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
  151. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
  152. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
  153. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
  154. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
  155. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
  156. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
  157. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
  158. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
  159. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
  160. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/conftest.py +0 -0
  161. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/fixtures/test-video.mp4 +0 -0
  162. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/reports_cache/raw/fields-list.html +0 -0
  163. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/reports_cache/raw/headers.html +0 -0
  164. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/reports_cache/raw/type.html +0 -0
  165. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_auth_bw.py +0 -0
  166. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_auth_oauth.py +0 -0
  167. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_auth_op.py +0 -0
  168. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_cli.py +0 -0
  169. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_integration_live_write.py +0 -0
  170. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_integration_write.py +0 -0
  171. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_reports_drift.py +0 -0
  172. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_transport_contract.py +0 -0
  173. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/test_vendor_imports.py +0 -0
  174. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/adextensions.xml +0 -0
  175. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/adgroups.xml +0 -0
  176. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/adimages.xml +0 -0
  177. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/ads.xml +0 -0
  178. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/advideos.xml +0 -0
  179. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/agencyclients.xml +0 -0
  180. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/audiencetargets.xml +0 -0
  181. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/bidmodifiers.xml +0 -0
  182. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/bids.xml +0 -0
  183. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/businesses.xml +0 -0
  184. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/campaigns.xml +0 -0
  185. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/changes.xml +0 -0
  186. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/clients.xml +0 -0
  187. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/creatives.xml +0 -0
  188. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/dictionaries.xml +0 -0
  189. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
  190. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
  191. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/feeds.xml +0 -0
  192. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/imports/adextensiontypes.xsd +0 -0
  193. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/imports/general.xsd +0 -0
  194. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/imports/generalclients.xsd +0 -0
  195. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/keywordbids.xml +0 -0
  196. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/keywords.xml +0 -0
  197. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/keywordsresearch.xml +0 -0
  198. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/leads.xml +0 -0
  199. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
  200. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/retargetinglists.xml +0 -0
  201. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/sitelinks.xml +0 -0
  202. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/smartadtargets.xml +0 -0
  203. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/strategies.xml +0 -0
  204. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/turbopages.xml +0 -0
  205. {direct_cli-0.3.0 → direct_cli-0.3.2}/tests/wsdl_cache/vcards.xml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: direct-cli
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Command-line interface for Yandex Direct API
5
5
  Author: axisrow
6
6
  License: MIT
@@ -118,6 +118,18 @@ Install with `pip install direct-cli`, then run commands with `direct`.
118
118
  Invoking the deprecated `direct-cli` entrypoint exits with
119
119
  `use direct instead of direct-cli`.
120
120
 
121
+ ### Quick Start: Check Balance
122
+
123
+ Yandex removed the legacy v4 `GetBalance` method. Direct CLI uses the v4 Live
124
+ `AccountManagement` method with `Action=Get` for `direct balance`, returning
125
+ money fields such as `Amount`, `AmountAvailableForTransfer`, and `Currency`.
126
+
127
+ ```bash
128
+ direct balance
129
+ direct balance --logins client-login,other-client --format table
130
+ direct balance --logins client-login --dry-run
131
+ ```
132
+
121
133
  ### Global Options
122
134
 
123
135
  | Option | Description |
@@ -127,6 +139,47 @@ Invoking the deprecated `direct-cli` entrypoint exits with
127
139
  | `--profile` | Credential profile name |
128
140
  | `--sandbox` | Use sandbox API |
129
141
 
142
+ ### V4 Live Goals
143
+
144
+ ```bash
145
+ direct v4goals get-stat-goals --campaign-ids 123,456
146
+ direct v4goals get-retargeting-goals --campaign-ids 123,456 --format table
147
+ direct v4goals get-stat-goals --campaign-ids 123 --dry-run
148
+ ```
149
+
150
+ ### V4 Live Events
151
+
152
+ ```bash
153
+ direct v4events get-events-log --from 2026-04-14T00:00:00 --to 2026-04-15T00:00:00
154
+ direct v4events get-events-log --from 2026-04-14T00:00:00 --to 2026-04-15T00:00:00 --currency RUB --limit 100 --offset 0 --format table
155
+ ```
156
+
157
+ ### V4 Live Finance
158
+
159
+ `get-credit-limits` requires a financial token and operation number. Pass them
160
+ with `--finance-token` and `--operation-num`, or set
161
+ `YANDEX_DIRECT_FINANCE_TOKEN` and `YANDEX_DIRECT_OPERATION_NUM`.
162
+ Money mutation commands are dry-run-only in this release and always require
163
+ `--dry-run`; dry-run output masks the financial token.
164
+
165
+ ```bash
166
+ direct v4finance get-credit-limits --logins client-login --finance-token FINANCE_TOKEN --operation-num 123
167
+ direct v4finance get-credit-limits --logins client-login,other-client --format table
168
+ direct v4finance check-payment --custom-transaction-id A123456789012345678901234567890B
169
+ direct v4finance transfer-money --from-campaign-id 123 --to-campaign-id 456 --amount 100.50 --finance-token FINANCE_TOKEN --operation-num 123 --dry-run
170
+ direct v4finance pay-campaigns --campaign-id 123 --amount 100.50 --contract-id CONTRACT_ID --pay-method CREDIT --finance-token FINANCE_TOKEN --operation-num 123 --dry-run
171
+ ```
172
+
173
+ ### V4 Live Shared Account
174
+
175
+ Shared-account mutations are dry-run-only in this release and always require
176
+ `--dry-run`.
177
+
178
+ ```bash
179
+ direct v4account enable-shared-account --client-login client-login --dry-run
180
+ direct v4account account-management --action Update --account-id 1327944 --day-budget 100.50 --spend-mode Default --money-in-sms Yes --money-out-sms No --email ops@example.com --money-warning-value 25 --dry-run
181
+ ```
182
+
130
183
  ### CLI Convention
131
184
 
132
185
  The current CLI convention is defined as follows.
@@ -324,6 +377,7 @@ direct keywords delete --id 88888
324
377
  ```bash
325
378
  # Get a report (saved to file)
326
379
  direct reports get --type CAMPAIGN_PERFORMANCE_REPORT --from 2024-01-01 --to 2024-01-31 --name "January Report" --fields "Date,CampaignId,Clicks,Cost" --format csv --output report.csv
380
+ direct reports get --type CUSTOM_REPORT --from 2024-01-01 --to 2024-01-31 --name "Goals Report" --fields "Date,CampaignId,GoalsRoi" --goals 12345,67890 --attribution-models AUTO --format csv --output goals-report.csv
327
381
 
328
382
  # List available report types
329
383
  direct reports list-types
@@ -489,9 +543,9 @@ Current command surface:
489
543
  | WSDL-backed API services | 29 |
490
544
  | Supported API services including Reports | 30 |
491
545
  | WSDL operations | 112 |
492
- | CLI groups including `auth` | 31 |
493
- | CLI subcommands including `auth` | 122 |
494
- | API CLI subcommands excluding `auth` | 118 |
546
+ | CLI groups including `auth` | 39 |
547
+ | CLI subcommands including `auth` | 130 |
548
+ | API CLI subcommands excluding `auth` | 126 |
495
549
 
496
550
  ### API Coverage And Drift Monitoring
497
551
 
@@ -946,6 +1000,7 @@ direct keywords delete --id 88888
946
1000
  ```bash
947
1001
  # Сформировать отчёт (сохраняется в файл)
948
1002
  direct reports get --type CAMPAIGN_PERFORMANCE_REPORT --from 2024-01-01 --to 2024-01-31 --name "Отчёт за январь" --fields "Date,CampaignId,Clicks,Cost" --format csv --output report.csv
1003
+ direct reports get --type CUSTOM_REPORT --from 2024-01-01 --to 2024-01-31 --name "Отчёт по целям" --fields "Date,CampaignId,GoalsRoi" --goals 12345,67890 --attribution-models AUTO --format csv --output goals-report.csv
949
1004
 
950
1005
  # Список доступных типов отчётов
951
1006
  direct reports list-types
@@ -1112,9 +1167,9 @@ YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rew
1112
1167
  | WSDL-backed API services | 29 |
1113
1168
  | API services с учётом Reports | 30 |
1114
1169
  | WSDL operations | 112 |
1115
- | CLI groups с `auth` | 31 |
1116
- | CLI subcommands с `auth` | 122 |
1117
- | API CLI subcommands без `auth` | 118 |
1170
+ | CLI groups с `auth` | 39 |
1171
+ | CLI subcommands с `auth` | 130 |
1172
+ | API CLI subcommands без `auth` | 126 |
1118
1173
 
1119
1174
  #### Live sandbox write smoke
1120
1175
 
@@ -79,6 +79,18 @@ Install with `pip install direct-cli`, then run commands with `direct`.
79
79
  Invoking the deprecated `direct-cli` entrypoint exits with
80
80
  `use direct instead of direct-cli`.
81
81
 
82
+ ### Quick Start: Check Balance
83
+
84
+ Yandex removed the legacy v4 `GetBalance` method. Direct CLI uses the v4 Live
85
+ `AccountManagement` method with `Action=Get` for `direct balance`, returning
86
+ money fields such as `Amount`, `AmountAvailableForTransfer`, and `Currency`.
87
+
88
+ ```bash
89
+ direct balance
90
+ direct balance --logins client-login,other-client --format table
91
+ direct balance --logins client-login --dry-run
92
+ ```
93
+
82
94
  ### Global Options
83
95
 
84
96
  | Option | Description |
@@ -88,6 +100,47 @@ Invoking the deprecated `direct-cli` entrypoint exits with
88
100
  | `--profile` | Credential profile name |
89
101
  | `--sandbox` | Use sandbox API |
90
102
 
103
+ ### V4 Live Goals
104
+
105
+ ```bash
106
+ direct v4goals get-stat-goals --campaign-ids 123,456
107
+ direct v4goals get-retargeting-goals --campaign-ids 123,456 --format table
108
+ direct v4goals get-stat-goals --campaign-ids 123 --dry-run
109
+ ```
110
+
111
+ ### V4 Live Events
112
+
113
+ ```bash
114
+ direct v4events get-events-log --from 2026-04-14T00:00:00 --to 2026-04-15T00:00:00
115
+ direct v4events get-events-log --from 2026-04-14T00:00:00 --to 2026-04-15T00:00:00 --currency RUB --limit 100 --offset 0 --format table
116
+ ```
117
+
118
+ ### V4 Live Finance
119
+
120
+ `get-credit-limits` requires a financial token and operation number. Pass them
121
+ with `--finance-token` and `--operation-num`, or set
122
+ `YANDEX_DIRECT_FINANCE_TOKEN` and `YANDEX_DIRECT_OPERATION_NUM`.
123
+ Money mutation commands are dry-run-only in this release and always require
124
+ `--dry-run`; dry-run output masks the financial token.
125
+
126
+ ```bash
127
+ direct v4finance get-credit-limits --logins client-login --finance-token FINANCE_TOKEN --operation-num 123
128
+ direct v4finance get-credit-limits --logins client-login,other-client --format table
129
+ direct v4finance check-payment --custom-transaction-id A123456789012345678901234567890B
130
+ direct v4finance transfer-money --from-campaign-id 123 --to-campaign-id 456 --amount 100.50 --finance-token FINANCE_TOKEN --operation-num 123 --dry-run
131
+ direct v4finance pay-campaigns --campaign-id 123 --amount 100.50 --contract-id CONTRACT_ID --pay-method CREDIT --finance-token FINANCE_TOKEN --operation-num 123 --dry-run
132
+ ```
133
+
134
+ ### V4 Live Shared Account
135
+
136
+ Shared-account mutations are dry-run-only in this release and always require
137
+ `--dry-run`.
138
+
139
+ ```bash
140
+ direct v4account enable-shared-account --client-login client-login --dry-run
141
+ direct v4account account-management --action Update --account-id 1327944 --day-budget 100.50 --spend-mode Default --money-in-sms Yes --money-out-sms No --email ops@example.com --money-warning-value 25 --dry-run
142
+ ```
143
+
91
144
  ### CLI Convention
92
145
 
93
146
  The current CLI convention is defined as follows.
@@ -285,6 +338,7 @@ direct keywords delete --id 88888
285
338
  ```bash
286
339
  # Get a report (saved to file)
287
340
  direct reports get --type CAMPAIGN_PERFORMANCE_REPORT --from 2024-01-01 --to 2024-01-31 --name "January Report" --fields "Date,CampaignId,Clicks,Cost" --format csv --output report.csv
341
+ direct reports get --type CUSTOM_REPORT --from 2024-01-01 --to 2024-01-31 --name "Goals Report" --fields "Date,CampaignId,GoalsRoi" --goals 12345,67890 --attribution-models AUTO --format csv --output goals-report.csv
288
342
 
289
343
  # List available report types
290
344
  direct reports list-types
@@ -450,9 +504,9 @@ Current command surface:
450
504
  | WSDL-backed API services | 29 |
451
505
  | Supported API services including Reports | 30 |
452
506
  | WSDL operations | 112 |
453
- | CLI groups including `auth` | 31 |
454
- | CLI subcommands including `auth` | 122 |
455
- | API CLI subcommands excluding `auth` | 118 |
507
+ | CLI groups including `auth` | 39 |
508
+ | CLI subcommands including `auth` | 130 |
509
+ | API CLI subcommands excluding `auth` | 126 |
456
510
 
457
511
  ### API Coverage And Drift Monitoring
458
512
 
@@ -907,6 +961,7 @@ direct keywords delete --id 88888
907
961
  ```bash
908
962
  # Сформировать отчёт (сохраняется в файл)
909
963
  direct reports get --type CAMPAIGN_PERFORMANCE_REPORT --from 2024-01-01 --to 2024-01-31 --name "Отчёт за январь" --fields "Date,CampaignId,Clicks,Cost" --format csv --output report.csv
964
+ direct reports get --type CUSTOM_REPORT --from 2024-01-01 --to 2024-01-31 --name "Отчёт по целям" --fields "Date,CampaignId,GoalsRoi" --goals 12345,67890 --attribution-models AUTO --format csv --output goals-report.csv
910
965
 
911
966
  # Список доступных типов отчётов
912
967
  direct reports list-types
@@ -1073,9 +1128,9 @@ YANDEX_DIRECT_LIVE_WRITE=1 pytest -m integration_live_write -v --record-mode=rew
1073
1128
  | WSDL-backed API services | 29 |
1074
1129
  | API services с учётом Reports | 30 |
1075
1130
  | WSDL operations | 112 |
1076
- | CLI groups с `auth` | 31 |
1077
- | CLI subcommands с `auth` | 122 |
1078
- | API CLI subcommands без `auth` | 118 |
1131
+ | CLI groups с `auth` | 39 |
1132
+ | CLI subcommands с `auth` | 130 |
1133
+ | API CLI subcommands без `auth` | 126 |
1079
1134
 
1080
1135
  #### Live sandbox write smoke
1081
1136
 
@@ -8,7 +8,11 @@ from typing import Any, Optional
8
8
 
9
9
  from .api import create_client
10
10
 
11
- VIDEO_CREATIVE_TYPES = {"VIDEO_EXTENSION_CREATIVE", "CPM_VIDEO_CREATIVE"}
11
+ VIDEO_CREATIVE_TYPES = {
12
+ "VIDEO_EXTENSION_CREATIVE",
13
+ "CPM_VIDEO_CREATIVE",
14
+ "CPC_VIDEO_CREATIVE",
15
+ }
12
16
 
13
17
 
14
18
  def _extract_items(response: Any) -> list[dict[str, Any]]:
@@ -18,7 +22,7 @@ def _extract_items(response: Any) -> list[dict[str, Any]]:
18
22
 
19
23
 
20
24
  def _advideo_get_accepts(client: Any, candidate: str) -> bool:
21
- """Return whether advideos.get accepts and returns the candidate ID."""
25
+ """Return whether advideos.get accepts the candidate ID."""
22
26
  body = {
23
27
  "method": "get",
24
28
  "params": {
@@ -28,7 +32,8 @@ def _advideo_get_accepts(client: Any, candidate: str) -> bool:
28
32
  },
29
33
  }
30
34
  try:
31
- return bool(_extract_items(client.advideos().post(data=body)))
35
+ _extract_items(client.advideos().post(data=body))
36
+ return True
32
37
  except Exception:
33
38
  return False
34
39
 
@@ -1,7 +1,7 @@
1
1
 
2
2
  __author__ = 'Pavel Maksimov'
3
3
  __email__ = 'vur21@ya.ru'
4
- __version__ = '2026.4.27'
4
+ __version__ = '2026.4.28'
5
5
 
6
6
 
7
7
  from .resource_mapping import *
@@ -43,10 +43,14 @@ class V4LiveClientAdapter(JSONAdapterMixin, TapiAdapter):
43
43
  token = api_params.get("access_token")
44
44
  login = api_params.get("login")
45
45
  language = api_params.get("language", "en")
46
-
47
- # Enrich the JSON body with token / locale / login (param.login for
48
- # agent calls). format_data_to_request does not see api_params, so we
49
- # do this here, after super() has already serialised the user data.
46
+ finance_token = api_params.get("finance_token")
47
+ operation_num = api_params.get("operation_num")
48
+
49
+ # Enrich the JSON body with top-level v4 Live fields.
50
+ # format_data_to_request does not see api_params, so we do this here,
51
+ # after super() has already serialised the user data. Agency/client
52
+ # selection is transport-level (Client-Login header); method params
53
+ # must stay schema-shaped.
50
54
  raw = params.get("data")
51
55
  if raw:
52
56
  if isinstance(raw, (bytes, bytearray)):
@@ -66,14 +70,19 @@ class V4LiveClientAdapter(JSONAdapterMixin, TapiAdapter):
66
70
  body.setdefault("token", token)
67
71
  if language:
68
72
  body.setdefault("locale", language)
69
- if login and isinstance(body.get("param"), dict):
70
- body["param"].setdefault("login", login)
73
+ if finance_token:
74
+ body.setdefault("finance_token", finance_token)
75
+ if operation_num is not None:
76
+ body.setdefault("operation_num", operation_num)
71
77
 
72
78
  params["data"] = orjson.dumps(body)
73
79
 
74
80
  if token:
75
81
  params["headers"]["Authorization"] = "Bearer {}".format(token)
76
82
 
83
+ if login:
84
+ params["headers"]["Client-Login"] = login
85
+
77
86
  return params
78
87
 
79
88
  def format_data_to_request(self, data) -> Optional[bytes]:
@@ -49,6 +49,8 @@ class YandexDirectV4Live:
49
49
  language: str = "en",
50
50
  retry_if_exceeded_limit: bool = True,
51
51
  retries_if_server_error: int = 5,
52
+ finance_token: Optional[str] = None,
53
+ operation_num: Optional[int] = None,
52
54
  ) -> None: ...
53
55
 
54
56
  def v4live(self) -> V4LiveExecutor: ...
@@ -5,6 +5,7 @@ API client wrapper for Direct CLI
5
5
  from typing import Optional, Dict, Any, List
6
6
 
7
7
  from direct_cli._vendor.tapi_yandex_direct import YandexDirect
8
+ from direct_cli._vendor.tapi_yandex_direct.v4 import YandexDirectV4Live
8
9
  from .auth import get_credentials
9
10
 
10
11
 
@@ -67,6 +68,64 @@ def create_client(
67
68
  )
68
69
 
69
70
 
71
+ def create_v4_client(
72
+ token: Optional[str] = None,
73
+ login: Optional[str] = None,
74
+ profile: Optional[str] = None,
75
+ sandbox: bool = False,
76
+ op_token_ref: Optional[str] = None,
77
+ op_login_ref: Optional[str] = None,
78
+ bw_token_ref: Optional[str] = None,
79
+ bw_login_ref: Optional[str] = None,
80
+ language: Optional[str] = None,
81
+ retry_if_exceeded_limit: bool = True,
82
+ retries_if_server_error: int = 5,
83
+ finance_token: Optional[str] = None,
84
+ operation_num: Optional[int] = None,
85
+ ) -> YandexDirectV4Live:
86
+ """
87
+ Create YandexDirect v4 Live client.
88
+
89
+ Args:
90
+ token: API access token
91
+ login: Client login (for agency accounts)
92
+ profile: Credential profile name
93
+ sandbox: Use sandbox API
94
+ op_token_ref: 1Password secret reference for token
95
+ op_login_ref: 1Password secret reference for login
96
+ bw_token_ref: Bitwarden item name/ID for token
97
+ bw_login_ref: Bitwarden item name/ID for login
98
+ language: API locale
99
+ retry_if_exceeded_limit: Retry when the API limit is exceeded
100
+ retries_if_server_error: Number of retries for server errors
101
+ finance_token: Financial token for v4 Live finance methods
102
+ operation_num: Financial operation number for v4 Live finance methods
103
+
104
+ Returns:
105
+ YandexDirect v4 Live client instance
106
+ """
107
+ final_token, final_login = get_credentials(
108
+ token,
109
+ login,
110
+ profile=profile,
111
+ op_token_ref=op_token_ref,
112
+ op_login_ref=op_login_ref,
113
+ bw_token_ref=bw_token_ref,
114
+ bw_login_ref=bw_login_ref,
115
+ )
116
+
117
+ return YandexDirectV4Live(
118
+ access_token=final_token,
119
+ login=final_login,
120
+ is_sandbox=sandbox,
121
+ language=language or "en",
122
+ retry_if_exceeded_limit=retry_if_exceeded_limit,
123
+ retries_if_server_error=retries_if_server_error,
124
+ finance_token=finance_token,
125
+ operation_num=operation_num,
126
+ )
127
+
128
+
70
129
  def fetch_all_pages(
71
130
  client: YandexDirect,
72
131
  resource_name: str,
@@ -41,6 +41,16 @@ from .commands.advideos import advideos
41
41
  from .commands.dynamicfeedadtargets import dynamicfeedadtargets
42
42
  from .commands.strategies import strategies
43
43
  from .commands.auth import auth
44
+ from .commands.balance import balance
45
+ from .commands.v4events import v4events
46
+ from .commands.v4finance import v4finance
47
+ from .commands.v4account import v4account
48
+ from .commands.v4shells import (
49
+ v4forecast,
50
+ v4meta,
51
+ v4wordstat,
52
+ )
53
+ from .commands.v4goals import v4goals
44
54
 
45
55
  # Load .env file
46
56
  load_dotenv()
@@ -173,6 +183,14 @@ for command in (
173
183
  advideos,
174
184
  dynamicfeedadtargets,
175
185
  strategies,
186
+ balance,
187
+ v4finance,
188
+ v4account,
189
+ v4goals,
190
+ v4events,
191
+ v4wordstat,
192
+ v4forecast,
193
+ v4meta,
176
194
  auth,
177
195
  ):
178
196
  _register_command(command)
@@ -6,7 +6,7 @@ import click
6
6
 
7
7
  from ..api import create_client
8
8
  from ..output import format_output, print_error
9
- from ..utils import get_default_fields, parse_ids
9
+ from ..utils import add_criteria_csv, get_default_fields, parse_ids
10
10
 
11
11
 
12
12
  @click.group()
@@ -17,13 +17,30 @@ def adextensions():
17
17
  @adextensions.command()
18
18
  @click.option("--ids", help="Comma-separated extension IDs")
19
19
  @click.option("--types", help="Filter by types")
20
+ @click.option("--states", help="Comma-separated states")
21
+ @click.option("--statuses", help="Comma-separated statuses")
22
+ @click.option("--modified-since", help="ModifiedSince datetime")
20
23
  @click.option("--limit", type=int, help="Limit number of results")
21
24
  @click.option("--fetch-all", is_flag=True, help="Fetch all pages")
22
25
  @click.option("--format", "output_format", default="json", help="Output format")
23
26
  @click.option("--output", help="Output file")
24
27
  @click.option("--fields", help="Comma-separated field names")
28
+ @click.option("--dry-run", is_flag=True, help="Show request without sending")
25
29
  @click.pass_context
26
- def get(ctx, ids, types, limit, fetch_all, output_format, output, fields):
30
+ def get(
31
+ ctx,
32
+ ids,
33
+ types,
34
+ states,
35
+ statuses,
36
+ modified_since,
37
+ limit,
38
+ fetch_all,
39
+ output_format,
40
+ output,
41
+ fields,
42
+ dry_run,
43
+ ):
27
44
  """Get ad extensions"""
28
45
  try:
29
46
  client = create_client(
@@ -41,6 +58,10 @@ def get(ctx, ids, types, limit, fetch_all, output_format, output, fields):
41
58
  criteria["Ids"] = parse_ids(ids)
42
59
  if types:
43
60
  criteria["Types"] = types.split(",")
61
+ add_criteria_csv(criteria, "States", states, upper=True)
62
+ add_criteria_csv(criteria, "Statuses", statuses, upper=True)
63
+ if modified_since:
64
+ criteria["ModifiedSince"] = modified_since
44
65
 
45
66
  params = {"SelectionCriteria": criteria, "FieldNames": field_names}
46
67
 
@@ -49,6 +70,10 @@ def get(ctx, ids, types, limit, fetch_all, output_format, output, fields):
49
70
 
50
71
  body = {"method": "get", "params": params}
51
72
 
73
+ if dry_run:
74
+ format_output(body, "json", None)
75
+ return
76
+
52
77
  result = client.adextensions().post(data=body)
53
78
 
54
79
  if fetch_all:
@@ -6,7 +6,7 @@ import click
6
6
 
7
7
  from ..api import create_client
8
8
  from ..output import format_output, print_error
9
- from ..utils import get_default_fields, parse_ids
9
+ from ..utils import add_criteria_csv, get_default_fields, parse_ids
10
10
 
11
11
 
12
12
  @click.group()
@@ -18,26 +18,46 @@ def adgroups():
18
18
  @click.option("--ids", help="Comma-separated ad group IDs")
19
19
  @click.option("--campaign-ids", help="Comma-separated campaign IDs")
20
20
  @click.option("--status", help="Filter by status")
21
+ @click.option("--statuses", help="Comma-separated statuses")
21
22
  @click.option("--types", help="Filter by types")
23
+ @click.option("--tag-ids", help="Comma-separated tag IDs")
24
+ @click.option("--tags", help="Comma-separated tag names")
25
+ @click.option("--app-icon-statuses", help="Comma-separated app icon statuses")
26
+ @click.option("--serving-statuses", help="Comma-separated serving statuses")
27
+ @click.option(
28
+ "--negative-keyword-shared-set-ids",
29
+ help="Comma-separated negative keyword shared set IDs",
30
+ )
22
31
  @click.option("--limit", type=int, help="Limit number of results")
23
32
  @click.option("--fetch-all", is_flag=True, help="Fetch all pages")
24
33
  @click.option("--format", "output_format", default="json", help="Output format")
25
34
  @click.option("--output", help="Output file")
26
35
  @click.option("--fields", help="Comma-separated field names")
36
+ @click.option("--dry-run", is_flag=True, help="Show request without sending")
27
37
  @click.pass_context
28
38
  def get(
29
39
  ctx,
30
40
  ids,
31
41
  campaign_ids,
32
42
  status,
43
+ statuses,
33
44
  types,
45
+ tag_ids,
46
+ tags,
47
+ app_icon_statuses,
48
+ serving_statuses,
49
+ negative_keyword_shared_set_ids,
34
50
  limit,
35
51
  fetch_all,
36
52
  output_format,
37
53
  output,
38
54
  fields,
55
+ dry_run,
39
56
  ):
40
57
  """Get ad groups"""
58
+ if status and statuses:
59
+ raise click.UsageError("--status and --statuses are mutually exclusive")
60
+
41
61
  try:
42
62
  client = create_client(
43
63
  token=ctx.obj.get("token"),
@@ -54,8 +74,19 @@ def get(
54
74
  criteria["CampaignIds"] = parse_ids(campaign_ids)
55
75
  if status:
56
76
  criteria["Statuses"] = [status]
77
+ add_criteria_csv(criteria, "Statuses", statuses, upper=True)
57
78
  if types:
58
79
  criteria["Types"] = types.split(",")
80
+ add_criteria_csv(criteria, "TagIds", tag_ids, integers=True)
81
+ add_criteria_csv(criteria, "Tags", tags)
82
+ add_criteria_csv(criteria, "AppIconStatuses", app_icon_statuses, upper=True)
83
+ add_criteria_csv(criteria, "ServingStatuses", serving_statuses, upper=True)
84
+ add_criteria_csv(
85
+ criteria,
86
+ "NegativeKeywordSharedSetIds",
87
+ negative_keyword_shared_set_ids,
88
+ integers=True,
89
+ )
59
90
 
60
91
  params = {"SelectionCriteria": criteria, "FieldNames": field_names}
61
92
 
@@ -64,6 +95,10 @@ def get(
64
95
 
65
96
  body = {"method": "get", "params": params}
66
97
 
98
+ if dry_run:
99
+ format_output(body, "json", None)
100
+ return
101
+
67
102
  result = client.adgroups().post(data=body)
68
103
 
69
104
  if fetch_all:
@@ -6,7 +6,7 @@ import click
6
6
 
7
7
  from ..api import create_client
8
8
  from ..output import format_output, print_error
9
- from ..utils import get_default_fields, load_base64_file, parse_ids
9
+ from ..utils import add_criteria_csv, get_default_fields, load_base64_file, parse_ids
10
10
 
11
11
 
12
12
  @click.group()
@@ -16,13 +16,27 @@ def adimages():
16
16
 
17
17
  @adimages.command()
18
18
  @click.option("--ids", help="Comma-separated image IDs")
19
+ @click.option("--image-hashes", help="Comma-separated ad image hashes")
20
+ @click.option("--associated", type=click.Choice(["YES", "NO"], case_sensitive=False))
19
21
  @click.option("--limit", type=int, help="Limit number of results")
20
22
  @click.option("--fetch-all", is_flag=True, help="Fetch all pages")
21
23
  @click.option("--format", "output_format", default="json", help="Output format")
22
24
  @click.option("--output", help="Output file")
23
25
  @click.option("--fields", help="Comma-separated field names")
26
+ @click.option("--dry-run", is_flag=True, help="Show request without sending")
24
27
  @click.pass_context
25
- def get(ctx, ids, limit, fetch_all, output_format, output, fields):
28
+ def get(
29
+ ctx,
30
+ ids,
31
+ image_hashes,
32
+ associated,
33
+ limit,
34
+ fetch_all,
35
+ output_format,
36
+ output,
37
+ fields,
38
+ dry_run,
39
+ ):
26
40
  """Get ad images"""
27
41
  try:
28
42
  client = create_client(
@@ -31,21 +45,28 @@ def get(ctx, ids, limit, fetch_all, output_format, output, fields):
31
45
  sandbox=ctx.obj.get("sandbox"),
32
46
  )
33
47
 
34
- field_names = (
35
- fields.split(",") if fields else get_default_fields("adimages")
36
- )
48
+ field_names = fields.split(",") if fields else get_default_fields("adimages")
37
49
 
38
50
  criteria = {}
39
51
  if ids:
40
52
  criteria["Ids"] = parse_ids(ids)
53
+ add_criteria_csv(criteria, "AdImageHashes", image_hashes)
54
+ if associated:
55
+ criteria["Associated"] = associated.upper()
41
56
 
42
- params = {"SelectionCriteria": criteria, "FieldNames": field_names}
57
+ params = {"FieldNames": field_names}
58
+ if criteria:
59
+ params["SelectionCriteria"] = criteria
43
60
 
44
61
  if limit:
45
62
  params["Page"] = {"Limit": limit}
46
63
 
47
64
  body = {"method": "get", "params": params}
48
65
 
66
+ if dry_run:
67
+ format_output(body, "json", None)
68
+ return
69
+
49
70
  result = client.adimages().post(data=body)
50
71
 
51
72
  if fetch_all: