Skip to content

feat(cli): v0.39.0 command line surreal-orm-lite (v0.39.0) - #382

Merged
EulogySnowfall merged 11 commits into
mainfrom
feature/v0.39.0-cli-entry-point
Oct 30, 2026
Merged

EulogySnowfall merged 11 commits into
mainfrom
feature/v0.39.0-cli-entry-point

Conversation

@EulogySnowfall

@EulogySnowfall EulogySnowfall commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

Summary

Adds the surreal-orm-lite command line (v0.39.0): a console script and python -m surreal_orm_lite.cli with nine commands (shell, makemigrations, migrate, upgrade, rollback, status, sqlmigrate, schemadiff, inspectdb), built on argparse with the full SurrealDB-ORM's options, SURREAL_* environment variables and output texts. Each command is a thin front end over the v0.38.0 migration system and the schema introspection; the CLI decides nothing about the schema.

Closes #375

Changes

  • src/surreal_orm_lite/cli/ (commands.py, __main__.py) and the [project.scripts] entry in pyproject.toml.
  • --connection picks a named connection, --version prints the version, sqlmigrate takes --backwards/--line, inspectdb takes --table/--no-overwrite, makemigrations takes --name, --models, --empty, --drop-missing, --from-db/--no-from-db. --help never shows the password and errors never carry the URL's credentials.
  • shell runs each statement on its own (also from piped input); Ctrl+C during a query exits with 130 after closing the connection.
  • The warning makemigrations() logs for skipped removals now names --drop-missing.
  • Tests: new tests/test_cli.py (offline, E2E on both lines over WS and HTTP, embedded engine, real entry-point subprocess) and tests/test_cli_docs.py; the earlier README/ROADMAP doc tests follow the new section 40 and the released-roadmap state.
  • Docs: README section 40 and the 2.x/3.x table rows, CHANGELOG.md, SECURITY.md (supported 0.39.x), docs/ROADMAP.md (v0.39.0 marked done, "Completed versions" block; prettier re-pads the tables, hence the wider diff), and the executed notebook examples/v0.39.0_cli_entry_point.ipynb.

SurrealDB 2.x vs 3.x

Every command runs on both lines and on the embedded engine. The one difference is the shell's layout for a transaction: on 3.x a BEGIN ... COMMIT block shows one block per statement ([1/3] to [3/3]), on 2.x only the statements inside the transaction answer. README section 40 and the "ORM behaviour: SurrealDB 2.6.x vs 3.x" table record it.

Validation

QA gate on 6056d98 (before the rebase onto main at 0.38.3 and the version bump), portes.sh complet green in 34 min:

  • Lint: ruff check and format, mypy on src/ and tests/typing_examples.py, pins, versions, uv.lock, commit identity.
  • 3.x suite: 15903 passed, 90 skipped, coverage 98.82 %. 2.x suite: 15825 passed, 168 skipped. 3.1.5 retro (informative): 15897 passed, 96 skipped, no regression.
  • Random order on 3.x, Python 3.11 on 3.x, and the modified notebook all pass.
  • Three isolated passes of the new and touched test files (test_cli.py, test_cli_docs.py, test_migration_files.py, test_migration_docs.py): 509 passed each time on 3.x and on 2.x.
  • Extra runs: Python 3.11 import probe plus surreal-orm-lite --help; 2.x full suite with seed 11 (15825 passed, 168 skipped); 3.x on Python 3.14 with seed 4242 (15899 passed, 94 skipped).
  • Merged tree with main at cc75646 (the 3.3.5 pin): no conflicts; 3.x with the retro container on 3.3.5: 15907 passed, 94 skipped; 2.x on Python 3.11: 15828 passed, 173 skipped (the extra skips are the multi-line tests that need SURREALDB_PORT_3X/_2X).
  • Notebook: outputs re-run on 3.x identical to the committed ones (15 code cells), identical on 3.1.5; on 2.x only the shell cell differs, as described above.

After the rebase and the bump: lint, versions, uv.lock, identity and the doc/ROADMAP/embedded/hybrid tests re-run green on both lines (1207 passed, 4 skipped); the last commit only touches the version files and the release docs.

Version

0.38.3 -> 0.39.0 (new public API: a minor). No other open PR holds a version.

… codes

The surreal-orm-lite console script and python -m surreal_orm_lite.cli, on
argparse: the full ORM's nine commands and global options, SURREAL_*
variables (option > environment > default, an empty variable unset), exit 2
for a missing namespace or database, 130 on Ctrl+C, a refusal inside a
running event loop before the registry is touched, a stderr logging handler
removed after main(), and the URL's userinfo scrubbed from stderr. The
commands themselves follow in the next commits.
makemigrations --empty writes a file to fill in by hand; --no-from-db with
--models imports the modules (the working directory put on sys.path when
neither it nor "" is there), diffs every registered model of the connection
against the migration files' state and lists the operations it wrote.
sqlmigrate prints show_sql() for --line and --backwards, offline. The warning
for the removals left out now names the --drop-missing flag too.
Each command registers its settings, resolves the connection class once and
runs in one asyncio.run() that closes the connection in a finally. Failures
are reported as '<Prefix> failed: <message>' on stderr (scrubbed, exit 1),
Ctrl+C as 'Interrupted.' (exit 130). E2E tests on both server lines, over
WebSocket and HTTP.
makemigrations diffs the models against the database's schema by default:
the connection is configured once the models are found, and a failure to
reach the database adds a hint towards --no-from-db (connection errors only).
schemadiff prints the full ORM's report and refuses to compare with no
registered model before configuring the connection.
inspectdb runs generate_models_from_db() on the command's connection: the source on stdout with one trailing newline, or written with -o (--no-overwrite refuses an existing file); --table limits the tables; failures are reported as 'Introspection failed: <message>', exit 1.
One asyncio.Runner per session; each line goes unchanged to query_raw() and
every statement's outcome is shown in its own block, as the server line answers
it (3.x and 2.x transaction envelopes, a missing table, parse errors from a
server or the embedded engine). exit/quit, EOF and Ctrl+C at the prompt end with
Goodbye! (exit 0); Ctrl+C during a query exits 130; a refused first connection is
'Shell failed: ...' (exit 1). The connection is closed once in every case and
the banner drops the URL's user:password@.
… real entry point

