diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8fba639..d5e8f5d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,9 +5,7 @@ on: pull_request: push: branches: - - master - main - - develop jobs: pre-commit: @@ -15,7 +13,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - name: Lint setuptools run: pipx run nox --forcecolor -s 'lint(setuptools)' @@ -23,11 +20,17 @@ jobs: - name: Lint pybind11 run: pipx run nox --forcecolor -s 'lint(pybind11)' + - name: Lint poetry + run: pipx run nox --forcecolor -s 'lint(poetry)' + - name: Lint flit run: pipx run nox --forcecolor -s 'lint(flit)' - - name: Lint poetry - run: pipx run nox --forcecolor -s 'lint(poetry)' + - name: Lint flit621 + run: pipx run nox --forcecolor -s 'lint(flit621)' + + - name: Lint trampolim + run: pipx run nox --forcecolor -s 'lint(trampolim)' checks: @@ -60,11 +63,18 @@ jobs: - name: Test pybind11 run: nox --forcecolor -s 'tests(pybind11)' + - name: Test poetry + run: nox --forcecolor -s 'tests(poetry)' + - name: Test flit run: nox --forcecolor -s 'tests(flit)' - - name: Test poetry - run: nox --forcecolor -s 'tests(poetry)' + - name: Test flit621 + run: nox --forcecolor -s 'tests(flit621)' + + - name: Test trampolim + if: matrix.python-version != '3.6' + run: nox --forcecolor -s 'tests(trampolim)' - name: Test poetry tooling run: nox --forcecolor -s tests_poetry diff --git a/README.md b/README.md index 33cb7cc2..5772392e 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,9 @@ This is a Python template project, with the following project types: 4. [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. +5. [flit621][flit]: Flit, but with PEP 621 style configuration (hidden feature). +6. [trampolim][]: A modern PEP 621 builder with support for tasks, allowing + arbitrary Python to run during the build process if needed. #### To use: @@ -118,4 +121,5 @@ If you don't have `nox` locally, you can use [pipx][], such as `pipx run nox` in [poetry]: https://python-poetry.org [pybind11]: https://pybind11.readthedocs.io/en/stable/ [setuptools]: https://setuptools.readthedocs.io/en/latest/ +[trampolim]: https://trampolim.readthedocs.io/en/latest/ [pipx]: https://pypa.github.io/pipx/ diff --git a/cookiecutter.json b/cookiecutter.json index a57f9738..11c6d06c 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -3,7 +3,7 @@ "org": "Scikit-HEP", "url": "https://github.com/{{ cookiecutter.org }}/{{ cookiecutter.project_name }}", "full_name": "My Name", - "project_type": ["setuptools", "pybind11", "flit", "poetry"], + "project_type": ["setuptools", "pybind11", "poetry", "flit", "flit621", "trampolim"], "email": "me@email.com", "maintainer": "The Scikit-HEP admins", "maintainer_email": "scikit-hep-admins@googlegroups.com", diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index fc63d58f..ab9eff81 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -2,14 +2,16 @@ project_name = "{{ cookiecutter.project_name }}" project_type = "{{ cookiecutter.project_type }}" -project_types = {"setuptools", "pybind11", "flit", "poetry"} +project_types = {"setuptools", "pybind11", "poetry", "flit", "flit621", "trampolim"} other_project_types = project_types - {project_type} project_underscore_name = project_name.replace("-", "_") project_dash_name = project_name.replace("_", "-") +src = Path("src") + if project_name != project_underscore_name: - Path(f"src/{project_name}").rename(f"src/{project_underscore_name}") + (src / project_name).rename(src / project_underscore_name) files = [p for p in Path(".").rglob("*") if p.is_file() and "-" in p.stem] @@ -21,3 +23,10 @@ f.replace(f.with_name(f"{base}{f.suffix}")) elif currents & other_project_types: f.unlink() + +# Hackaround lack of "src/" support in trampolim - remove when proper support +# is added (and maybe after editable support is added?) +# Also remove if clause in .pre-commit-config.yaml +if project_type == "trampolim": + for f in Path("src").iterdir(): + f.rename(f.stem) diff --git a/noxfile.py b/noxfile.py index 6d6a6f3a..592ac0ee 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,9 +1,8 @@ import nox from pathlib import Path -import shutil DIR = Path(__file__).parent.resolve() -BACKENDS = "setuptools", "pybind11", "flit", "poetry" +BACKENDS = "setuptools", "pybind11", "poetry", "flit", "flit621", "trampolim" JOB_FILE = """\ default_context: @@ -11,6 +10,8 @@ project_type: {backend} """ +ENV = {"SETUPTOOLS_SCM_PRETEND_VERSION": "0.1.0"} + def make_cookie(session: nox.Session, backend: str) -> str: tmp_dir = session.create_tmp() @@ -45,7 +46,7 @@ def lint(session: nox.Session, backend: str) -> None: "../tmp_git", external=True, ) - shutil.move("../tmp_git/.git", ".git") + Path("../tmp_git/.git").rename(".git") session.run("git", "add", ".", external=True) session.run( @@ -64,7 +65,7 @@ def tests(session, backend): make_cookie(session, backend) - session.install(".[test]", env={"SETUPTOOLS_SCM_PRETEND_VERSION": "0.1.0"}) + session.install(".[test]", env=ENV) session.run("python", "-m", "pytest", "-ra") @@ -85,14 +86,18 @@ def dist(session, backend): make_cookie(session, backend) - session.run( - "python", "-m", "build", env={"SETUPTOOLS_SCM_PRETEND_VERSION": "0.1.0"} - ) - files = list(Path("dist").iterdir()) + session.run("python", "-m", "build", env=ENV) + (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") - session.run("twine", "check", *(str(f) for f in files)) + # Twine only supports metadata 2.1, trampoline produces metadata 2.2 + if backend != "trampolim": + session.run("twine", "check", str(sdist), str(wheel)) - for f in files: - dist = DIR / "dist" - dist.mkdir(exist_ok=True) - shutil.move(str(f), str(dist)) + dist = DIR / "dist" + dist.mkdir(exist_ok=True) + sdist.rename(dist / sdist.stem) + wheel.rename(dist / wheel.stem) diff --git a/{{cookiecutter.project_name}}/.github/workflows/ci-trampolim.yml b/{{cookiecutter.project_name}}/.github/workflows/ci-trampolim.yml new file mode 100644 index 00000000..045b0430 --- /dev/null +++ b/{{cookiecutter.project_name}}/.github/workflows/ci-trampolim.yml @@ -0,0 +1,80 @@ + +name: CI + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + - main + - develop + release: + types: + - published + +jobs: + pre-commit: + name: Format + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v2 + - uses: pre-commit/action@v2.0.3 + with: + extra_args: --hook-stage manual --all-files + + checks: + name: Check Python ${{ matrix.python-version }} on ${{ matrix.runs-on }} + runs-on: ${{ matrix.runs-on }} + needs: [pre-commit] + strategy: + fail-fast: false + matrix: + python-version: [3.6, 3.9] + runs-on: [ubuntu-latest, macos-latest, windows-latest] + + include: + - python-version: pypy-3.7 + runs-on: ubuntu-latest + + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install package + run: python -m pip install .[test] + + - name: Test package + run: python -m pytest -ra + + + dist: + name: Distribution build + runs-on: ubuntu-latest + needs: [pre-commit] + + steps: + - uses: actions/checkout@v1 + + - name: Build sdist and wheel + run: pipx run build + + - uses: actions/upload-artifact@v2 + with: + path: dist + + - uses: pypa/gh-action-pypi-publish@v1.4.2 + if: github.event_name == 'release' && github.event.action == 'published' + with: + user: __token__ + # Remember to generate this and set it in "GitHub Secrets" + password: ${{ secrets.pypi_password }} + # Remove this line + repository_url: https://test.pypi.org/legacy/ + # Check not supported currently by twine + trampolim + verify_metadata: false diff --git a/{{cookiecutter.project_name}}/.github/workflows/ci.yml b/{{cookiecutter.project_name}}/.github/workflows/ci.yml index c1f8ccf1..972784eb 100644 --- a/{{cookiecutter.project_name}}/.github/workflows/ci.yml +++ b/{{cookiecutter.project_name}}/.github/workflows/ci.yml @@ -67,6 +67,9 @@ jobs: with: path: dist + - name: Check products + run: pip run twine check dist/* + - uses: pypa/gh-action-pypi-publish@v1.4.2 if: github.event_name == 'release' && github.event.action == 'published' with: diff --git a/{{cookiecutter.project_name}}/.pre-commit-config.yaml b/{{cookiecutter.project_name}}/.pre-commit-config.yaml index a5516403..2c25f947 100644 --- a/{{cookiecutter.project_name}}/.pre-commit-config.yaml +++ b/{{cookiecutter.project_name}}/.pre-commit-config.yaml @@ -49,7 +49,11 @@ repos: rev: v0.901 hooks: - id: mypy + {%- if cookiecutter.project_type == "trampolim" %} + files: {{ cookiecutter.project_name }} + {%- else %} files: src + {%- endif %} {%- if cookiecutter.project_type == "setuptools" or cookiecutter.project_type == "pybind11" %} diff --git a/{{cookiecutter.project_name}}/pyproject-flit621,trampolim.toml b/{{cookiecutter.project_name}}/pyproject-flit621,trampolim.toml new file mode 100644 index 00000000..bcade722 --- /dev/null +++ b/{{cookiecutter.project_name}}/pyproject-flit621,trampolim.toml @@ -0,0 +1,87 @@ +[build-system] +{%- if cookiecutter.project_type == "trampolim" %} +requires = ['trampolim ~=0.0.3'] +build-backend = 'trampolim' +{%- else %} +requires = ['flit_core ~=3.2'] +build-backend = 'flit_core.buildapi' +{%- endif %} + +[project] +name = "{{ cookiecutter.project_name.replace("-", "_") }}" +authors = [ + { name = "{{ cookiecutter.full_name }}", email = "{{ cookiecutter.email }}" }, +] +maintainers = [ + { name = "{{ cookiecutter.maintainer }}", email = "{{ cookiecutter.maintainer_email }}" }, +] +license = { file = "LICENSE" } + +version = "0.1.0" +description = "{{ cookiecutter.project_short_description }}" +readme = "README.md" + +requires-python = ">=3.6" + +classifiers = [ + "License :: OSI Approved :: BSD License", + "Topic :: Scientific/Engineering", + "Intended Audience :: Science/Research", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Development Status :: 1 - Planning", +] + +dependencies = [ + "numpy >=1.13.3", + "typing; python_version<'3.5'", +] + +[project.optional-dependencies] +test = [ + "pytest >=6", +] +dev = [ + "pytest >=6", +] +docs = [ + "Sphinx >=3.0.0", + "myst_parser>=0.13", + "sphinx-book-theme>=0.0.33", + "sphinx_copybutton", +] + +[project.urls] +homepage = "{{ cookiecutter.url }}" + + +[tool.pytest.ini_options] +addopts = "-ra -Wd" +testpaths = ["tests"] + + +[tool.mypy] +files = "src" +python_version = "3.6" +warn_unused_configs = true + +disallow_any_generics = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_defs = true +disallow_incomplete_defs = true +check_untyped_defs = true +disallow_untyped_decorators = true +no_implicit_optional = true +warn_redundant_casts = true +warn_unused_ignores = true +warn_return_any = true +no_implicit_reexport = true +strict_equality = true