Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
be20db1
feat(nox): add tooling that enables demo generation and syncing
Apr 19, 2025
c6687a8
Merge pull request #1 from koliver-kv/feature/finish-noxfile-sessions…
koliver-kv Apr 19, 2025
7b5d326
fix(noxfile): fix missing code not added into new demo generation and…
Apr 19, 2025
d8ba739
refactor: move coverage and mypy configurations into individual confi…
Apr 19, 2025
9ea8541
fix: remove coverage and mypy configs accidentally left inside pyproj…
Apr 19, 2025
65f1531
feat: add ruff implementations
Apr 19, 2025
4b576f1
fix(cicd): fix several issues surrounding github actions having chang…
Apr 19, 2025
95c374b
Merge pull request #2 from koliver-kv/feature/ruff-implementation
koliver-kv Apr 19, 2025
359defa
fix(cicd): ensure all actions use upload-artifact@v4 and download-art…
Apr 19, 2025
c4c1f74
chore(dependencies): remove old flake8 and bandit dependencies
Apr 19, 2025
ca0fe54
fix(cicd): add missing escaping to github action definition
Apr 19, 2025
2469f4c
chore(noxfile): replace safety check with safety scan due to future d…
Apr 19, 2025
1f82fea
chore(noxfile): remove no longer needed installation of bandit
Apr 19, 2025
878c28e
chore: remove usages and dependencies for pyupgrade due to ruff bundl…
Apr 19, 2025
bf906d0
chore(noxfile): replace coverage[toml] installation with coverage
Apr 19, 2025
b54d77a
chore(dependencies): replace safety with pip-audit due to ridiculous …
Apr 19, 2025
db017c7
chore: remove remaining coverage[toml] references in favor of coverage
Apr 19, 2025
c4d40a3
fix: fix .coveragerc syntax
Apr 19, 2025
f5312a0
chore(config): add a coverage exclusion for if TYPE_CHECKING blocks
Apr 19, 2025
c821b91
fix(cicd): move from merging artifacts to downloading based on path g…
Apr 19, 2025
06996ce
chore: add str wrapper to satisfy mypy
Apr 19, 2025
0093932
chore: add future annotation import to noxfile
Apr 19, 2025
d2b0307
chore(docs): replace python PEP links with direct url instead of redi…
Apr 19, 2025
643309a
chore(cicd): remove bandit step from pre-commit-config.yaml due to au…
Apr 19, 2025
1b57dac
chore(docs): add exclusion to allow proper sphinx config
Apr 19, 2025
a5b3f9c
chore(cicd): update python version used to build docs
Apr 19, 2025
ef1c06c
chore: remove unused import from tools
Apr 19, 2025
47d6d78
chore: replace single quotes with double quotes in tests.yml setting
Apr 19, 2025
2a52f25
chore: change line in noxfile to not be broken apart
Apr 19, 2025
19c2e17
chore: change line in noxfile to be one line instead of multiple
Apr 19, 2025
d9ae1e5
refactor: add parentheses requested by ruff for noxfile logic
Apr 19, 2025
6465aab
refactor: run ruff format on noxfile
Apr 19, 2025
f11025c
refactor: run ruff format on the tools folder
Apr 19, 2025
80b32b8
refactor: run ruff format on the noxfile
Apr 19, 2025
ca853ae
chore: remove black from pre-commit-config.yaml and dependencies
Apr 19, 2025
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
4 changes: 2 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4.5.0
with:
python-version: "3.8"
python-version: "3.9"
- run: |
pip install --constraint=.github/workflows/constraints.txt pip
pip install --constraint=.github/workflows/constraints.txt nox
- name: Build documentation
run: nox --force-color --session=docs
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: docs
path: docs/_build
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

