From 71824bd6ee2de766e9f5f0610f05969ecde3214a Mon Sep 17 00:00:00 2001 From: Adam Bolte Date: Wed, 4 Dec 2024 14:04:41 +1100 Subject: [PATCH 1/5] Migrate .coveragerc contents to pyproject.toml Also replaces the `exclude_lines` directive with `exclude_also`. --- {{cookiecutter.package_name}}/.coveragerc | 25 -------------- {{cookiecutter.package_name}}/pyproject.toml | 36 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 25 deletions(-) delete mode 100644 {{cookiecutter.package_name}}/.coveragerc diff --git a/{{cookiecutter.package_name}}/.coveragerc b/{{cookiecutter.package_name}}/.coveragerc deleted file mode 100644 index a366412..0000000 --- a/{{cookiecutter.package_name}}/.coveragerc +++ /dev/null @@ -1,25 +0,0 @@ -[run] -branch = True -source = - {{cookiecutter.package_name}} - -[paths] -source = - src/{{cookiecutter.package_name}} - **/site-packages/{{cookiecutter.package_name}} - -[report] -exclude_lines = - pragma: no cover - def __repr__ - if self.debug - raise AssertionError - raise NotImplentedError - if 0: - if __name__ == .__main__.: - -ignore_errors = True - -[html] -title = {{cookiecutter.package_name}} Coverage Test Report -directory = docs/source/_static/coverage diff --git a/{{cookiecutter.package_name}}/pyproject.toml b/{{cookiecutter.package_name}}/pyproject.toml index 0e8ae61..56293da 100644 --- a/{{cookiecutter.package_name}}/pyproject.toml +++ b/{{cookiecutter.package_name}}/pyproject.toml @@ -69,6 +69,42 @@ path = "{{cookiecutter.package_name}}/__init__.py" [tool.black] line-length = 79 +[tool.coverage.run] +branch = true +source = [ + "{{cookiecutter.package_name}}", +] + +[tool.coverage.paths] +source = [ + "src/{{cookiecutter.package_name}}", + "**/site-packages/{{cookiecutter.package_name}}", +] + +[tool.coverage.report] +# Regexes for lines to exclude from consideration +exclude_also = [ + # Don't complain about missing debug-only code: + "def __repr__", + "if self\\.debug", + + # Don't complain if tests don't hit defensive assertion code: + "raise AssertionError", + "raise NotImplementedError", + + # Don't complain if non-runnable code isn't run: + "if 0:", + "if __name__ == .__main__.:", + + # Don't complain about abstract methods, they aren't run: + "@(abc\\.)?abstractmethod", +] +ignore_errors = true + +[tool.coverage.html] +title = "{{cookiecutter.package_name}} Coverage Test Report" +directory = "docs/source/_static/coverage" + [tool.isort] # https://github.com/PyCQA/isort/wiki/isort-Settings # https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html From c98a2235ec862f209044fcdf2338d5210a5540ea Mon Sep 17 00:00:00 2001 From: Adam Bolte Date: Wed, 4 Dec 2024 17:20:58 +1100 Subject: [PATCH 2/5] Migrate .pylintrc contents to pyproject.toml --- {{cookiecutter.package_name}}/.pylintrc | 264 ------------------- {{cookiecutter.package_name}}/pyproject.toml | 231 ++++++++++++++++ 2 files changed, 231 insertions(+), 264 deletions(-) delete mode 100644 {{cookiecutter.package_name}}/.pylintrc diff --git a/{{cookiecutter.package_name}}/.pylintrc b/{{cookiecutter.package_name}}/.pylintrc deleted file mode 100644 index 16352e7..0000000 --- a/{{cookiecutter.package_name}}/.pylintrc +++ /dev/null @@ -1,264 +0,0 @@ -[MASTER] - -# Use multiple processes to speed up Pylint. -jobs=4 - -# Pickle collected data for later comparisons. -persistent=yes - -# When enabled, pylint would attempt to guess common misconfiguration and emit -# user-friendly hints instead of false-positive error messages. -suggestion-mode=yes - - -[MESSAGES CONTROL] - -disable=raw-checker-failed, - bad-inline-option, - locally-disabled, - file-ignored, - suppressed-message, - useless-suppression, - deprecated-pragma, - use-symbolic-message-instead, - invalid-name, - too-many-instance-attributes, - too-many-arguments, - unused-argument, - wrong-import-order, - missing-module-docstring, - missing-class-docstring, - missing-function-docstring, - too-many-branches, - too-many-nested-blocks, - no-else-break, - broad-except, - pointless-string-statement - -enable=useless-object-inheritance, - unused-variable, - unused-import, - not-callable, - arguments-differ, - redefined-outer-name - -[REPORTS] - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio). You can also give a reporter class, e.g. -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages. -reports=no - -# Activate the evaluation score. -score=yes - - -[LOGGING] - -# Format style used to check logging format string. `old` means using % -# formatting, `new` is for `{}` formatting,and `fstr` is for f-strings. -logging-format-style=old - -# Logging modules to check that the string format arguments are in logging -# function parameter format. -logging-modules=logging - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid defining new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_, - _cb - -# A regular expression matching the name of dummy variables (i.e. expected to -# not be used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore. -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=160 - -# Maximum number of lines in a module. -max-module-lines=1000 - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[BASIC] - -# Naming style matching correct argument names. -argument-naming-style=snake_case - -# Regular expression matching correct argument names. Overrides argument- -# naming-style. -#argument-rgx= - -# Naming style matching correct attribute names. -attr-naming-style=snake_case - -# Regular expression matching correct attribute names. Overrides attr-naming- -# style. -#attr-rgx= - -# Bad variable names which should always be refused, separated by a comma. -bad-names=foo, - bar, - baz, - toto, - tutu, - tata - -# Naming style matching correct class attribute names. -class-attribute-naming-style=any - -# Naming style matching correct class names. -class-naming-style=PascalCase - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Naming style matching correct function names. -function-naming-style=snake_case - -# Good variable names which should always be accepted, separated by a comma. -good-names=i, - j, - k, - ex, - Run, - _ - -# Include a hint for the correct naming format with invalid-name. -include-naming-hint=no - -# Naming style matching correct inline iteration names. -inlinevar-naming-style=any - -# Naming style matching correct method names. -method-naming-style=snake_case - -# Naming style matching correct module names. -module-naming-style=snake_case - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -# These decorators are taken in consideration only for invalid-name. -property-classes=abc.abstractproperty - -# Naming style matching correct variable names. -variable-naming-style=snake_case - - -[STRING] - -# This flag controls whether the implicit-str-concat-in-sequence should -# generate a warning on implicit string concatenation in sequences defined over -# several lines. -check-str-concat-over-line-jumps=no - - -[IMPORTS] - -# List of modules that can be imported at any level, not just the top level -# one. -allow-any-import-level= - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Deprecated modules which should not be used, separated by a comma. -deprecated-modules=optparse,tkinter.tix - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled). -ext-import-graph= - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled). -import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled). -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - -# Couples of modules and preferred modules, separated by a comma. -preferred-modules= - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__, - __new__, - setUp, - __post_init__ - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict, - _fields, - _replace, - _source, - _make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=cls diff --git a/{{cookiecutter.package_name}}/pyproject.toml b/{{cookiecutter.package_name}}/pyproject.toml index 56293da..0d89856 100644 --- a/{{cookiecutter.package_name}}/pyproject.toml +++ b/{{cookiecutter.package_name}}/pyproject.toml @@ -122,3 +122,234 @@ follow_imports = "skip" no_implicit_optional = true show_column_numbers = true warn_no_return = true + +[tool.pylint.REPORTS] +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +output-format = "text" + +# Tells whether to display a full report or only the messages. +reports = "no" + +# Activate the evaluation score. +score = "yes" + +[tool.pylint.LOGGING] +# Format style used to check logging format string. `old` means using % +# formatting, `new` is for `{}` formatting,and `fstr` is for f-strings. +logging-format-style = "old" + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules = "logging" + +[tool.pylint.VARIABLES] +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins = [] + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables = "yes" + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks = [ + "cb_", + "_cb", +] + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx = "_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_" + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore. +ignored-argument-names = "_.*|^ignored_|^unused_" + +# Tells whether we should check for unused import in __init__ files. +init-import = "no" + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules = [ + "six.moves", + "past.builtins", + "future.builtins", + "builtins", + "io", +] + +[tool.pylint.FORMAT] +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format = "" + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines = '^\s*(# )??$' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren = 4 + +# String used as indentation unit. This is usually " " (4 spaces) or +# "\t" (1 tab). +indent-string = " " + +# Maximum number of characters on a single line. +max-line-length = 160 + +# Maximum number of lines in a module. +max-module-lines = 1000 + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt = "no" + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt = "no" + +[tool.pylint.BASIC] +# Naming style matching correct argument names. +argument-naming-style = "snake_case" + +# Regular expression matching correct argument names. Overrides +# argument-naming-style. +#argument-rgx = + +# Naming style matching correct attribute names. +attr-naming-style = "snake_case" + +# Regular expression matching correct attribute names. Overrides +# attr-naming-style. +#attr-rgx = + +# Bad variable names which should always be refused, separated by a comma. +bad-names = [ + "foo", + "bar", + "baz", + "toto", + "tutu", + "tata", +] + +# Naming style matching correct class attribute names. +class-attribute-naming-style = "any" + +# Naming style matching correct class names. +class-naming-style = "PascalCase" + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length = -1 + +# Naming style matching correct function names. +function-naming-style = "snake_case" + +# Good variable names which should always be accepted, separated by a comma. +good-names = [ + "i", + "j", + "k", + "ex", + "Run", + "_", +] + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint = "no" + +# Naming style matching correct inline iteration names. +inlinevar-naming-style = "any" + +# Naming style matching correct method names. +method-naming-style = "snake_case" + +# Naming style matching correct module names. +module-naming-style = "snake_case" + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes = [ + "abc.abstractproperty", +] + +# Naming style matching correct variable names. +variable-naming-style = "snake_case" + +[tool.pylint.STRING] +# This flag controls whether the implicit-str-concat-in-sequence should +# generate a warning on implicit string concatenation in sequences defined over +# several lines. +check-str-concat-over-line-jumps = "no" + +[tool.pylint.IMPORTS] +# List of modules that can be imported at any level, not just the top level +# one. +allow-any-import-level = [] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all = "no" + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks = "no" + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules = [ + "optparse", + "tkinter.tix", +] + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled). +ext-import-graph = "" + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled). +import-graph = "" + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled). +int-import-graph = "" + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library = [] + +# Force import order to recognize a module as part of a third party library. +known-third-party = "enchant" + +# Couples of modules and preferred modules, separated by a comma. +preferred-modules = [] + +[tool.pylint.CLASSES] +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods = [ + "__init__", + "__new__", + "setUp", + "__post_init__", +] + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected = [ + "_asdict", + "_fields", + "_replace", + "_source", + "_make", +] + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg = [ + "cls", +] + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg = [ + "cls", +] From 58d3a96a75e5e7320c5bcf91f5388948e9f56f99 Mon Sep 17 00:00:00 2001 From: Adam Bolte Date: Wed, 4 Dec 2024 19:05:40 +1100 Subject: [PATCH 3/5] Update template details in README.rst --- README.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 28574a6..90adba9 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ Cookiecutter Python Project ########################### This project contains a Cookiecutter template that helps you create new Python -3.7+ package projects by automatically generating most of the boiler plate +3.11+ package projects by automatically generating most of the boiler plate content for you. Cookiecutter is a command-line utility that creates projects from templates. @@ -21,14 +21,15 @@ the following items: - A Makefile that automates many common developer tasks, such as: - Creating a Virtual environment - - Checking code style. - - Performing static analysis checks. - - Running unit tests. - - Checking code coverage. - - Generating documentation. + - Checking and formatting code style with ``black`` and ``isort``. + - Performing static analysis checks with ``pylint``. + - Performing type checking with ``mypy``. + - Running unit tests with Python's ``unittest``. + - Checking code coverage with ``coverage``. + - Generating documentation with ``Sphinx``. - Generating, testing and uploading a project release to PyPI. -- A ``setup.py`` file used to generate project install and releases. +- A ``pyproject.toml`` file used to manage nearly all project configuration. - A ``CONTRIBUTING.rst`` guide. On Github this file is shown when sending a pull request or an issue. This file also gets included in the generated developer documentation. @@ -38,9 +39,8 @@ the following items: - An ``examples`` directory with a minimal quickstart example script. This script imports the package and prints the package version. It is also called by the unit test suite to ensure it always works. -- A ``tests`` directory containing a basic unit test (using unittest) and - a shell script that can be used to test a wheel distribution of the - package. +- A ``tests`` directory containing a basic unit test and a shell + script that can be used to test a wheel distribution of the package. - A Github Actions continuous integration configuration. - A ``docs`` directory with pre-configured Sphinx documentation containing: From 84681f2e875310cb3da4f98fb796008b2a201715 Mon Sep 17 00:00:00 2001 From: Adam Bolte Date: Wed, 4 Dec 2024 19:13:15 +1100 Subject: [PATCH 4/5] Remove pylint reference to .pylintrc --- {{cookiecutter.package_name}}/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/{{cookiecutter.package_name}}/Makefile b/{{cookiecutter.package_name}}/Makefile index c44afa1..4cf7767 100644 --- a/{{cookiecutter.package_name}}/Makefile +++ b/{{cookiecutter.package_name}}/Makefile @@ -120,8 +120,7 @@ check-types: # help: check-lint - run static analysis checks .PHONY: check-lint check-lint: - @pylint --rcfile=.pylintrc \ - {{cookiecutter.package_name}} \ + @pylint {{cookiecutter.package_name}} \ examples \ tests From 316cfba254bce8c29311ac0bda88509836b6547c Mon Sep 17 00:00:00 2001 From: Adam Bolte Date: Wed, 4 Dec 2024 19:30:18 +1100 Subject: [PATCH 5/5] Minor pylint fixes to examples and tests --- {{cookiecutter.package_name}}/examples/quickstart.py | 6 ++++-- {{cookiecutter.package_name}}/tests/test_examples.py | 2 +- {{cookiecutter.package_name}}/tests/test_version.py | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/{{cookiecutter.package_name}}/examples/quickstart.py b/{{cookiecutter.package_name}}/examples/quickstart.py index 77349c7..5e045c4 100644 --- a/{{cookiecutter.package_name}}/examples/quickstart.py +++ b/{{cookiecutter.package_name}}/examples/quickstart.py @@ -1,4 +1,5 @@ -""" +"""Quickstart example + This example script imports the {{cookiecutter.package_name}} package and prints out the version. """ @@ -6,7 +7,8 @@ import {{cookiecutter.package_name}} -def main(): +def main() -> None: + """Begin execution""" print(f"{{cookiecutter.package_name}} version: {% raw -%} { {%- endraw %}{{cookiecutter.package_name}}.__version__{% raw -%} diff --git a/{{cookiecutter.package_name}}/tests/test_examples.py b/{{cookiecutter.package_name}}/tests/test_examples.py index c66b411..6ae00b6 100644 --- a/{{cookiecutter.package_name}}/tests/test_examples.py +++ b/{{cookiecutter.package_name}}/tests/test_examples.py @@ -25,7 +25,7 @@ class ExamplesTestCase(unittest.TestCase): in a subprocess. """ - def run_in_venv(self, filepath, timeout=5.0, **kwargs): + def run_in_venv(self, filepath: str, timeout = 5.0, **kwargs) -> bool: """Run a Python script in a virtual env in a subprocess. filepath references must be relative to the repo root directory. diff --git a/{{cookiecutter.package_name}}/tests/test_version.py b/{{cookiecutter.package_name}}/tests/test_version.py index 02612f9..d6b7c9f 100644 --- a/{{cookiecutter.package_name}}/tests/test_version.py +++ b/{{cookiecutter.package_name}}/tests/test_version.py @@ -1,3 +1,5 @@ +"""Version unit tests""" + import unittest import {{cookiecutter.package_name}} @@ -6,7 +8,7 @@ class VersionTestCase(unittest.TestCase): """Version tests""" - def test_version(self): + def test_version(self) -> None: """check {{cookiecutter.package_name}} exposes a version attribute""" self.assertTrue(hasattr({{cookiecutter.package_name}}, "__version__")) self.assertIsInstance({{cookiecutter.package_name}}.__version__, str)