rhiza 0.3.0__py3-none-any.whl → 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
rhiza/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """Utility tools and command-line helpers for the Rhiza project.
2
+
3
+ This package groups small, user-facing utilities that can be invoked from
4
+ the command line or other automation scripts.
5
+ """
rhiza/__main__.py ADDED
@@ -0,0 +1,10 @@
1
+ """Rhiza module entry point.
2
+
3
+ This module allows running the Rhiza CLI with `python -m rhiza` by
4
+ delegating execution to the Typer application defined in `rhiza.cli`.
5
+ """
6
+
7
+ from rhiza.cli import app
8
+
9
+ if __name__ == "__main__":
10
+ app()
rhiza/cli.py ADDED
@@ -0,0 +1,47 @@
1
+ """Rhiza command-line interface (CLI).
2
+
3
+ This module defines the Typer application entry points exposed by Rhiza.
4
+ Commands are thin wrappers around implementations in `rhiza.commands.*`.
5
+ """
6
+
7
+ from pathlib import Path
8
+
9
+ import typer
10
+
11
+ from rhiza.commands.hello import hello as hello_cmd
12
+ from rhiza.commands.inject import inject as inject_cmd
13
+
14
+ app = typer.Typer(help="rhiza — configuration materialization tools")
15
+
16
+
17
+ @app.command()
18
+ def hello():
19
+ """Sanity check command."""
20
+ hello_cmd()
21
+
22
+
23
+ @app.command()
24
+ def materialize(
25
+ target: Path = typer.Argument(
26
+ default=Path("."), # default to current directory
27
+ exists=True,
28
+ file_okay=False,
29
+ dir_okay=True,
30
+ help="Target git repository (defaults to current directory)",
31
+ ),
32
+ branch: str = typer.Option("main", "--branch", "-b", help="Rhiza branch to use"),
33
+ force: bool = typer.Option(False, "--force", "-y", help="Overwrite existing files"),
34
+ ):
35
+ """Inject Rhiza configuration into a target repository.
36
+
37
+ Parameters
38
+ ----------
39
+ target:
40
+ Path to the target Git repository directory. Defaults to the
41
+ current working directory.
42
+ branch:
43
+ Name of the Rhiza branch to use when sourcing templates.
44
+ force:
45
+ If True, overwrite existing files without prompting.
46
+ """
47
+ inject_cmd(target, branch, force)
@@ -0,0 +1,5 @@
1
+ """Command implementations for the Rhiza CLI.
2
+
3
+ This package contains the functions that back Typer commands exposed by
4
+ `rhiza.cli`, such as `hello` and `inject`.
5
+ """
@@ -0,0 +1,9 @@
1
+ """Small demo CLI entrypoint for Rhiza tools.
2
+
3
+ This module provides a minimal example command that prints a greeting.
4
+ """
5
+
6
+
7
+ def hello():
8
+ """Print a friendly greeting from Rhiza."""
9
+ print("Hello from Rhiza!")
@@ -0,0 +1,160 @@
1
+ """Command-line helpers for working with Rhiza templates.
2
+
3
+ This module currently exposes a thin wrapper that shells out to the
4
+ `tools/inject_rhiza.sh` script. It exists so the functionality can be
5
+ invoked via a Python entry point while delegating the heavy lifting to
6
+ the maintained shell script.
7
+ """
8
+
9
+ import shutil
10
+ import subprocess
11
+ import sys
12
+ import tempfile
13
+ from pathlib import Path
14
+
15
+ import yaml
16
+ from loguru import logger
17
+
18
+
19
+ def expand_paths(base_dir: Path, paths: list[str]) -> list[Path]:
20
+ """Expand files/directories relative to base_dir into a flat list of files.
21
+
22
+ Given a list of paths relative to ``base_dir``, return a flat list of all
23
+ individual files.
24
+ """
25
+ all_files = []
26
+ for p in paths:
27
+ full_path = base_dir / p
28
+ if full_path.is_file():
29
+ all_files.append(full_path)
30
+ elif full_path.is_dir():
31
+ all_files.extend([f for f in full_path.rglob("*") if f.is_file()])
32
+ else:
33
+ # Path does not exist — could log a warning
34
+ continue
35
+ return all_files
36
+
37
+
38
+ def inject(target: Path, branch: str, force: bool):
39
+ """Materialize rhiza templates into TARGET repository."""
40
+ # Convert to absolute path to avoid surprises
41
+ target = target.resolve()
42
+
43
+ # Validate target is a git repository
44
+ if not (target / ".git").is_dir():
45
+ logger.error(f"Target directory is not a git repository: {target}")
46
+ raise sys.exit(1)
47
+
48
+ logger.info(f"Target repository: {target}")
49
+ logger.info(f"Rhiza branch: {branch}")
50
+
51
+ # -----------------------
52
+ # Ensure template.yml
53
+ # -----------------------
54
+ template_file = target / ".github" / "template.yml"
55
+ template_file.parent.mkdir(parents=True, exist_ok=True)
56
+
57
+ if not template_file.exists():
58
+ logger.info("Creating default .github/template.yml")
59
+ template_content = {
60
+ "template-repository": "jebel-quant/rhiza",
61
+ "template-branch": branch,
62
+ "include": [
63
+ ".github",
64
+ ".editorconfig",
65
+ ".gitignore",
66
+ ".pre-commit-config.yaml",
67
+ "Makefile",
68
+ "pytest.ini",
69
+ ],
70
+ }
71
+ with open(template_file, "w") as f:
72
+ yaml.dump(template_content, f)
73
+ logger.success(".github/template.yml created")
74
+ else:
75
+ logger.info("Using existing .github/template.yml")
76
+
77
+ # -----------------------
78
+ # Load template.yml
79
+ # -----------------------
80
+ with open(template_file) as f:
81
+ config = yaml.safe_load(f)
82
+
83
+ rhiza_repo = config.get("template-repository")
84
+ rhiza_branch = config.get("template-branch", branch)
85
+ include_paths = config.get("include", [])
86
+ excluded_paths = config.get("exclude", [])
87
+
88
+ if not include_paths:
89
+ logger.error("No include paths found in template.yml")
90
+ raise sys.exit(1)
91
+
92
+ logger.info("Include paths:")
93
+ for p in include_paths:
94
+ logger.info(f" - {p}")
95
+
96
+ # -----------------------
97
+ # Sparse clone rhiza
98
+ # -----------------------
99
+ tmp_dir = Path(tempfile.mkdtemp())
100
+ logger.info(f"Cloning {rhiza_repo}@{rhiza_branch} into temporary directory")
101
+
102
+ try:
103
+ subprocess.run(
104
+ [
105
+ "git",
106
+ "clone",
107
+ "--depth",
108
+ "1",
109
+ "--filter=blob:none",
110
+ "--sparse",
111
+ "--branch",
112
+ rhiza_branch,
113
+ f"https://github.com/{rhiza_repo}.git",
114
+ str(tmp_dir),
115
+ ],
116
+ check=True,
117
+ stdout=subprocess.DEVNULL,
118
+ )
119
+
120
+ subprocess.run(["git", "sparse-checkout", "init"], cwd=tmp_dir, check=True)
121
+ subprocess.run(["git", "sparse-checkout", "set", "--skip-checks", *include_paths], cwd=tmp_dir, check=True)
122
+
123
+ # After sparse-checkout
124
+ all_files = expand_paths(tmp_dir, include_paths)
125
+
126
+ # Filter out excluded files
127
+ # excluded_set = {tmp_dir / e for e in excluded_paths}
128
+ excluded_files = expand_paths(tmp_dir, excluded_paths)
129
+
130
+ files_to_copy = [f for f in all_files if f not in excluded_files]
131
+ # print(files_to_copy)
132
+
133
+ # Copy loop
134
+ for src_file in files_to_copy:
135
+ dst_file = target / src_file.relative_to(tmp_dir)
136
+ if dst_file.exists() and not force:
137
+ logger.warning(f"{dst_file.relative_to(target)} already exists — use force=True to overwrite")
138
+ continue
139
+
140
+ dst_file.parent.mkdir(parents=True, exist_ok=True)
141
+ shutil.copy2(src_file, dst_file)
142
+ logger.success(f"[ADD] {dst_file.relative_to(target)}")
143
+
144
+ finally:
145
+ shutil.rmtree(tmp_dir)
146
+
147
+ logger.success("Rhiza templates materialized successfully")
148
+ logger.info("""
149
+ Next steps:
150
+ 1. Review changes:
151
+ git status
152
+ git diff
153
+
154
+ 2. Commit:
155
+ git add .
156
+ git commit -m "chore: import rhiza templates"
157
+
158
+ This is a one-shot snapshot.
159
+ Re-run this script to update templates explicitly.
160
+ """)
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.4
2
+ Name: rhiza
3
+ Version: 0.4.0
4
+ Summary: Reusable configuration templates for modern Python projects
5
+ Project-URL: Homepage, https://github.com/jebel-quant/rhiza-cli
6
+ Project-URL: Repository, https://github.com/jebel-quant/rhiza-cli
7
+ Project-URL: Issues, https://github.com/jebel-quant/rhiza/issues-cli
8
+ Author: Thomas Schmelzer
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: ci,configuration,ruff,taskfile,templates
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Software Development :: Build Tools
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: loguru>=0.7.3
23
+ Requires-Dist: pyyaml==6.0.3
24
+ Requires-Dist: typer>=0.20.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: marimo==0.18.4; extra == 'dev'
27
+ Requires-Dist: pdoc>=16.0.0; extra == 'dev'
28
+ Requires-Dist: pre-commit==4.5.0; extra == 'dev'
29
+ Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
30
+ Requires-Dist: pytest-html>=4.1.1; extra == 'dev'
31
+ Requires-Dist: pytest==9.0.2; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # rhiza-cli
35
+ Command line interface for Rhiza
@@ -0,0 +1,11 @@
1
+ rhiza/__init__.py,sha256=wI9tfPnLnVJRkAZrjCmAOvU4cGn-2BOTN_MFZc0c0OQ,190
2
+ rhiza/__main__.py,sha256=Lx0GqVZo6ymm0f18_uYB6E7_SOWwJNYjb73Vr31oLoM,236
3
+ rhiza/cli.py,sha256=FCCqwWZMDRSeDm6GERvlXkck0RSxq3rzWqUh3Q0XVJk,1343
4
+ rhiza/commands/__init__.py,sha256=X5ZRDDl37X8mEbiMWoqjTGlLhebkYhZ2SaLJd4KcHdw,166
5
+ rhiza/commands/hello.py,sha256=_zhLoGLM21cm5XBYohwm5gbsNMpJ96ZxCcLwHrwhKVs,216
6
+ rhiza/commands/inject.py,sha256=9MpS08TtOhjxIturzN2ejvEnrvGJUCGMjuS4JTuE2G4,5028
7
+ rhiza-0.4.0.dist-info/METADATA,sha256=as92HkPHqiwg4HWlwGkR7CCCRdw5s8cLASHnP2luFek,1388
8
+ rhiza-0.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
9
+ rhiza-0.4.0.dist-info/entry_points.txt,sha256=NAwZUpbXvfKv50a_Qq-PxMHl3lcjAyZO63IBeuUNgfY,45
10
+ rhiza-0.4.0.dist-info/licenses/LICENSE,sha256=4m5X7LhqX-6D0Ks79Ys8CLpmza8cxDG34g4S9XSNAGY,1077
11
+ rhiza-0.4.0.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ rhiza = rhiza.__main__:app
rhiza/.gitkeep DELETED
File without changes
@@ -1,709 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: rhiza
3
- Version: 0.3.0
4
- Summary: Reusable configuration templates for modern Python projects
5
- Project-URL: Homepage, https://github.com/jebel-quant/rhiza
6
- Project-URL: Repository, https://github.com/jebel-quant/rhiza
7
- Project-URL: Issues, https://github.com/jebel-quant/rhiza/issues
8
- Author: Thomas Schmelzer
9
- License: MIT
10
- License-File: LICENSE
11
- Keywords: ci,configuration,ruff,templates
12
- Classifier: Intended Audience :: Developers
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3 :: Only
16
- Classifier: Programming Language :: Python :: 3.11
17
- Classifier: Programming Language :: Python :: 3.12
18
- Classifier: Programming Language :: Python :: 3.13
19
- Classifier: Programming Language :: Python :: 3.14
20
- Classifier: Topic :: Software Development :: Build Tools
21
- Requires-Python: >=3.11
22
- Provides-Extra: dev
23
- Requires-Dist: marimo==0.18.4; extra == 'dev'
24
- Requires-Dist: pdoc>=16.0.0; extra == 'dev'
25
- Requires-Dist: pre-commit==4.5.0; extra == 'dev'
26
- Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
27
- Requires-Dist: pytest-html>=4.1.1; extra == 'dev'
28
- Requires-Dist: pytest==9.0.2; extra == 'dev'
29
- Description-Content-Type: text/markdown
30
-
31
- <div align="center">
32
-
33
- # <img src="assets/rhiza-logo.svg" alt="Rhiza Logo" width="30" style="vertical-align: middle;"> Rhiza
34
-
35
- ![Created with Rhiza](https://img.shields.io/badge/synced%20with-rhiza-2FA4A9?logoUrl=https://raw.githubusercontent.com/Jebel-Quant/rhiza/main/assets/rhiza-logo.svg)
36
- [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
37
- [![Python versions](https://img.shields.io/badge/Python-3.11%20•%203.12%20•%203.13%20•%203.14-blue?logo=python)](https://www.python.org/)
38
- [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg?logo=ruff)](https://github.com/astral-sh/ruff)
39
- [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
40
- [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
41
-
42
-
43
- [![CI Status](https://github.com/jebel-quant/rhiza/workflows/CI/badge.svg)](https://github.com/jebel-quant/rhiza/actions)
44
- [![Pre-commit](https://github.com/jebel-quant/rhiza/workflows/PRE-COMMIT/badge.svg)](https://github.com/jebel-quant/rhiza/actions?query=workflow%3APRE-COMMIT)
45
- [![Deptry](https://github.com/jebel-quant/rhiza/workflows/DEPTRY/badge.svg)](https://github.com/jebel-quant/rhiza/actions?query=workflow%3ADEPTRY)
46
- [![Book](https://github.com/jebel-quant/rhiza/workflows/BOOK/badge.svg)](https://github.com/jebel-quant/rhiza/actions?query=workflow%3ABOOK)
47
- [![MARIMO](https://github.com/Jebel-Quant/rhiza/actions/workflows/marimo.yml/badge.svg)](https://github.com/Jebel-Quant/rhiza/actions/workflows/marimo.yml)
48
-
49
- [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/jebel-quant/rhiza)
50
-
51
- A collection of reusable configuration templates
52
- for modern Python projects.
53
- Save time and maintain consistency across your projects
54
- with these pre-configured templates.
55
-
56
- ![Last Updated](https://img.shields.io/github/last-commit/jebel-quant/rhiza/main?label=Last%20updated&color=blue)
57
-
58
- </div>
59
-
60
- ## ✨ Features
61
-
62
- - 🚀 **CI/CD Templates** - Ready-to-use GitHub Actions and GitLab CI workflows
63
- - 🧪 **Testing Framework** - Comprehensive test setup with pytest
64
- - 📚 **Documentation** - Automated documentation generation
65
- - 🔍 **Code Quality** - Linting, formatting, and dependency checking
66
- - 📝 **Editor Configuration** - Cross-platform .editorconfig for consistent coding style
67
- - 📊 **Marimo Integration** - Interactive notebook support
68
-
69
- ## 🚀 Getting Started
70
-
71
- Start by cloning the repository:
72
-
73
- ```bash
74
- # Clone the repository
75
- git clone https://github.com/jebel-quant/rhiza.git
76
- cd rhiza
77
- ```
78
-
79
- The project uses a [Makefile](Makefile) as the primary entry point for all tasks.
80
- It relies on [uv and uvx](https://github.com/astral-sh/uv) for fast Python package management.
81
-
82
- Install all dependencies using:
83
-
84
- ```bash
85
- make install
86
- ```
87
-
88
- This will:
89
- - Install `uv` and `uvx` into the `bin/` directory
90
- - Create a Python virtual environment in `.venv/`
91
- - Install all project dependencies from `pyproject.toml`
92
-
93
- Both the `.venv` and `bin` directories are listed in `.gitignore`.
94
-
95
- ## 📋 Available Tasks
96
-
97
- Run `make help` to see all available targets:
98
-
99
- ```makefile
100
- Usage:
101
- make <target>
102
-
103
- Targets:
104
-
105
- Bootstrap
106
- install-uv ensure uv/uvx is installed
107
- install-extras run custom build script (if exists)
108
- install install
109
- clean clean
110
-
111
- Development and Testing
112
- test run all tests
113
- marimo fire up Marimo server
114
- marimushka export Marimo notebooks to HTML
115
- deptry run deptry if pyproject.toml exists
116
-
117
- Documentation
118
- docs create documentation with pdoc
119
- book compile the companion book
120
- fmt check the pre-commit hooks and the linting
121
- all Run everything
122
-
123
- Releasing and Versioning
124
- bump bump version
125
- release create tag and push to remote with prompts
126
- post-release perform post-release tasks
127
-
128
- Meta
129
- sync sync with template repository as defined in .github/template.yml
130
- help Display this help message
131
- customisations list available customisation scripts
132
- update-readme update README.md with current Makefile help output
133
- ```
134
-
135
- The [Makefile](Makefile) provides organized targets for bootstrapping, development, testing, and documentation tasks.
136
-
137
- > **Note:** The help output above is automatically generated from the Makefile.
138
- > When you modify Makefile targets or descriptions, run `make update-readme` to update this section,
139
- > or the pre-commit hook will update it automatically when you commit changes to the Makefile.
140
-
141
- ## 📊 Marimo Notebooks
142
-
143
- This project supports [Marimo](https://marimo.io/) notebooks. You can run the Marimo server using:
144
-
145
- ```bash
146
- make marimo
147
- ```
148
-
149
- ### Configuration
150
-
151
- To ensure Marimo can import the local package (`src/config`), the following configuration is added to `pyproject.toml`:
152
-
153
- ```toml
154
- [tool.marimo.runtime]
155
- pythonpath = ["src"]
156
- ```
157
-
158
- ### Dependency Management
159
-
160
- Marimo notebooks can define their own dependencies using inline script metadata. This allows notebooks to be self-contained and reproducible.
161
-
162
- To use the current package (`rhiza`) within a notebook, you can define it as a dependency and point `uv` to the local path. Add the following block at the top of your `.py` notebook file:
163
-
164
- ```python
165
- # /// script
166
- # requires-python = ">=3.11"
167
- # dependencies = [
168
- # "marimo",
169
- # "pandas",
170
- # "rhiza",
171
- # ]
172
- #
173
- # [tool.uv.sources]
174
- # rhiza = { path = "../.." }
175
- # ///
176
- ```
177
-
178
- Adjust the `path` in `[tool.uv.sources]` relative to the notebook's location.
179
-
180
- ## Testing your documentation
181
-
182
- Any README.md file will be scanned for Python code blocks.
183
- If any are found, they will be tested in [test_readme.py](tests/test_config_templates/test_readme.py).
184
-
185
- ```python
186
- # Some generic Python code block
187
- import math
188
- print("Hello, World!")
189
- print(1 + 1)
190
- print(round(math.pi, 2))
191
- print(round(math.cos(math.pi/4.0), 2))
192
- ```
193
-
194
- For each code block, we define a block of expected output.
195
- If the output matches the expected output, a [test](tests/test_config_templates/test_readme.py) passes,
196
- Otherwise, it fails.
197
-
198
- ```result
199
- Hello, World!
200
- 2
201
- 3.14
202
- 0.71
203
- ```
204
-
205
- ## 🎨 Documentation Customization
206
-
207
- You can customize the look and feel of your documentation by providing your own templates.
208
-
209
- ### API Documentation (pdoc)
210
-
211
- The `make docs` command checks for a directory at `book/pdoc-templates`. If found, it uses the templates within that directory to generate the API documentation.
212
-
213
- To customize the API docs:
214
- 1. Create the directory: `mkdir -p book/pdoc-templates`
215
- 2. Add your Jinja2 templates (e.g., `module.html.jinja2`) to this directory.
216
-
217
- See the [pdoc documentation](https://pdoc.dev/docs/pdoc.html#templates) for more details on templating.
218
-
219
- ### Companion Book (minibook)
220
-
221
- The `make book` command checks for a template at `book/minibook-templates/custom.html.jinja2`. If found, it uses this template for the minibook generation.
222
-
223
- To customize the book:
224
- 1. Create the directory: `mkdir -p book/minibook-templates`
225
- 2. Create your custom template at `book/minibook-templates/custom.html.jinja2`.
226
-
227
- ## 📁 Available Templates
228
-
229
- This repository provides a curated set of reusable configuration templates, organised by purpose.
230
-
231
- ### 🌱 Core Project Configuration
232
- Foundational files that define project structure, standards, and contribution practices.
233
-
234
- - **.gitignore** — Sensible defaults for Python projects
235
- - **.editorconfig** — Editor configuration to enforce consistent coding standards
236
- - **ruff.toml** — Configuration for the Ruff linter and formatter
237
- - **pytest.ini** — Configuration for the `pytest` testing framework
238
- - **Makefile** — Simple make targets for common development tasks
239
- - **CODE_OF_CONDUCT.md** — Generic code of conduct for open-source projects
240
- - **CONTRIBUTING.md** — Generic contributing guidelines for open-source projects
241
-
242
- ### 🔧 Developer Experience
243
- Tooling that improves local development, onboarding, and reproducibility.
244
-
245
- - **.devcontainer/** — Development container setup (VS Code / Dev Containers)
246
- - **.pre-commit-config.yaml** — Common and useful pre-commit hooks
247
- - **docker/** — Example `Dockerfile` and `.dockerignore`
248
-
249
- ### 🚀 CI / CD & Automation
250
- Templates related to continuous integration, delivery, and repository automation.
251
-
252
- - **.github/** — GitHub Actions workflows, scripts, and repository templates
253
-
254
- ## ⚙️ Workflow Configuration
255
-
256
- The GitHub Actions workflows can be customized using repository variables:
257
-
258
- ### Python Version Control
259
-
260
- Control which Python versions are used in your workflows:
261
-
262
- - **`PYTHON_MAX_VERSION`** - Maximum Python version for CI testing matrix
263
- - Default: `'3.14'` (tests on 3.11, 3.12, 3.13, 3.14)
264
- - Set to `'3.13'` to test on 3.11, 3.12, 3.13 only
265
- - Set to `'3.12'` to test on 3.11, 3.12 only
266
- - Set to `'3.11'` to test on 3.11 only
267
-
268
- - **`PYTHON_DEFAULT_VERSION`** - Default Python version for release, pre-commit, book, and marimo workflows
269
- - Default: `'3.14'`
270
- - Set to `'3.12'` or `'3.13'` if dependencies are not compatible with newer versions
271
-
272
- **To set these variables:**
273
-
274
- 1. Go to your repository Settings → Secrets and variables → Actions → Variables tab
275
- 2. Click "New repository variable"
276
- 3. Add `PYTHON_MAX_VERSION` and/or `PYTHON_DEFAULT_VERSION` with your desired values
277
-
278
- ## 🧩 Bringing Rhiza into an Existing Project
279
-
280
- Rhiza provides reusable configuration templates that you can integrate into your existing Python projects.
281
- You can choose to adopt all templates or selectively pick the ones that fit your needs.
282
-
283
- ### Prerequisites
284
-
285
- Before integrating Rhiza into your existing project:
286
-
287
- - **Python 3.11+** - Ensure your project supports Python 3.11 or newer
288
- - **Git** - Your project should be a Git repository
289
- - **Backup** - Consider committing any uncommitted changes before integration
290
- - **Review** - Review the [Available Templates](#-available-templates) section to understand what could be added
291
-
292
- ### Quick Start: Automated Injection
293
-
294
- The fastest way to integrate Rhiza is using the provided `inject_rhiza.sh` script:
295
-
296
- ```bash
297
- # Navigate to your repository
298
- cd /path/to/your/project
299
-
300
- # Run the injection script
301
- uvx rhiza .
302
- ```
303
-
304
- This will:
305
- - ✅ Create a default template configuration (`.github/template.yml`)
306
- - ✅ Perform an initial sync of a basic set of templates
307
- - ✅ Provide clear next steps for review and customization
308
-
309
- **Options:**
310
- - `--branch <branch>` - Use a specific rhiza branch (default: main)
311
- - `--help` - Show detailed usage information
312
-
313
- **Example with branch option:**
314
- ```bash
315
- # Use a development branch
316
- uvx --branch develop .
317
- ```
318
-
319
- ### Method 1: Manual Integration (Selective Adoption)
320
-
321
- This approach is ideal if you want to cherry-pick specific templates or customize them before integration.
322
-
323
- #### Step 1: Clone Rhiza
324
-
325
- First, clone the Rhiza repository to a temporary location:
326
-
327
- ```bash
328
- # Clone to a temporary directory
329
- cd /tmp
330
- git clone https://github.com/jebel-quant/rhiza.git
331
- ```
332
-
333
- #### Step 2: Copy Desired Templates
334
-
335
- Navigate to your project and copy the configuration files you need:
336
-
337
- ```bash
338
- # Navigate to your project
339
- cd /path/to/your/project
340
-
341
- # We recommend working on a fresh branch
342
- git checkout -b rhiza
343
-
344
- # Ensure required directories exist
345
- mkdir -p .github/workflows
346
- mkdir -p .github/scripts
347
-
348
- # Copy the template configuration
349
- cp /tmp/rhiza/.github/template.yml .github/template.yml
350
-
351
- # Copy the sync helper script
352
- cp /tmp/rhiza/.github/scripts/sync.sh .github/scripts
353
- ```
354
-
355
- At this stage:
356
-
357
- - ❌ No templates are copied yet
358
- - ❌ No existing files are modified
359
- - ✅ Only the sync mechanism is installed
360
- - ⚠️ **Do not merge this branch yet.**
361
-
362
- #### Step 3: Perform the first sync
363
-
364
- Run the sync script to apply the templates defined in '.github/template.yml'
365
-
366
- ```bash
367
- ./.github/scripts/sync.sh
368
- ```
369
-
370
- This will:
371
-
372
- - Fetch the selected templates from the Rhiza repository
373
- - Apply them locally according to your include/exclude rules
374
- - Stage or commit the resulting changes on the current branch
375
-
376
- Review the changes carefully:
377
-
378
- ```bash
379
- git status
380
- git diff
381
- ```
382
-
383
- If happy with the suggested changes push them
384
-
385
- ```bash
386
- git add .
387
- git commit -m "Integrate Rhiza templates"
388
- git push -u origin rhiza
389
- ```
390
-
391
- ### Method 2: Automated Sync (Continuous Updates)
392
-
393
- This approach keeps your project’s configuration in sync with Rhiza’s latest templates while giving you control over which files are applied.
394
-
395
- Prerequisites:
396
-
397
- - A .github/template.yml file exists, defining **which templates to include or exclude**.
398
- - The first manual sync (./.github/scripts/sync.sh) has been performed.
399
- - The .github/workflows/sync.yml workflow is present in your repository.
400
-
401
- The workflow can run:
402
-
403
- **On a schedule** — e.g., weekly updates
404
- **Manually** — via the GitHub Actions “Run workflow” button
405
-
406
- ⚠️ .github/template.yml remains the **source of truth**. All automated updates are driven by its include/exclude rules.
407
-
408
- #### Step 1: Configure GitHub Token
409
-
410
- If you want the sync workflow to trigger other workflows (e.g. to create pull requests), create a Personal Access Token (PAT):
411
-
412
- 1. Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
413
- 2. Generate a new token with `repo` and `workflow` scopes
414
- 3. Add it as a repository secret named `PAT_TOKEN`
415
- 4. Update the workflow to use `token: ${{ secrets.PAT_TOKEN }}`
416
-
417
- #### Step 2: Run Initial Sync (again)
418
-
419
- You can trigger the sync workflow manually:
420
-
421
- 1. Go to your repository's "Actions" tab
422
- 2. Select the "Sync Templates" workflow
423
- 3. Click "Run workflow"
424
- 4. Review and merge the resulting pull request
425
-
426
- The workflow will:
427
- - Download the latest templates from Rhiza
428
- - Copy them to your project based on your `template.yml` configuration
429
- - Create a pull request with the changes (if any)
430
- - Automatically run weekly to keep your templates up to date
431
-
432
- ### What to Expect After Integration
433
-
434
- After integrating Rhiza, your project will have:
435
-
436
- - **Automated CI/CD** - GitHub Actions workflows for testing, linting, and releases
437
- - **Code Quality Tools** - Pre-commit hooks, ruff formatting, and pytest configuration
438
- - **Task Automation** - Makefile with common development tasks (`make test`, `make fmt`, etc.)
439
- - **Dev Container** - Optional VS Code/Codespaces development environment
440
- - **Documentation** - Templates for automated documentation generation
441
-
442
- ### Next Steps
443
-
444
- 1. **Test the integration** - Run `make test` to ensure tests pass
445
- 2. **Run pre-commit** - Execute `make fmt` to verify code quality checks
446
- 3. **Review workflows** - Check GitHub Actions tabs to see workflows in action
447
- 4. **Customize** - Adjust templates to match your project's specific needs
448
- 5. **Update documentation** - Add project-specific instructions to your README
449
-
450
- ### Troubleshooting
451
-
452
- **Issue: Makefile targets conflict with existing scripts**
453
- - Solution: Review the Makefile and merge targets with your existing build scripts, or rename conflicting targets
454
-
455
- **Issue: Pre-commit hooks fail on existing code**
456
- - Solution: Run `make fmt` to fix formatting issues, or temporarily exclude certain files in `.pre-commit-config.yaml`
457
-
458
- **Issue: GitHub Actions workflows fail**
459
- - Solution: Check Python version compatibility and adjust `PYTHON_MAX_VERSION` repository variable if needed
460
-
461
- **Issue: Dev container fails to build**
462
- - Solution: Review `.devcontainer/devcontainer.json` and ensure all dependencies are available for your project
463
-
464
- ## 🖥️ Dev Container Compatibility
465
-
466
- This repository includes a
467
- template **Dev Container** configuration
468
- for seamless development experience in
469
- both **VS Code** and **GitHub Codespaces**.
470
-
471
- ### What's Configured
472
-
473
- The `.devcontainer` setup provides:
474
-
475
- - 🐍 **Python 3.14** runtime environment
476
- - 🔧 **UV Package Manager** - Fast Python package installer and resolver
477
- - ⚡ **Makefile** - For running project workflows
478
- - 🧪 **Pre-commit Hooks** - Automated code quality checks
479
- - 📊 **Marimo Integration** - Interactive notebook support with VS Code extension
480
- - 🔍 **Python Development Tools** - Pylance, Python extension, and optimized settings
481
- - 🚀 **Port Forwarding** - Port 8080 for development servers
482
- - 🔐 **SSH Agent Forwarding** - Full Git functionality with your host SSH keys
483
-
484
- ### Usage
485
-
486
- #### In VS Code
487
-
488
- 1. Install the "Dev Containers" extension
489
- 2. Open the repository in VS Code
490
- 3. Click "Reopen in Container" when prompted
491
- 4. The environment will automatically set up with all dependencies
492
-
493
- #### In GitHub Codespaces
494
-
495
- 1. Navigate to the repository on GitHub
496
- 2. Click the green "Code" button
497
- 3. Select "Codespaces" tab
498
- 4. Click "Create codespace on main" (or your branch)
499
- 5. Your development environment will be ready in minutes
500
-
501
- The dev container automatically runs the initialization script that:
502
-
503
- - Installs UV package manager
504
- - Configures the Python virtual environment
505
- - Installs project dependencies
506
- - Sets up pre-commit hooks
507
-
508
- ### Publishing Devcontainer Images
509
-
510
- The repository includes workflows for building and publishing devcontainer images:
511
-
512
- #### CI Validation
513
-
514
- The **DEVCONTAINER** workflow automatically validates that your devcontainer builds successfully:
515
- - Triggers on changes to `.devcontainer/**` files or the workflow itself
516
- - Builds the image without publishing (`push: never`)
517
- - Works on pushes to any branch and pull requests
518
- - Gracefully skips if no `.devcontainer/devcontainer.json` exists
519
-
520
- ### VS Code Dev Container SSH Agent Forwarding
521
-
522
- Dev containers launched locally via VS code
523
- are configured with SSH agent forwarding
524
- to enable seamless Git operations:
525
-
526
- - **Mounts your SSH directory** - Your `~/.ssh` folder is mounted into the container
527
- - **Forwards SSH agent** - Your host's SSH agent is available inside the container
528
- - **Enables Git operations** - Push, pull, and clone using your existing SSH keys
529
- - **Works transparently** - No additional setup required in VS Code dev containers
530
-
531
- ### Troubleshooting
532
-
533
- Common issues and solutions when using this configuration template.
534
-
535
- ---
536
-
537
- #### SSH authentication fails on macOS when using devcontainer
538
-
539
- **Symptom**: When building or using the devcontainer on macOS, Git operations (pull, push, clone) fail with SSH authentication errors, even though your SSH keys work fine on the host.
540
-
541
- **Cause**: macOS SSH config often includes `UseKeychain yes`, which is a macOS-specific directive. When the devcontainer mounts your `~/.ssh` directory, other platforms (Linux containers) don't recognize this directive and fail to parse the SSH config.
542
-
543
- **Solution**: Add `IgnoreUnknown UseKeychain` to the top of your `~/.ssh/config` file on your Mac:
544
-
545
- ```ssh-config
546
- # At the top of ~/.ssh/config
547
- IgnoreUnknown UseKeychain
548
-
549
- Host *
550
- AddKeysToAgent yes
551
- UseKeychain yes
552
- IdentityFile ~/.ssh/id_rsa
553
- ```
554
-
555
- This tells SSH clients on non-macOS platforms to ignore the `UseKeychain` directive instead of failing.
556
-
557
- **Reference**: [Stack Overflow solution](https://stackoverflow.com/questions/75613632/trying-to-ssh-to-my-server-from-the-terminal-ends-with-error-line-x-bad-configu/75616369#75616369)
558
-
559
-
560
- ## 🔧 Custom Build Extras
561
-
562
- The project includes a hook for installing additional system dependencies and custom build steps needed across all build phases.
563
-
564
- ### Using build-extras.sh
565
-
566
- Create a file `.github/scripts/customisations/build-extras.sh` in your repository to install system packages or dependencies (this repository uses a dedicated `customisations` folder for repo-specific scripts):
567
- ```bash
568
- #!/bin/bash
569
- set -euo pipefail
570
-
571
- # Example: Install graphviz for diagram generation
572
- sudo apt-get update
573
- sudo apt-get install -y graphviz
574
-
575
- # Add other custom installation commands here
576
- ```
577
-
578
- ### When it Runs
579
-
580
- The `build-extras.sh` script (from `.github/scripts/customisations`) is automatically invoked during:
581
- - `make install` - Initial project setup
582
- - `make test` - Before running tests
583
- - `make book` - Before building documentation
584
- - `make docs` - Before generating API documentation
585
-
586
- This ensures custom dependencies are available whenever needed throughout the build lifecycle. The `Makefile` intentionally only checks the `.github/scripts/customisations` folder for repository-specific hooks such as `build-extras.sh` and `post-release.sh`.
587
-
588
- ### Important: Exclude from Template Updates
589
-
590
- If you customize this file, add it to the exclude list in your `action.yml` configuration to prevent it from being overwritten during template updates. Use the `customisations` path to avoid clobbering:
591
- ```yaml
592
- exclude: |
593
- .github/scripts/customisations/build-extras.sh
594
- ```
595
-
596
-
597
- ### Common Use Cases
598
-
599
- - Installing graphviz for diagram rendering
600
- - Adding LaTeX for mathematical notation
601
- - Installing system libraries for specialized tools
602
- - Setting up additional build dependencies
603
- - Downloading external resources or tools
604
-
605
- ### Post-release scripts
606
-
607
- If you need repository-specific post-release tasks, place a `post-release.sh` script in `.github/scripts/customisations/post-release.sh`. The `Makefile` will only look in the `customisations` folder for that hook.
608
-
609
-
610
- ## 🚀 Releasing
611
-
612
- This template includes a robust release workflow that handles version bumping, tagging, and publishing.
613
-
614
- ### The Release Process
615
-
616
- The release process consists of two interactive steps: **Bump** and **Release**.
617
-
618
- #### 1. Bump Version
619
-
620
- First, update the version in `pyproject.toml`:
621
-
622
- ```bash
623
- make bump
624
- ```
625
-
626
- This command will interactively guide you through:
627
- 1. Selecting a bump type (patch, minor, major) or entering a specific version
628
- 2. Warning you if you're not on the default branch
629
- 3. Showing the current and new version
630
- 4. Prompting whether to commit the changes
631
- 5. Prompting whether to push the changes
632
-
633
- The script ensures safety by:
634
- - Checking for uncommitted changes before bumping
635
- - Validating that the tag doesn't already exist
636
- - Verifying the version format
637
-
638
- #### 2. Release
639
-
640
- Once the version is bumped and committed, run the release command:
641
-
642
- ```bash
643
- make release
644
- ```
645
-
646
- This command will interactively guide you through:
647
- 1. Checking if your branch is up-to-date with the remote
648
- 2. If your local branch is ahead, showing the unpushed commits and prompting you to push them
649
- 3. Creating a git tag (e.g., `v1.2.4`)
650
- 4. Pushing the tag to the remote, which triggers the GitHub Actions release workflow
651
-
652
- The script provides safety checks by:
653
- - Warning if you're not on the default branch
654
- - Verifying no uncommitted changes exist
655
- - Checking if the tag already exists locally or on remote
656
- - Showing the number of commits since the last tag
657
-
658
- ### What Happens After Release
659
-
660
- The release workflow (`.github/workflows/release.yml`) triggers on the tag push and:
661
-
662
- 1. **Validates** - Checks the tag format and ensures no duplicate releases
663
- 2. **Builds** - Builds the Python package (if `pyproject.toml` exists)
664
- 3. **Drafts** - Creates a draft GitHub release with artifacts
665
- 4. **PyPI** - Publishes to PyPI (if not marked private)
666
- 5. **Devcontainer** - Publishes devcontainer image (if `PUBLISH_DEVCONTAINER=true`)
667
- 6. **Finalizes** - Publishes the GitHub release with links to PyPI and container images
668
-
669
- ### Configuration Options
670
-
671
- **Python Version Configuration:**
672
- - Set repository variable `PYTHON_MAX_VERSION` to control maximum Python version in CI tests
673
- - Options: `'3.11'`, `'3.12'`, `'3.13'`, or `'3.14'` (default)
674
- - Example: Set to `'3.13'` to test on Python 3.11, 3.12, and 3.13 only
675
- - Set repository variable `PYTHON_DEFAULT_VERSION` to control default Python version in workflows
676
- - Options: `'3.11'`, `'3.12'`, `'3.13'`, or `'3.14'` (default)
677
- - Example: Set to `'3.12'` if dependencies are not compatible with Python 3.14
678
- - Used in release, pre-commit, book, and marimo workflows
679
-
680
- **PyPI Publishing:**
681
- - Automatic if package is registered as a Trusted Publisher
682
- - Use `PYPI_REPOSITORY_URL` and `PYPI_TOKEN` for custom feeds
683
- - Mark as private with `Private :: Do Not Upload` in `pyproject.toml`
684
-
685
- **Devcontainer Publishing:**
686
- - Set repository variable `PUBLISH_DEVCONTAINER=true` to enable
687
- - Override registry with `DEVCONTAINER_REGISTRY` variable (defaults to ghcr.io)
688
- - Requires `.devcontainer/devcontainer.json` to exist
689
- - Image published as `{registry}/{owner}/{repository}/devcontainer:vX.Y.Z`
690
-
691
- ## 🤝 Contributing
692
-
693
- Contributions are welcome! Please feel free to submit a Pull Request.
694
-
695
- 1. Fork the repository
696
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
697
- 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
698
- 4. Push to the branch (`git push origin feature/amazing-feature`)
699
- 5. Open a Pull Request
700
-
701
- ## 📄 License
702
-
703
- This project is licensed under the MIT License - see the LICENSE file for details.
704
-
705
- ## 🙏 Acknowledgments
706
-
707
- - [GitHub Actions](https://github.com/features/actions) - For CI/CD capabilities
708
- - [Marimo](https://marimo.io/) - For interactive notebooks
709
- - [UV](https://github.com/astral-sh/uv) - For fast Python package operations
@@ -1,5 +0,0 @@
1
- rhiza/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- rhiza-0.3.0.dist-info/METADATA,sha256=IfqYOorDht5OPRJqq8IRbdqlN6x_C-nREPSlthRbo6g,26003
3
- rhiza-0.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
4
- rhiza-0.3.0.dist-info/licenses/LICENSE,sha256=4m5X7LhqX-6D0Ks79Ys8CLpmza8cxDG34g4S9XSNAGY,1077
5
- rhiza-0.3.0.dist-info/RECORD,,
File without changes