diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 1324dc6..d03ce28 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -4,16 +4,21 @@ about: Report a problem with Package labels: bug --- + ### Issue + This happened. ### Expected behavior + This should have happened instead. ### Steps to reproduce + If applicable and possible, please provide a [minimal working example](https://stackoverflow.com/help/minimal-reproducible-example). diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f0f2b83..1dd2bfe 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,5 @@ blank_issues_enabled: true contact_links: - - name: Package chat - url: https://example.org - about: Our chat for help and general discussion - - name: Stack Overflow - url: https://stackoverflow.com/questions/tagged/package - about: Forum for asking and answering questions about Package + - name: GitHub discussions + url: https://github.com/felix-hilden/python-package/discussions + about: Q&A and general discussions diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md index 0a3af2a..ddbe027 100644 --- a/.github/ISSUE_TEMPLATE/feature.md +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -4,5 +4,9 @@ about: Request for a new feature labels: enhancement --- + + +(write here) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 72a2595..cb74370 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,11 +1,13 @@ + Related issue: #XXX -- [ ] Tests written +- [ ] Tests written and passed - [ ] Documentation and changelog entry written -- [ ] All `tox` checks passed with an appropriately configured environment +- [ ] All `tox` checks passed diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index bf2a495..8298039 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -8,14 +8,14 @@ on: branches: - master tags-ignore: - - '*' + - "*" pull_request: jobs: matrix: strategy: matrix: - python-version: [3.6, 3.7, 3.9] + python-version: ["3.9", "3.10", "3.11", "3.12"] name: Pytest on ${{matrix.python-version}} runs-on: ubuntu-latest @@ -27,23 +27,23 @@ jobs: python-version: ${{matrix.python-version}} - name: Install package run: | - python -m pip install --upgrade pip - pip install .[tests] + python -m pip install -U pip uv + uv pip install --system . -r requirements/test - name: Run test suite run: pytest full-build: - name: Full 3.8 build + name: Full build runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: "3.12" - name: Install package run: | - python -m pip install --upgrade pip - pip install .[dev] + python -m pip install -U pip uv + uv pip install --system . -r requirements/dev - name: Run tox environments run: tox diff --git a/.gitignore b/.gitignore index a6cd26b..5832fd4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,27 +1,69 @@ # See for more potential targets to ignore: # https://github.com/github/gitignore/blob/master/Python.gitignore -# Python +# Python files +__pycache__/ *.py[cod] -**__pycache__/ -build/ -dist/ -*.egg-info/ +*$py.class +*.so +__pypackages__/ -# Editors -.idea/ -.vim/ +# Distribution / packaging +.pypirc +.Python +/build/ +/develop-eggs/ +/dist/ +/downloads/ +/eggs/ +/.eggs/ +/lib/ +/lib64/ +/parts/ +/sdist/ +/var/ +/wheels/ +/share/python-wheels/ +/.installed.cfg +*.egg-info/ +*.egg +/*.egg-info/ +/MANIFEST -# Tools +# Testing +htmlcov/ +.tox/ +.nox/ .coverage +.coverage.* +.cache +nosetests.xml coverage.xml -docs/build -.tox/ +*.cover +*.py,cover +cover/ +.pytest_cache/ + +# Documentation +/docs/build/ # Environments -.env -.venv -env/ -venv/ -env.bak/ -venv.bak/ +/.env/ +/.venv/ +/env/ +/venv/ +/ENV/ +/env.bak/ +/venv.bak/ + +# Type checkers +.mypy_cache/ +.dmypy.json +dmypy.json +.pyre/ +.pytype/ + +# Editors +.idea/ +.vim/ +.vscode/ diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..03db5cd --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,18 @@ +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + jobs: + post_install: + - pip install -r requirements/docs + - pip install . + +sphinx: + builder: html + configuration: docs/src/conf.py + fail_on_warning: false + +formats: + - htmlzip diff --git a/LICENSE b/LICENSE index fc56bf7..e58397a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019-2021 Felix Hildén +Copyright (c) 2019-2024 Felix Hildén Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MANIFEST.in b/MANIFEST.in index 224428f..aac2410 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,2 @@ -include readme.rst -include package/VERSION +include readme.rst tox.ini +global-exclude *.py[cod] __pycache__ *.so diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index ee23016..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = src -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index c93b5b8..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=src -set BUILDDIR=build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/src/404.rst b/docs/src/404.rst index 7b72b98..6f0020b 100644 --- a/docs/src/404.rst +++ b/docs/src/404.rst @@ -1,6 +1,8 @@ -======= +:orphan: + Package ======= + Oops! The page you are looking for was not found. Maybe you'll find what you're looking for by searching the documentation or returning to the `home page `_. diff --git a/docs/src/conf.py b/docs/src/conf.py index 0c7005b..31aa6ae 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -2,23 +2,23 @@ import sys from pathlib import Path -_root = Path(os.path.realpath(__file__)).parent.parent.parent -sys.path.insert(0, _root) +from package import __version__ -project = 'package' -author = 'Felix Hildén' -copyright = '2019-2021, Felix Hildén' -release = Path(_root, 'package', 'VERSION').read_text().strip() +# Insert package root to path +_src_dir = Path(os.path.realpath(__file__)).parent +_package_root = _src_dir.parent.parent / "src" +sys.path.insert(0, str(_package_root)) +sys.path.insert(0, str(_src_dir)) -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.autosummary', - 'sphinx.ext.napoleon', - 'sphinx_autodoc_typehints', - 'sphinx_rtd_theme', -] +project = "package" +author = "Felix Hildén" +copyright = "2019-2024, Felix Hildén" +version = __version__ +release = version -master_doc = 'index' -exclude_patterns = ['build'] -autosummary_generate = True -html_theme = 'sphinx_rtd_theme' +extensions = ["sphinx.ext.autodoc", "sphinx.ext.napoleon", "sphinx_rtd_theme"] + +html_theme = "sphinx_rtd_theme" +python_use_unqualified_type_names = True +autodoc_default_options = {"members": True, "undoc-members": True} +autodoc_typehints = "description" diff --git a/package/VERSION b/package/VERSION deleted file mode 100644 index 6e8bf73..0000000 --- a/package/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.1.0 diff --git a/package/__init__.py b/package/__init__.py deleted file mode 100644 index bfab277..0000000 --- a/package/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -Package docstring. - -See online documentation at `RTD `_. -""" -import os as _os -from pathlib import Path as _Path - -_version_file = _Path(_os.path.realpath(__file__)).parent / 'VERSION' -__version__ = _version_file.read_text().strip() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..86f0fd7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,52 @@ +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "package" +description = "Python package template." +readme = "readme.rst" +license = {file = "LICENSE"} +dynamic = ["version"] + +requires-python = ">=3.9" +dependencies = [] + +keywords = [] +authors = [{name = "Felix Hildén", email = "felix.hilden@gmail.com"}] +maintainers = [{name = "Felix Hildén", email = "felix.hilden@gmail.com"}] +classifiers = [ + "Development Status :: 4 - Beta", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", +] + +[project.urls] +homepage = "https://github.com/felix-hilden/python-package" +download = "https://github.com/felix-hilden/python-package" +source = "https://github.com/felix-hilden/python-package" +issues = "https://github.com/felix-hilden/python-package/issues" +documentation = "https://github.com/felix-hilden/python-package" + +[tool.setuptools.dynamic] +version = {attr = "package.__version__"} + +[tool.pytest.ini_options] +python_files = "*.py" +testpaths = ["tests"] + +[tool.coverage.run] +source = ["src"] +branch = true +command_line = "-m pytest" + +[tool.coverage.report] +precision = 1 +show_missing = true +skip_covered = true + +[tool.ruff.lint] +ignore = ["D107", "D203", "D212", "D413"] + +[tool.ruff.format] +skip-magic-trailing-comma = true diff --git a/readme.rst b/readme.rst index 78546a6..f370d5f 100644 --- a/readme.rst +++ b/readme.rst @@ -4,25 +4,39 @@ python-package A package template for Python. -Please find the assumed tooling, further considerations and explanations below. -Any unwanted part of the package can simply be removed. To start using this template, familiarise yourself with the files and tooling, -change any references from "package" to your chosen package name -and set up with external providers like Read The Docs. +change any references from "package" to your chosen package name. + +Tooling +------- -Assumed tooling ---------------- -- Hosted on GitHub - Pytest and Coverage for testing -- Tox and linters for static analysis -- Numpy-style ``.rst`` documentation with Sphinx (see ``docs/src/conf.py``) -- CI performed with GitHub Actions -- Documentation hosted on Read The Docs - -Considerations --------------- -- Create a separate readme for PyPI -- Create a contribution guide +- Uv, tox, ruff etc. +- Numpy-style ``.rst`` docs with Sphinx hosted on Read The Docs +- Hosted on GitHub with GH Actions CI + +Setup +----- + +- Change any references to "Package" to your liking +- Create ``.pypirc`` file for publishing the package + +.. code:: ini + + [pypi] + username = __token__ + password = pypi- + +.. code:: bash + + # Bootstrap + pip install uv + uv venv + source .venv/bin/activate # or .venv/Scripts/activate on Windows + + # Setup and verify + uv pip install -e . -r requirements/dev + tox .. |build| image:: https://github.com/felix-hilden/python-package/workflows/CI/badge.svg :target: https://github.com/felix-hilden/python-package/actions diff --git a/readthedocs.yml b/readthedocs.yml deleted file mode 100644 index c94c8b9..0000000 --- a/readthedocs.yml +++ /dev/null @@ -1,17 +0,0 @@ -version: 2 - -sphinx: - builder: html - configuration: docs/src/conf.py - fail_on_warning: false - -formats: all - -python: - version: 3.7 - install: - - method: pip - path: . - extra_requirements: - - docs - system_packages: false diff --git a/requirements/build b/requirements/build new file mode 100644 index 0000000..e47b6e9 --- /dev/null +++ b/requirements/build @@ -0,0 +1,2 @@ +build +twine diff --git a/requirements/dev b/requirements/dev new file mode 100644 index 0000000..a733839 --- /dev/null +++ b/requirements/dev @@ -0,0 +1,7 @@ +-r docs +-r test +-r build + +tox>=4 +doc8>=0.9 +ruff diff --git a/requirements/docs b/requirements/docs new file mode 100644 index 0000000..f6e0729 --- /dev/null +++ b/requirements/docs @@ -0,0 +1,2 @@ +sphinx==7.3.7 +sphinx-rtd-theme==2.0.0 diff --git a/requirements/test b/requirements/test new file mode 100644 index 0000000..141e849 --- /dev/null +++ b/requirements/test @@ -0,0 +1,2 @@ +pytest>=6 +coverage[toml]>=5 diff --git a/setup.py b/setup.py deleted file mode 100644 index 376f124..0000000 --- a/setup.py +++ /dev/null @@ -1,75 +0,0 @@ -import setuptools -import os -from pathlib import Path - -""" -See the following resources: -* https://setuptools.readthedocs.io/en/latest/setuptools.html -* https://docs.python.org/3.7/distutils/setupscript.html -""" - -root = Path(os.path.realpath(__file__)).parent -version_file = root / 'package' / 'VERSION' -readme_file = root / 'readme.rst' - -pypi_url = 'https://pypi.org/project/python-package' -github_url = 'https://github.com/felix-hilden/python-package' -documentation_url = 'https://nonexistentproject.rtfd.org' - -extras_require = { - 'docs': [ - 'sphinx', - 'sphinx-rtd-theme', - 'sphinx-autodoc-typehints' - ], - 'tests': [ - 'coverage', - 'pytest', - ], - 'checks': [ - 'tox', - 'doc8', - 'flake8', - 'flake8-bugbear', - 'pydocstyle', - 'pygments', - ] -} -extras_require['dev'] = ( - extras_require['docs'] + extras_require['tests'] + extras_require['checks'] -) - -setuptools.setup( - name='python-package', - version=version_file.read_text().strip(), - description='Python package template', - long_description=readme_file.read_text(), - long_description_content_type='text/x-rst', - - url=documentation_url, - download_url=pypi_url, - project_urls={ - 'Source': github_url, - 'Issues': github_url + '/issues', - 'Documentation': documentation_url, - }, - - author='Felix Hildén', - author_email='felix.hilden@gmail.com', - maintainer='Felix Hildén', - maintainer_email='felix.hilden@gmail.com', - - license='MIT', - keywords='python package template', - packages=setuptools.find_packages(exclude=('tests', 'tests.*',)), - include_package_data=True, - package_data={ - 'package': ['VERSION'] - }, - - python_requires='>=3.6', - install_requires=[], - extras_require=extras_require, - - classifiers=[], -) diff --git a/src/package/__init__.py b/src/package/__init__.py new file mode 100644 index 0000000..d6de38b --- /dev/null +++ b/src/package/__init__.py @@ -0,0 +1,7 @@ +""" +Package docstring. + +See online documentation at `RTD `_. +""" + +__version__ = "0.1.0" diff --git a/tests/__init__.py b/tests/__init__.py index 66f860e..c327f0b 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,6 +1,5 @@ import package -class TestPackage: - def test(self): - assert package.__version__ +def test_package(): + assert package.__version__ diff --git a/tox.ini b/tox.ini index ad66245..698803d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,80 +1,81 @@ [tox] -envlist = flake8,doc8,pydocstyle,coverage,docs - -[flake8] -select = C,E,F,W,B,B9 -ignore = E501 - -[pytest] -python_files = *.py -testpaths = tests - -[coverage:run] -source = package -branch = True -command_line = -m pytest - -[coverage:report] -precision = 1 -skip_covered = True +min_version = 4 +envlist = + check + doc8 + docs + build-{lin,mac,win} + coverage +labels = + test = coverage + check = doc8, check + format = format + docs = doc8, docs + build = build-{lin,mac,win} + publish = publish-{lin,mac,win} +no_package = true [doc8] ; Ignore for Windows development -ignore = D002,D004 +ignore = D004 max-line-length = 80 -[pydocstyle] -ignore = D203,D212,D413,D416 - [testenv] -description = Run test suite with pytest -extras = test -commands = pytest {posargs} -whitelist_externals = pytest +description = Run test suite with code coverage +platform = + lin: linux + mac: darwin + win: win32 +allowlist_externals = coverage +commands = coverage run + coverage report -[testenv:test] +[testenv:coverage] ; Inherit everything from testenv -[testenv:docs] -description = Build Sphinx HTML documentation -extras = docs -changedir = docs -whitelist_externals = make -commands = make html +[testenv:check] +description = Check code formatting +allowlist_externals = ruff +commands = ruff check . + +[testenv:format] +description = Format code +allowlist_externals = ruff +commands = ruff format . [testenv:doc8] description = Check documentation .rst files -extras = checks -whitelist_externals = doc8 +allowlist_externals = doc8 commands = doc8 docs/src -[testenv:flake8] -description = Check code style -extras = checks -whitelist_externals = flake8 -commands = flake8 package tests setup.py - -[testenv:pydocstyle] -description = Check documentation string style -extras = checks -whitelist_externals = pydocstyle -commands = pydocstyle package +[testenv:docs] +description = Build Sphinx documentation +allowlist_externals = sphinx-build +change_dir = docs +commands = sphinx-build -M html src build -W -[testenv:lint] -; Duplication needed https://github.com/tox-dev/tox/issues/647 -description = Run all static checks -extras = checks -whitelist_externals = - doc8 - flake8 - pydocstyle +[testenv:build-{lin,mac,win}] +description = Build and check package +deps = -r requirements/build +allowlist_externals = rm, cmd commands = - flake8 package tests setup.py - doc8 docs/src - pydocstyle package + python -m build + twine check --strict dist/* +commands_post = + lin,mac: rm -r dist + win: cmd /c rmdir /s /q dist -[testenv:coverage] -description = Run test suite with code coverage -whitelist_externals = coverage -commands = coverage run - coverage report +[testenv:publish-{lin,mac,win}] +description = Build, check and publish package +deps = -r requirements/build +allowlist_externals = rm, cmd +commands_pre = + lin,mac: rm -rf dist + win: cmd /c if exist dist rmdir /s /q dist +commands = + python -m build + twine check --strict dist/* + twine upload dist/* --config-file .pypirc +commands_post = + lin,mac: rm -r dist + win: cmd /c rmdir /s /q dist