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: 0 additions & 1 deletion .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,3 @@ jobs:
- uses: pre-commit/[email protected] # Official pre-commit GitHub Action
with:
extra_args: '--verbose --all-files' # Run on all files with verbose output
token: ${{ inputs.github_token }} # Pass GitHub token if provided to avoid rate limiting
1 change: 0 additions & 1 deletion ruff.toml

This file was deleted.

20 changes: 20 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Ruff configuration for tschm/.config-templates

# Maximum line length
line-length = 120

# Target Python version
target-version = "py312"

[lint]
# Linting rules to select
select = ["D", "E", "F", "I", "N", "W", "UP"]

[lint.pydocstyle]
# Use Google docstring convention
convention = "google"

[format]
quote-style = "double"
indent-style = "space"
line-ending = "auto"
32 changes: 32 additions & 0 deletions template/.github/CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Code of Conduct

## Purpose

This code of conduct outlines expectations for behavior when participating in the
chebpy project with the aim of fostering a constructive and professional
engineering environment.

## Expected Behavior

Participants are expected to:

- Be respectful in communication and collaboration.
- Focus on technical topics and project goals.
- Accept constructive feedback gracefully and offer it in kind.
- Assume good intentions from others and engage with a problem-solving mindset.
- Use appropriate language and conduct in all community spaces.

## Scope

This Code of Conduct applies in all project spaces—online and offline—and also applies
when individuals are representing the project in public spaces.

## Enforcement

Project maintainers are responsible for enforcing the code and may take proportionate
corrective action in response to unexpected behavior.

## Attribution