project = "Hypermodern Python Cookiecutter"
author = "Claudio Jolowicz"
copyright = f"{datetime.now().year}, {author}"
copyright = f"{datetime.now().year}, {author}" # noqa: A001
extensions = ["sphinx.ext.intersphinx", "myst_parser"]
intersphinx_mapping = {"mypy": ("https://mypy.readthedocs.io/en/stable/", None)}
language = "en"
Expand Down
10 changes: 5 additions & 5 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -2666,10 +2666,10 @@ You can also read the articles on [this blog][hypermodern python blog].
[nox]: https://nox.thea.codes/
[package metadata]: https://packaging.python.org/en/latest/specifications/core-metadata/
[pep 257]: http://www.python.org/dev/peps/pep-0257/
[pep 440]: https://www.python.org/dev/peps/pep-0440/
[pep 517]: https://www.python.org/dev/peps/pep-0517/
[pep 518]: https://www.python.org/dev/peps/pep-0518/
[pep 561]: https://www.python.org/dev/peps/pep-0561/
[pep 440]: https://peps.python.org/pep-0440/
[pep 517]: https://peps.python.org/pep-0517/
[pep 518]: https://peps.python.org/pep-0518/
[pep 561]: https://peps.python.org/pep-0561/
[pep 8]: http://www.python.org/dev/peps/pep-0008/
[pep8-naming codes]: https://github.com/pycqa/pep8-naming#pep-8-naming-conventions
[pep8-naming]: https://github.com/pycqa/pep8-naming
Expand Down Expand Up @@ -2740,6 +2740,6 @@ You can also read the articles on [this blog][hypermodern python blog].
[versions and constraints]: https://python-poetry.org/docs/dependency-specification/
[virtual environment]: https://docs.python.org/3/tutorial/venv.html
[virtualenv]: https://virtualenv.pypa.io/
[wheel]: https://www.python.org/dev/peps/pep-0427/
[wheel]: https://peps.python.org/pep-0427/
[xdoctest]: https://github.com/Erotemic/xdoctest
[yaml]: https://yaml.org/
105 changes: 93 additions & 12 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Nox sessions."""

from __future__ import annotations

from pathlib import Path
import shutil

Expand All @@ -8,25 +10,97 @@
from nox.sessions import Session


python_versions = ["3.12", "3.11", "3.10", "3.9"]

nox.options.sessions = ["docs"]
owner, repository = "cjolowicz", "cookiecutter-hypermodern-python"
owner, repository = "56kyle", "cookiecutter-hypermodern-python"
labels = "cookiecutter", "documentation"
bump_paths = "README.md", "docs/guide.rst", "docs/index.rst", "docs/quickstart.md"

REPO_ROOT: Path = Path(__file__).parent
NEXTGEN_STARTER_CACHE_FOLDER: Path = platformdirs.user_cache_path(
appname="cookiecutter-hypermodern-python",
appauthor="56kyle",
ensure_exists=True
)
REPO_ROOT: Path = Path(__file__).parent.resolve()
TEMPLATE_FOLDER: Path = REPO_ROOT / "{{cookiecutter.project_name}}"


COOKIECUTTER_HYPERMODERN_PYTHON_CACHE_FOLDER: Path = Path(
platformdirs.user_cache_path(
appname="cookiecutter-hypermodern-python",
appauthor="56kyle",
ensure_exists=True,
)
).resolve()

PROJECT_DEMOS_FOLDER: Path = NEXTGEN_STARTER_CACHE_FOLDER / "project_demos"
PROJECT_DEMOS_FOLDER: Path = COOKIECUTTER_HYPERMODERN_PYTHON_CACHE_FOLDER / "project_demos"
DEFAULT_DEMO_NAME: str = "demo-project"
DEMO_ROOT_FOLDER: Path = PROJECT_DEMOS_FOLDER / DEFAULT_DEMO_NAME

GENERATE_DEMO_PROJECT_OPTIONS: tuple[str, ...] = (
*("--repo-folder", REPO_ROOT),
*("--demos-cache-folder", PROJECT_DEMOS_FOLDER),
*("--demo-name", DEFAULT_DEMO_NAME),
)

SYNC_POETRY_WITH_DEMO_OPTIONS: tuple[str, ...] = (
*("--template-folder", TEMPLATE_FOLDER),
*("--demos-cache-folder", PROJECT_DEMOS_FOLDER),
*("--demo-name", DEFAULT_DEMO_NAME),
)

@nox.session(name="generate-demo-project")
def generate_demo_project(session: Session) -> Session:
pass

@nox.session(name="generate-demo-project", python=python_versions[-1])
def generate_demo_project(session: Session) -> None:
session.install("cookiecutter", "platformdirs", "loguru")
session.run(
"python",
"tools/generate-demo-project.py",
*GENERATE_DEMO_PROJECT_OPTIONS,
external=True,
)


@nox.session(name="sync-poetry-with-demo", python=python_versions[-1])
def sync_poetry_with_demo(session: Session) -> None:
session.install("cookiecutter", "platformdirs", "loguru")
session.run(
"python",
"tools/sync-poetry-with-demo.py",
*SYNC_POETRY_WITH_DEMO_OPTIONS,
external=True,
)


@nox.session(name="poetry-in-demo", python=python_versions[-1])
def poetry_in_demo(session: Session) -> None:
session.install("cookiecutter", "platformdirs", "loguru")
session.run(
"python",
"tools/generate-demo-project.py",
*GENERATE_DEMO_PROJECT_OPTIONS,
external=True,
)
original_dir: Path = Path.cwd()
session.cd(DEMO_ROOT_FOLDER)
session.run("poetry", *session.posargs)
session.cd(original_dir)
session.run(
"python",
"tools/sync-poetry-with-demo.py",
*SYNC_POETRY_WITH_DEMO_OPTIONS,
external=True,
)


@nox.session(name="poetry-lock")
def poetry_lock(session: Session) -> None:
"""Shorthand for poetry-in-demo -- lock."""
session._runner.posargs = ["lock", *session.posargs]
poetry_in_demo(session)


@nox.session(name="poetry-update")
def poetry_update(session: Session) -> None:
"""Shorthand for poetry-in-demo -- update."""
session._runner.posargs = ["update", *session.posargs]
poetry_in_demo(session)


@nox.session(name="prepare-release")
Expand Down Expand Up @@ -77,7 +151,14 @@ def docs(session: Session) -> None:
@nox.session
def linkcheck(session: Session) -> None:
"""Build the documentation."""
args = session.posargs or ["-b", "linkcheck", "-W", "--keep-going", "docs", "docs/_build"]
args = session.posargs or [
"-b",
"linkcheck",
"-W",
"--keep-going",
"docs",
"docs/_build",
]

builddir = Path("docs", "_build")
if builddir.exists():
Expand Down
9 changes: 2 additions & 7 deletions tools/dependencies-table.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,11 @@ def main() -> None:
if package["name"] in dependencies
}

table = {
format_dependency(dependency): descriptions[dependency]
for dependency in sorted(dependencies)
}
table = {format_dependency(dependency): descriptions[dependency] for dependency in sorted(dependencies)}

width = max(len(name) for name in table)
width2 = max(len(description) for description in table.values())
separator = LINE_FORMAT.format(
name="=" * width, width=width, description="=" * width2
)
separator = LINE_FORMAT.format(name="=" * width, width=width, description="=" * width2)

print(separator)

Expand Down
40 changes: 19 additions & 21 deletions tools/generate-demo-project.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
import shutil
import sys
from pathlib import Path
"""Python script for generating a demo project."""

import shutil
import sys
from pathlib import Path

import click

from cookiecutter.main import cookiecutter
from loguru import logger

from tools.util import DEFAULT_DEMO_NAME
from tools.util import PROJECT_DEMOS_FOLDER
from tools.util import REPO_ROOT

FOLDER_TYPE: click.Path = click.Path(dir_okay=True, file_okay=False, resolve_path=True, path_type=Path)


def generate_demo_project() -> Path:
"""Generates a demo project and returns its Path."""
PROJECT_DEMOS_FOLDER.mkdir(exist_ok=True)
_remove_any_existing_demo(PROJECT_DEMOS_FOLDER)
def generate_demo_project(repo_folder: Path, demos_cache_folder: Path, demo_name: str) -> Path:
"""Generates a demo project and returns its root path."""
demos_cache_folder.mkdir(exist_ok=True)
_remove_any_existing_demo(demos_cache_folder)
cookiecutter(
template=str(REPO_ROOT),
template=str(repo_folder),
no_input=True,
extra_context={
"project_name": DEFAULT_DEMO_NAME,
},
extra_context={"project_name": demo_name},
overwrite_if_exists=True,
output_dir=str(PROJECT_DEMOS_FOLDER)
output_dir=str(demos_cache_folder),
)
return PROJECT_DEMOS_FOLDER / DEFAULT_DEMO_NAME
return demos_cache_folder / demo_name


def _remove_any_existing_demo(parent_path: Path) -> None:
Expand All @@ -38,14 +33,17 @@ def _remove_any_existing_demo(parent_path: Path) -> None:


@click.command()
def main() -> None:
"""Geneates a demo project."""
@click.option("--repo-folder", "-r", required=True, type=FOLDER_TYPE)
@click.option("--demos-cache-folder", "-c", required=True, type=FOLDER_TYPE)
@click.option("--demo-name", "-d", required=True, type=str)
def main(repo_folder: Path, demos_cache_folder: Path, demo_name: str) -> None:
"""Updates the poetry.lock file."""
try:
generate_demo_project()
generate_demo_project(repo_folder=repo_folder, demos_cache_folder=demos_cache_folder, demo_name=demo_name)
except Exception as error:
click.secho(f"error: {error}", fg="red")
sys.exit(1)


if __name__ == '__main__':
if __name__ == "__main__":
main(prog_name="generate-demo-project")
4 changes: 1 addition & 3 deletions tools/prepare-github-release.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@

def git(*args: str, **kwargs: Any) -> str:
try:
process = subprocess.run(
["git", *args], check=True, capture_output=True, text=True
)
process = subprocess.run(["git", *args], check=True, capture_output=True, text=True)
return process.stdout
except subprocess.CalledProcessError as error:
print(error.stdout, end="")
Expand Down
8 changes: 2 additions & 6 deletions tools/publish-github-release.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,14 @@ def publish_release(*, owner: str, repository_name: str, token: str, tag: str) -
try:
[pull_request] = list(repository.pull_requests(head=f"{owner}:release-{tag}"))
except ValueError:
raise RuntimeError(
f"there should be exactly one pull request for {owner}:release-{tag}"
)
raise RuntimeError(f"there should be exactly one pull request for {owner}:release-{tag}")

pull_request = repository.pull_request(pull_request.number)

try:
[*_, commit] = pull_request.commits()
except ValueError:
raise RuntimeError(
f"there should be at least one commit associated with #{pull_request.number}"
)
raise RuntimeError(f"there should be at least one commit associated with #{pull_request.number}")

try:
[release] = [release for release in repository.releases() if release.draft]
Expand Down
43 changes: 0 additions & 43 deletions tools/sync-poetry-lock-to-demo.py

This file was deleted.

Loading
Loading