Skip to content

Navigation Menu

Sign in
Sign up

Proposal: installable package with a pyproject and Typer CLI - #6

Draft
FBumann wants to merge 2 commits into
open-energy-transition:main from
FBumann:proposal/pyproject-typer-packaging
Draft

Proposal: installable package with a pyproject and Typer CLI #6
FBumann wants to merge 2 commits into
open-energy-transition:main from
FBumann:proposal/pyproject-typer-packaging

Conversation

@FBumann

@FBumann FBumann commented Aug 15, 2026
edited
Loading

Copy link
Copy Markdown

Hi, I used you package and thought it could benefit from some modern python tools.
I added typer, uv, pyprject.toml and ruff.
This is a working implementation, but its only a proposal. Happy to hear what you think of it, and happy to refine things.


AI generated content below

This is a proposal, not a merge request

Opening this as a draft because it changes the shape of the project, and that's a maintainer call rather than something to decide in a diff. Treat it as an issue that happens to come with a working implementation: if the direction isn't wanted, closing it costs nothing. If parts are wanted and others aren't, I'm happy to split it up.

The question I'd like answered: should Grid2Poster become an installable package with a console script, or stay a set of scripts you run from a checkout?

Why

Today the tool is six top-level modules plus requirements.txt, run as python create_grid_poster.py. That works well inside a clone, but it means:

  • dependencies are unpinned, so two contributors can get different geopandas/osmnx versions and different output
  • themes/ and regions/ are only reachable from the repository root, so the tool can't be installed and used from another directory
  • cache/, posters/ and themes/ are created in the working directory at import time, as a side effect of importing common
  • the CLI is a single 300-line argparse block that's getting hard to read at ~45 options

What's in here

Packaging. pyproject.toml (PEP 621, hatchling) replaces requirements.txt; modules move to src/grid2poster/; uv.lock is checked in so everyone resolves the same versions. Installs a grid2poster command, and python -m grid2poster also works.

Bundled data. themes/ and regions/ move to src/grid2poster/data/ and are found via importlib.resources — so an installed copy works from any directory. A themes/ or regions/ directory in the working directory still takes precedence, so local overrides and experiments are unaffected.

Typer CLI. argparse → Typer. Every option keeps its name, default and short flag; the options are grouped into help panels (Region / Grid data / Style / Layout / Output / Network) so --help is navigable.

Ruff. Lint + format config in pyproject.toml, and the tree formatted to match.

Nothing you can type today stops working

This was the constraint I held myself to. Click can't express two of argparse's syntaxes, so normalize_legacy_argv() rewrites them before Typer sees them:

Old command Status
python create_grid_poster.py --country Brazil works — forwarding shim, deprecation note on stderr
--format png svg (argparse nargs="+") works — rewritten to --format png,svg
--export-geojson (bare) works
--export-geojson out.geojson (argparse nargs="?") works — rewritten to --export-geojson-path
--boundary-geojson ./regions/europe.geojson works — resolves to the bundled region

The one exception: argparse accepts unambiguous abbreviations of long options (--coun Brazil), and Click has no equivalent. Options must be spelled out in full.

Two additions fall out of bundling the regions, since otherwise they'd be unreachable outside a checkout: --list-regions, and --boundary-geojson accepting a bare region name (--boundary-geojson europe).

Try it

uv sync
uv run grid2poster --country Luxembourg --single-query --paper-size a5
uv run grid2poster --list-regions
uv run python create_grid_poster.py --country Luxembourg --format png svg # old syntax

Reviewing

The diff is large but most of it is mechanical. In order of how much attention it deserves:

  • src/grid2poster/cli.py — the only real rewrite
  • src/grid2poster/common.pydata_dir() lookup, lazy directory creation
  • src/grid2poster/theming.py — theme lookup via themes_dir(); drops DEFAULT_THEMES / ensure_builtin_themes(), whose three themes are byte-identical to the shipped JSON files
  • pyproject.toml
  • osm_data.py, prepare.py, render.py — import paths plus a handful of ruff fixes; the rest is the format sweep
  • data/themes/*, data/regions/* — pure moves, no content changes

Open questions

  1. Direction — is an installable package wanted at all?
  2. Do the bundled themes/regions belong in the package, or should they stay at the repository root as browsable content? The CWD-override means both can be true, but the shipped copy has to live somewhere.
  3. Should the create_grid_poster.py shim stay, or is a clean break preferable given the tool is young?
  4. Splitting — happy to break this into separate PRs (packaging, then Typer, then the ruff sweep) if that's easier to review.
  5. Conflict with Add voltages filtering argument #4 — "Add voltages filtering argument" touches create_grid_poster.py and osm_data.py, so it collides with this. Add voltages filtering argument #4 should land first; I'll rebase this on top and port the new option to Typer.
  6. Package metadata creditauthors is set to the LICENSE copyright holder and maintainers to the organization, with no email addresses, since publishing those is the holder's call rather than mine. @ly0 wrote the large majority of the commits and isn't named; I didn't want to guess at a preferred name or address. Please correct these fields to whatever you'd want published.

Not included

No tests and no CI. There are none in the repo today, and adding them here would have made an already-broad PR broader — but I'd argue a change this size should come with them, and I'm glad to add a pytest suite over the pure logic (voltage-tier parsing, the legacy-argv shim, theme loading, format parsing) plus a GitHub Actions workflow if you want that before merging.

What I verified

Renders were run end to end against a live Overpass mirror, in both the new and old syntax, producing PNG + SVG + GeoJSON. The built wheel contains all 41 themes and 32 regions. ruff check and ruff format --check are clean. The CWD-override and bundled-fallback lookups were checked from a directory outside the repository.

FBumann and others added 2 commits August 15, 2026 15:38
Turn the flat script layout into an installable package without changing
how any existing command behaves.
- Move the pipeline modules into src/grid2poster/ and declare the project
 in pyproject.toml (PEP 621, hatchling), replacing requirements.txt.
 Dependencies are pinned in uv.lock so contributors resolve identically.
- Install a `grid2poster` console script (also `python -m grid2poster`).
- Bundle themes/ and regions/ as package data under src/grid2poster/data/,
 resolved via importlib.resources. A themes/ or regions/ directory in the
 working directory still wins, so local overrides keep working and the
 command works from any directory once installed.
- Port the CLI from argparse to Typer. Every option keeps its name,
 default and short flag; the ~45 options are grouped into help panels.
- Keep the old syntax working. Click has no variadic or optional-value
 options, so normalize_legacy_argv() rewrites `--format png svg` and
 `--export-geojson PATH` into their Typer equivalents, and
 --boundary-geojson resolves old ./regions/*.geojson paths against the
 bundled regions. create_grid_poster.py stays as a forwarding shim.
- Add --list-regions and let --boundary-geojson take a bare region name,
 so the bundled regions are reachable outside a checkout.
- Drop DEFAULT_THEMES/ensure_builtin_themes(); the three themes it wrote
 to disk are byte-identical to the shipped JSON files.
- Create cache/ and posters/ on first write instead of at import time.
- Add ruff lint and format configuration, and format the tree.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rewrite the install section around uv sync / pip install -e . / uv tool
install, and update every invocation from `python create_grid_poster.py`
to `grid2poster`. Add an upgrade section spelling out what still works
from the old CLI and the one thing that does not (argparse's automatic
abbreviation of long options).
Predefined regions are now listed by name rather than by path, matching
--list-regions, and a Development section documents the package layout
and the ruff commands.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

1 participant

AltStyle によって変換されたページ (->オリジナル) /