Skip to content
Open
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
17 changes: 16 additions & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
# .coveragerc to control coverage.py
[run]
branch = True
source = src
omit = tests/*

[paths]
source =
src/
*/site-packages/

[report]
# Regexes for lines to exclude from consideration
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover

# Don't complain about missing debug-only code:
def __repr__
if self.debug:
if self\.debug

# Don't complain if tests don't hit defensive assertion code:
raise AssertionError
raise NotImplementedError

# Don't complain if non-runnable code isn't run:
if 0:
if __name__ == .__main__.:
24 changes: 7 additions & 17 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,15 @@ jobs:
name: Build and Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- uses: actions/checkout@v7

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.12

- name: Install tox
run: uv tool install tox --with tox-uv
run: python -m pip install tox

- name: Test
run: tox -e default
Expand All @@ -40,20 +35,15 @@ jobs:
name: Build Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- uses: actions/checkout@v7

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.12

- name: Install tox
run: uv tool install tox --with tox-uv
run: python -m pip install tox

- name: Build docs
run: tox -e docs
Expand All @@ -62,7 +52,7 @@ jobs:
run: touch ./docs/_build/html/.nojekyll

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
uses: actions/upload-pages-artifact@v5
with:
path: ./docs/_build/html

Expand All @@ -77,7 +67,7 @@ jobs:
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- name: Download all the dists
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: python-package-distributions
path: dist/
Expand All @@ -98,4 +88,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v5
21 changes: 7 additions & 14 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,20 @@ jobs:
runs-on: ${{ matrix.platform }}
name: Python ${{ matrix.python }}, ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- uses: actions/checkout@v7

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}

- name: Install tox
run: uv tool install tox --with tox-uv

- name: Install dependencies
run: uv sync --all-extras --python ${{ matrix.python }}
run: python -m pip install tox coverage

- name: Run tests
run: |
tox -e default -- --cov --cov-branch --cov-report=xml
run: >-
tox
-- -rFEx --durations 10 --color yes --cov --cov-branch --cov-report=xml # pytest args

