Usage ===== Basic command ------------- .. code-block:: bash uv-start [options] The project name must not contain spaces or underscores. Options ------- .. list-table:: :header-rows: 1 :widths: 30 70 * - Flag - Description * - ``-t, --type [lib|package]`` - Project type to create. **lib** (default) creates a simple library with a ``src/`` layout. **package** creates an installable package with an entry-point script. * - ``-p, --python [3.14|3.13|3.12|3.11|3.10]`` - Python version for the new project (default: **3.13**). * - ``-w, --workspace`` - Create a `uv workspace `_ (monorepo). You will be prompted to add a shared utilities library and additional sub-projects. * - ``-g, --github`` - Initialise a Git repository **and** create a GitHub remote. Sets up CI/CD workflows automatically. * - ``--private`` - Make the GitHub repository private. Requires ``--github``. * - ``--data`` - Create a data analysis project. Installs Jupyter, pandas, matplotlib, and seaborn. No ``src/`` layout — just a flat project with a starter notebook, lab matplotlib style, and colour palette. * - ``--config NAME EMAIL`` - Save author name and email for project templates. Stored in ``~/.config/uv-start/config.toml``. Examples -------- Create a library (default) ^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: bash uv-start my-lib Creates a ``my-lib/`` directory with a ``src/my_lib/`` package, test directory, and all dev-tool configuration. Create an installable package ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: bash uv-start my-cli -t package Same as a library but also registers a console script entry-point so the package can be run from the command line. Specify a Python version ^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: bash uv-start my-project -p 3.12 Target Python 3.12 instead of the default 3.13. Create a project with a GitHub repo ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: bash uv-start my-project -g Initialises a local Git repo, creates a **public** GitHub remote, pushes an initial commit, and sets up CI workflows. .. code-block:: bash uv-start my-project -g --private Same as above but the GitHub repository is **private**. Create a workspace (monorepo) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: bash uv-start my-workspace -w Sets up a uv workspace. You will be interactively prompted to: 1. Add a ``common-utils`` shared library 2. Add additional sub-projects to the workspace Combine workspace and GitHub: .. code-block:: bash uv-start my-workspace -w -g Create a data analysis project ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: bash uv-start my-analysis --data Creates a flat project (no ``src/`` layout) pre-configured for interactive data analysis: - **Jupyter**, **pandas**, **matplotlib**, and **seaborn** installed in the ``.venv`` - Lab matplotlib style (``hhlab_style01.mplstyle``) at the project root - ``colors.py`` — a ``COLOR`` enum with the lab's standard palette - ``sample.ipynb`` — starter notebook that applies the style and imports ``COLOR`` - ``CLAUDE.md`` — instructions for AI-assisted work that enforce consistent figure styling Combine with ``--github`` to create a GitHub repository at the same time: .. code-block:: bash uv-start my-analysis --data -g Generated project structure --------------------------- Standard project ^^^^^^^^^^^^^^^^ .. code-block:: text project-name/ ├── src/ │ └── project_name/ │ └── __init__.py ├── tests/ ├── pyproject.toml ├── README.md ├── LICENSE ├── .env.example └── .pre-commit-config.yaml Workspace ^^^^^^^^^ .. code-block:: text workspace-name/ ├── packages/ │ ├── package1/ │ └── package2/ ├── pyproject.toml ├── README.md └── .pre-commit-config.yaml Data analysis project ^^^^^^^^^^^^^^^^^^^^^ .. code-block:: text analysis-name/ ├── hhlab_style01.mplstyle ← lab matplotlib style, loaded by the notebook ├── colors.py ← COLOR enum with the lab palette ├── sample.ipynb ← starter notebook ├── CLAUDE.md ← AI instructions for consistent figure style ├── pyproject.toml ├── README.md ├── .env.example └── .gitignore Development tools configured ----------------------------- Every generated project comes with: - **Ruff** — linter and formatter (line length 79, flake8 + isort rules) - **Ty** — static type checker (checks ``src/`` and ``tests/``) - **pytest** — test framework with automatic discovery in ``tests/`` - **commitizen** — conventional commits, automatic version bumping, and changelog generation (see :ref:`version-bumps` below) - **pre-commit** — Git hooks that run linting, formatting, and type checking before each commit .. _data-analysis: Data analysis project details ------------------------------ Matplotlib style ^^^^^^^^^^^^^^^^ ``hhlab_style01.mplstyle`` is placed at the project root so it can be referenced by name from any notebook in the same directory: .. code-block:: python import matplotlib.pyplot as plt plt.style.use('hhlab_style01.mplstyle') Always apply this style before creating any figure. Lab colour palette ^^^^^^^^^^^^^^^^^^ ``colors.py`` defines the ``COLOR`` enum with the lab's standard palette. Use the enum values — never raw hex strings or default matplotlib colors: .. code-block:: python from colors import COLOR ax.scatter(x, y, color=COLOR.BLUE.value) ax.bar(labels, heights, color=COLOR.PINK.value) Available colours: .. list-table:: :header-rows: 1 :widths: 25 15 60 * - Name - Hex - Typical use * - ``COLOR.BLUE`` - ``#526C94`` - Primary data series * - ``COLOR.LIGHT_BLUE`` - ``#75B1CE`` - Secondary / paired condition * - ``COLOR.PINK`` - ``#DC6B83`` - Contrast / highlight * - ``COLOR.YELLOW`` - ``#D8C367`` - Third condition * - ``COLOR.TURQUOISE`` - ``#00bfb2`` - Fourth condition * - ``COLOR.LIGHT_GREEN`` - ``#CCDBA2`` - Fifth condition * - ``COLOR.LAVENDER`` - ``#C6B2D1`` - Sixth condition * - ``COLOR.PURPLE`` - ``#654875`` - Seventh condition * - ``COLOR.OLIVE`` - ``#889466`` - Eighth condition * - ``COLOR.GREY`` - ``#D4D3CF`` - Background / negative control * - ``COLOR.DARKGREY`` - ``#4A4A4A`` - Text / annotations To add a new colour, extend the ``COLOR`` enum in ``colors.py`` rather than scattering raw hex values through notebooks. Starter notebook ^^^^^^^^^^^^^^^^ ``sample.ipynb`` opens with the standard imports already in place: .. code-block:: python import matplotlib.pyplot as plt import pandas as pd import seaborn as sns from colors import COLOR plt.style.use('hhlab_style01.mplstyle') It also includes a commented example scatter plot to illustrate the expected usage pattern. CLAUDE.md ^^^^^^^^^ The generated ``CLAUDE.md`` tells Claude Code (and other AI tools) to always apply the lab style and use the ``COLOR`` enum. This keeps AI-generated figure code consistent with hand-written code across the project. .. _version-bumps: Conventional commits and version bumps -------------------------------------- Generated projects use `commitizen `_ to enforce `conventional commits `_ and automate `semantic versioning `_. Use ``cz commit`` instead of ``git commit`` to get an interactive prompt that builds a correctly formatted message: .. code-block:: bash cz commit To bump the version based on your commit history: .. code-block:: bash cz bump Commitizen inspects all commits since the last tag and determines the version bump automatically: .. list-table:: :header-rows: 1 :widths: 25 20 55 * - Commit prefix - Version bump - Example * - ``fix:`` - **PATCH** (0.0.X) - ``fix: handle missing config file`` * - ``feat:`` - **MINOR** (0.X.0) - ``feat: add --config flag`` * - ``BREAKING CHANGE:`` in footer, or ``!`` after type - **MAJOR** (X.0.0) - ``feat!: replace .env with config system`` Other commit types — ``chore:``, ``docs:``, ``refactor:``, ``ci:``, ``test:``, ``style:``, ``perf:``, ``build:`` — are recorded in the changelog but **do not** trigger a version bump. .. note:: While ``major_version_zero`` is enabled in the commitizen configuration (the default for generated projects), breaking changes bump the **minor** version instead of major, following the `SemVer spec for 0.x releases `_. Workspace versioning ^^^^^^^^^^^^^^^^^^^^ When a workspace is created with ``-w``, all packages share a **single synchronized version**. The commitizen configuration lives only in the root ``pyproject.toml`` and its ``version_files`` list covers every sub-package: - ``src//__init__.py`` — ``__version__`` string - ``pyproject.toml`` — ``version`` field - ``README.md`` — version badge Running ``cz bump`` at the workspace root updates all of these files across the root project and every sub-package in one step. The release CI workflow does the same automatically when a conventional commit lands on ``main``. GitHub CI/CD workflows ---------------------- When ``--github`` is used, two GitHub Actions workflows are created: **CI pipeline** — runs on every push and pull request: - Ruff linting and format checking - Ty type checking - pytest test suite **Release pipeline** — runs on pushes to ``main``: - Automatic version bumping based on conventional commits - GitHub release creation with changelog - For workspaces, bumps the single synchronized version across all packages Logging system -------------- Every generated project includes a ready-to-use logging module at ``src//config.py``. It provides environment-variable-driven configuration with sensible defaults, console and rotating file handlers, and environment-specific overrides. Getting a logger ^^^^^^^^^^^^^^^^ Import ``get_logger`` from your package's ``config`` module: .. code-block:: python from my_package.config import get_logger logger = get_logger(__name__) logger.debug("Detailed diagnostic info") logger.info("General operational messages") logger.warning("Something unexpected happened") logger.error("Something failed") The first call to ``get_logger`` configures the root logger based on environment variables. Subsequent calls return child loggers that inherit this configuration. Environment variables ^^^^^^^^^^^^^^^^^^^^^ Control logging behaviour via the ``.env`` file or shell environment. Each generated project includes a ``.env.example`` with sensible defaults. Copy it to activate: .. code-block:: bash cp .env.example .env .. warning:: The ``.env`` file is gitignored by default. Never commit it — it is for local configuration and secrets only. Available variables: .. list-table:: :header-rows: 1 :widths: 30 15 55 * - Variable - Default - Description * - ``LOG_LEVEL`` - ``INFO`` - Minimum level to capture (``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``, ``CRITICAL``) * - ``ENABLE_CONSOLE_LOGGING`` - ``true`` - Print log messages to the terminal * - ``ENABLE_FILE_LOGGING`` - ``true`` - Write log messages to a rotating file * - ``LOG_FILE_PATH`` - ``logs/app.log`` - Path to the log file * - ``LOG_MAX_BYTES`` - ``1048576`` - Max size per log file before rotation (1 MB) * - ``LOG_BACKUP_COUNT`` - ``5`` - Number of rotated log files to keep * - ``LOG_FORMAT`` - see below - Python `logging format string `_ * - ``ENV`` - ``development`` - Active environment; loads ``.env.`` overrides if present Default log format:: %(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s Environment-specific configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Create environment-specific ``.env`` files to override defaults: - ``.env.example`` — template with defaults (checked into version control) - ``.env`` — your local copy of ``.env.example`` (gitignored, never commit) - ``.env.development`` — local development overrides (gitignored) - ``.env.production`` — production settings (gitignored) Example ``.env.production``: .. code-block:: bash LOG_LEVEL=WARNING ENABLE_CONSOLE_LOGGING=false LOG_FILE_PATH=/var/log/myapp/app.log Activate an environment: .. code-block:: bash export ENV=production The configuration strategy is: 1. Load hard-coded defaults 2. Load the base ``.env`` file (if present) 3. Load ``.env.`` (if present), overriding previous values