Adapted from the [Contributor Covenant](https://www.contributor-covenant.org), with
modifications for brevity and neutrality.
93 changes: 93 additions & 0 deletions template/.github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Contributing

This document is a guide to contributing to the project.

We welcome all contributions. You don't need to be an expert
to help out.

## Checklist

Contributions are made through
[pull requests](https://help.github.com/articles/using-pull-requests/).
Before sending a pull request, make sure you do the following:

- Run 'make check' to make sure your code adheres to our [coding style](#code-style)
and all tests pass.
- [Write unit tests](#writing-unit-tests) for new functionality added.

## Building from source

You'll need to build the project locally in order to start editing code.
To install from source, clone the Github
repository, navigate to its root, and run the following command:

```bash
make install
```

## Contributing code

To contribute to the project, send us pull requests.
For those new to contributing, check out Github's
[guide](https://help.github.com/articles/using-pull-requests/).

Once you've made your pull request, a member of the
development team will assign themselves to review it.
You might have a few
back-and-forths with your reviewer before it is accepted,
which is completely normal.
Your pull request will trigger continuous integration tests
for many different
Python versions and different platforms. If these tests start failing,
please
fix your code and send another commit, which will re-trigger the tests.

If you'd like to add a new feature, please do propose your
change on a Github issue, to make sure
that your priorities align with ours.

If you'd like to contribute code but don't know where to start,
try one of the
following:

- Read the source and enhance the documentation,
or address TODOs
- Browse the open issues,
and look for the issues tagged "help wanted".

## Code style

We use ruff to enforce our Python coding style.
Before sending us a pull request, navigate to the project
root and run

```bash
make fmt
```

to make sure that your changes abide by our style conventions.
Please fix any errors that are reported before sending
the pull request.

## Writing unit tests

Most code changes will require new unit tests.
Even bug fixes require unit tests,
since the presence of bugs usually indicates insufficient tests.
When adding tests, try to find a file in which your tests should belong;
if you're testing a new feature, you might want to create a new test file.

We use the popular Python [pytest](https://docs.pytest.org/en/) framework for our
tests.

## Running unit tests

We use `pytest` to run our unit tests.
To run all unit tests run the following command:

```bash
make test
```

Please make sure that your change doesn't cause any
of the unit tests to fail.
31 changes: 19 additions & 12 deletions template/.github/renovate.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
{
"extends": [
"config:recommended",
":enablePreCommit",
":automergeMinor",
":dependencyDashboard",
":semanticCommits",
":pinVersions"
],
"enabledManagers": ["pip_requirements", "pre-commit", "github-actions"],
"schedule": [
"before 10am on tuesday"
]
"extends": [
"config:recommended",
":enablePreCommit",
":automergeMinor",
":dependencyDashboard",
":maintainLockFilesWeekly",
":semanticCommits",
":pinDevDependencies"
],
"enabledManagers": [
"pep621",
"pre-commit",
"github-actions",
"devcontainer"
],
"timezone": "Asia/Dubai",
"schedule": [
"before 10am on tuesday"
]
}
47 changes: 47 additions & 0 deletions template/.github/taskfiles/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
version: '3'

tasks:
uv:
desc: Install uv and uvx
cmds:
- curl -sSf https://astral.sh/uv/install.sh | sh > /dev/null 2>&1 || (echo "${RED}Installation failed!${RESET}" >&2; exit 1)
- export PATH="$HOME/.cargo/bin:$PATH"

Comment on lines +4 to +9
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

uv PATH export is ineffective across commands; may cause uv not found

Each cmd runs in a separate shell. The PATH export won’t persist to subsequent commands/tasks. Use a single shell block or set env at the task level.

   uv:
     desc: Install uv and uvx
     cmds:
-      - curl -sSf https://astral.sh/uv/install.sh | sh > /dev/null 2>&1 || (echo "${RED}Installation failed!${RESET}" >&2; exit 1)
-      - export PATH="$HOME/.cargo/bin:$PATH"
+      - |
+        set -euo pipefail
+        # ANSI colors (local to this block)
+        BLUE="\033[36m"; RED="\033[31m"; RESET="\033[0m"
+        curl -sSf https://astral.sh/uv/install.sh | sh > /dev/null 2>&1 \
+          || { echo -e "${RED}Installation failed!${RESET}" >&2; exit 1; }
+        export PATH="$HOME/.cargo/bin:$PATH"
+        command -v uv >/dev/null || { echo -e "${RED}uv not on PATH after install${RESET}" >&2; exit 1; }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uv:
desc: Install uv and uvx
cmds:
- curl -sSf https://astral.sh/uv/install.sh | sh > /dev/null 2>&1 || (echo "${RED}Installation failed!${RESET}" >&2; exit 1)
- export PATH="$HOME/.cargo/bin:$PATH"
uv:
desc: Install uv and uvx
cmds:
- |
set -euo pipefail
# ANSI colors (local to this block)
BLUE="\033[36m"; RED="\033[31m"; RESET="\033[0m"
curl -sSf https://astral.sh/uv/install.sh | sh > /dev/null 2>&1 \
|| { echo -e "${RED}Installation failed!${RESET}" >&2; exit 1; }
export PATH="$HOME/.cargo/bin:$PATH"
command -v uv >/dev/null || { echo -e "${RED}uv not on PATH after install${RESET}" >&2; exit 1; }
🤖 Prompt for AI Agents
In template/.github/taskfiles/build.yml around lines 4 to 9, the PATH export is
ineffective because each cmds entry runs in its own shell so subsequent commands
won't see the updated PATH; fix by either (a) combining the install and PATH
export into a single shell block (e.g. join with && or use a multiline shell
block) so export persists for the next command, or (b) move the PATH addition
into the task-level env section (or global env) so all cmds inherit the updated
PATH; implement one of these options so uv is found by following commands.

install:
desc: Install all dependencies using uv
deps: [uv]
cmds:
- |
# Check if .venv folder already exists
if [ -d ".venv" ]; then
printf "${BLUE}[INFO] Virtual environment already exists, skipping installation${RESET}\n"
else
# we need the virtual environment at least for the tests to work
# even if we don't install anything

# Create the virtual environment
printf "${BLUE}[INFO] Creating virtual environment...${RESET}\n"

# Create the virtual environment
uv venv --python 3.12 || { printf "${RED}[ERROR] Failed to create virtual environment${RESET}\n"; exit 1; }

if [ -f "pyproject.toml" ]; then
printf "${BLUE}[INFO] Installing dependencies${RESET}\n"
uv sync --all-extras --frozen || { printf "${RED}[ERROR] Failed to install dependencies${RESET}\n"; exit 1; }
else
printf "${YELLOW}[WARN] No pyproject.toml found, skipping install${RESET}\n"
fi
fi

Comment on lines +15 to +35
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

install skips dependency sync if .venv exists

This skips uv sync entirely whenever .venv exists, which is surprising in CI and can leave stale deps. Create the venv if missing, but always run sync when pyproject.toml exists.

-        # Check if .venv folder already exists
-        if [ -d ".venv" ]; then
-          printf "${BLUE}[INFO] Virtual environment already exists, skipping installation${RESET}\n"
-        else
-          # we need the virtual environment at least for the tests to work
-          # even if we don't install anything
-
-          # Create the virtual environment
-          printf "${BLUE}[INFO] Creating virtual environment...${RESET}\n"
-
-          # Create the virtual environment
-          uv venv --python 3.12 || { printf "${RED}[ERROR] Failed to create virtual environment${RESET}\n"; exit 1; }
-
-          if [ -f "pyproject.toml" ]; then
-            printf "${BLUE}[INFO] Installing dependencies${RESET}\n"
-            uv sync --all-extras --frozen || { printf "${RED}[ERROR] Failed to install dependencies${RESET}\n"; exit 1; }
-          else
-            printf "${YELLOW}[WARN] No pyproject.toml found, skipping install${RESET}\n"
-          fi
-        fi
+        # Ensure virtual environment exists
+        if [ ! -d ".venv" ]; then
+          printf "${BLUE}[INFO] Creating virtual environment...${RESET}\n"
+          uv venv --python 3.12 || { printf "${RED}[ERROR] Failed to create virtual environment${RESET}\n"; exit 1; }
+        fi
+
+        # Sync dependencies if project file exists
+        if [ -f "pyproject.toml" ]; then
+          printf "${BLUE}[INFO] Installing dependencies${RESET}\n"
+          uv sync --all-extras --frozen || { printf "${RED}[ERROR] Failed to install dependencies${RESET}\n"; exit 1; }
+        else
+          printf "${YELLOW}[WARN] No pyproject.toml found, skipping install${RESET}\n"
+        fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Check if .venv folder already exists
if [ -d ".venv" ]; then
printf "${BLUE}[INFO] Virtual environment already exists, skipping installation${RESET}\n"
else
# we need the virtual environment at least for the tests to work
# even if we don't install anything
# Create the virtual environment
printf "${BLUE}[INFO] Creating virtual environment...${RESET}\n"
# Create the virtual environment
uv venv --python 3.12 || { printf "${RED}[ERROR] Failed to create virtual environment${RESET}\n"; exit 1; }
if [ -f "pyproject.toml" ]; then
printf "${BLUE}[INFO] Installing dependencies${RESET}\n"
uv sync --all-extras --frozen || { printf "${RED}[ERROR] Failed to install dependencies${RESET}\n"; exit 1; }
else
printf "${YELLOW}[WARN] No pyproject.toml found, skipping install${RESET}\n"
fi
fi
# Ensure virtual environment exists
if [ ! -d ".venv" ]; then
printf "${BLUE}[INFO] Creating virtual environment...${RESET}\n"
uv venv --python 3.12 || { printf "${RED}[ERROR] Failed to create virtual environment${RESET}\n"; exit 1; }
fi
# Sync dependencies if project file exists
if [ -f "pyproject.toml" ]; then
printf "${BLUE}[INFO] Installing dependencies${RESET}\n"
uv sync --all-extras --frozen || { printf "${RED}[ERROR] Failed to install dependencies${RESET}\n"; exit 1; }
else
printf "${YELLOW}[WARN] No pyproject.toml found, skipping install${RESET}\n"
fi
🤖 Prompt for AI Agents
In template/.github/taskfiles/build.yml around lines 15 to 35, the script
currently skips running "uv sync" whenever the .venv directory exists which can
leave stale dependencies in CI; change the flow so the script creates the
virtualenv only if missing but always checks for pyproject.toml and runs "uv
sync --all-extras --frozen" (exiting with an error message on failure)
regardless of whether .venv was just created or already present, preserving the
existing log messages and exit handling.

build:
desc: Build the package using hatch
deps: [install]
cmds:
- |
if [ -f "pyproject.toml" ]; then
printf "${BLUE}[INFO] Building package...${RESET}\n"
uv pip install hatch
uv run hatch build
else
printf "${YELLOW}[WARN] No pyproject.toml found, skipping build${RESET}\n"
fi
13 changes: 13 additions & 0 deletions template/.github/taskfiles/cleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: '3'

tasks:
clean:
desc: Clean generated files and directories
cmds:
- printf " ${BLUE}[INFO] Cleaning project...${RESET}\n"
- git clean -d -X -f
- rm -rf dist build *.egg-info .coverage .pytest_cache
- printf " ${BLUE}[INFO] Removing local branches with no remote counterpart...${RESET}\n"
- git fetch -p
- |
git branch -vv | grep ': gone]' | awk '{print $$1}' | xargs -r git branch -D
140 changes: 140 additions & 0 deletions template/.github/taskfiles/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
version: '3'

includes:
build:
taskfile: ./build.yml
internal: true

tasks:
test:
desc: Run all tests
cmds:
- task build:install -s
- printf "${BLUE}[INFO] Running tests...${RESET}\n"
- |
# Find source folder
SOURCE_FOLDER="src/$(find src -mindepth 1 -maxdepth 1 -type d -not -path '*/\.*' | head -1 | sed 's|^src/||')"

if [ -z "$SOURCE_FOLDER" ] || [ -z "{{.TESTS_FOLDER}}" ]; then
printf "${YELLOW}[WARN] No valid source folder structure found, skipping tests${RESET}\n"
else
uv pip install pytest pytest-cov pytest-html
mkdir -p _tests/html-coverage _tests/html-report
uv run pytest {{.TESTS_FOLDER}} --cov=$SOURCE_FOLDER --cov-report=term --cov-report=html:_tests/html-coverage --html=_tests/html-report/report.html
fi

docs:
desc: Build documentation using pdoc
cmds:
- task build:install -s
- |
if [ -f "pyproject.toml" ]; then
printf "${BLUE}[INFO] Building documentation...${RESET}\n"
SOURCE_FOLDER=src/$(find src -mindepth 1 -maxdepth 1 -type d -not -path '*/\.*' | head -1)
uv pip install pdoc
uv run pdoc -o _pdoc "$SOURCE_FOLDER"
else
printf "${YELLOW}[WARN] No pyproject.toml found, skipping docs${RESET}\n"
fi

marimushka:
desc: Export Marimo notebooks to HTML
cmds:
- task build:install -s
- printf "${BLUE}[INFO] Exporting notebooks from {{.MARIMO_FOLDER}}...${RESET}\n"
- |
if [ ! -d "{{.MARIMO_FOLDER}}" ]; then
printf "${YELLOW}[WARN] Directory '{{.MARIMO_FOLDER}}' does not exist. Skipping marimushka.${RESET}\n"
else
mkdir -p _marimushka
py_files=$(find "{{.MARIMO_FOLDER}}" -name "*.py" | tr '\n' ' ')
if [ -z "$py_files" ]; then
printf "${YELLOW}[WARN] No Python files found in '{{.MARIMO_FOLDER}}'.${RESET}\n"
echo "<html><head><title>Marimo Notebooks</title></head><body><h1>Marimo Notebooks</h1><p>No notebooks found.</p></body></html>" > _marimushka/index.html
else
printf "${BLUE}[INFO] Found Python files: %s${RESET}\n" "$py_files"
for py_file in $py_files; do
printf " ${BLUE}[INFO] Processing %s...${RESET}\n" "$py_file"
rel_path=$(echo "$py_file" | sed "s|^{{.MARIMO_FOLDER}}/||")
dir_path=$(dirname "$rel_path")
base_name=$(basename "$rel_path" .py)
mkdir -p "_marimushka/$dir_path"
uvx marimo export html --include-code --sandbox --output "_marimushka/$dir_path/$base_name.html" "$py_file"
done
echo "<html><head><title>Marimo Notebooks</title></head><body><h1>Marimo Notebooks</h1><ul>" > _marimushka/index.html
find _marimushka -name "*.html" -not -path "*index.html" | sort | while read html_file; do
rel_path=$(echo "$html_file" | sed "s|^_marimushka/||")
name=$(basename "$rel_path" .html)
echo "<li><a href=\"$rel_path\">$name</a></li>" >> _marimushka/index.html
done
echo "</ul></body></html>" >> _marimushka/index.html
touch _marimushka/.nojekyll
fi
fi

book:
desc: Build the companion book with test results and notebooks
cmds:
- printf "${BLUE}[INFO] Building combined documentation...${RESET}\n"
- printf "${BLUE}[INFO] Delete the _book folder...${RESET}\n"
- rm -rf _book
- printf "${BLUE}[INFO] Create empty _book folder...${RESET}\n"
- mkdir -p _book
- touch _book/links.json
- |
printf "${BLUE}[INFO] Copy API docs...${RESET}\n"
if [ -d _pdoc ]; then
mkdir -p _book/pdoc
cp -r _pdoc/* _book/pdoc
echo '{"API": "./pdoc/index.html"}' > _book/links.json
else
echo '{}' > _book/links.json
fi

printf "${BLUE}[INFO] Copy coverage report...${RESET}\n"
if [ -d _tests/html-coverage ] && [ "$(ls -A _tests/html-coverage 2>/dev/null)" ]; then
mkdir -p _book/tests/html-coverage
cp -r _tests/html-coverage/* _book/tests/html-coverage
jq '. + {"Coverage": "./tests/html-coverage/index.html"}' _book/links.json > _book/tmp && mv _book/tmp _book/links.json
else
printf "${YELLOW}[WARN] No coverage report found or directory is empty${RESET}\n"
fi

printf "${BLUE}[INFO] Copy test report...${RESET}\n"
if [ -d _tests/html-report ] && [ "$(ls -A _tests/html-report 2>/dev/null)" ]; then
mkdir -p _book/tests/html-report
cp -r _tests/html-report/* _book/tests/html-report
jq '. + {"Test Report": "./tests/html-report/report.html"}' _book/links.json > _book/tmp && mv _book/tmp _book/links.json
else
printf "${YELLOW}[WARN] No test report found or directory is empty${RESET}\n"
fi

printf "${BLUE}[INFO] Copy notebooks...${RESET}\n"
if [ -d _marimushka ] && [ "$(ls -A _marimushka 2>/dev/null)" ]; then
mkdir -p _book/marimushka
cp -r _marimushka/* _book/marimushka
jq '. + {"Notebooks": "./marimushka/index.html"}' _book/links.json > _book/tmp && mv _book/tmp _book/links.json
printf "${BLUE}[INFO] Copied notebooks from {{.MARIMO_FOLDER}} to _book/marimushka${RESET}\n"
else
printf "${YELLOW}[WARN] No notebooks found or directory is empty${RESET}\n"
fi

printf "${BLUE}[INFO] Generated links.json:${RESET}\n"
cat _book/links.json

uvx [email protected] --title "{{.BOOK_TITLE}}" --subtitle "{{.BOOK_SUBTITLE}}" --links "$(cat _book/links.json)" --output "_book"

touch "_book/.nojekyll"

marimo:
desc: Start a Marimo server
cmds:
- task build:install -s
- printf " ${BLUE}[INFO] Start Marimo server with {{.MARIMO_FOLDER}}...${RESET}\n"
- |
if [ ! -d "{{.MARIMO_FOLDER}}" ]; then
printf " ${YELLOW}[WARN] Marimo folder '{{.MARIMO_FOLDER}}' not found, skipping start${RESET}\n"
else
uv pip install marimo
uv run marimo edit "{{.MARIMO_FOLDER}}"
fi
Loading