diff --git a/.bandit.yml b/.bandit.yml deleted file mode 100644 index 3215b915..00000000 --- a/.bandit.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -# Configuration file for the Bandit python security scanner -# https://bandit.readthedocs.io/en/latest/config.html -# This config is applied to bandit when scanning the "tests" tree - -# Tests are first included by `tests`, and then excluded by `skips`. -# If `tests` is empty, all tests are considered included. - -tests: -# - B101 -# - B102 - -skips: - - B101 # skip "assert used" check since assertions are required in pytests diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 92ff8268..00000000 --- a/.flake8 +++ /dev/null @@ -1,25 +0,0 @@ -[flake8] -max-line-length = 80 -# Select (turn on) -# * Complexity violations reported by mccabe (C) - -# http://flake8.pycqa.org/en/latest/user/error-codes.html#error-violation-codes -# * Documentation conventions compliance reported by pydocstyle (D) - -# http://www.pydocstyle.org/en/stable/error_codes.html -# * Default errors and warnings reported by pycodestyle (E and W) - -# https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes -# * Default errors reported by pyflakes (F) - -# http://flake8.pycqa.org/en/latest/glossary.html#term-pyflakes -# * Default warnings reported by flake8-bugbear (B) - -# https://github.com/PyCQA/flake8-bugbear#list-of-warnings -# * The B950 flake8-bugbear opinionated warning - -# https://github.com/PyCQA/flake8-bugbear#opinionated-warnings -select = C,D,E,F,W,B,B950 -# Ignore flake8's default warning about maximum line length, which has -# a hard stop at the configured value. Instead we use -# flake8-bugbear's B950, which allows up to 10% overage. -# -# Also ignore flake8's warning about line breaks before binary -# operators. It no longer agrees with PEP8. See, for example, here: -# https://github.com/ambv/black/issues/21. Guido agrees here: -# https://github.com/python/peps/commit/c59c4376ad233a62ca4b3a6060c81368bd21e85b. -ignore = E501,W503 diff --git a/.github/labeler.yml b/.github/labeler.yml index befbdf9b..eeea8f5b 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -18,7 +18,7 @@ dependencies: # Add any dependency files used. - .pre-commit-config.yaml - requirements*.txt - - setup.py + - pyproject.toml docker: - changed-files: - any-glob-to-any-file: @@ -62,12 +62,9 @@ test: - any-glob-to-any-file: # Add any test-related files or paths. - .ansible-lint - - .bandit.yml - - .flake8 - - .isort.cfg - .mdl_config.yaml - .yamllint - - pytest.ini + - pyproject.toml - tests/** typescript: - changed-files: diff --git a/.gitignore b/.gitignore index 242b4aa6..579601b2 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ __pycache__ .pytest_cache .python-version *.egg-info +build dist diff --git a/.isort.cfg b/.isort.cfg deleted file mode 100644 index 46d45f3f..00000000 --- a/.isort.cfg +++ /dev/null @@ -1,10 +0,0 @@ -[settings] -combine_star=true -force_sort_within_sections=true - -import_heading_stdlib=Standard Python Libraries -import_heading_thirdparty=Third-Party Libraries -import_heading_firstparty=cisagov Libraries - -# Run isort under the black profile to align with our other Python linting -profile=black diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 14d0e20f..f1e13906 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -136,7 +136,9 @@ repos: name: bandit (tests tree) files: tests args: - - --config=.bandit.yml + # Skip "assert used" check since assertions are used + # frequently in pytests. + - --skip=B101 # Run bandit on everything except the "tests" tree - repo: https://github.com/PyCQA/bandit rev: 1.9.1 @@ -154,6 +156,9 @@ repos: - id: flake8 additional_dependencies: - flake8-docstrings==1.7.0 + # This is necessary to read the flake8 configuration from + # the pyproject.toml file. + - flake8-pyproject==1.2.3 - repo: https://github.com/PyCQA/isort rev: 7.0.0 hooks: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..bbd68920 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,125 @@ +# For more information about configuring project metadata for the +# setuptools build backend, please see +# https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html +[build-system] +build-backend = "setuptools.build_meta" +requires = ["setuptools"] + +[project] +authors = [ + { name = "Cybersecurity and Infrastructure Security Agency", email = "github@cisa.dhs.gov" } +] +# See https://pypi.python.org/pypi?%3Aaction=list_classifiers +classifiers = [ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + "Development Status :: 3 - Alpha", + "Environment :: Console", + # Indicate who your project is intended for + "Intended Audience :: Developers", + "Natural Language :: English", + "Operating System :: OS Independent", + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: Implementation :: CPython", +] +dependencies = [ + "docopt", + "schema", +] +description = "Example Python library" +dynamic = ["readme", "version"] +keywords = ["skeleton"] +license = "CC0-1.0" +name = "example" +requires-python = ">=3.9" + +[project.optional-dependencies] +# IMPORTANT: Keep type hinting-related dependencies of the dev section +# in sync with the mypy pre-commit hook configuration (see +# .pre-commit-config.yaml). Any changes to type hinting-related +# dependencies here should be reflected in the additional_dependencies +# field of the mypy pre-commit hook to avoid discrepancies in type +# checking between environments. +dev = [ + "types-docopt", + "types-setuptools", +] +test = [ + "coverage", + "coveralls", + "pre-commit", + "pytest-cov", + "pytest", +] + +[project.scripts] +example = "example.example:main" + +[project.urls] +homepage = "https://github.com/cisagov/skeleton-python-library" +issues = "https://github.com/cisagov/skeleton-python-library/issues" +# Landing page for CISA's cybersecurity mission +mission = "https://www.cisa.gov/cybersecurity" +source = "https://github.com/cisagov/skeleton-python-library" + +[tool.flake8] +max-line-length = 80 +# Select (turn on) +# * Complexity violations reported by mccabe (C) - +# http://flake8.pycqa.org/en/latest/user/error-codes.html#error-violation-codes +# * Documentation conventions compliance reported by pydocstyle (D) - +# http://www.pydocstyle.org/en/stable/error_codes.html +# * Default errors and warnings reported by pycodestyle (E and W) - +# https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes +# * Default errors reported by pyflakes (F) - +# http://flake8.pycqa.org/en/latest/glossary.html#term-pyflakes +# * Default warnings reported by flake8-bugbear (B) - +# https://github.com/PyCQA/flake8-bugbear#list-of-warnings +# * The B950 flake8-bugbear opinionated warning - +# https://github.com/PyCQA/flake8-bugbear#opinionated-warnings +select = ["C", "D", "E", "F", "W", "B", "B950"] +# Ignore flake8's default warning about maximum line length, which has +# a hard stop at the configured value. Instead we use +# flake8-bugbear's B950, which allows up to 10% overage. +# +# Also ignore flake8's warning about line breaks before binary +# operators. It no longer agrees with PEP8. See, for example, here: +# https://github.com/ambv/black/issues/21. Guido agrees here: +# https://github.com/python/peps/commit/c59c4376ad233a62ca4b3a6060c81368bd21e85b. +extend-ignore = ["E501", "W503"] + +[tool.isort] +combine_star = true +force_sort_within_sections = true + +import_heading_stdlib = "Standard Python Libraries" +import_heading_thirdparty = "Third-Party Libraries" +import_heading_firstparty = "cisagov Libraries" + +# Run isort under the black profile to align with our other Python +# linting +profile = "black" + +[tool.pytest.ini_options] +# Increase verbosity, display extra test summary info for tests that +# did not pass, display code coverage results, and enable debug +# logging. +addopts = "--verbose -ra --cov --log-cli-level=DEBUG" + +[tool.setuptools.dynamic] +readme = {file = ["README.md"], content-type = "text/markdown"} +version = {attr = "example._version.__version__"} + +[tool.setuptools.package-data] +example = ["data/*.txt"] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index a1c266eb..00000000 --- a/pytest.ini +++ /dev/null @@ -1,4 +0,0 @@ -[pytest] -# Increase verbosity, display extra test summary info for tests that did not pass, -# display code coverage results, and enable debug logging -addopts = --verbose -ra --cov --log-cli-level=DEBUG diff --git a/setup.py b/setup.py deleted file mode 100644 index 16fe44cc..00000000 --- a/setup.py +++ /dev/null @@ -1,116 +0,0 @@ -""" -This is the setup module for the example project. - -Based on: - -- https://packaging.python.org/distributing/ -- https://github.com/pypa/sampleproject/blob/master/setup.py -- https://blog.ionelmc.ro/2014/05/25/python-packaging/#the-structure -""" - -# Standard Python Libraries -import codecs -from glob import glob -from os.path import abspath, basename, dirname, join, splitext - -# Third-Party Libraries -from setuptools import find_packages, setup - - -def readme(): - """Read in and return the contents of the project's README.md file.""" - with open("README.md", encoding="utf-8") as f: - return f.read() - - -# Below two methods were pulled from: -# https://packaging.python.org/guides/single-sourcing-package-version/ -def read(rel_path): - """Open a file for reading from a given relative path.""" - here = abspath(dirname(__file__)) - with codecs.open(join(here, rel_path), "r") as fp: - return fp.read() - - -def get_version(version_file): - """Extract a version number from the given file path.""" - for line in read(version_file).splitlines(): - if line.startswith("__version__"): - delim = '"' if '"' in line else "'" - return line.split(delim)[1] - raise RuntimeError("Unable to find version string.") - - -setup( - name="example", - # Versions should comply with PEP440 - version=get_version("src/example/_version.py"), - description="Example Python library", - long_description=readme(), - long_description_content_type="text/markdown", - # Landing page for CISA's cybersecurity mission - url="https://www.cisa.gov/cybersecurity", - # Additional URLs for this project per - # https://packaging.python.org/guides/distributing-packages-using-setuptools/#project-urls - project_urls={ - "Source": "https://github.com/cisagov/skeleton-python-library", - "Tracker": "https://github.com/cisagov/skeleton-python-library/issues", - }, - # Author details - author="Cybersecurity and Infrastructure Security Agency", - author_email="github@cisa.dhs.gov", - license="License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", - # See https://pypi.python.org/pypi?%3Aaction=list_classifiers - classifiers=[ - # How mature is this project? Common values are - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable - "Development Status :: 3 - Alpha", - # Indicate who your project is intended for - "Intended Audience :: Developers", - # Pick your license as you wish (should match "license" above) - "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", - # Specify the Python versions you support here. In particular, ensure - # that you indicate whether you support Python 2, Python 3 or both. - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", - "Programming Language :: Python :: Implementation :: CPython", - ], - python_requires=">=3.9", - # What does your project relate to? - keywords="skeleton", - packages=find_packages(where="src"), - package_dir={"": "src"}, - package_data={"example": ["data/*.txt"]}, - py_modules=[splitext(basename(path))[0] for path in glob("src/*.py")], - include_package_data=True, - install_requires=["docopt", "schema", "setuptools"], - extras_require={ - # IMPORTANT: Keep type hinting-related dependencies of the dev section - # in sync with the mypy pre-commit hook configuration (see - # .pre-commit-config.yaml). Any changes to type hinting-related - # dependencies here should be reflected in the additional_dependencies - # field of the mypy pre-commit hook to avoid discrepancies in type - # checking between environments. - "dev": [ - "types-docopt", - "types-setuptools", - ], - "test": [ - "coverage", - "coveralls", - "pre-commit", - "pytest-cov", - "pytest", - ], - }, - # Conveniently allows one to run the CLI tool as `example` - entry_points={"console_scripts": ["example = example.example:main"]}, -)