- name: Check for codecov token availability
id: codecov-check
Expand All @@ -71,7 +64,7 @@ jobs:
- name: Upload coverage reports to Codecov with GitHub Action
uses: codecov/codecov-action@v7
if: ${{ steps.codecov-check.outputs.codecov == 'true' }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: ${{ github.repository }}
flags: ${{ matrix.platform }} - py${{ matrix.python }}
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ To create a brand new repository, you can use the `hatchit` CLI command:
hatchit my-awesome-package --description "A robust new tool" --license MIT
```

By default, `hatchit` builds standard `tox` environments with pip installation. If you want to use the blazing fast `uv` ecosystem instead, just add `--use-uv`:

```bash
hatchit my-awesome-package --description "A robust new tool" --license MIT --use-uv
```

Alternatively, since `hatchit` is a 100% compatible Copier template, you can use `copier` directly to render the project!

```bash
Expand Down Expand Up @@ -50,13 +56,15 @@ That's it! You're ready to start writing code.

## Development Process

`hatchit` structures your project around `tox` and `uv`. To run your tests during development:
`hatchit` structures your project around `tox` for automated testing. To run your tests during development:

```bash
cd my-awesome-package
tox -e default
```

If you configured the project with `--use-uv`, tox will automatically use `uv` under the hood!

To build your documentation locally and preview:
```bash
tox -e docs
Expand Down
11 changes: 11 additions & 0 deletions add_biocframe_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import re
from pathlib import Path

pyproj = Path("/home/jayaram/Projects/biocpy/biocutils/pyproject.toml")
with open(pyproj, "r") as f:
content = f.read()

content = content.replace('"pandas>=3.0.5",\n', '"pandas>=3.0.5",\n "biocframe",\n "iranges",\n')

with open(pyproj, "w") as f:
f.write(content)
24 changes: 24 additions & 0 deletions check_missing_testing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os
from pathlib import Path

projects_dir = Path("/home/jayaram/Projects")
missing_testing = []

for pyproj in projects_dir.rglob("pyproject.toml"):
if ".venv" in str(pyproj) or ".tox" in str(pyproj) or "trash" in str(pyproj):
continue

with open(pyproj, 'r') as f:
content = f.read()

# only care if we just migrated it - we can tell if it has tox.ini with `extras = testing`
tox_file = pyproj.parent / "tox.ini"
if tox_file.exists():
with open(tox_file, 'r') as tf:
tox_content = tf.read()
if "extras = testing" in tox_content:
if "\ntesting =" not in content and "\ntesting=" not in content:
missing_testing.append(str(pyproj))

for p in sorted(missing_testing):
print(p)
23 changes: 23 additions & 0 deletions check_uv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import os
import glob
from pathlib import Path

projects_dir = Path("/home/jayaram/Projects")
uv_projects = []

for pyproj in projects_dir.rglob("pyproject.toml"):
if ".venv" in str(pyproj) or ".tox" in str(pyproj):
continue

project_root = pyproj.parent
workflows_dir = project_root / ".github" / "workflows"
run_tests = workflows_dir / "run-tests.yml"

if run_tests.exists():
with open(run_tests, 'r') as f:
if 'setup-uv' in f.read():
uv_projects.append(str(project_root))

print("Projects using uv:")
for p in sorted(uv_projects):
print(p)
6 changes: 5 additions & 1 deletion copier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,14 @@ github_username:
type: str
default: "YOUR_ORG_OR_USERNAME"
help: GitHub Organization or Username
use_uv:
type: bool
default: false
help: "Use uv for dependency management and tox running?"

# Tasks to run after generation
_tasks:
- "uv lock"
- "{% if use_uv %}uv lock{% else %}echo Skip uv lock{% endif %}"
- "git init"
- "git add ."
# Use ignore_errors because git commit might fail if git user isn't configured, or we can just run it.
Expand Down
5 changes: 5 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
sphinx>=7.0.0
furo
myst-nb
sphinx-autodoc-typehints
linkify-it-py
95 changes: 95 additions & 0 deletions fix_biocutils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import re
from pathlib import Path

repo = Path("/home/jayaram/Projects/biocpy/biocutils")

# 1. Fix pyproject.toml
pyproj = repo / "pyproject.toml"
with open(pyproj, "r") as f:
content = f.read()

# Remove the duplicate dev group
content = re.sub(r'\[project\.optional-dependencies\]\ndev = \[\n( ".*?",\n)*\]\n?', '', content)
with open(pyproj, "w") as f:
f.write(content.strip() + "\n")


# 2. Fix tox.ini
tox_ini = repo / "tox.ini"
tox_content = """# Tox configuration file
# Read more under https://tox.wiki/

[tox]
minversion = 4.0
envlist = default

[testenv]
description = Invoke pytest to run automated tests
extras = testing
commands =
pytest {posargs}

[testenv:typecheck]
description = Run static type checking with mypy
deps = mypy
commands =
mypy src/

[testenv:lint]
description = Perform static analysis and style checks
deps = ruff
skip_install = True
commands =
ruff check {posargs:.}
ruff format --check {posargs:.}

[testenv:{build,clean}]
description =
build: Build the package
clean: Remove old distribution files
deps = build
skip_install = True
commands =
clean: python -c 'import shutil; [shutil.rmtree(p, True) for p in ("build", "dist", "docs/_build")]'
clean: python -c 'import pathlib, shutil; [shutil.rmtree(p, True) for p in pathlib.Path("src").glob("*.egg-info")]'
build: python -m build {posargs}

[testenv:{docs,doctests,linkcheck}]
description =
docs: Invoke sphinx-build to build the docs
doctests: Invoke sphinx-build to run doctests
linkcheck: Check for broken links in the documentation
deps =
-r {toxinidir}/docs/requirements.txt
setenv =
DOCSDIR = {toxinidir}/docs
BUILDDIR = {toxinidir}/docs/_build
docs: BUILD = html
doctests: BUILD = doctest
linkcheck: BUILD = linkcheck
commands =
sphinx-apidoc -f -o "{env:DOCSDIR}/api" src/
sphinx-build --color -b {env:BUILD} -d "{env:BUILDDIR}/doctrees" "{env:DOCSDIR}" "{env:BUILDDIR}/{env:BUILD}" {posargs}

[testenv:publish]
description =
Publish the package you have been developing to a package index server.
skip_install = True
deps = twine
commands =
python -m twine upload {posargs:dist/*}
"""
with open(tox_ini, "w") as f:
f.write(tox_content)

# 3. Fix run-tests.yml
run_tests = repo / ".github" / "workflows" / "run-tests.yml"
with open(run_tests, "r") as f:
content = f.read()

content = re.sub(r'\n\s*- name: Set up uv\n\s*uses: astral-sh/setup-uv@v5\n\s*with:\n\s*enable-cache: true\n', '', content)
content = content.replace("uv tool install tox --with tox-uv", "python -m pip install tox")
content = re.sub(r'\n\s*- name: Install dependencies\n\s*run: uv sync --all-extras --python \$\{\{ matrix\.python \}\}\n', '', content)
with open(run_tests, "w") as f:
f.write(content)

11 changes: 11 additions & 0 deletions fix_hatchit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sys
sys.path.append("/home/jayaram/.gemini/antigravity-ide/brain/9bc824b7-d246-454a-b7c0-32f2b65d7d0d/scratch")
import migrate_to_pip
from pathlib import Path

root = Path("/home/jayaram/Projects/biocpy/hatchit")
migrate_to_pip.process_tox_ini(root / "tox.ini")
migrate_to_pip.process_pyproject_toml(root / "pyproject.toml")
migrate_to_pip.process_github_action(root / ".github" / "workflows" / "run-tests.yml")
migrate_to_pip.process_github_action(root / ".github" / "workflows" / "publish-pypi.yml")
migrate_to_pip.process_readthedocs(root / ".readthedocs.yml")
12 changes: 12 additions & 0 deletions fix_hatchit2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import sys
from pathlib import Path

# Load functions from our existing scripts
import imp
fix_tox_ini = imp.load_source('fix_tox_ini', 'fix_tox_ini.py')
fix_tox_skip_install = imp.load_source('fix_tox_skip_install', 'fix_tox_skip_install.py')

root = Path("/home/jayaram/Projects/biocpy/hatchit")
fix_tox_ini.fix_tox(root / "tox.ini")
fix_tox_skip_install.fix_tox(root / "tox.ini")
fix_tox_skip_install.fix_pyproject(root / "pyproject.toml")
18 changes: 18 additions & 0 deletions fix_missing_testing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from pathlib import Path

paths = [
Path("/home/jayaram/Projects/biocpy/biostrings/pyproject.toml"),
Path("/home/jayaram/Projects/biocpy/iranges/pyproject.toml")
]

for p in paths:
if not p.exists(): continue
with open(p, 'r') as f:
content = f.read()

if "testing = [" not in content:
content = content.replace("[project.optional-dependencies]",
"[project.optional-dependencies]\ntesting = [\n \"pytest>=9.1.1\",\n \"pytest-cov>=7.1.0\",\n]\n")
with open(p, 'w') as f:
f.write(content)

Loading
Loading