doc: README and CLAUDE.md for the uv workflow; fix debug env var and platform claims
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,24 +4,25 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## What this is
|
## What this is
|
||||||
|
|
||||||
`app_skellington` is a small Python library (published to PyPI) for building CLI applications. It has nothing runnable on its own. It glues together argparse-based multi-level command menus, name-based dependency injection, ConfigObj INI config with spec validation, and colorlog logging. It targets Python >=3.8 on Linux, Windows and Mac. Runtime deps are `appdirs`, `configobj` and `colorlog`.
|
`app_skellington` is a small Python library (published to PyPI) for building CLI applications. It has nothing runnable on its own. It glues together argparse-based multi-level command menus, name-based dependency injection, ConfigObj INI config with spec validation, and colorlog logging. It targets Python >=3.8. Only Linux is tested; Windows and macOS are goals. Runtime deps are `appdirs`, `configobj` and `colorlog`.
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install -e '.[dev]' pytest # dev extras = ruff, pre-commit; pytest is NOT in the extras
|
uv sync # .venv with the package (editable) + dev group: ruff, pytest, pre-commit, pyyaml
|
||||||
pytest tests # full suite from repo root (or `pytest .` from inside tests/)
|
uv run pytest # full suite (testpaths = tests)
|
||||||
pytest tests/cfg/test_cfg.py::TestConfig_e2e::test_uses_spec_as_defaults # single test
|
uv run pytest tests/cfg/test_cfg.py::TestConfig_e2e::test_uses_spec_as_defaults # single test
|
||||||
pytest tests -k "<keyword>"
|
uv run pytest -k "<keyword>"
|
||||||
|
uv run --python 3.8 pytest # any supported Python; uv.lock forks per version
|
||||||
|
|
||||||
ruff check --fix # lint + import sorting (config in pyproject.toml)
|
uv run ruff check --fix # lint + import sorting (config in pyproject.toml)
|
||||||
ruff format # formatter, line length 88
|
uv run ruff format # formatter, line length 88
|
||||||
|
|
||||||
python -m build # sdist + wheel into dist/
|
uv build # sdist + wheel into dist/; the version shows in the file names
|
||||||
python -m setuptools_scm # print the version the build will get
|
uv lock # after any dependency change; commit uv.lock
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Versioning is tag-driven.** setuptools_scm uses `release-branch-semver` and derives the version from the latest `vX.Y.Z` git tag. It writes `app_skellington/_version.py` at build time. That file is tracked, but don't hand-edit it. `pip install -e .` also rewrites it, so `git restore` it rather than committing the churn. A release means tagging, then `python -m build`, then `twine upload dist/*`. The README covers the full publish steps.
|
- **Versioning is tag-driven.** setuptools_scm uses `release-branch-semver` and derives the version from the latest `vX.Y.Z` git tag. It generates `app_skellington/_version.py`, which is git-ignored, so never commit it. The release steps (tag on `main`, `uv build`, TestPyPI, verify, PyPI) are in the README's Publish section.
|
||||||
- **ruff** handles formatting (88 columns) and lint (`E`, `F`, `W`, `I`). E501 is ignored on purpose, since the formatter owns line length. Keep the `ruff==` pin in `pyproject.toml` equal to the `rev:` in `.pre-commit-config.yaml`.
|
- **ruff** handles formatting (88 columns) and lint (`E`, `F`, `W`, `I`). E501 is ignored on purpose, since the formatter owns line length. Keep the `ruff==` pin in `pyproject.toml` equal to the `rev:` in `.pre-commit-config.yaml`.
|
||||||
- Tests cover only `cfg` (ConfigObj fixtures live in `tests/cfg/`) plus a CommandTree constructor smoke test. `tests/test_log.py` is empty.
|
- Tests cover only `cfg` (ConfigObj fixtures live in `tests/cfg/`) plus a CommandTree constructor smoke test. `tests/test_log.py` is empty.
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ Application framework for Python, features include:
|
|||||||
- Simple to define services and automatic dependency injection based on name (with custom invocation as an option). \*WIP
|
- Simple to define services and automatic dependency injection based on name (with custom invocation as an option). \*WIP
|
||||||
- INI-style config and and validation (provided through ConfigObj).
|
- INI-style config and and validation (provided through ConfigObj).
|
||||||
- Colored logging (provided through colorlog)
|
- Colored logging (provided through colorlog)
|
||||||
- Works on Linux, Windows, and Mac.
|
- Linux supported. Windows and macOS are goals, but untested.
|
||||||
|
|
||||||
Principles:
|
Principles:
|
||||||
- Lend to creating beautiful, easy to read and understand code in the application.
|
- Lend to creating beautiful, easy to read and understand code in the application.
|
||||||
- Minimize coupling of applications to this framework.
|
- Minimize coupling of applications to this framework.
|
||||||
- Compatible with Linux, Windows, and Mac. Try to be compatible as possible otherwise.
|
- Aim for Linux, Windows and macOS. Only Linux is tested today; full multi-platform CI is a long-term goal.
|
||||||
- Try to be compatible with alternate Python runtimes such as PyPy and older python environments. \*WIP
|
- Try to be compatible with alternate Python runtimes such as PyPy and older python environments. \*WIP
|
||||||
|
|
||||||
# Python Package Index (PyPi) - Installation Instruction
|
# Python Package Index (PyPi) - Installation Instruction
|
||||||
@@ -70,7 +70,7 @@ argument.
|
|||||||
|
|
||||||
# Debug - Turn on Logging
|
# Debug - Turn on Logging
|
||||||
|
|
||||||
Set 'APPSKELLINGTON_ENABLE_LOGGING' environment variable to any value which turns
|
Set the 'APPSKELLINGTON_DEBUG' environment variable to any value to turn
|
||||||
on AppSkellington-level logging. For example,
|
on AppSkellington-level logging. For example,
|
||||||
|
|
||||||
APPSKELLINGTON_DEBUG=1 <executable>
|
APPSKELLINGTON_DEBUG=1 <executable>
|
||||||
@@ -82,83 +82,65 @@ or
|
|||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
|
|
||||||
Tests are a WIP and not fully built out yet. Recommendation is to run 'pytest' in the 'tests' directory.
|
```
|
||||||
|
uv run pytest # full suite
|
||||||
|
uv run pytest tests/cfg/test_cfg.py::TestConfig_e2e::test_uses_spec_as_defaults
|
||||||
|
uv run pytest -k "<keyword>"
|
||||||
|
uv run --python 3.8 pytest # against another supported Python
|
||||||
|
```
|
||||||
|
|
||||||
# Development
|
# Development
|
||||||
|
|
||||||
I recommend pyenv to install a reliable, controlled python of preferred version locally.
|
Install [uv](https://docs.astral.sh/uv/). It manages Python versions and the
|
||||||
|
virtual environment, so you don't need pyenv or a hand-made venv.
|
||||||
|
|
||||||
```
|
```
|
||||||
curl https://pyenv.run | bash
|
|
||||||
|
|
||||||
# Add to .bashrc or similar for different shells:
|
|
||||||
tee -a "$HOME"/.profile <<'EOF'
|
|
||||||
|
|
||||||
export PYENV_ROOT="$HOME/.pyenv"
|
|
||||||
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
|
||||||
eval "$(pyenv init -)"
|
|
||||||
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
* reference https://github.com/pyenv/pyenv
|
|
||||||
* Use pyenv to install desired python version, and/or create any virtual environments you desire
|
|
||||||
|
|
||||||
Clone the repo:
|
|
||||||
```commandline
|
|
||||||
git clone https://git-repos.zavage.net/zavage-software/app_skellington.git
|
git clone https://git-repos.zavage.net/zavage-software/app_skellington.git
|
||||||
|
cd app_skellington
|
||||||
|
uv sync # creates .venv with the package (editable) + dev tools
|
||||||
|
uv run pre-commit install # ruff lint + format on every commit
|
||||||
```
|
```
|
||||||
|
|
||||||
Install pre-commit hooks:
|
Lint and format (ruff, line length 88):
|
||||||
```commandline
|
```
|
||||||
pre-commit install
|
uv run ruff check --fix
|
||||||
|
uv run ruff format
|
||||||
```
|
```
|
||||||
|
|
||||||
Build:
|
Build the sdist and wheel into `dist/`:
|
||||||
```
|
```
|
||||||
python -m build
|
uv build
|
||||||
```
|
```
|
||||||
|
|
||||||
Install:
|
Dependencies are locked in `uv.lock`. After editing dependencies in
|
||||||
|
`pyproject.toml`, run `uv lock` and commit the result.
|
||||||
```
|
|
||||||
pip install .
|
|
||||||
```
|
|
||||||
|
|
||||||
Formatting and Linters:
|
|
||||||
```
|
|
||||||
black app_skellington
|
|
||||||
isort app_skellington
|
|
||||||
flake8 app_skellington
|
|
||||||
```
|
|
||||||
|
|
||||||
Publish:
|
|
||||||
|
|
||||||
```
|
|
||||||
# Push latest commit, or on commit ready to publish:
|
|
||||||
git push
|
|
||||||
|
|
||||||
# Create a tag with the desired version number and push:
|
|
||||||
git tag -a v0.2.0 -m "0.2.0 provides modern pyproject.toml build with setuptools, versioning, and publishing"
|
|
||||||
git push origin v0.2.0
|
|
||||||
|
|
||||||
# Build the wheel:
|
|
||||||
python -m build
|
|
||||||
|
|
||||||
# Publish to pypi:
|
|
||||||
twine check dist/*
|
|
||||||
twine upload dist/*
|
|
||||||
```
|
|
||||||
* Reference https://packaging.python.org/en/latest/overview/
|
|
||||||
|
|
||||||
|
|
||||||
# Version
|
# Version
|
||||||
|
|
||||||
setuptools_scm will infer the version based on the latest tag in your Git history.
|
setuptools_scm derives the version from the latest `vX.Y.Z` git tag. Between
|
||||||
Ensure you are tagging your commits with meaningful version numbers like v1.0.0, v1.1.0, etc.
|
tags you get development versions like `0.3.0.dev4+g1a2b3c4`. The generated
|
||||||
|
`app_skellington/_version.py` is git-ignored.
|
||||||
|
|
||||||
You can view the current version number with the command:
|
uv build # the version appears in the dist/ file names
|
||||||
|
|
||||||
python -m setuptools_scm
|
# Publish
|
||||||
|
|
||||||
|
Publish only from a tagged commit on `main`, after CI is green, and only after
|
||||||
|
TestPyPI has been checked.
|
||||||
|
|
||||||
|
```
|
||||||
|
git switch main && git pull --ff-only
|
||||||
|
git tag -a v0.2.3 -m "0.2.3: <summary>"
|
||||||
|
git push origin v0.2.3
|
||||||
|
rm -rf dist && uv build
|
||||||
|
ls dist # must be exactly app_skellington-0.2.3.tar.gz and app_skellington-0.2.3-py3-none-any.whl
|
||||||
|
|
||||||
|
uv publish --publish-url https://test.pypi.org/legacy/ dist/* # TestPyPI first
|
||||||
|
scripts/verify_index_release.sh 0.2.3 # every supported Python
|
||||||
|
uv publish dist/* # then PyPI
|
||||||
|
scripts/verify_index_release.sh 0.2.3 https://pypi.org/simple/
|
||||||
|
```
|
||||||
|
* Reference https://packaging.python.org/en/latest/overview/
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -4,14 +4,14 @@ Contained is the early stages of unit testing for app_skellington framework.
|
|||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
Run all tests (cwd is testing directory):
|
Run all tests (from the repo root):
|
||||||
|
|
||||||
pytest .
|
uv run pytest
|
||||||
|
|
||||||
Run test by keyword:
|
Run test by keyword:
|
||||||
|
|
||||||
pytest -k "<test keyword>" .
|
uv run pytest -k "<test keyword>"
|
||||||
|
|
||||||
Run test by directory:
|
Run test by directory:
|
||||||
|
|
||||||
pytest <dirname>
|
uv run pytest tests/<dirname>
|
||||||
|
|||||||
Reference in New Issue
Block a user