Skip to content

Rename CLI entry point to direct#8

Merged
axisrow merged 2 commits into
mainfrom
rename-cli-to-direct
Apr 9, 2026
Merged

Rename CLI entry point to direct#8
axisrow merged 2 commits into
mainfrom
rename-cli-to-direct

Conversation

@axisrow

@axisrow axisrow commented Apr 9, 2026

Copy link
Copy Markdown
Owner

Summary\n- Rename the console script from to .\n- Pin Click usage/help to and update the README examples.\n- Adjust CLI help assertions to match the new command name.\n\n## Verification\n- \n-

==================================== ERRORS ====================================
______________________ ERROR collecting tests/test_cli.py ______________________
ImportError while importing test module '/home/hapi/direct-cli/tests/test_cli.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/lib/python3.11/importlib/init.py:126: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tests/test_cli.py:9: in
from direct_cli.cli import cli
direct_cli/cli.py:11: in
from .commands.campaigns import campaigns
direct_cli/commands/init.py:5: in
from .campaigns import campaigns
direct_cli/commands/campaigns.py:8: in
from ..api import create_client
direct_cli/api.py:7: in
from tapi_yandex_direct import YandexDirect
E ModuleNotFoundError: No module named 'tapi_yandex_direct'
=========================== short test summary info ============================
ERROR tests/test_cli.py
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
1 error in 0.13s could not complete in this environment because is not installed.

Copilot AI review requested due to automatic review settings April 9, 2026 05:44
@axisrow

axisrow commented Apr 9, 2026

Copy link
Copy Markdown
Owner Author

@claude review. Focus on critical issues: bugs, security vulnerabilities, logical errors, data loss risks, performance problems. Do NOT nitpick style, naming conventions, minor formatting, or subjective preferences — only flag issues that could break functionality or cause real harm in production.

@claude

claude Bot commented Apr 9, 2026

Copy link
Copy Markdown

Claude finished @axisrow's task in 1m 2s —— View job


Code Review: Rename CLI entry point to direct

  • Read changed files
  • Analyze for critical issues
  • Post review findings

The 4 changed files implement the rename cleanly. The mechanics are all correct. Two issues worth flagging:


1. Name collision risk — potentially breaking in shared environments

direct is a very generic single-word name. On many systems (e.g., ImageMagick installs a direct binary on some distros, and countless other packages may use this name), this entry point will silently shadow or be shadowed by an unrelated tool. The original direct-cli was less likely to collide.

This is a real production risk: a user who installs your package on a system where direct already exists in PATH (or vice versa) will get confusing behavior with no error, just silent wrong-tool execution.

Consider a slightly more specific name like ydirect or ya-direct that's unique to this tool.


2. Breaking change without version bump (pyproject.toml:5)

Renaming a console script entry point is a breaking change for any user who has direct-cli in scripts or automation. The version remains 0.1.2. This warrants at least a minor bump to 0.2.0 per semver conventions, and ideally a note in the changelog/README about the rename.


What's correct:

  • @click.group(name="direct") in cli.py:43 — necessary so Click's CliRunner shows Usage: direct in tests and help output (without this, tests would fail since CliRunner doesn't go through the shell entry point)
  • Test assertions in test_cli.py:23,30 — correct and consistent with the name= parameter
  • pyproject.toml script rename — correct syntax
  • README updates — complete and consistent

The CI failure in the PR body (ModuleNotFoundError: No module named 'tapi_yandex_direct') is an environment issue, not a code bug — the test runner didn't have dependencies installed.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR renames the installed console entry point for the Direct CLI to direct and updates user-facing help/docs to reflect the new command name.

Changes:

  • Rename the PyPI console script from direct-cli to direct.
  • Force Click’s top-level command name to direct so help/usage output matches.
  • Update README examples and CLI help assertions to use direct.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
pyproject.toml Renames the installed console script to direct.
direct_cli/cli.py Sets the Click group name to direct to align help/usage output.
README.md Updates all command examples to use direct instead of direct-cli.
tests/test_cli.py Updates help output assertions to match direct usage strings.

Comment thread pyproject.toml

