Skip to content

Releases: axisrow/direct-cli

0.4.3 — batch ads/adgroups add & update

Choose a tag to compare

@axisrow axisrow released this 17 Jun 03:53

Features — batch ads add via --from-file / --ads-json (#562, #558 follow-up):

  • ads add now accepts a batch of flag-form ad rows from a JSONL file
    (--from-file) or an inline JSON array (--ads-json); each row is the same
    flag set keyed by the kebab flag name without the leading dashes (e.g.
    {"type":"TEXT_AD","title":"...","text":"...","href":"...","adgroup-id":1}).
    --adgroup-id becomes the batch default and may be overridden per row. Single
    typed-flag mode is unchanged.
  • The ~400-line flag→object logic of ads add was extracted into a reusable,
    ctx-free build_ad_object() so the single-flag command and the batch
    normalizer emit byte-identical ad objects (golden-tested across every
    subtype).
  • New shared direct_cli/commands/_batch.py engine (JSONL/inline loading,
    chunking, per-chunk send with partial-success reporting, dry-run preview,
    add/update-aware result key). keywords add was migrated onto it with no
    behavior change (its existing batch suite is the proof).
  • Chunk size ADS_ADD_MAX_BATCH = 100 (conservative chunk, not the 1000-object
    API ceiling — a partial failure rolls back at most 100 ads).

Features — batch ads update via --from-file / --ads-json (#563, #558 follow-up):

  • ads update now accepts a batch of flag-form ad-update rows from a JSONL file
    (--from-file) or an inline JSON array (--ads-json); each row is the same
    flag set keyed by the kebab flag name without the leading dashes plus its own
    id and type (e.g. {"id":5,"type":"TEXT_AD","title":"New"}). The
    --clear-image-hash mechanic works per row as a JSON boolean. Single
    typed-flag mode is unchanged.
  • The subtype-dispatch body of ads update (type validation, the
    incompatible-flag / "does not convert between subtypes" guard, per-subtype
    assembly, and the empty-subtype no-op guard) was extracted into a reusable,
    ctx-free build_ad_update_object() so the single-flag command and the batch
    normalizer emit byte-identical ad-update objects (golden-tested across every
    subtype). Reuses the shared _batch.py engine with method="update" /
    result_key="UpdateResults".
  • --id and --type become per-row in batch mode (each row carries its own);
    single-item mode still requires both. The per-row normalizer reproduces the
    command's --id/--type required checks, the --image-hash /
    --clear-image-hash mutex, and the same Click-type coercion as the single
    path (a JSON float id is rejected, not truncated).

Features — batch adgroups add via --from-file / --adgroups-json (#564, #558 follow-up):

  • adgroups add now accepts a batch of flag-form ad-group rows from a JSONL
    file (--from-file) or an inline JSON array (--adgroups-json); each row is
    the same flag set keyed by the kebab flag name without the leading dashes
    (e.g. {"name":"G","campaign-id":12,"region-ids":"225","type":"TEXT_AD_GROUP"}).
    --campaign-id becomes the batch default and may be overridden per row.
    Single typed-flag mode is unchanged.
  • The flag→object logic of adgroups add (type validation, the
    incompatible-flag guard, the negative-keyword compatibility check, region IDs,
    and per-subtype assembly) was extracted into a reusable, ctx-free
    build_adgroup_object() so the single-flag command and the batch normalizer
    emit byte-identical ad-group objects (golden-tested across every subtype).
    --name / --campaign-id / --region-ids become per-row in batch mode;
    single-item mode still requires them (parity-gate INTERNAL_VALIDATION
    entries). Per-row coercion runs every typed field through its single-flag
    Click type (a JSON float campaign-id is rejected, not truncated).
  • The shared _batch.send_batch gained an optional post callable so
    adgroups keeps its endpoint routing: a UnifiedAdGroup payload must use API
    v501 (_post_adgroups). Because that routing keys off the whole body, a batch
    may not mix UNIFIED_AD_GROUP with other ad-group types — the CLI refuses
    the mix up front with a clear UsageError rather than send non-unified groups
    to the v501 endpoint.

Features — batch adgroups update via --from-file / --adgroups-json (#565, #558 follow-up):

  • adgroups update now accepts a batch of flag-form ad-group-update rows from a
    JSONL file (--from-file) or an inline JSON array (--adgroups-json); each
    row is the same flag set keyed by the kebab flag name without the leading
    dashes plus its own id (e.g. {"id":5,"name":"New"}). The --dynamic-feed
    routing works per row as a JSON boolean. Single typed-flag mode is unchanged.
  • The subtype-dispatch body of adgroups update (the mixed-subtype reject
    guard, per-subtype assembly, the --dynamic-feed DynamicTextAdGroup ↔
    DynamicTextFeedAdGroup routing, and the empty-payload no-op guard) was
    extracted into a reusable, ctx-free build_adgroup_update_object() so the
    single-flag command and the batch normalizer emit byte-identical objects
    (golden-tested across every subtype). --id becomes per-row in batch mode;
    single-item mode still requires it (parity-gate INTERNAL_VALIDATION entry).
    Per-row coercion runs every typed field through its single-flag Click type (a
    JSON float id is rejected, not truncated).
  • Reuses the shared _batch.send_batch with method="update" /
    result_key="UpdateResults" and the post=_post_adgroups endpoint routing.
    As with adgroups add, a batch may not mix UNIFIED_AD_GROUP with other
    ad-group types (unified groups use API v501) — the CLI refuses the mix up
    front with a clear UsageError.

Fixes — reject non-positive IDs before the request (#558):

  • Mutating commands and lifecycle ops took their object-ID selector
    (--id / --adgroup-id / --campaign-id / --keyword-id / --client-id)
    as a bare int, which accepted 0 and negatives and forwarded them to the
    API (opaque rejection). Every such selector now uses click.IntRange(min=1)
    and rejects a non-positive id with a clear UsageError (exit 2) before any
    request. Coverage is the full mutation surface, not a subset:

    • every delete / suspend / resume / archive / unarchive /
      moderate lifecycle command (via the shared _lifecycle.py factory);
    • ads add / ads update, adgroups add / adgroups update,
      keywords add / keywords update;
    • campaigns update, feeds update, strategies update,
      retargeting update, negativekeywordsharedsets update, vcards add;
    • smartadtargets add / update / set-bids,
      audiencetargets add / set-bids, dynamicads add / set-bids,
      dynamicfeedadtargets add / set-bids;
    • the bid setters bids set / set-auto, keywordbids set / set-auto
      (the campaign-id / adgroup-id / keyword-id "exactly one of" trios),
      bidmodifiers add / set;
    • agencyclients update --client-id.

    The ad-image lifecycle (--hash, a string) is unchanged. Secondary
    reference-ID flags that point at other objects inside a write payload
    (e.g. --feed-id, --counter-id, --vcard-id, --region-id,
    --retargeting-list-id) are left as-is for now and tracked as follow-up.

  • Batch-size caps (the docs allow up to 1000 objects per add/update and 10000
    ids per delete) are intentionally not added: the CLI builds a
    single-item payload for every mutation, so there is no caller-controllable
    array to overflow. Multi-item batch mode (--from-file) for ads/adgroups is
    tracked as follow-up work.

  • De-staled the KEYWORDS_ADD_MAX_BATCH comment: it claimed the API caps a
    keywords.add request at 10 (citing an outdated doc page that states no such
    number). The real documented per-call limit is 1000; the value 10 is a
    conservative chunk size for batch add, not the API ceiling — comment fixed,
    value unchanged.

Fixes — explain Error 8300 on delete/moderate (#548):

  • raise_for_api_result_errors now appends a hint when the API returns code
    8300, mirroring the existing 8800 hint: the ad is likely not in DRAFT
    status, and Status=UNKNOWN is an API fallback value (a status outside the
    v5 enum), not a business status — such ads can only be archived/unarchived,
    not deleted or sent to moderation. Covers ads delete / ads moderate and
    any command routing through format_output. English-only, matching the 8800
    hint (output.py does not import i18n).

Docs — audiencetargets get requires a filter (#554):

  • Clarified that audiencetargets get cannot page the whole account: unlike
    retargeting get --fetch-all, the live API hard-rejects an empty
    SelectionCriteria (error 8000 with no criteria, 4001 with {}). The
    required-filter guard now explains this and recommends the campaigns get
    batched campaign_ids sweep instead. No API behavior change; message only.

Fixes — preflight SelectionCriteria array limits on get (#555, P0):

  • keywordbids get now rejects --campaign-ids >10, --adgroup-ids >1000,
    --keyword-ids >10000; dynamicads get / smartadtargets get reject
    --campaign-ids >2 — before the request, with a clear UsageError (exit 2)
    naming the array and ceiling, instead of the opaque API error_code=4001.
    These are runtime ceilings (the WSDL declares the arrays unbounded), pinned
    next to each command with a doc/live-4001 citation, the same discipline as
    KEYWORDS_ADD_MAX_BATCH. Verified live 2026-06-16. Other get arrays
    (AdGroupIds/Ids on dynamic/smart, etc.) are intentionally not capped
    because the live API accepts them.

Internal — dedup v4 Live output-option stack (#550):

  • Replaced the byte-identical --format/--output/--dry-run trio across the
    standard v4 Live and balance commands with a shared v4_output_options
    decorator (the v4 analogue of get_options, epic #491). The CLI surface is
    unchanged — same option order, names, click.Choice(["json","table","csv", "tsv"]) format, defaults, and h...
Read more

0.4.2 — get requires SelectionCriteria + auth precedence

Choose a tag to compare

@axisrow axisrow released this 17 Jun 03:56
f92b48a

BREAKING CHANGES - get requires SelectionCriteria (#498):

  • adgroups / ads / keywords / strategies / creatives / dynamicads /
    smartadtargets / audiencetargets get now refuse an empty
    SelectionCriteria before the API call, raising a UsageError that asks for
    at least one filter — instead of sending {"SelectionCriteria": {}} (which the
    API rejects with the opaque error 4001 for ad-group/ad/keyword resources).
    Extends the same guard already shipped for bids / keywordbids in 0.4.1
    (#483). WSDL declares GetRequest.SelectionCriteria as minOccurs=1 for all
    eight resources.
  • retargeting get gains --dry-run and the shared read/pagination option
    stack; its SelectionCriteria stays optional (WSDL minOccurs=0), so a
    no-filter call is still valid and now omits the empty criteria from the
    payload.
  • All eight commands and retargeting get build their request via the shared
    build_common_params helper, completing the dedup epic #491 (B3c).

BREAKING CHANGES - auth precedence (#489):

  • Base YANDEX_DIRECT_TOKEN / YANDEX_DIRECT_LOGIN credentials from the
    environment or current-directory .env now win over the active OAuth profile
    selected by direct auth use when --profile is not passed. Explicit
    --token, --login, and --profile still take priority.
  • direct auth status reports the selected effective credentials, including
    base env/.env and secret-manager fallbacks, instead of reporting only the
    active OAuth profile.
  • direct auth login can now ask interactive users whether to save the OAuth
    access token and resolved login into the current-directory .env; the default
    answer is no.

Docs — live-write coverage limitation (#538):

  • Documented why the SMART_CAMPAIGN / DYNAMIC_TEXT_CAMPAIGN / adimages
    live-write lifecycle (dynamicads, smartadtargets, adimages) stays
    recorded only as 3500/5004 error cassettes. Verified via direct API calls that
    the available sandbox agency account has no client accounts under it
    (agencyclients.get → empty), cannot create one (3001 "No rights to create
    clients", access by request only), and that without a client login every
    agency-scoped mutation returns 8000. Closed #538 as a documented account-tier
    limitation; no CLI code change. See tests/MANUAL_COVERAGE.md.

0.4.1

Choose a tag to compare

@axisrow axisrow released this 30 May 14:34

Russian-default CLI localization across all command modules (epic #466)

Fixed — bug hunt (#483)

  • bids get / keywordbids get: refuse an empty SelectionCriteria before the API call, raising a UsageError that asks for at least one filter (--campaign-ids / --adgroup-ids / --keyword-ids / --serving-statuses) instead of letting the API reject it with the opaque error 4001.
  • bids set-auto: require exactly one of --campaign-id, --adgroup-id, or --keyword-id via the shared add_single_id_selector (the three are mutually exclusive per the API docs), matching bids set.
  • reports get: reject a --fields value that parses to an empty list (e.g. ",,,") before building the request, instead of sending an invalid FieldNames: [] (API error 8000).
  • Error-handling consistency: get/lifecycle handlers across bids, keywordbids, negativekeywordsharedsets, balance, strategies, retargeting, ads (all 8 commands), and advideos now re-raise click.UsageError / click.ClickException before the generic except Exception, so validation errors keep their Click formatting and exit code 2 instead of being downgraded to an Abort.
  • Vendor tapi_yandex_direct: to_columns() no longer raises IndexError on report rows shorter than the header (pads with ""); the error handler reads error_detail with .get() so an unfamiliar error structure no longer masks the original API error with a KeyError.
  • utils.parse_priority_goals_spec: corrected the item type annotation to List[Dict[str, Any]].

Fixed — --help hung on a client-login network call (#485)

  • After #480, get_credentials resolved the bare Client-Login via a network clients.get on every CLI invocation — including <group> --help. Help/version passes now skip the resolver, the resolver is capped with a hard timeout, and the unit suite neutralizes it so tests never touch the network.

Fixed — auth login saved Passport email, breaking v4 (#482)

  • direct auth login stored the Passport email (<login>@yandex.ru) in auth.json, which Direct v4 rejects with FaultCode 259. Login now resolves the bare Client-Login via a one-shot v5 clients.get, falling back to the Passport login only if that call fails. Older profiles are migrated in place (one-time).

Localized — interpolated error messages (#478)

  • All 121 interpolated UsageError/BadParameter/print_* messages rewritten into the stable t("<template>").format(**kwargs) pattern, with 96 unique English templates translated to Russian.

Localized — static error messages (#477)

  • All 179 static UsageError/BadParameter literals across 33 command modules wrapped in t(...), with Russian translations in translations/*.json.

Added — scalable i18n mechanism (#467)

  • Source-string-keyed translation catalog. t() is source-keyed and context-free safe. --locale flag switches between Russian (default) and English.

Localized — Core search (#468)

  • 510 unique strings across campaigns, ads, adgroups, keywords, keywordbids, bids.

Localized — Targeting & creatives (#469)

  • 247 unique strings across 16 modules (strategies, bidmodifiers, smartadtargets, vcards, feeds, etc.).

Localized — Account, clients, reporting (#470)

  • 142 source strings across 10 modules (clients, agencyclients, reports, changes, auth, etc.). First modules with localized runtime messages.

Localized — v4 Live services (#471)

  • 87 source strings across 9 v4 modules. All 42 CLI command groups now fully localized — closes epic #466.

Added — v4 Live deferred methods (#462)

  • GetKeywordsSuggestion, AdImageAssociation, PayCampaignsByCard exposed in the CLI.

Fixed — docs URLs (#464)

  • Removed-doc services pointed at live WSDL.

Full Changelog: v0.4.0...v0.4.1

0.4.0 — typed v4 Live CLI + write-command coverage gates

Choose a tag to compare

@axisrow axisrow released this 29 May 17:34
fcacd94

Milestone release closing the 0.4.0 roadmap (#123): typed Yandex Direct API v4 Live CLI support and completion of the post-0.3.0 write-command coverage gates. All public v4 input stays typed and canonical — no --json passthrough — and mirrors dg-v4/live/* wire shapes 1:1.

Published to PyPI: https://pypi.org/project/direct-cli/0.4.0/

Added — typed v4 Live CLI

  • v4 Live command foundation with typed Click groups and a --dry-run seam that prints the {method, param} body before token/locale enrichment (#124, closes #111).
  • v4finance and v4account typed finance and shared-account commands (#125).
  • v4goals, v4events, v4wordstat, and v4forecast typed commands (#126).
  • v4events get-events-log and v4forecast create-new-forecast expose every documented input field (#456).
  • Russian-default CLI help with English opt-in, starting with v4finance (#458).
  • Remaining deferred v4 Live methods exposed: v4keywords get-suggestion, v4adimage get/set, and v4finance pay-campaigns-by-card (dry-run-only). All v4 finance commands carry a "not tested against the live API" disclaimer (#459).

Changed — write-command coverage gates

  • Extended the WSDL schema gate to mutating operations; keywordbids.set is enum-validated against its WSDL *FieldEnum (#118).
  • Per-method WRITE_SANDBOX integration coverage completed (#122).
  • Closed the remaining mutating DRY_RUN_PAYLOAD_EXCLUSIONS (#127).

Docs / tooling

  • Offline VCR cassettes for all v5 read-only commands (#455).
  • v4 Live read cassettes and a fix for an unbounded retry-loop (#457, closes #454).
  • Docs/wire-shape scanner with the 2026-05-29 sweep (#451).
  • Repointed 4 services (dynamicads, dynamicfeedadtargets, smartadtargets, vcards) whose human-readable doc pages Yandex removed in Sep 2025 to their live WSDL endpoints; the services remain fully functional (#463).
  • Re-ran and triaged the wire-shape audit — no real code↔docs drift (#460).

strict_parity_ok, live_model_parity_ok, and schema_parity_ok all report true.

0.3.16 — v4finance Live-4 currency regression fix

Choose a tag to compare

@axisrow axisrow released this 29 May 12:55
26842d8

BREAKING CHANGES (regression fix — reverts 0.3.15 wire-shape changes):

  • direct v4finance transfer-money now requires --currency again and
    re-emits Currency on every FromCampaigns / ToCampaigns item.
    The 0.3.15 removal verified against dg-v4/reference/TransferMoney
    (legacy v4); the actual Live 4 docs at
    dg-v4/live/TransferMoney define PayCampElement with
    CampaignID, Sum, and Currency, and explicitly mark Currency as
    obligatory in the Live 4 changelog. The CLI now matches the live
    docs 1:1. See audit comment on #125 for the reproducible diff.
  • direct v4finance pay-campaigns now requires --currency again and
    re-emits Currency on every Payments[] item. Same root cause:
    dg-v4/reference/PayCampaigns (legacy) lacks Currency,
    dg-v4/live/PayCampaigns (Live 4) requires it.
  • direct v4finance pay-campaigns accepts --pay-method Overdraft
    again. The Live 4 changelog explicitly adds Overdraft for direct
    advertisers (paired with Bank for agencies). Only Bank keeps the
    --contract-id requirement.
  • direct v4finance create-invoice now requires --currency again and
    re-emits Currency on every Payments[] item, mirroring
    dg-v4/live/CreateInvoice.

This release reverts the wire-shape changes shipped by PRs #441, #442,
#443 (which closed #432, #433, #434). The CLI lives in the v4finance
Live group and must mirror dg-v4/live/*, not dg-v4/reference/*.

0.3.15 — v4finance docs-strict wire-shape (superseded by 0.3.16)

Choose a tag to compare

@axisrow axisrow released this 29 May 12:55
2308ef3

BREAKING CHANGES:

  • direct v4finance transfer-money no longer accepts --currency, and
    the wire-body no longer carries Currency on FromCampaigns/
    ToCampaigns items. The official v4 docs
    (dg-v4/reference/TransferMoney) define PayCampElement with only
    CampaignID and Sum; Sum is in conventional units. The CLI now
    matches the docs 1:1. Closes #432.
  • direct v4finance pay-campaigns no longer accepts --currency. The
    v4 documentation (dg-v4/reference/PayCampaigns) defines
    PayCampElement with only CampaignID and SumCurrency is not
    part of the wire-body and was never forwarded to the API. The option
    is removed entirely to make the CLI surface 1:1 with the docs.
  • direct v4finance pay-campaigns no longer accepts --pay-method Overdraft. The v4 documentation
    (dg-v4/reference/PayCampaigns#PayMethod) lists only "Bank" as a
    supported value; Overdraft was a historical undocumented value
    retained by the CLI for sandbox flow. Strict 1:1 docs alignment
    drops it.
  • direct v4finance create-invoice no longer accepts --currency. The
    v4 documentation (dg-v4/reference/CreateInvoice) defines
    PayCampElement with only CampaignID and SumCurrency is not
    part of the wire-body and was never forwarded to the API. The option
    is removed entirely to make the CLI surface 1:1 with the docs.

0.3.14 — Reports docs-drift protection + Wave 2 nested FieldNames

Choose a tag to compare

@axisrow axisrow released this 29 May 03:11

Fixed:

  • Reports drift checker now points at the canonical Yandex docs URLs
    (/ru/type, /ru/period, /ru/fields-list, /ru/spec) after Yandex
    retired the /ru/reports/<page> path layout and renamed spec.html
    to spec. The pre-existing tests/reports_cache/raw/ had silently
    been captcha-poisoned for three of those pages (~14.6 KB Yandex
    SmartCaptcha gateway in place of real docs); cache is now refetched
    from the live canonical URLs and spec.json is byte-equivalent to
    the pre-migration snapshot except for one updated description string.
  • Five RESOURCE_MAPPING_V5[*]["docs"] URLs that Yandex moved from the
    legacy …/ru/<group>/<group> to …/ru/<group> single-segment form
    (dynamictextadtargets, dynamicfeedadtargets, reports,
    smartadtargets, vcards). Closes #426.

Added (drift protection):

  • direct_cli/reports_coverage.py::fetch_reports_spec and
    direct_cli/wsdl_coverage.py::fetch_wsdl / fetch_live_wsdl now
    refuse responses that look like a Yandex SmartCaptcha gateway (markers
    showcaptcha, smartcaptcha, <title>Captcha) or are suspiciously
    short. This prevents silently poisoning the docs/WSDL cache with
    rate-limited captcha HTML.
  • tests/test_api_coverage.py::TestReportsCoverage::test_reports_cache_files_are_real_content
    and TestWsdlCacheFreshness::test_wsdl_cache_files_are_real_content
    guard the committed cache files against the same poisoning.
  • scripts/check_all_docs_urls.py — health-checks every URL in
    RESOURCE_MAPPING_V5 and REPORTS_SPEC_URLS. Hard-fails on
    redirect-to-captcha, canonical move (Location with a different path
    segment), 4xx, or captcha body; soft-warns on 5xx; paces requests to
    avoid Yandex rate-limit. Wired into scripts/release_pypi.sh as a
    mandatory pre-release gate together with refresh_reports_cache.py
    and a focused pytest pass.

Contract (CLAUDE.md):

  • New rule "No URL literals outside the registry" — every Yandex
    docs/API URL is declared once in RESOURCE_MAPPING_V5 or
    REPORTS_SPEC_URLS; importers reference the constant.
  • New rule "Docs/cache freshness guard" — fetchers and cache files
    enforce minimum-size and no-captcha invariants.
  • New section "PyPI Release" — documents the three pre-release health
    checks executed by release_pypi.sh.

Breaking changes:

  • direct ads get flag --text-ad-fields is renamed to the
    WSDL-canonical --text-ad-field-names form matching the
    TextAdFieldNames request parameter declared by AdsGetRequest.
    The old --text-ad-fields form is no longer accepted — update
    scripts and automation accordingly. Closes #406.
  • direct campaigns add / direct campaigns update and direct strategies add / direct strategies update now reject --priority-goals
    / --priority-goal values below 100,000 (0.1 unit in micro-currency).
    Per Yandex Direct API (add-text-campaign, strategies-types),
    PriorityGoalsItem.Value is xsd:long in advertiser currency
    multiplied by 1,000,000 — the same contract as --budget,
    --average-cpa, and other money flags after #399/#400. The error
    message suggests the micro-currency conversion (e.g. Did you mean 500000000?). Negative values are also rejected up-front rather than
    reaching the API. Both parsers share a single
    validate_priority_goal_value helper. Closes #387.

Added:

  • direct sitelinks get now exposes --sitelink-field-names for the
    separate WSDL SitelinkFieldNames request parameter
    (SitelinkFieldEnum: Title, Href, Description, TurboPageId).
    Previously only the top-level --fields (mapping to FieldNames)
    was available, so the nested Sitelinks[] projection could not be
    controlled from CLI.
  • direct keywordbids get now exposes --fields,
    --search-field-names, and --network-field-names for the
    separate FieldNames, SearchFieldNames, and NetworkFieldNames
    request parameters declared by KeywordBidsGetRequest. Defaults
    from COMMON_FIELDS are preserved when flags are absent.
  • Regression test test_every_nested_fieldnames_param_has_cli_option
    (tests/test_api_coverage.py) scans every cached WSDL get
    request type for *FieldNames parameters and verifies that each
    one has a matching kebab-case CLI option. Acknowledged remaining
    gaps are tracked in NESTED_FIELDNAMES_EXCLUSIONS and #402 so
    future additions cannot silently slip in.
  • direct feeds get now exposes --file-feed-field-names and
    --url-feed-field-names for the separate WSDL FileFeedFieldNames
    (FileFeedFieldEnum: Filename) and UrlFeedFieldNames
    (UrlFeedFieldEnum: Login, Url, RemoveUtmTags) request
    parameters declared by FeedsGetRequest. Previously only the
    top-level --fields (mapping to FieldNames) was available, so
    the nested FileFeed / UrlFeed projections could not be
    controlled from CLI. Closes #412.
  • direct keywords get now exposes
    --autotargeting-settings-brand-options-field-names
    (AutotargetingBrandOptionsFieldEnum: WithoutBrands,
    WithAdvertiserBrand, WithCompetitorsBrand) and
    --autotargeting-settings-categories-field-names
    (AutotargetingCategoriesFieldEnum: Exact, Narrow,
    Alternative, Accessory, Broader) for the separate WSDL
    *FieldNames request parameters declared by
    KeywordsGetRequest. Previously only the top-level --fields
    (mapping to FieldNames) was available, so the nested
    AutotargetingSettings.BrandOptions / Categories projections
    could not be controlled from CLI. Closes #413.
  • direct creatives get now exposes
    --cpc-video-creative-field-names,
    --cpm-video-creative-field-names,
    --smart-creative-field-names, and
    --video-extension-creative-field-names for the four nested
    WSDL *FieldNames request parameters declared by
    CreativesGetRequest (CpcVideoCreativeFieldEnum,
    CpmVideoCreativeFieldEnum, SmartCreativeFieldEnum,
    VideoExtensionCreativeFieldEnum). Previously only the top-level
    --fields (mapping to FieldNames) was available, so the
    per-subtype projections could not be controlled from CLI.
    Closes #411.
  • direct clients get now exposes --contract-field-names,
    --contragent-field-names, --contragent-tin-info-field-names,
    --organization-field-names, and --tin-info-field-names for
    the five nested WSDL *FieldNames request parameters declared
    by ClientsGetRequest (ContractInfoFieldEnum,
    ContragentInfoFieldEnum, TinInfoFieldEnum,
    OrgInfoFieldEnum, TinInfoFieldEnum). The command also gains
    --dry-run for parity with other read-path commands.
    Previously only the top-level --fields (mapping to FieldNames)
    was available, so the per-subtype ERIR projections could not be
    controlled from CLI. Closes #410.
  • direct agencyclients get now exposes --contract-field-names,
    --contragent-field-names, --contragent-tin-info-field-names,
    --organization-field-names, and --tin-info-field-names for
    the five nested WSDL *FieldNames request parameters declared
    by AgencyClientsGetRequest (ContractInfoFieldEnum,
    ContragentInfoFieldEnum, TinInfoFieldEnum,
    OrgInfoFieldEnum, TinInfoFieldEnum). The command also gains
    --dry-run for parity with other read-path commands.
    Previously only the top-level --fields (mapping to FieldNames)
    was available, so the per-subtype ERIR projections could not be
    controlled from CLI. Closes #407.
  • direct adgroups get now exposes eight additional
    --*-field-names flags for the separate WSDL *FieldNames
    request parameters declared by AdGroupsGetRequest:
    --autotargeting-settings-brand-options-field-names,
    --autotargeting-settings-categories-field-names,
    --dynamic-text-ad-group-field-names,
    --dynamic-text-feed-ad-group-field-names,
    --mobile-app-ad-group-field-names,
    --smart-ad-group-field-names,
    --text-ad-group-feed-params-field-names, and
    --unified-ad-group-field-names. Previously only the top-level
    --fields (mapping to FieldNames) was available, so the
    per-subtype ad-group projections could not be controlled from
    CLI. Closes #405.
  • direct ads get now exposes sixteen additional --*-field-names
    flags for the separate WSDL *FieldNames request parameters
    declared by AdsGetRequest: --cpc-video-ad-builder-ad-field-names,
    --cpm-banner-ad-builder-ad-field-names,
    --cpm-video-ad-builder-ad-field-names,
    --dynamic-text-ad-field-names, --listing-ad-field-names,
    --mobile-app-ad-builder-ad-field-names,
    --mobile-app-ad-field-names,
    --mobile-app-cpc-video-ad-builder-ad-field-names,
    --mobile-app-image-ad-field-names,
    --responsive-ad-field-names, --shopping-ad-field-names,
    --smart-ad-builder-ad-field-names,
    --text-ad-builder-ad-field-names,
    --text-ad-field-names,
    --text-ad-price-extension-field-names, and
    --text-image-ad-field-names. Previously only the top-level
    --fields (mapping to FieldNames) and non-canonical
    --text-ad-fields were available, so the per-ad-subtype projections
    could not be controlled from CLI. Closes #406.

BREAKING CHANGES:

  • direct campaigns get flags --text-campaign-fields,
    --mobile-app-campaign-fields, --dynamic-text-campaign-fields,
    --cpm-banner-campaign-fields, --smart-campaign-fields,
    --unified-campaign-fields,
    --text-campaign-search-strategy-placement-types-fields,
    --dynamic-text-campaign-search-strategy-placement-types-fields,
    --unified-campaign-search-strategy-placement-types-fields, and
    --unified-campaign-package-bidding-strategy-platforms-fields
    are renamed to their kebab-case WSDL-canonical *-field-names
    form (--text-campaign-field-names,
    --mobile-app-campaign-field-names, ...), matching the parameter
    names declared by CampaignsGetRequest. The old --*-fields
    forms are no longer accepted — update scripts and automation
    accordingly. Closes #409.

**Additional features:*...

Read more

0.3.13 — BiddingStrategy parity sweep

Choose a tag to compare

@axisrow axisrow released this 29 May 03:11

Breaking changes:

  • direct campaigns add and direct campaigns update now require all
    bidding-strategy money flags to be passed directly in micro-rubles,
    matching the existing --budget, --average-cpa, --bid-ceiling, and
    --filter-average-cpc contract. The CLI no longer accepts decimal currency
    values or performs unit conversion for campaign money
    inputs. Closes #399.
  • direct ads add and direct ads update now apply the same API-native
    micro-ruble contract to --price-extension-price and
    --price-extension-old-price; price-extension values are no longer parsed
    as decimal currency amounts.

Закрытый майлстоун 0.3.13 — BiddingStrategy parity sweep + optional WSDL field parity (#240#397).

0.3.12 — Optional WSDL field parity completion

Choose a tag to compare

@axisrow axisrow released this 26 May 00:28
c23f153

55 commits, ~50 closed issues — but this is essentially one cohesive patch:
all optional WSDL fields that were deferred from 0.3.8–0.3.10 are now wired
through as typed CLI flags.
No new API endpoints, no architecture changes.

Added

Campaigns — typed add/update flags for all campaign subtypes:

  • TextCampaign, DynamicTextCampaign, SmartCampaign, UnifiedCampaign,
    MobileAppCampaign, CpmBannerCampaign optional settings and strategy controls.
  • Campaign-level --tracking-params, --time-targeting-json, --notification-json.
    Closes #291#296.

Ad groups — typed add/update flags for all group subtypes:

  • DYNAMIC_TEXT_AD_GROUP advanced fields, DYNAMIC_TEXT_FEED_AD_GROUP,
    MOBILE_APP_AD_GROUP, CPM_* rare subtypes, UNIFIED_AD_GROUP,
    SMART_AD_GROUP, TextAdGroupFeedParams, negative keyword typed flags.
    Closes #279#284.

Ads add — typed flags for every ad subtype:

  • TEXT_AD extension fields, RESPONSIVE_AD, SHOPPING_AD, LISTING_AD,
    AdBuilder family, DYNAMIC_TEXT_AD, mobile app, SMART_AD_BUILDER_AD.
    Closes #273#278.

Ads update — full subtype coverage:

  • DYNAMIC_TEXT_AD, RESPONSIVE_AD, SHOPPING_AD, LISTING_AD,
    AdBuilder family, SMART_AD_BUILDER_AD, MOBILE_APP_IMAGE_AD,
    residual field classification. Closes #267#272.
  • TEXT_AD update: VideoExtension, PriceExtension, callout operations.
    Closes #238, #245.

Keywords — autotargeting typed projection:

  • Scalar flags, AutotargetingCategories, AutotargetingBrandOptions,
    AutotargetingSettings, batch input handling.
    Closes #285#289.

Strategies — remaining optional fields:

  • CustomPeriodBudget, ExplorationBudget, remaining subtype optional fields
    for both add and update. Closes #297#300.

Bids — selector/context/priority optional fields for bids set
and keywordbids set. Closes #301.

Other resources:

  • audiencetargets add: ContextBid, StrategyPriority. Closes #302.
  • dynamicfeedadtargets add: condition arguments parity. Closes #303.
  • smartadtargets add/update: condition arguments parity. Closes #304.
  • clients update: EmailSubscriptions, Settings, full
    ErirAttributes (Organization, Contract, Contragent). Closes #305#308.
  • feeds add/update: FileFeed upload, UrlFeed parity. Closes #253, #264.
  • sitelinks add: TurboPageId. Closes #257.
  • retargeting add/update: Description. Closes #256.
  • bidmodifiers add: optional adjustment parity. Closes #254.
  • vcards add: InstantMessenger, PointOnMap. Closes #246.
  • adextensions get: CalloutFieldNames flag.

Fixed

  • load_dotenv() no longer leaks YANDEX_DIRECT_* env vars from the
    developer's .env file into CLI subprocess calls. Closes #356.
  • Credential precedence: .env file values no longer override active
    direct auth profile. Closes #357, #358.

v0.3.11

Choose a tag to compare

@axisrow axisrow released this 22 May 13:23

Added:

  • direct campaigns add and direct campaigns update now expose
    --tracking-params for the campaign-level tracking query string
    (TextCampaign / DynamicTextCampaign / SmartCampaign .TrackingParams).
    campaigns update gained an optional --type discriminator —
    required when --tracking-params is set, validated against
    the three subtypes supported by the CLI. Backward compatible:
    existing campaigns update --id N --name X calls without --type
    keep working unchanged. Closes #230.
  • direct v4account account-management now supports --action Get,
    Deposit, Invoice, and TransferMoney in addition to Update,
    matching the official v4 Live docs
    (https://yandex.ru/dev/direct/doc/dg-v4/reference/AccountManagement-docpage/).
    Get is read-only and accepts optional --logins / --account-ids
    filters. Deposit, Invoice, and TransferMoney are financial
    mutations: they need --finance-token (or --master-token +
    --operation-num + --finance-login) and respect the existing
    dry-run-unless-sandbox rule. A Click-side allow-list rejects flags
    that do not belong to the chosen action before any body is built.
    Refs #125.

Fixed:

  • direct v4 * command wrappers now let click.ClickException
    (including UsageError from call_v4 shape validation) propagate to
    Click instead of swallowing it in the generic except Exception.
    Shape-validation errors keep their usage hint and exit with code 2,
    matching Click's contract; non-Click runtime errors still surface
    through print_error + Abort (exit 1). Closes #227.

Breaking changes: