Skip to content

Instantly share code, notes, and snippets.

@GhostofGoes
Last active January 31, 2024 00:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GhostofGoes/75051c4aeb215bc3cf48c10f5454b399 to your computer and use it in GitHub Desktop.
Save GhostofGoes/75051c4aeb215bc3cf48c10f5454b399 to your computer and use it in GitHub Desktop.
Example pyproject.toml
# This example pyproject.toml is for a basic pip+setuptools setup.
# If you use a project management tool (like Poetry), then
# those tools will have slightly different configurations or additions.
# I highly recommend using a project management tool for your project.
# Project management is a highly opinionated subject.
# There are a lot of good, robust tools in this space now (as of 2023)
# Two that I've used and recommend are Poetry and PDM.
# Poetry is more mature, PDM is recent, both work well.
# - Poetry: https://python-poetry.org/
# - PDM: https://pdm.fming.dev/latest/
# Resources
#
# - https://packaging.python.org/en/latest/tutorials/packaging-projects/
# - https://betterprogramming.pub/a-pyproject-toml-developers-cheat-sheet-5782801fb3ed
#
# Examples of pyproject.toml files from open-source projects:
# - https://github.com/carlosperate/awesome-pyproject
# - https://github.com/SpikeInterface/spikeinterface/blob/master/pyproject.toml
# - https://github.com/codespell-project/codespell/blob/master/pyproject.toml
# - https://github.com/hynek/structlog/blob/main/pyproject.toml
[build-system]
build-backend = "setuptools.build_meta"
requires = ["setuptools>=61.0", "wheel>=0.37.1"]
[project]
# https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
name = "acme"
version = "0.0.1"
description = "ACME tool"
readme = "README.md"
requires-python = ">=3.9,<4.0"
# "LICENSE" is name of the license file, which must be in root of project folder
license = {file = "LICENSE"}
authors = [
{name = "Joe Example", email = "example@example.com"},
]
keywords = ["keyword", "are", "cool"]
# https://pypi.org/classifiers/
# Add PyPI classifiers here
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: Implementation :: CPython",
]
# Required dependencies for install/usage of your package or application
# If you don't have any dependencies, leave this section empty
# Format for dependency strings: https://peps.python.org/pep-0508/
dependencies = [
# ... put stuff here ...
]
[project.scripts]
# Command line interface entrypoint scripts
acme = "acme.__main__:main"
[project.urls]
# Use PyPI-standard names here
# Homepage
# Documentation
# Changelog
# Issue Tracker
# Source
# Discord server
"Homepage" = "<url>"
"Documentation" = "<url>"
# Development dependencies
# pip install -e .[lint,test,exe]
# pip install -e .[dev]
[project.optional-dependencies]
lint = [
# checks for spelling mistakes
"codespell>=2.2.4",
# ruff linter checks for issues and potential bugs
"ruff",
# checks for unused code
"vulture",
# required for codespell to parse pyproject.toml
"tomli",
# validation of pyproject.toml
"validate-pyproject[all]",
# automatic sorting of imports
"isort",
# automatic code formatting to follow a consistent style
"black",
]
test = [
# Handles most of the testing work, including execution
# Docs: https://docs.pytest.org/en/stable/contents.html
"pytest",
# "Coverage" is how much of the code is actually run (it's "coverage")
# Generates coverage reports from test suite runs
"pytest-cov",
"tomli",
# pytest wrapper around the "mock" library
"pytest-mock",
# Randomizes the order of test execution
"pytest-randomly",
# Required for comparing device data exports and a few other complex structures
# Docs: https://zepworks.com/deepdiff/current/
"deepdiff",
# Test parallelization, as well as remote execution (which we may do someday)
"pytest-xdist[psutil]",
# Detailed pytest results saved to a JSON file
"pytest-json-report",
# Better parsing of doctests
"xdoctest",
# Mocking of HTTP responses for the "requests" module
"requests-mock",
# Colors for doctest output
"Pygments",
]
exe = [
"setuptools",
"wheel",
"build",
"tomli",
"pyinstaller",
"staticx;platform_system=='Linux'",
]
dev = [
# https://hynek.me/articles/python-recursive-optional-dependencies/
"acme[lint,test,exe]",
# Useful for building quick scripts for testing purposes
# https://github.com/google/python-fire
"fire",
# Code quality tools
"mypy",
# Improved exception traceback output
# https://github.com/qix-/better-exceptions
"better_exceptions",
# Analyzing dependencies
# install graphviz to generate graphs
"graphviz",
"pipdeptree",
]
[tool.setuptools]
# https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html
platforms = ["Linux", "Windows"]
include-package-data = true
zip-safe = true # This just means it's safe to zip up the bdist
# Non-code data that should be included in the package source code
# https://setuptools.pypa.io/en/latest/userguide/datafiles.html
[tool.setuptools.package-data]
acme = ["*.xml"]
# Python modules and packages that are included in the
# distribution package (and therefore become importable)
[tool.setuptools.packages.find]
exclude = ["tests", "tests.*", "examples"]
# PDM example
[tool.pdm.scripts]
isort = "isort acme"
black = "black acme"
format = {composite = ["isort", "black"]}
check_isort = "isort --check acme tests"
check_black = "black --check acme tests"
vulture = "vulture --min-confidence 100 acme tests"
ruff = "ruff check acme tests"
fix = "ruff check --fix acme tests"
codespell = "codespell --toml ./pyproject.toml"
lint = {composite = ["vulture", "codespell", "ruff", "check_isort", "check_black"]}
[tool.codespell]
# codespell supports pyproject.toml since version 2.2.2
# NOTE: the "tomli" package must be installed for this to work
# https://github.com/codespell-project/codespell#using-a-config-file
# NOTE: ignore words for codespell must be lowercase
check-filenames = ""
ignore-words-list = "word,another,something"
skip = "htmlcov,.doctrees,*.pyc,*.class,*.ico,*.out,*.PNG,*.inv,*.png,*.jpg,*.dot"
[tool.black]
line-length = 88
# If you need to exclude directories from being reformatted by black
# force-exclude = '''
# (
# somedirname
# | dirname
# | filename\.py
# )
# '''
[tool.isort]
profile = "black"
known_first_party = ["acme"]
# If you need to exclude files from having their imports sorted
extend_skip_glob = [
"acme/somefile.py",
"acme/somedir/*",
]
# https://beta.ruff.rs/docs
[tool.ruff]
line-length = 99
show-source = true
# Rules: https://beta.ruff.rs/docs/rules
# If you violate a rule, lookup the rule on the Rules page in ruff docs.
# Many rules have links you can click with a explanation of the rule and how to fix it.
# If there isn't a link, go to the project the rule was source from (e.g. flake8-bugbear)
# and review it's docs for the corresponding rule.
# If you're still confused, ask a fellow developer for assistance.
# You can also run "ruff rule <rule>" to explain a rule on the command line, without a browser or internet access.
select = [
"E", # pycodestyle
"F", # Pyflakes
"W", # Warning
"B", # flake8-bugbear
"A", # flake8-builtins
"C4", # flake8-comprehensions
"T10", # flake8-debugger
"EXE", # flake8-executable,
"ISC", # flake8-implicit-str-concat
"G", # flake8-logging-format
"PIE", # flake8-pie
"T20", # flake8-print
"PT", # flake8-pytest-style
"RSE", # flake8-raise
"RET", # flake8-return
"TID", # flake8-tidy-imports
"ARG", # flake8-unused-arguments
"PGH", # pygrep-hooks
"PLC", # Pylint Convention
"PLE", # Pylint Errors
"PLW", # Pylint Warnings
"RUF", # Ruff-specific rules
# ** Things to potentially enable in the future **
# DTZ requires all usage of datetime module to have timezone-aware
# objects (so have a tz argument or be explicitly UTC).
# "DTZ", # flake8-datetimez
# "PTH", # flake8-use-pathlib
# "SIM", # flake8-simplify
]
# Files to exclude from linting
extend-exclude = [
"*.pyc",
"__pycache__",
]
# Linting error codes to ignore
ignore = [
"F403", # unable to detect undefined names from star imports
"F405", # undefined locals from star imports
"W605", # invalid escape sequence
"A003", # shadowing python builtins
"RET505", # unnecessary 'else' after 'return' statement
"RET504", # Unnecessary variable assignment before return statement
"RET507", # Unnecessary {branch} after continue statement
"PT011", # pytest-raises-too-broad
"PT012", # pytest.raises() block should contain a single simple statement
"PLW0603", # Using the global statement to update is discouraged
"PLW2901", # for loop variable overwritten by assignment target
"G004", # Logging statement uses f-string
"PIE790", # no-unnecessary-pass
"PIE810", # multiple-starts-ends-with
"PGH003", # Use specific rule codes when ignoring type issues
"PLC1901", # compare-to-empty-string
]
# Linting error codes to ignore on a per-file basis
[tool.ruff.per-file-ignores]
"__init__.py" = ["F401", "E501"]
"acme/somefile.py" = ["E402", "E501"]
"acme/somedir/*" = ["E501"]
# Configuration for mypy
# https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml-file
[tool.mypy]
python_version = "3.9"
follow_imports = "skip"
ignore_missing_imports = true
files = "acme" # directory mypy should analyze
# Directories to exclude from mypy's analysis
exclude = [
"acme/somedir",
"acme/somefile\\.py",
"dirname",
]
# Configuration for pytest
# https://docs.pytest.org/en/latest/reference/customize.html#pyproject-toml
[tool.pytest.ini_options]
testpaths = "tests" # directory containing your tests
norecursedirs = [
".vscode",
"__pycache__"
]
# Warnings that should be ignored
filterwarnings = [
"ignore::DeprecationWarning"
]
# custom markers that can be used using pytest.mark
markers = [
"slow: lower-importance tests that take an excessive amount of time",
]
# Configuration for coverage.py
[tool.coverage.run]
# files or directories to exclude from coverage calculations
omit = [
'acme/somedir/*',
'acme/somefile.py',
]
# Configuration for vulture
[tool.vulture]
# Files or directories to exclude from vulture
# The syntax is a little funky
exclude = [
"somedir",
"*somefile.py",
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment