diff --git a/.github/workflows/reusable-cookie.yml b/.github/workflows/reusable-cookie.yml index d6fd6fac..28b66070 100644 --- a/.github/workflows/reusable-cookie.yml +++ b/.github/workflows/reusable-cookie.yml @@ -13,38 +13,8 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Lint setuptools - run: pipx run nox -s 'lint(setuptools)' - - - name: Lint pybind11 - run: pipx run nox -s 'lint(pybind11)' - - - name: Lint scikit-build - run: pipx run nox -s 'lint(skbuild)' - - - name: Lint meson-python - run: pipx run nox -s 'lint(mesonpy)' - - - name: Lint poetry - run: pipx run nox -s 'lint(poetry)' - - - name: Lint flit - run: pipx run nox -s 'lint(flit)' - - - name: Lint pdm - run: pipx run nox -s 'lint(pdm)' - - - name: Lint whey - run: pipx run nox -s 'lint(whey)' - - - name: Lint maturin - run: pipx run nox -s 'lint(maturin)' - - - name: Lint hatch - run: pipx run nox -s 'lint(hatch)' - - - name: Lint setuptools PEP 621 - run: pipx run nox -s 'lint(setuptools621)' + - name: Lint all + run: pipx run nox -s 'lint' checks: name: Check Python ${{ matrix.python-version }} on ${{ matrix.runs-on }} @@ -71,47 +41,48 @@ jobs: run: pip install nox - name: Test setuptools - run: nox -s 'tests(setuptools)' + run: nox -s 'tests(setuptools, novcs)' -s 'tests(setuptools, vcs)' - name: Test pybind11 - run: nox -s 'tests(pybind11)' + run: nox -s 'tests(pybind11, novcs)' -s 'tests(pybind11, vcs)' - name: Test scikit-build - run: nox -s 'tests(skbuild)' + run: nox -s 'tests(skbuild, novcs)' -s 'tests(skbuild, vcs)' - name: Test poetry - run: nox -s 'tests(poetry)' + run: nox -s 'tests(poetry, novcs)' -s 'tests(poetry, vcs)' - name: Test flit - run: nox -s 'tests(flit)' + run: nox -s 'tests(flit, novcs)' -s 'tests(flit, vcs)' - name: Test pdm - run: nox -s 'tests(pdm)' + run: nox -s 'tests(pdm, novcs)' -s 'tests(pdm, vcs)' - name: Test whey - run: nox -s 'tests(whey)' + run: nox -s 'tests(whey, novcs)' - name: Test maturin - run: nox -s 'tests(maturin)' + run: nox -s 'tests(maturin, novcs)' - name: Test hatch - run: nox -s 'tests(hatch)' + run: nox -s 'tests(hatch, novcs)' -s 'tests(hatch, vcs)' - name: Test setuptools PEP 621 - run: nox -s 'tests(setuptools621)' + run: nox -s 'tests(setuptools621, novcs)' -s 'tests(setuptools621, vcs)' - name: Native poetry tooling - run: nox -s 'native(poetry)' + run: nox -s 'native(poetry, novcs)' -s 'native(poetry, vcs)' - name: Native pdm tooling - run: nox -s 'native(pdm)' + + run: nox -s 'native(pdm, novcs)' -s 'native(pdm, vcs)' - name: Activate MSVC for Meson if: runner.os == 'Windows' uses: ilammy/msvc-dev-cmd@v1 - name: Test meson-python - run: nox -s 'tests(mesonpy)' + run: nox -s 'tests(mesonpy, novcs)' - name: Compare copier template generation run: nox -s compare_copier @@ -128,53 +99,53 @@ jobs: - name: Test setuptools run: | - pipx run nox -s 'nox(setuptools)' - pipx run nox -s 'nox(setuptools)' -- docs + pipx run nox -s 'nox(setuptools, vcs)' + pipx run nox -s 'nox(setuptools, vcs)' -- docs - name: Test pybind11 run: | - pipx run nox -s 'nox(pybind11)' - pipx run nox -s 'nox(pybind11)' -- docs + pipx run nox -s 'nox(pybind11, vcs)' + pipx run nox -s 'nox(pybind11, vcs)' -- docs - name: Test scikit-build run: | - pipx run nox -s 'nox(skbuild)' - pipx run nox -s 'nox(skbuild)' -- docs + pipx run nox -s 'nox(skbuild, vcs)' + pipx run nox -s 'nox(skbuild, vcs)' -- docs - name: Test poetry run: | - pipx run nox -s 'nox(poetry)' - pipx run nox -s 'nox(poetry)' -- docs + pipx run nox -s 'nox(poetry, novcs)' + pipx run nox -s 'nox(poetry, novcs)' -- docs - name: Test flit run: | - pipx run nox -s 'nox(flit)' - pipx run nox -s 'nox(flit)' -- docs + pipx run nox -s 'nox(flit, novcs)' + pipx run nox -s 'nox(flit, novcs)' -- docs - name: Test pdm run: | - pipx run nox -s 'nox(pdm)' - pipx run nox -s 'nox(pdm)' -- docs + pipx run nox -s 'nox(pdm, vcs)' + pipx run nox -s 'nox(pdm, vcs)' -- docs - name: Test whey run: | - pipx run nox -s 'nox(whey)' - pipx run nox -s 'nox(whey)' -- docs + pipx run nox -s 'nox(whey, novcs)' + pipx run nox -s 'nox(whey, novcs)' -- docs - name: Test maturin run: | - pipx run nox -s 'nox(maturin)' - pipx run nox -s 'nox(maturin)' -- docs + pipx run nox -s 'nox(maturin, novcs)' + pipx run nox -s 'nox(maturin, novcs)' -- docs - name: Test hatch run: | - pipx run nox -s 'nox(hatch)' - pipx run nox -s 'nox(hatch)' -- docs + pipx run nox -s 'nox(hatch, vcs)' + pipx run nox -s 'nox(hatch, vcs)' -- docs - name: Test setuptools PEP 621 run: | - pipx run nox -s 'nox(setuptools621)' - pipx run nox -s 'nox(setuptools621)' -- docs + pipx run nox -s 'nox(setuptools621, vcs)' + pipx run nox -s 'nox(setuptools621, vcs)' -- docs - name: Activate MSVC for Meson if: runner.os == 'Windows' @@ -182,8 +153,8 @@ jobs: - name: Test meson-python run: | - pipx run nox -s 'nox(mesonpy)' - pipx run nox -s 'nox(mesonpy)' -- docs + pipx run nox -s 'nox(mesonpy, novcs)' + pipx run nox -s 'nox(mesonpy, novcs)' -- docs dist: name: Distribution build diff --git a/README.md b/README.md index 4182de42..60d4ab8b 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ templates for Python packages? - Lives with the [Scientific-Python Development Guide][]: Every decision is clearly documented and every tool described, and everything is kept in sync. - Eleven different backends to choose from for building packages. +- Optional VCS versioning for most backends. - Template generation tested in GitHub Actions using nox. - Supports generation with [copier][], [cookiecutter][], and [cruft][]. - Supports GitHub Actions if targeting a `github.com` url (the default), and @@ -46,7 +47,7 @@ During generation you can select from the following backends for your package: projects supporting standards. Replaces setuptools, venv/pipenv, pip, wheel, and twine. Supports [PEP 621][]. 4. [whey][]: A modern [PEP 621][] builder with some automation options for Trove - classifiers. Development seems to be stalled, possibly. + classifiers. Development seems to be stalled, possibly. (No VCS versioning) 5. [poetry][]: An all-in-one solution to pure Python projects. Replaces setuptools, venv/pipenv, pip, wheel, and twine. Higher learning curve, but is all-in-one. Makes some bad default assumptions for libraries. The only one @@ -59,9 +60,9 @@ During generation you can select from the following backends for your package: [pybind11][] and wheels generated by [cibuildwheel][]. 9. [scikit-build][]: A scikit-build (CMake) project also using pybind11, using scikit-build-core. **(Recommended for C++ projects)** -10. [meson-python][]: A Meson project also using pybind11. -11. [maturin][]: A [PEP 621][] builder for Rust binary extensions. - **(Recommended for Rust projects)** +10. [meson-python][]: A Meson project also using pybind11. (No VCS versioning) +11. [maturin][]: A [PEP 621][] builder for Rust binary extensions. (No VCS + versioning) **(Recommended for Rust projects)** Currently, the best choice is probably hatch for pure Python projects, and setuptools (such as the pybind11 choice) for binary projects. diff --git a/cookiecutter.json b/cookiecutter.json index e8917624..f2a02d73 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -19,6 +19,7 @@ "mesonpy", "maturin" ], + "vcs": true, "__year": "{% now 'utc', '%Y' %}", "__project_slug": "{{ cookiecutter.project_name | lower | replace('-', '_') | replace('.', '_') }}", "__type": "{{ 'compiled' if cookiecutter.backend in ['pybind11', 'skbuild', 'mesonpy', 'maturin'] else 'pure' }}", @@ -45,6 +46,7 @@ "skbuild": "Scikit-build-core - Compiled C++ (recommended)", "mesonpy": "Meson-python - Compiled C++ (also good)", "maturin": "Maturin - Compiled Rust (recommended)" - } + }, + "vcs": "Use version control for versioning" } } diff --git a/copier.yml b/copier.yml index ee6c0b72..e9a33341 100644 --- a/copier.yml +++ b/copier.yml @@ -83,6 +83,13 @@ backend: "Maturin - Compiled Rust (recommended)": maturin # [[[end]]] +# [[[cog print(cc.vcs.yaml()) ]]] +vcs: + type: bool + help: Use version control for versioning + # [[[end]]] + when: "{{ backend not in ['whey', 'maturin', 'mesonpy'] }}" + _templates_suffix: "" _subdirectory: "{% raw %}{{cookiecutter.project_name}}{% endraw %}" diff --git a/helpers/cog_cc.py b/helpers/cog_cc.py index 4732065a..8d539d18 100644 --- a/helpers/cog_cc.py +++ b/helpers/cog_cc.py @@ -65,7 +65,11 @@ def __init__(self, filename: str): name, value, prompt, - "str" if isinstance(value, str) else "", + "str" + if isinstance(value, str) + else "bool" + if isinstance(value, bool) + else "", choices=choices, ), ) diff --git a/noxfile.py b/noxfile.py index 91168824..1438730f 100644 --- a/noxfile.py +++ b/noxfile.py @@ -9,10 +9,13 @@ import difflib import json +import os import re import shutil +import stat import sys import urllib.request +from collections.abc import Callable from pathlib import Path import nox @@ -28,13 +31,30 @@ default_context: project_name: cookie-{backend} backend: {backend} + vcs: {vcs} """ -def make_copier(session: nox.Session, backend: str) -> None: +def _remove_readonly(func: Callable[[str], None], path: str, _: object) -> None: + os.chmod(path, stat.S_IWRITE) # noqa: PTH101 + func(path) + + +def rmtree_ro(path: Path) -> None: + if sys.version_info >= (3, 12): + shutil.rmtree(path, onexc=_remove_readonly) + else: + shutil.rmtree(path, onerror=_remove_readonly) + + +def get_expected_version(backend: str, vcs: bool) -> str: + return "0.2.3" if vcs and backend not in {"whey", "maturin", "mesonpy"} else "0.1.0" + + +def make_copier(session: nox.Session, backend: str, vcs: bool) -> None: package_dir = Path(f"copy-{backend}") if package_dir.exists(): - shutil.rmtree(package_dir) + rmtree_ro(package_dir) session.run( "copier", @@ -50,6 +70,7 @@ def make_copier(session: nox.Session, backend: str) -> None: "--data=full_name=My Name", "--data=email=me@email.com", "--data=license=BSD", + f"--data=vcs={vcs}", ) init_git(session, package_dir) @@ -57,12 +78,14 @@ def make_copier(session: nox.Session, backend: str) -> None: return package_dir -def make_cookie(session: nox.Session, backend: str) -> None: +def make_cookie(session: nox.Session, backend: str, vcs: bool) -> None: package_dir = Path(f"cookie-{backend}") if package_dir.exists(): - shutil.rmtree(package_dir) + rmtree_ro(package_dir) - Path("input.yml").write_text(JOB_FILE.format(backend=backend), encoding="utf-8") + Path("input.yml").write_text( + JOB_FILE.format(backend=backend, vcs=vcs), encoding="utf-8" + ) session.run( "cookiecutter", @@ -76,17 +99,17 @@ def make_cookie(session: nox.Session, backend: str) -> None: return package_dir -def make_cruft(session: nox.Session, backend: str) -> None: +def make_cruft(session: nox.Session, backend: str, vcs: bool) -> None: package_dir = Path(f"cruft-{backend}") if package_dir.exists(): - shutil.rmtree(package_dir) + rmtree_ro(package_dir) tmp_dir = Path("tmp_loc") tmp_dir.mkdir() session.cd(tmp_dir) Path("input.yml").write_text( - JOB_FILE.format(backend=backend, pkg=package_dir), encoding="utf-8" + JOB_FILE.format(backend=backend, pkg=package_dir, vcs=vcs), encoding="utf-8" ) session.run( "cruft", @@ -120,7 +143,7 @@ def init_git(session: nox.Session, package_dir: Path) -> None: "feat: initial version", external=True, ) - session.run("git", "-C", f"{package_dir}", "tag", "v0.1.0", external=True) + session.run("git", "-C", f"{package_dir}", "tag", "v0.2.3", external=True) IGNORE_FILES = {"__pycache__", ".git", ".copier-answers.yml", ".cruft.json"} @@ -151,13 +174,14 @@ def diff_files(p1: Path, p2: Path) -> bool: @nox.session() +@nox.parametrize("vcs", [False, True], ids=["novcs", "vcs"]) @nox.parametrize("backend", BACKENDS, ids=BACKENDS) -def lint(session: nox.Session, backend: str) -> None: +def lint(session: nox.Session, backend: str, vcs: bool) -> None: session.install("cookiecutter", "pre-commit") tmp_dir = session.create_tmp() session.cd(tmp_dir) - cookie = make_cookie(session, backend) + cookie = make_cookie(session, backend, vcs) session.chdir(cookie) session.run( @@ -171,12 +195,12 @@ def lint(session: nox.Session, backend: str) -> None: @nox.session @nox.parametrize("backend", BACKENDS, ids=BACKENDS) -def autoupdate(session, backend): +def autoupdate(session: nox.Session, backend: str) -> None: session.install("cookiecutter", "pre-commit") tmp_dir = session.create_tmp() session.cd(tmp_dir) - cookie = make_cookie(session, backend) + cookie = make_cookie(session, backend, True) session.chdir(cookie) session.run("pre-commit", "autoupdate") @@ -184,27 +208,38 @@ def autoupdate(session, backend): @nox.session() +@nox.parametrize("vcs", [False, True], ids=["novcs", "vcs"]) @nox.parametrize("backend", BACKENDS, ids=BACKENDS) -def tests(session, backend): +def tests(session: nox.Session, backend: str, vcs: bool) -> None: session.install("cookiecutter") tmp_dir = session.create_tmp() session.cd(tmp_dir) - cookie = make_cookie(session, backend) + cookie = make_cookie(session, backend, vcs) session.chdir(cookie) + name = f"cookie-{backend}" session.install(".[test]") session.run("python", "-m", "pytest", "-ra") + version = session.run( + "python", + "-c", + f'import importlib.metadata as m; print(m.version("{name}"))', + silent=True, + ).strip() + expected_version = get_expected_version(backend, vcs) + assert version == expected_version, f"{version=} != {expected_version=}" @nox.session() +@nox.parametrize("vcs", [False, True], ids=["novcs", "vcs"]) @nox.parametrize("backend", ("poetry", "pdm", "hatch"), ids=("poetry", "pdm", "hatch")) -def native(session, backend): +def native(session: nox.Session, backend: str, vcs: bool) -> None: session.install("cookiecutter", backend) tmp_dir = session.create_tmp() session.cd(tmp_dir) - cookie = make_cookie(session, backend) + cookie = make_cookie(session, backend, vcs) session.chdir(cookie) if backend == "hatch": @@ -216,21 +251,23 @@ def native(session, backend): @nox.session() +@nox.parametrize("vcs", [False, True], ids=["novcs", "vcs"]) @nox.parametrize("backend", BACKENDS, ids=BACKENDS) -def dist(session, backend): +def dist(session: nox.Session, backend: str, vcs: bool) -> None: session.install("cookiecutter", "build", "twine") tmp_dir = session.create_tmp() session.cd(tmp_dir) - cookie = make_cookie(session, backend) + cookie = make_cookie(session, backend, vcs) session.chdir(cookie) session.run("python", "-m", "build", silent=True) (sdist,) = Path("dist").glob("*.tar.gz") (wheel,) = Path("dist").glob("*.whl") - if "0.1.0" not in str(wheel): - session.error(f"{wheel} must be version 0.1.0") + expected_version = get_expected_version(backend, vcs) + if expected_version not in str(wheel): + session.error(f"{wheel} must be version {expected_version}") session.run("twine", "check", f"{sdist}", f"{wheel}") @@ -241,13 +278,14 @@ def dist(session, backend): @nox.session(name="nox") +@nox.parametrize("vcs", [False, True], ids=["novcs", "vcs"]) @nox.parametrize("backend", BACKENDS, ids=BACKENDS) -def nox_session(session, backend): +def nox_session(session: nox.Session, backend: str, vcs: bool) -> None: session.install("cookiecutter", "nox") tmp_dir = session.create_tmp() session.cd(tmp_dir) - cookie = make_cookie(session, backend) + cookie = make_cookie(session, backend, vcs) session.chdir(cookie) if session.posargs: @@ -264,13 +302,14 @@ def compare_copier(session): session.cd(tmp_dir) for backend in BACKENDS: - cookie = make_cookie(session, backend) - copier = make_copier(session, backend) + for vcs in (False, True): + cookie = make_cookie(session, backend, vcs) + copier = make_copier(session, backend, vcs) - if diff_files(cookie, copier): - session.log(f"{backend} passed") - else: - session.error(f"{backend} files are not the same!") + if diff_files(cookie, copier): + session.log(f"{backend} {vcs=} passed") + else: + session.error(f"{backend} {vcs=} files are not the same!") @nox.session() @@ -281,13 +320,14 @@ def compare_cruft(session): session.cd(tmp_dir) for backend in BACKENDS: - cookie = make_cookie(session, backend) - copier = make_cruft(session, backend) - - if diff_files(cookie, copier): - session.log(f"{backend} passed") - else: - session.error(f"{backend} files are not the same!") + for vcs in (False, True): + cookie = make_cookie(session, backend, vcs) + cruft = make_cruft(session, backend, vcs) + + if diff_files(cookie, cruft): + session.log(f"{backend} {vcs=} passed") + else: + session.error(f"{backend} {vcs=} files are not the same!") PC_VERS = re.compile( diff --git a/{{cookiecutter.project_name}}/pyproject.toml b/{{cookiecutter.project_name}}/pyproject.toml index d7022fa1..4e8de00a 100644 --- a/{{cookiecutter.project_name}}/pyproject.toml +++ b/{{cookiecutter.project_name}}/pyproject.toml @@ -9,38 +9,60 @@ build-backend = "pdm.backend" requires = ["maturin>=0.15,<2"] build-backend = "maturin" {%- elif cookiecutter.backend == "hatch" %} +{%- if cookiecutter.vcs %} +requires = ["hatchling", "hatch-vcs"] +{%- else %} requires = ["hatchling"] +{%- endif %} build-backend = "hatchling.build" {%- elif cookiecutter.backend == "setuptools621" %} -requires = ["setuptools>=61.0"] +{%- if cookiecutter.vcs %} +requires = ["setuptools>=61", "setuptools_scm[toml]>=7"] +{%- else %} +requires = ["setuptools>=61"] +{%- endif %} build-backend = "setuptools.build_meta" {%- elif cookiecutter.backend == "flit" %} +{%- if cookiecutter.vcs %} +requires = ["flit_scm"] +build-backend = "flit_scm:buildapi" +{%- else %} requires = ["flit_core>=3.4"] build-backend = "flit_core.buildapi" +{%- endif %} {%- elif cookiecutter.backend == "setuptools" %} +{%- if cookiecutter.vcs %} requires = ["setuptools>=42", "setuptools_scm[toml]>=3.4"] +{%- else %} +requires = ["setuptools>=42"] +{%- endif %} build-backend = "setuptools.build_meta" {%- elif cookiecutter.backend == "pybind11" %} +{%- if cookiecutter.vcs %} requires = ["setuptools>=42", "setuptools_scm[toml]>=3.4", "pybind11"] +{%- else %} +requires = ["setuptools>=42", "pybind11"] +{%- endif %} build-backend = "setuptools.build_meta" {%- elif cookiecutter.backend == "skbuild" %} requires = ["pybind11", "scikit-build-core"] build-backend = "scikit_build_core.build" -{%- elif cookiecutter.backend == "mesonpy" %} +{%- elif cookiecutter.backend == "mesonpy" %} requires = ["meson-python", "pybind11"] build-backend = "mesonpy" {%- elif cookiecutter.backend == "poetry" %} +{%- if cookiecutter.vcs %} +requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"] +build-backend = "poetry_dynamic_versioning.backend" +{%- else %} requires = ["poetry_core>=1.0.0"] build-backend = "poetry.core.masonry.api" {%- endif %} +{%- endif %} {%- if cookiecutter.backend in ["setuptools", "pybind11"] %} -[tool.setuptools_scm] -write_to = "src/{{ cookiecutter.__project_slug }}/_version.py" - - [tool.check-manifest] ignore = [ ".github/**", @@ -56,7 +78,11 @@ ignore = [ [tool.poetry] name = "{{ cookiecutter.project_name }}" +{%- if cookiecutter.vcs %} +version = "0.0.0" +{%- else %} version = "0.1.0" +{%- endif %} authors = [ "{{ cookiecutter.full_name }} <{{ cookiecutter.email }}>", ] @@ -112,13 +138,18 @@ docs = [ "sphinx_copybutton", ] +{%- if cookiecutter.vcs %} +[tool.poetry-dynamic-versioning] +enable = true +substitution.files = ["src/{{ cookiecutter.__project_slug }}/__init__.py"] +{%- endif %} {%- else %} [project] name = "{{ cookiecutter.project_name }}" -{%- if cookiecutter.backend not in ["flit", "hatch"] %} +{%- if cookiecutter.backend in ['maturin', 'mesonpy', 'whey'] or not cookiecutter.vcs and cookiecutter.backend in ['setuptools621', 'skbuild'] %} version = "0.1.0" {%- endif %} authors = [ @@ -155,7 +186,7 @@ classifiers = [ "Topic :: Scientific/Engineering", "Typing :: Typed", ] -{%- if cookiecutter.backend in ["flit", "hatch"] %} +{%- if cookiecutter.backend not in ['maturin', 'mesonpy', 'whey'] and cookiecutter.vcs or cookiecutter.backend in ['pdm', 'hatch', 'flit'] %} dynamic = ["version"] {%- endif %} dependencies = [] @@ -192,6 +223,11 @@ Changelog = "{{ cookiecutter.url }}/releases" [tool.scikit-build] minimum-version = "0.4" build-dir = "build/{wheel_tag}" +{%- if cookiecutter.vcs %} +metadata.version.provider = "scikit_build_core.metadata.setuptools_scm" +sdist.include = ["src/{{ cookiecutter.__project_slug }}/_version.py"] +{%- endif %} + {%- elif cookiecutter.backend == "whey" %} @@ -212,20 +248,47 @@ sdist-generator = "git" # default is cargo [tool.hatch] +{%- if not cookiecutter.vcs %} version.path = "src/{{ cookiecutter.__project_slug }}/__init__.py" +{%- else %} +version.source = "vcs" +build.hooks.vcs.version-file = "src/{{ cookiecutter.__project_slug }}/_version.py" +{%- endif %} envs.default.dependencies = [ "pytest", "pytest-cov", ] {%- elif cookiecutter.backend == "pdm" %} +{%- if cookiecutter.vcs %} + + +[tool.pdm.version] +source = "scm" +write_to = "{{ cookiecutter.__project_slug }}/_version.py" +write_template = "version = '{}'" + +{%- else %} +[tool.pdm.version] +source = "file" +path = "src/{{ cookiecutter.__project_slug }}/__init__.py" + +{%- endif %} + [tool.pdm.dev-dependencies] devtest = ["pytest", "pytest-cov"] {%- endif %} +{%- if cookiecutter.backend in ["setuptools", "pybind11", "poetry", "flit", "skbuild", "setuptools621"] and cookiecutter.vcs %} + + +[tool.setuptools_scm] +write_to = "src/{{ cookiecutter.__project_slug }}/_version.py" +{%- endif %} + {%- if cookiecutter.__type == "compiled" %} diff --git a/{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/__init__.py b/{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/__init__.py index 340316c6..3cd31f44 100644 --- a/{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/__init__.py +++ b/{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/__init__.py @@ -7,10 +7,24 @@ from __future__ import annotations -{% if cookiecutter.backend == "setuptools" or cookiecutter.backend == "pybind11" -%} +{%- if cookiecutter.backend in ["setuptools", "pybind11", "hatch", "skbuild", "setuptools621", "flit"] and cookiecutter.vcs %} + from ._version import version as __version__ -{%- else -%} + +{%- elif cookiecutter.backend == "pdm" and cookiecutter.vcs %} + +import importlib.metadata + +__version__ = importlib.metadata.version("{{ cookiecutter.__project_slug }}") + +{%- elif cookiecutter.backend == "poetry" and cookiecutter.vcs %} + +__version__ = "0.0.0" + +{%- else %} + __version__ = "0.1.0" + {%- endif %} __all__ = ("__version__",) diff --git a/{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/{% if cookiecutter.backend in ['setuptools', 'pybind11'] %}_version.pyi{% endif %} b/{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/{% if cookiecutter.vcs and cookiecutter.backend not in ['whey', 'mesonpy', 'poetry', 'maturin'] %}_version.pyi{% endif %} similarity index 69% rename from {{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/{% if cookiecutter.backend in ['setuptools', 'pybind11'] %}_version.pyi{% endif %} rename to {{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/{% if cookiecutter.vcs and cookiecutter.backend not in ['whey', 'mesonpy', 'poetry', 'maturin'] %}_version.pyi{% endif %} index 91744f98..f8c6240f 100644 --- a/{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/{% if cookiecutter.backend in ['setuptools', 'pybind11'] %}_version.pyi{% endif %} +++ b/{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/{% if cookiecutter.vcs and cookiecutter.backend not in ['whey', 'mesonpy', 'poetry', 'maturin'] %}_version.pyi{% endif %} @@ -1,4 +1,6 @@ from __future__ import annotations version: str +{%- if cookiecutter.backend != "pdm" %} version_tuple: tuple[int, int, int] | tuple[int, int, int, str, str] +{%- endif %} diff --git a/{{cookiecutter.project_name}}/tests/test_package.py b/{{cookiecutter.project_name}}/tests/test_package.py index 357dce64..4d7300d7 100644 --- a/{{cookiecutter.project_name}}/tests/test_package.py +++ b/{{cookiecutter.project_name}}/tests/test_package.py @@ -1,7 +1,9 @@ from __future__ import annotations +import importlib.metadata + import {{ cookiecutter.__project_slug }} as m def test_version(): - assert m.__version__ + assert importlib.metadata.version("{{ cookiecutter.__project_slug }}") == m.__version__ diff --git a/{{cookiecutter.project_name}}/{% if cookiecutter.backend in ['setuptools','pybind11'] %}setup.cfg{% endif %} b/{{cookiecutter.project_name}}/{% if cookiecutter.backend in ['setuptools','pybind11'] %}setup.cfg{% endif %} index 5b9705d3..ba2c1826 100644 --- a/{{cookiecutter.project_name}}/{% if cookiecutter.backend in ['setuptools','pybind11'] %}setup.cfg{% endif %} +++ b/{{cookiecutter.project_name}}/{% if cookiecutter.backend in ['setuptools','pybind11'] %}setup.cfg{% endif %} @@ -1,5 +1,8 @@ [metadata] name = {{ cookiecutter.__project_slug }} +{%- if not cookiecutter.vcs %} +version = 0.1.0 +{%- endif%} description = {{ cookiecutter.project_short_description }} long_description = file: README.md long_description_content_type = text/markdown