A surrealkv:// path keeps its data across makemigrations, migrate and status (AC-22); an ASYNC event migration is applied on 3.x and refused on 2.x with only the empty tracking table left (AC-24); the chain runs through python -m surreal_orm_lite.cli in a subprocess (AC-26).
README section 40 (install, connection options, commands, the SurrealQL shell, several databases, exit codes, security, server lines, differences from the full ORM's CLI), the 2.x/3.x and embedded-engine rows, the features, roadmap and comparison rows, and the two sentences that promised the CLI for v0.39.0 now point to section 40.

tests/test_cli_docs.py pins all of it. The earlier doc tests follow the new text: section lists gain section 40, the roadmap and comparison rows, section 31's inspectdb clause and section 39's Limits phrase; test_migration_docs.py's link list of section 39 also gains the section 40 link (an unlisted dependency).
Runs the surreal-orm-lite command line in a subprocess from a temporary project: --help/--version, makemigrations, migrate, status, sqlmigrate, schemadiff with a model change, inspectdb, the SurrealQL shell with piped input, rollback and cleanup. Outputs saved from SurrealDB 3.x, free of ports, paths and version numbers.
@codecov

codecov Bot commented Oct 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.25187% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.50%. Comparing base (cc75646) to head (6598059).

Files with missing lines Patch % Lines
src/surreal_orm_lite/cli/__main__.py 50.00% 1 Missing and 1 partial ⚠️
src/surreal_orm_lite/cli/commands.py 99.74% 0 Missing and 1 partial ⚠️
@@            Coverage Diff             @@
##             main     #382      +/-   ##
==========================================
+ Coverage   98.49%   98.50%   +0.01%     
==========================================
  Files          53       56       +3     
  Lines       17442    17843     +401     
  Branches     3143     3184      +41     
==========================================
+ Hits        17179    17577     +398     
- Misses        154      155       +1     
- Partials      109      111       +2     
Files with missing lines Coverage Δ
src/surreal_orm_lite/cli/__init__.py 100.00% <100.00%> (ø)
src/surreal_orm_lite/migrations/autodetect.py 100.00% <ø> (ø)
src/surreal_orm_lite/cli/commands.py 99.74% <99.74%> (ø)
src/surreal_orm_lite/cli/__main__.py 50.00% <50.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@EulogySnowfall EulogySnowfall left a comment

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.

Automated review — maintainer's agent team (round 1)

Reviewed the PR as it will be merged (head 6598059) against the v0.39.0 design: the nine commands, global options and SURREAL_* resolution, exit codes (0/1/2/130), connection lifecycle (one asyncio.run() per command, closed in a finally; one asyncio.Runner for the shell), credential scrubbing and --help without defaults, the [project.scripts] entry (checked in a built wheel: surreal_orm_lite/cli/* is packaged and entry_points.txt points at surreal_orm_lite.cli.commands:main), and the 2.x/3.x shell difference documented in README section 40 and the behaviour table.

Release: version 0.39.0 consistent in pyproject.toml, __init__.py, tests/test_v050.py and the uv.lock package line only; CHANGELOG.md ## [0.39.0]; SECURITY.md supports 0.39.x; docs/ROADMAP.md marks v0.39.0 done; the notebook is executed (15 code cells, sequential counts, no error output). Commits are the user's, no .github/ change. CI is green on both server lines and Python 3.11 to 3.15.

Verdict: no blocking findings. 0 blocking, 1 suggestion (inline).

)

try:
path = _run(generate, _configure(settings, args.command)) if from_db else asyncio.run(generate())

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.

[suggestion] In the default --from-db path, _configure() runs inside the try, so an add_connection() refusal (_ConfigureError) is caught by except Exception and reported as makemigrations failed: add_connection('default'): ... instead of Error: add_connection('default'): ..., which is what the design's error table prescribes for a refused configuration and what migrate, status, schemadiff, etc. print. Reproduced with python -m surreal_orm_lite.cli -n ns -d db --user= makemigrations --name x -m mymodels (exit 1 in both cases, only the text differs).

Suggested fix: resolve the manager before the try when from_db is set (e.g. manager = _configure(settings, args.command) if from_db else None), so main() reports the _ConfigureError like the other commands, and add the matching offline test next to the existing Error: add_connection('default') one.

@EulogySnowfall
EulogySnowfall merged commit 8a4b955 into main Oct 30, 2026
22 checks passed
@EulogySnowfall

Copy link
Copy Markdown
Owner Author

Merged by the maintainer's automation: review approved, CI green, version 0.39.0 ready.

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.

Roadmap: v0.39.0 — CLI surreal-orm-lite (shell, migrate, inspectdb)

1 participant