[project.scripts]
direct-cli = "direct_cli.cli:cli"
direct = "direct_cli.cli:cli"

Copilot AI Apr 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the legacy console script name (direct-cli) is a breaking change for any existing automation/docs. Consider keeping direct-cli as an additional script entry (alias) for at least one release, or otherwise bump the version appropriately and call out the breaking change prominently in release notes.

Suggested change
direct = "direct_cli.cli:cli"
direct = "direct_cli.cli:cli"
direct-cli = "direct_cli.cli:cli"

Copilot uses AI. Check for mistakes.
Comment thread direct_cli/cli.py


@click.group()
@click.group(name="direct")

Copilot AI Apr 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoding the Click group name to "direct" forces help/error messages to always show direct, even if the command is invoked under a different executable name (e.g., if you decide to keep a direct-cli alias for backwards compatibility). If you want help to reflect the actual argv[0], consider leaving the group name unset and, for tests, passing prog_name="direct" to CliRunner.invoke(...) instead.

Suggested change
@click.group(name="direct")
@click.group()

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: Hardcoded name="direct"

Skipping — hardcoding the name is intentional. It ensures clean, predictable help output (Usage: direct) regardless of how the tool is invoked. Leaving it unset would show python -m direct_cli.cli during development or full paths in some environments. The current approach is consistent and the tests assert the expected output.

Comment thread pyproject.toml
Comment on lines 44 to 46
[project.scripts]
direct-cli = "direct_cli.cli:cli"
direct = "direct_cli.cli:cli"

Copilot AI Apr 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions "Pin Click usage/help" (suggesting a Click version pin), but this change set only renames the entry point / usage strings and does not adjust the Click dependency constraint. Either update the dependency spec accordingly or clarify the PR description to match what was changed.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: PR description mentions "Pin Click usage/help"

This appears to be a misreading of the PR description. "Pin" here is used in the colloquial sense of "set/fix the Click group name to direct" (the name="direct" parameter on @click.group()), not "pin a dependency version." No change to the Click dependency constraint (click>=8.0.0) is needed — the current constraint is correct and unrelated to this rename.

@axisrow

axisrow commented Apr 9, 2026

Copy link
Copy Markdown
Owner Author

Re: Name collision risk (direct is too generic)

Skipping — this is a product/naming preference, not a code defect. The name direct was chosen intentionally for brevity. While theoretical collisions with other packages are possible, this is a tradeoff the maintainer has accepted. No factual evidence was provided that ImageMagick or any common package installs a direct binary.

Add backward-compatible `direct-cli` console script alias alongside
the new `direct` entry point. Bump version from 0.1.2 to 0.2.0 to
reflect the breaking change in the CLI entry point name.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@axisrow

axisrow commented Apr 9, 2026

Copy link
Copy Markdown
Owner Author

@claude review. Focus on critical issues: bugs, security vulnerabilities, logical errors, data loss risks, performance problems. Do NOT nitpick style, naming conventions, minor formatting, or subjective preferences — only flag issues that could break functionality or cause real harm in production.

@claude

claude Bot commented Apr 9, 2026

Copy link
Copy Markdown

Claude finished @axisrow's task in 1m 4s —— View job


Code Review: Rename CLI entry point to direct

  • Read changed files
  • Analyze for critical issues
  • Post review findings

No critical bugs, security vulnerabilities, logical errors, or data loss risks found. The implementation is correct.

What's in good shape:

  • pyproject.toml: Both direct and direct-cli entry points are registered (pyproject.toml:45-46), pointing to the same function. Version bumped to 0.2.0. Backward compatibility is preserved and breaking change is properly versioned.
  • direct_cli/cli.py:43: @click.group(name="direct") — correct. Without this, CliRunner in tests shows the Python import path instead of the command name, so assertions would fail.
  • tests/test_cli.py:23,30: assertIn("Usage: direct", ...) and assertIn("Usage: direct campaigns", ...) — substring assertions are valid. Click's help output for these invocations will be Usage: direct [OPTIONS] COMMAND [ARGS]... and Usage: direct campaigns [OPTIONS] COMMAND [ARGS]... respectively.
  • README.md: All examples updated consistently in both English and Russian sections.

