diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 399991af..fc167a48 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,7 +27,7 @@ repos: hooks: - id: isort name: Sort import statements - args: [--settings-path, pyproject.toml] + args: [--settings-path, develop.toml] stages: [pre-commit] # Add Black code formatters. @@ -36,7 +36,7 @@ repos: hooks: - id: black name: Format code - args: [--config, pyproject.toml] + args: [--config, develop.toml] - repo: https://github.com/asottile/blacken-docs rev: 1.19.1 hooks: @@ -67,7 +67,7 @@ repos: args: [--config, .flake8] # Run Pylint from the local repo to make sure venv packages -# specified in pyproject.toml are available. +# specified in develop.toml are available. - repo: local hooks: - id: pylint @@ -76,7 +76,7 @@ repos: language: python files: ^src/package/|^tests/ types: [text, python] - args: [--rcfile, pyproject.toml] + args: [--rcfile, develop.toml] # Type-check all Python code. - repo: local @@ -87,7 +87,7 @@ repos: language: python files: ^src/package/|^tests/ types: [text, python] - args: [--config-file, pyproject.toml] + args: [--config-file, develop.toml] # Check for potential security issues. - repo: https://github.com/PyCQA/bandit @@ -95,7 +95,7 @@ repos: hooks: - id: bandit name: Check for security issues - args: [--configfile, pyproject.toml] + args: [--configfile, develop.toml] files: ^src/package/|^tests/ types: [text, python] additional_dependencies: ['bandit[toml]'] @@ -165,7 +165,7 @@ repos: hooks: - id: pytest name: Run unit tests - entry: pytest -c pyproject.toml --cov-config pyproject.toml src/package/ tests/ docs/ + entry: pytest -c develop.toml --cov-config develop.toml src/package/ tests/ docs/ language: python verbose: true always_run: true diff --git a/Makefile b/Makefile index 061534ff..cdddd51a 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,7 @@ upgrade: .venv/upgraded-on .venv/upgraded-on: pyproject.toml python -m pip install --upgrade pip setuptools python -m pip install --upgrade wheel - python -m pip install --upgrade --upgrade-strategy eager --editable .[actions,dev,docs,hooks,test] + python -m pip install --upgrade --upgrade-strategy eager --editable . --requirement develop-requirements.txt $(MAKE) upgrade-quiet force-upgrade: rm -f .venv/upgraded-on diff --git a/develop-requirements.txt b/develop-requirements.txt new file mode 100644 index 00000000..cfac6b19 --- /dev/null +++ b/develop-requirements.txt @@ -0,0 +1,34 @@ + +# Manage git hooks. +pre-commit >=4.0.0,<4.3.0 + +# Manage conventional commits. +commitizen ==4.5.0 + +# Packaging and distribution. +flit >=3.2.0,<4.0.0 +twine >=6.0.0,<6.1.0 + +# Tools for development and to check Python code. +mypy >=1.0.0,<1.15 +pylint >=3.0.0,<3.4.0 +perflint >=0.8.0,<1.0.0 + +# Support for CI and package integrity. +cyclonedx-bom >=4.0.0,<5.0.0 +pip-audit >=2.4.4,<3.0.0 + +# Documentation. +sphinx >=5.1.1,<9.0.0 +sphinx-markdown-builder >=0.6.4,<1.0.0 + +# All things testing. +# Note that the `custom_exit_code` and `env` plugins may currently be unmaintained. +faker ==37.1.0 +hypothesis >=6.21.0,<6.130.9 +pytest >=7.2.0,<9.0.0 +pytest-cases ==3.8.6 +pytest-cov ==6.1.0 +pytest-custom_exit_code ==0.3.0 +pytest-doctestplus ==1.3.0 +pytest-env ==1.1.5 diff --git a/develop.toml b/develop.toml new file mode 100644 index 00000000..fd47fe7f --- /dev/null +++ b/develop.toml @@ -0,0 +1,177 @@ + +# https://bandit.readthedocs.io/en/latest/config.html +# Skip test B101 because of issue https://github.com/PyCQA/bandit/issues/457 +[tool.bandit] +tests = [] +skips = ["B101"] + + +# https://github.com/psf/black#configuration +[tool.black] +line-length = 120 + + +# https://github.com/commitizen-tools/commitizen +# https://commitizen-tools.github.io/commitizen/bump/ +[tool.commitizen] +bump_message = """bump: release $current_version → $new_version + +Automatically generated by Commitizen. +""" +tag_format = "v$major.$minor.$patch$prerelease" +update_changelog_on_bump = true +version_files = [ + "src/package/__init__.py:__version__", +] +major_version_zero = false +version = "2.16.0" + + +# https://github.com/pytest-dev/pytest-cov +# https://github.com/nedbat/coveragepy +[tool.coverage.report] +fail_under = 100 +show_missing = true + +[tool.coverage.run] +branch = true +omit = [ + "src/package/__main__.py", +] + + +# https://pycqa.github.io/isort/ +[tool.isort] +profile = "black" +multi_line_output = 3 +line_length = 120 +skip_gitignore = true + + +# https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml +[tool.mypy] +# mypy_path = +# exclude = +show_error_codes = true +show_column_numbers = true +pretty = true +show_traceback = true +check_untyped_defs = true +incremental = false +strict = true +warn_return_any = true +warn_redundant_casts = true +warn_unreachable = true +warn_unused_configs = true +warn_unused_ignores = true +disallow_any_explicit = true +disallow_untyped_calls = true +disallow_untyped_defs = true +disallow_incomplete_defs = true +disallow_untyped_decorators = true +# disable_error_code = +# allow_redefinition = + +[[tool.mypy.overrides]] +module = [ + "pytest.*", +] +ignore_missing_imports = true + + +# https://pylint.pycqa.org/en/latest/user_guide/configuration/index.html +[tool.pylint.main] +fail-under = 10.0 +suggestion-mode = true +load-plugins = [ + "perflint", # A Linter for performance anti-patterns. + "pylint.extensions.bad_builtin", + "pylint.extensions.broad_try_clause", + "pylint.extensions.check_elif", + "pylint.extensions.code_style", + "pylint.extensions.comparison_placement", + "pylint.extensions.confusing_elif", + "pylint.extensions.consider_refactoring_into_while_condition", + "pylint.extensions.consider_ternary_expression", + "pylint.extensions.dict_init_mutate", + # "pylint.extensions.docparams", + # "pylint.extensions.docstyle", + "pylint.extensions.dunder", + "pylint.extensions.empty_comment", + "pylint.extensions.for_any_all", + "pylint.extensions.magic_value", + # "pylint.extensions.mccabe", + "pylint.extensions.no_self_use", + "pylint.extensions.overlapping_exceptions", + "pylint.extensions.private_import", + "pylint.extensions.redefined_loop_name", + "pylint.extensions.redefined_variable_type", + "pylint.extensions.set_membership", + "pylint.extensions.typing", + "pylint.extensions.while_used", +] +disable = [ + "fixme", + "line-too-long", # Replaced by Flake8 Bugbear B950 check. + "too-few-public-methods", + "too-many-ancestors", + "too-many-arguments", + "too-many-boolean-expressions", + "too-many-branches", + "too-many-instance-attributes", + "too-many-lines", + "too-many-locals", + "too-many-nested-blocks", + "too-many-positional-arguments", + "too-many-public-methods", + "too-many-return-statements", + "too-many-statements", + "too-many-try-statements", +] + +[tool.pylint.MISCELLANEOUS] +notes = [ + "FIXME", + "TODO", + "BUGBUG", +] + +[tool.pylint.FORMAT] +max-line-length = 120 + + +# https://docs.pytest.org/en/latest/reference/customize.html#configuration-file-formats +# https://docs.pytest.org/en/latest/reference/reference.html#configuration-options +# https://docs.pytest.org/en/latest/reference/reference.html#command-line-flags +# +# To integrate Hypothesis into pytest and coverage, we use its native plugin: +# https://hypothesis.readthedocs.io/en/latest/details.html#the-hypothesis-pytest-plugin +# +# To discover tests in documentation, we use doctest and the doctest-plus plugin which +# adds multiple useful options to control tests in documentation. More details at: +# https://docs.python.org/3/library/doctest.html +# https://github.com/scientific-python/pytest-doctestplus +# +# To avoid failing pytest when no tests were dicovered, we need an extra plugin: +# https://docs.pytest.org/en/latest/reference/exit-codes.html +# https://github.com/yashtodi94/pytest-custom_exit_code +[tool.pytest.ini_options] +minversion = "7.0" +addopts = """-vv -ra --tb native --durations 0 \ + --hypothesis-show-statistics --hypothesis-explain --hypothesis-verbosity verbose \ + --doctest-modules --doctest-continue-on-failure --doctest-glob '*.rst' --doctest-plus \ + --suppress-no-test-exit-code \ + --cov package \ +""" # Consider adding --pdb +# https://docs.python.org/3/library/doctest.html#option-flags +doctest_optionflags = "IGNORE_EXCEPTION_DETAIL" +env = [ + "PYTHONDEVMODE=1", # https://docs.python.org/3/library/devmode.html +] +filterwarnings = [ + "error", + "always::DeprecationWarning", + # https://docs.pytest.org/en/latest/how-to/failures.html#warning-about-unraisable-exceptions-and-unhandled-thread-exceptions + "error::pytest.PytestUnraisableExceptionWarning", + "error::pytest.PytestUnhandledThreadExceptionWarning", +] diff --git a/pyproject.toml b/pyproject.toml index e88532f9..d44e4a07 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,4 @@ + # https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html # https://flit.pypa.io/en/latest/pyproject_toml.html [build-system] @@ -37,39 +38,6 @@ something = "package.__main__:main" [project.entry-points] [project.optional-dependencies] -# The 'actions' requirements match exactly the packages installed by the workflows. -# We keep them listed here to ensure the infrastructure BOM is consistent with what's -# installed. Make sure to keep the requirements in sync with the workflows! -actions = [ - "commitizen ==4.5.0", - "twine ==6.1.0", -] -dev = [ - "flit >=3.2.0,<4.0.0", - "mypy >=1.0.0,<1.15", - "pip-audit >=2.4.4,<3.0.0", - "pylint >=3.0.0,<3.4.0", - "perflint >=0.8.0,<1.0.0", - "cyclonedx-bom >=4.0.0,<5.0.0", -] -docs = [ - "sphinx >=5.1.1,<9.0.0", - "sphinx-markdown-builder >=0.6.4,<1.0.0", -] -hooks = [ - "pre-commit >=3.0.0,<4.1.0", -] -# Note that the `custom_exit_code` and `env` plugins may currently be unmaintained. -test = [ - "faker ==37.1.0", - "hypothesis >=6.21.0,<6.130.9", - "pytest >=7.2.0,<9.0.0", - "pytest-cases ==3.8.6", - "pytest-custom_exit_code ==0.3.0", - "pytest-cov ==6.1.0", - "pytest-doctestplus ==1.3.0", - "pytest-env ==1.1.5", -] [project.urls] Homepage = "https://github.com/jenstroeger/python-package-template" @@ -78,47 +46,6 @@ Documentation = "https://github.com/jenstroeger/python-package-template/wiki" Issues = "https://github.com/jenstroeger/python-package-template/issues" -# https://bandit.readthedocs.io/en/latest/config.html -# Skip test B101 because of issue https://github.com/PyCQA/bandit/issues/457 -[tool.bandit] -tests = [] -skips = ["B101"] - - -# https://github.com/psf/black#configuration -[tool.black] -line-length = 120 - - -# https://github.com/commitizen-tools/commitizen -# https://commitizen-tools.github.io/commitizen/bump/ -[tool.commitizen] -bump_message = """bump: release $current_version → $new_version - -Automatically generated by Commitizen. -""" -tag_format = "v$major.$minor.$patch$prerelease" -update_changelog_on_bump = true -version_files = [ - "src/package/__init__.py:__version__", -] -major_version_zero = false -version = "2.16.0" - - -# https://github.com/pytest-dev/pytest-cov -# https://github.com/nedbat/coveragepy -[tool.coverage.report] -fail_under = 100 -show_missing = true - -[tool.coverage.run] -branch = true -omit = [ - "src/package/__main__.py", -] - - # https://flit.pypa.io/en/latest/pyproject_toml.html#sdist-section # See also: https://github.com/pypa/flit/issues/565 [tool.flit.sdist] @@ -131,143 +58,8 @@ exclude = [ ".gitignore", ".pre-commit-config.yaml", "CHANGELOG.md", + "develop-requirements.txt", + "develop.toml", "Makefile", "SECURITY.md", ] - - -# https://pycqa.github.io/isort/ -[tool.isort] -profile = "black" -multi_line_output = 3 -line_length = 120 -skip_gitignore = true - - -# https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml -[tool.mypy] -# mypy_path = -# exclude = -show_error_codes = true -show_column_numbers = true -pretty = true -show_traceback = true -check_untyped_defs = true -incremental = false -strict = true -warn_return_any = true -warn_redundant_casts = true -warn_unreachable = true -warn_unused_configs = true -warn_unused_ignores = true -disallow_any_explicit = true -disallow_untyped_calls = true -disallow_untyped_defs = true -disallow_incomplete_defs = true -disallow_untyped_decorators = true -# disable_error_code = -# allow_redefinition = - -[[tool.mypy.overrides]] -module = [ - "pytest.*", -] -ignore_missing_imports = true - - -# https://pylint.pycqa.org/en/latest/user_guide/configuration/index.html -[tool.pylint.main] -fail-under = 10.0 -suggestion-mode = true -load-plugins = [ - "perflint", # A Linter for performance anti-patterns. - "pylint.extensions.bad_builtin", - "pylint.extensions.broad_try_clause", - "pylint.extensions.check_elif", - "pylint.extensions.code_style", - "pylint.extensions.comparison_placement", - "pylint.extensions.confusing_elif", - "pylint.extensions.consider_refactoring_into_while_condition", - "pylint.extensions.consider_ternary_expression", - "pylint.extensions.dict_init_mutate", - # "pylint.extensions.docparams", - # "pylint.extensions.docstyle", - "pylint.extensions.dunder", - "pylint.extensions.empty_comment", - "pylint.extensions.for_any_all", - "pylint.extensions.magic_value", - # "pylint.extensions.mccabe", - "pylint.extensions.no_self_use", - "pylint.extensions.overlapping_exceptions", - "pylint.extensions.private_import", - "pylint.extensions.redefined_loop_name", - "pylint.extensions.redefined_variable_type", - "pylint.extensions.set_membership", - "pylint.extensions.typing", - "pylint.extensions.while_used", -] -disable = [ - "fixme", - "line-too-long", # Replaced by Flake8 Bugbear B950 check. - "too-few-public-methods", - "too-many-ancestors", - "too-many-arguments", - "too-many-boolean-expressions", - "too-many-branches", - "too-many-instance-attributes", - "too-many-lines", - "too-many-locals", - "too-many-nested-blocks", - "too-many-positional-arguments", - "too-many-public-methods", - "too-many-return-statements", - "too-many-statements", - "too-many-try-statements", -] - -[tool.pylint.MISCELLANEOUS] -notes = [ - "FIXME", - "TODO", - "BUGBUG", -] - -[tool.pylint.FORMAT] -max-line-length = 120 - - -# https://docs.pytest.org/en/latest/reference/customize.html#configuration-file-formats -# https://docs.pytest.org/en/latest/reference/reference.html#configuration-options -# https://docs.pytest.org/en/latest/reference/reference.html#command-line-flags -# -# To integrate Hypothesis into pytest and coverage, we use its native plugin: -# https://hypothesis.readthedocs.io/en/latest/details.html#the-hypothesis-pytest-plugin -# -# To discover tests in documentation, we use doctest and the doctest-plus plugin which -# adds multiple useful options to control tests in documentation. More details at: -# https://docs.python.org/3/library/doctest.html -# https://github.com/scientific-python/pytest-doctestplus -# -# To avoid failing pytest when no tests were dicovered, we need an extra plugin: -# https://docs.pytest.org/en/latest/reference/exit-codes.html -# https://github.com/yashtodi94/pytest-custom_exit_code -[tool.pytest.ini_options] -minversion = "7.0" -addopts = """-vv -ra --tb native --durations 0 \ - --hypothesis-show-statistics --hypothesis-explain --hypothesis-verbosity verbose \ - --doctest-modules --doctest-continue-on-failure --doctest-glob '*.rst' --doctest-plus \ - --suppress-no-test-exit-code \ - --cov package \ -""" # Consider adding --pdb -# https://docs.python.org/3/library/doctest.html#option-flags -doctest_optionflags = "IGNORE_EXCEPTION_DETAIL" -env = [ - "PYTHONDEVMODE=1", # https://docs.python.org/3/library/devmode.html -] -filterwarnings = [ - "error", - "always::DeprecationWarning", - # https://docs.pytest.org/en/latest/how-to/failures.html#warning-about-unraisable-exceptions-and-unhandled-thread-exceptions - "error::pytest.PytestUnraisableExceptionWarning", - "error::pytest.PytestUnhandledThreadExceptionWarning", -]