Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ All notable changes to this project are documented in this file. The format is b

### Fixed

- `host/alembic.ini`, both this repo's and the one `smpy new` scaffolds, sets `path_separator = os`. Alembic then splits `prepend_sys_path` and `version_locations` on the OS path separator. Without the setting, an app that adds either option gets a `DeprecationWarning` on every migration command, and a checkout path with a space is split in two. An existing app on Alembic 1.16 or newer can add the same line under `[alembic]` (#872).
- The `simple-module-creating` and `simple-module-conventions` skills, which ship inside `simple_module_cli`, linked the module layout standard as `../../docs/module-layout.md`. That path does not exist in an installed CLI. They now link https://docs.py.simplemodule.dev/module-layout, and a test fails if a shipped skill links a file outside `skills/`. `docs/module-layout.md` gains a "Downstream modules" section on copying this repo's root-layout test (`ALLOWED_ROOT`, `DOMAIN_AREAS`) into an app or a standalone module repo (#875).
- `smpy new` warns when the CLI running it is older than the latest `simple_module_cli` on PyPI. A new app pins the framework to the CLI's own version, and `uvx --from simple_module_cli` quietly reuses a copy installed with `uv tool install`, so an old tool used to scaffold an outdated app without saying so. The warning names both fixes: `uv tool upgrade simple_module_cli`, or `uvx --from simple_module_cli@latest`. The check is best effort, with a 3-second timeout; offline or on any PyPI error it is skipped, and it never blocks the scaffold. A CLI that is itself a pre-release, dev or local build is never warned. The README, the CLI and hosting READMEs and the landing page's copy command now use `uvx --from simple_module_cli@latest`, and the installation and quickstart guides, the docs home and the make-commands reference say how to upgrade an installed CLI, with `pipx upgrade` as the alternative (#899).
- The first-module guidance now agrees with itself. The guides (`docs/index.md`, quickstart, installation, Your first module) wire a new module with `smpy add ../modules/orders --path host`, the command `smpy create-module` prints, which adds it to `host/pyproject.toml` as a workspace source. They used to say `uv add ./modules/orders`, which in a `smpy new` workspace edits the root `pyproject.toml` instead. A flat app uses `smpy add ./modules/orders`. The landing page `smpy new` generates drops the `create-admin` step (the `/setup` wizard already creates the first administrator), lists the wiring and migration steps after `create-module`, and its "Read the docs" button opens the first-module guide on docs.py.simplemodule.dev instead of the GitHub repo. The first-module guide and the `simple-module-conventions` skill note that SQLModel's `Field(regex=...)` is accepted but not enforced on a DTO, and show a `field_validator` instead (#898).
Expand Down
14 changes: 14 additions & 0 deletions docs/superpowers/specs/2026-11-11-alembic-path-separator-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# `path_separator = os` in both alembic.ini files (#872)

Alembic warns ("No path_separator found in configuration; falling back to legacy
splitting...") and splits on spaces only when `prepend_sys_path` or `version_locations`
is set (alembic/config.py). Neither of our files sets them today. But a downstream host
that adds `prepend_sys_path = %(here)s` (smpy_modules did) gets the warning on every
migration command, and a checkout path containing a space breaks.

Fix: add `path_separator = os` to `host/alembic.ini` and to the scaffold template. It
has been supported since Alembic 1.16, and our floor is 1.16.3.

Test: `framework/cli/tests/test_cli_alembic_ini.py` copies each ini into a directory
whose name has a space and sets a two-entry `prepend_sys_path`. It expects no warning
(warnings are errors) and two whole paths. It fails without the line and passes with it.
3 changes: 3 additions & 0 deletions framework/cli/simple_module_cli/templates/host/alembic.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# the repo root is what lets alembic read the repo-root .env — and therefore
# the same SM_DATABASE_URL the app itself uses.
script_location = %(here)s/migrations
# Split prepend_sys_path / version_locations on os.pathsep, not on spaces, so a
# checkout path with a space works and Alembic does not warn (GH #872).
path_separator = os
sqlalchemy.url =

# Run the project's ruff on every new revision, so `make migration` output
Expand Down
32 changes: 32 additions & 0 deletions framework/cli/tests/test_cli_alembic_ini.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Both alembic.ini files split path lists on os.pathsep (GH #872)."""

from __future__ import annotations

import os
import shutil
import warnings
from pathlib import Path

import pytest
from alembic.config import Config
from simple_module_cli import app_project

_REPO = Path(__file__).resolve().parents[3]
_INIS = [
_REPO / "host" / "alembic.ini",
Path(app_project.__file__).parent / "templates" / "host" / "alembic.ini",
]


@pytest.mark.parametrize("ini", _INIS, ids=["repo-host", "scaffold-template"])
def test_prepend_sys_path_with_a_space_splits_on_pathsep(tmp_path: Path, ini: Path) -> None:
"""Without ``path_separator`` Alembic warns and splits ``my app`` into two paths."""
copy = tmp_path / "my app" / "alembic.ini"
copy.parent.mkdir()
shutil.copy(ini, copy)
config = Config(str(copy))
config.set_main_option("prepend_sys_path", f"%(here)s{os.pathsep}%(here)s/src")
with warnings.catch_warnings():
warnings.simplefilter("error")
paths = config.get_prepend_sys_paths_list()
assert paths == [str(copy.parent), f"{copy.parent}/src"]
3 changes: 3 additions & 0 deletions host/alembic.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
# Resolve script_location relative to this ini file, not the invocation cwd,
# so `alembic -c host/alembic.ini ...` works from the repo root.
script_location = %(here)s/migrations
# Split prepend_sys_path / version_locations on os.pathsep, not on spaces, so a
# checkout path with a space works and Alembic does not warn (GH #872).
path_separator = os
sqlalchemy.url =

# Run the project's ruff on every new revision, so `make migration` output
Expand Down
Loading