One non-critical note (for awareness, not blocking):

Running direct-cli --help (the backward-compat alias) will display Usage: direct in its output — not Usage: direct-cli — because the group name is hardcoded. This is a UX inconsistency for users still on the old alias, but it's not a functional break and the maintainer has confirmed it's intentional.

Verdict: Ready to merge.

@axisrow
axisrow merged commit aa29289 into main Apr 9, 2026
1 check passed
@axisrow
axisrow deleted the rename-cli-to-direct branch April 9, 2026 05:57
axisrow added a commit that referenced this pull request May 30, 2026
* fix(auth): stop --help and unit tests from hanging on client-login network call

A regression from #480 made get_credentials() resolve the bare Client-Login
via a network clients.get on every CLI invocation when an OAuth profile with
an email login lacked the login_migration_checked flag — including plain
`<group> --help`. That call had no timeout (neither the vendored client nor
tapi2 set one), so a slow link or a Yandex SmartCaptcha gateway could hang the
CLI indefinitely. Under CliRunner this also hung the unit suite (it stalled on
test_registered_mapped_groups_show_docs_url, which fires ~30 `--help` calls).

Three independent guards:
- auth.py: cap the best-effort resolver with LOGIN_RESOLVE_TIMEOUT_SECONDS=8
  and disable retries, so it can never wait forever.
- cli.py: skip the resolver entirely on --help/--version/-h passes
  (allow_login_resolve=False) — no command runs, so no login is needed.
- tests/conftest.py: autouse fixture neutralizes the network resolver for the
  whole unit suite; the module-level test-credential probe no longer triggers it.

Adds regression tests asserting a --help pass makes zero resolver calls and
that allow_login_resolve=False suppresses the migration.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* fix: resolve 13 confirmed bugs from the #483 bug hunt

Verified each finding against the live API, the WSDL cache, and the official
Yandex Direct docs before fixing. Bugs 10 and 14 were false positives
(no UsageError source inside the try — style only) and are intentionally skipped.

Functional fixes:
- bids/keywordbids get: reject empty SelectionCriteria with a UsageError
  before the request (live API error 4001) (#1, #2).
- bids get: re-raise UsageError so the new guard surfaces with exit code 2 (#8).
- bids set-auto: require exactly one of CampaignId/AdGroupId/KeywordId via
  add_single_id_selector (docs: the three are mutually exclusive) (#4).
- vendored to_columns: pad short report rows instead of IndexError (#3).
- vendored error handler: error_data.get("error_detail") to avoid KeyError (#11).
- reports build_report_request: reject empty FieldNames (live API error 8000) (#12).

Swallowed-validation fixes (add `except click.UsageError/ClickException: raise`
before the bare `except Exception`): balance (#6), strategies get (#7),
campaigns get (#9), ads get (#13), negativekeywordsharedsets update (#5).

Type annotation: parse_priority_goals_spec items -> List[Dict[str, Any]] (#15).

build_api_coverage_report: supply --campaign-ids for bids/keywordbids get
wire-capture so the empty-criteria guard does not break schema parity.

Closes #483

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* fix: broaden #483 coverage and add CHANGELOG (cherry-picked from #484)

Incorporates the genuinely-better parts of the parallel PR #484 into this
branch, which already carries the regression tests, the #15 annotation fix,
and the localized messages:

- ads: re-raise click.UsageError in all lifecycle handlers (update, delete,
  archive, unarchive, suspend, resume, moderate) in addition to get — so the
  whole resource matches bug #13's "get + 8 lifecycle" scope. Defensive: these
  handlers have no pre-API UsageError source today, but the guard keeps them
  consistent and future-proof.
- retargeting get/delete, advideos get: same defensive re-raise for uniformity
  (issue #483 items 10/14; not live defects, but harmless consistency).
- bids/keywordbids get: the empty-criteria message now also lists
  --serving-statuses, which likewise populates SelectionCriteria (kept the
  t() localization wrapper).
- CHANGELOG.md: document the bug-hunt fixes (#483) and the --help network-hang
  follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

---------

Co-authored-by: axisrow <[email protected]>
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants