Use pyproject.toml instead of setup.py, etc.

* Ditch setup.py in favor of setuptools' PEP 621 support. Ref:
  https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html

* Declare development dependencies in pyproject.toml rather than
  requirements/*.in

* Ditch pip-compile-multi which does not support sourcing deps from pyproject.toml

* Compile dependencies into dev-deps/*.txt rather than requirements/*.txt

* Don't include development-related files in the sdist or wheel.

* Drop less important bidict.metadata attributes
  (__maintainer__, __email__, __status__, __keywords__, __project_urls__)
  and make __author__ a dictionary with "name" and "email" keys
  to match the standard format in pyproject.toml.
This commit is contained in:
Joshua Bronson 2022-12-03 21:32:49 -05:00
parent 55204e7b5f
commit 79baf860b7
26 changed files with 278 additions and 298 deletions

View File

@ -12,9 +12,14 @@ RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/
# Install dev dependencies globally in the image.
# (Still easy to experiment with upgrades/new dependencies by installing them in --user scope,
# and if you want to keep them, add them to the requirements file and rebuild the container.)
COPY requirements/*.txt /tmp/bidict-requirements/
RUN pip3 --disable-pip-version-check install -U pip && pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/bidict-requirements/dev.txt \
&& rm -rf /tmp/bidict-requirements
COPY dev-deps/*.txt /tmp/bidict-dev-deps/
RUN pip3 --disable-pip-version-check install -U pip && \
pip3 --disable-pip-version-check --no-cache-dir install \
-r /tmp/bidict-dev-deps/test.txt \
-r /tmp/bidict-dev-deps/lint.txt \
-r /tmp/bidict-dev-deps/docs.txt \
-r /tmp/bidict-dev-deps/dev.txt \
&& rm -rf /tmp/bidict-dev-deps
# [Optional] Install additional OS packages.
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \

View File

@ -20,7 +20,7 @@ jobs:
python-version: '3.11'
- run: python -m pip install -U pip setuptools wheel
- name: install dependencies
run: pip install -r requirements/lint.txt
run: pip install -r dev-deps/lint.txt
- uses: pre-commit/action@v3.0.0
with:
extra_args: --verbose

View File

@ -38,7 +38,7 @@ jobs:
with:
python-version: ${{ matrix.pyversion }}
cache: pip
cache-dependency-path: requirements/tests.txt
cache-dependency-path: dev-deps/test.txt
- run: python -m pip install -U pip setuptools wheel tox
- name: cache .hypothesis dir
uses: actions/cache@v3.0.11

View File

@ -6,6 +6,7 @@ repos:
- id: end-of-file-fixer
- id: mixed-line-ending
- id: double-quote-string-fixer
- id: check-toml
- id: check-yaml
- repo: https://github.com/Lucas-C/pre-commit-hooks
@ -49,11 +50,6 @@ repos:
hooks:
- id: pyright
- repo: https://github.com/mgedmin/check-manifest
rev: "0.48"
hooks:
- id: check-manifest
# https://pre-commit.com/#repository-local-hooks
- repo: local
hooks:

View File

@ -62,7 +62,7 @@ Making Changes
(create a `virtualenv <http://virtualenv.pypa.io>`__ and)
install the extra packages required for development
if you haven't already:
``pip install -r requirements/dev.txt``
``pip install -r requirements/test.txt -r requirements/lint.txt -r requirements/docs.txt``
We use `EditorConfig <https://editorconfig.org/>`__
and `pre-commit <https://pre-commit.com/>`__

View File

@ -1,30 +1,3 @@
# Tip: pre-commit run check-manifest
include LICENSE
include *.py
include *.md
include *.rst
include *.sh
include *.json
include *.yaml
include *.yml
include *.ini
include .coveragerc
include .flake8
include .editorconfig
include .pre-commit-config.yaml
include .pylintrc
include .vscode/tasks.json
include pyproject.toml
include docs/_static/custom.css
include docs/_static/bidict-types-diagram.dot
include bidict/py.typed
recursive-include .devcontainer *
recursive-include assets *.*
recursive-include docs/_static *.*
recursive-include docs *.py
recursive-include docs *.rst
recursive-include docs Makefile
recursive-include requirements *.*
recursive-include tests *.py
recursive-include tests *.txt
recursive-exclude docs *
recursive-exclude tests *

View File

@ -1,9 +1,7 @@
.. Forward declarations for all the custom interpreted text roles that
Sphinx defines and that are used below. This helps Sphinx-unaware tools
(e.g. rst2html, PyPI's and GitHub's renderers, etc.).
.. role:: doc
.. Use :doc: rather than :ref: references below for better interop as well.
.. (Forward declaration for the "doc" role that Sphinx defines for interop with renderers that
are often used to show this doc and that are unaware of Sphinx (GitHub.com, PyPI.org, etc.).
Use :doc: rather than :ref: here for better interop as well.)
bidict

View File

@ -75,9 +75,8 @@ from ._exc import BidictException as BidictException, DuplicationError as Duplic
from ._exc import KeyDuplicationError as KeyDuplicationError, ValueDuplicationError as ValueDuplicationError, KeyAndValueDuplicationError as KeyAndValueDuplicationError
from ._iter import inverted as inverted
from .metadata import (
__author__ as __author__, __maintainer__ as __maintainer__, __copyright__ as __copyright__, __email__ as __email__,
__url__ as __url__, __license__ as __license__, __status__ as __status__, __description__ as __description__,
__keywords__ as __keywords__, __version__ as __version__, __project_urls__ as __project_urls__,
__author__ as __author__, __copyright__ as __copyright__, __description__ as __description__,
__license__ as __license__, __url__ as __url__, __version__ as __version__,
)

View File

@ -8,22 +8,8 @@
__version__ = '0.22.1.dev0'
__author__ = 'Joshua Bronson'
__maintainer__ = 'Joshua Bronson'
__author__ = {'name': 'Joshua Bronson', 'email': 'jabronson@gmail.com'}
__copyright__ = '© 2009-2022 Joshua Bronson'
__email__ = 'jabronson@gmail.com'
__description__ = 'The bidirectional mapping library for Python.'
__keywords__ = 'dict dictionary mapping datastructure bimap bijection bijective ' \
'injective inverse reverse bidirectional two-way 2-way'
__license__ = 'MPL 2.0'
__status__ = 'Beta'
__url__ = 'https://bidict.readthedocs.io'
__project_urls__ = {
'Donate': 'https://github.com/sponsors/jab',
'Documentation': 'https://bidict.readthedocs.io',
'Enterprise Support': 'https://bidict.readthedocs.io/#enterprise-support',
'Changelog': 'https://bidict.readthedocs.io/changelog.html',
'Source Code': 'https://github.com/jab/bidict',
'Issue Tracker': 'https://github.com/jab/bidict/issues',
'Chat': 'https://gitter.im/jab/bidict',
}

46
dev-deps/dev.txt Normal file
View File

@ -0,0 +1,46 @@
#
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --allow-unsafe --extra=dev --output-file=dev-deps/dev.txt --resolver=backtracking pyproject.toml
#
build==0.9.0
# via pip-tools
click==8.1.3
# via pip-tools
distlib==0.3.6
# via virtualenv
filelock==3.8.0
# via
# tox
# virtualenv
packaging==21.3
# via
# build
# tox
pep517==0.13.0
# via build
pip-tools==6.11.0
# via bidict (pyproject.toml)
platformdirs==2.5.4
# via virtualenv
pluggy==1.0.0
# via tox
py==1.11.0
# via tox
pyparsing==3.0.9
# via packaging
six==1.16.0
# via tox
tox==3.27.1
# via bidict (pyproject.toml)
virtualenv==20.17.0
# via tox
wheel==0.38.4
# via pip-tools
# The following packages are considered to be unsafe in a requirements file:
pip==22.3.1
# via pip-tools
setuptools==65.6.3
# via pip-tools

View File

@ -1,9 +1,8 @@
# SHA1:8eac8303d3f8f56a476fe673bdee9e142c5b17ef
#
# This file is autogenerated by pip-compile-multi
# To update, run:
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile-multi
# pip-compile --allow-unsafe --extra=docs --output-file=dev-deps/docs.txt --resolver=backtracking pyproject.toml
#
alabaster==0.7.12
# via sphinx
@ -18,7 +17,7 @@ charset-normalizer==2.1.1
docutils==0.19
# via sphinx
furo==2022.9.29
# via -r requirements/docs.in
# via bidict (pyproject.toml)
idna==3.4
# via requests
imagesize==1.4.1
@ -45,14 +44,14 @@ soupsieve==2.3.2.post1
# via beautifulsoup4
sphinx==5.3.0
# via
# -r requirements/docs.in
# bidict (pyproject.toml)
# furo
# sphinx-basic-ng
# sphinx-copybutton
sphinx-basic-ng==1.0.0b1
# via furo
sphinx-copybutton==0.5.1
# via -r requirements/docs.in
# via bidict (pyproject.toml)
sphinxcontrib-applehelp==1.0.2
# via sphinx
sphinxcontrib-devhelp==1.0.2

View File

@ -1,9 +1,8 @@
# SHA1:54b2a7dd4371784658253790152399eb1fb07798
#
# This file is autogenerated by pip-compile-multi
# To update, run:
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile-multi
# pip-compile --allow-unsafe --extra=lint --output-file=dev-deps/lint.txt --resolver=backtracking pyproject.toml
#
astroid==2.12.13
# via pylint
@ -20,7 +19,7 @@ distlib==0.3.6
filelock==3.8.0
# via virtualenv
hypothesis==6.59.0
# via -r requirements/lint.in
# via bidict (pyproject.toml)
identify==2.5.9
# via pre-commit
iniconfig==1.1.1
@ -42,13 +41,13 @@ platformdirs==2.5.4
pluggy==1.0.0
# via pytest
pre-commit==2.20.0
# via -r requirements/lint.in
# via bidict (pyproject.toml)
pylint==2.15.7
# via -r requirements/lint.in
# via bidict (pyproject.toml)
pyparsing==3.0.9
# via packaging
pytest==7.2.0
# via -r requirements/lint.in
# via bidict (pyproject.toml)
pyyaml==6.0
# via pre-commit
sortedcontainers==2.4.0
@ -63,4 +62,5 @@ wrapt==1.14.1
# via astroid
# The following packages are considered to be unsafe in a requirements file:
# setuptools
setuptools==65.6.3
# via nodeenv

99
dev-deps/test.txt Normal file
View File

@ -0,0 +1,99 @@
#
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --allow-unsafe --extra=test --output-file=dev-deps/test.txt --resolver=backtracking pyproject.toml
#
alabaster==0.7.12
# via sphinx
attrs==22.1.0
# via
# hypothesis
# pytest
babel==2.11.0
# via sphinx
certifi==2022.9.24
# via requests
charset-normalizer==2.1.1
# via requests
coverage[toml]==6.5.0
# via
# bidict (pyproject.toml)
# pytest-cov
docutils==0.19
# via sphinx
hypothesis==6.59.0
# via bidict (pyproject.toml)
icdiff==2.0.5
# via pytest-icdiff
idna==3.4
# via requests
imagesize==1.4.1
# via sphinx
iniconfig==1.1.1
# via pytest
jinja2==3.1.2
# via sphinx
markupsafe==2.1.1
# via jinja2
packaging==21.3
# via
# pytest
# sphinx
pluggy==1.0.0
# via pytest
pprintpp==0.4.0
# via pytest-icdiff
py==1.11.0
# via bidict (pyproject.toml)
py-cpuinfo==9.0.0
# via pytest-benchmark
pygal==3.0.0
# via pytest-benchmark
pygaljs==1.0.2
# via pytest-benchmark
pygments==2.13.0
# via sphinx
pyparsing==3.0.9
# via packaging
pytest==7.2.0
# via
# bidict (pyproject.toml)
# pytest-benchmark
# pytest-cov
# pytest-icdiff
pytest-benchmark[histogram]==4.0.0
# via bidict (pyproject.toml)
pytest-cov==4.0.0
# via bidict (pyproject.toml)
pytest-icdiff==0.6
# via bidict (pyproject.toml)
pytz==2022.6
# via babel
requests==2.28.1
# via sphinx
snowballstemmer==2.2.0
# via sphinx
sortedcollections==2.1.0
# via bidict (pyproject.toml)
sortedcontainers==2.4.0
# via
# bidict (pyproject.toml)
# hypothesis
# sortedcollections
sphinx==5.3.0
# via bidict (pyproject.toml)
sphinxcontrib-applehelp==1.0.2
# via sphinx
sphinxcontrib-devhelp==1.0.2
# via sphinx
sphinxcontrib-htmlhelp==2.0.0
# via sphinx
sphinxcontrib-jsmath==1.0.1
# via sphinx
sphinxcontrib-qthelp==1.0.3
# via sphinx
sphinxcontrib-serializinghtml==1.1.5
# via sphinx
urllib3==1.26.13
# via requests

View File

@ -40,7 +40,6 @@ import bidict
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or custom ones.
extensions = [
'sphinx_copybutton',
'sphinx.ext.autodoc',
'sphinx.ext.autosectionlabel',
'sphinx.ext.coverage',
@ -49,6 +48,12 @@ extensions = [
'sphinx.ext.viewcode',
'sphinx.ext.todo',
]
try:
import sphinx_copybutton # noqa: F401
except ImportError:
pass
else:
extensions.append('sphinx_copybutton')
intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
#todo_include_todos = True
@ -67,8 +72,8 @@ master_doc = 'index'
# General information about the project.
project = 'bidict'
author = bidict.__author__
copyright = bidict.__copyright__.lstrip('© ')
author = bidict.metadata.__author__['name']
copyright = bidict.metadata.__copyright__.lstrip('© ')
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the

View File

@ -1,3 +1,77 @@
[project]
name = "bidict"
dynamic = ["version"]
description = "The bidirectional mapping library for Python."
authors = [{name="Joshua Bronson", email="jabronson@gmail.com"}]
license = {text="MPL 2.0"}
dependencies = []
requires-python = ">=3.7"
readme = "README.rst"
keywords = [
"bidict", "bimap", "bidirectional", "dict", "dictionary", "mapping", "collections",
]
classifiers = [
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Software Development :: Libraries :: Python Modules",
"Typing :: Typed",
]
[project.urls]
Homepage = "https://bidict.readthedocs.io"
Repository = "https://github.com/jab/bidict"
Documentation = "https://bidict.readthedocs.io"
Donate = "https://github.com/sponsors/jab"
Changelog = "https://bidict.readthedocs.io/changelog.html"
Chat = "https://gitter.im/jab/bidict"
"Source Code" = "https://github.com/jab/bidict"
"Issue Tracker" = "https://github.com/jab/bidict/issues"
"Enterprise Support" = "https://bidict.readthedocs.io/#enterprise-support"
[build-system]
requires = ["setuptools"]
requires = ["setuptools >= 40.9.0"]
build-backend = "setuptools.build_meta"
[tool.setuptools]
packages = ["bidict"]
[project.optional-dependencies]
docs = [
"sphinx",
"sphinx-copybutton",
"furo",
]
test = [
"hypothesis",
"coverage",
"py",
"pytest",
"pytest-benchmark[histogram]",
"pytest-cov",
"pytest-icdiff",
"sortedcollections",
"sortedcontainers",
# run_tests.py depends on Sphinx to run doctests (see note in run_tests.py)
"sphinx",
]
lint = [
"pre-commit",
# pre-commit would ideally be the only direct dependency needed for linting, but the
# pylint pre-commit hooks requires "repo: local", so it's included in lint dependencies:
"pylint",
# pylint runs against tests/*.py, which depend on pytest and hypothesis:
"pytest",
"hypothesis",
]
dev = [
"pip-tools",
"tox",
]

View File

@ -1,7 +0,0 @@
-r docs.in
-r tests.in
-r lint.in
check-manifest
pip-compile-multi
pre-commit
tox

View File

@ -1,40 +0,0 @@
# SHA1:568a48025f520165298b1af2fe3176cc40a0d5ba
#
# This file is autogenerated by pip-compile-multi
# To update, run:
#
# pip-compile-multi
#
-r docs.txt
-r lint.txt
-r tests.txt
build==0.9.0
# via
# check-manifest
# pip-tools
check-manifest==0.48
# via -r requirements/dev.in
click==8.1.3
# via
# pip-compile-multi
# pip-tools
pep517==0.13.0
# via build
pip-compile-multi==2.6.1
# via -r requirements/dev.in
pip-tools==6.11.0
# via pip-compile-multi
six==1.16.0
# via tox
tomli==2.0.1
# via check-manifest
toposort==1.7
# via pip-compile-multi
tox==3.27.1
# via -r requirements/dev.in
wheel==0.38.4
# via pip-tools
# The following packages are considered to be unsafe in a requirements file:
# pip
# setuptools

View File

@ -1,3 +0,0 @@
furo
sphinx
sphinx-copybutton

View File

@ -1,7 +0,0 @@
pre-commit
# pre-commit would ideally be the only direct dependency needed for linting, but the
# pylint pre-commit hooks requires "repo: local", so we add it to our lint dependencies:
pylint
# pylint runs against tests/*.py which import pytest and hypothesis
pytest
hypothesis

View File

@ -1,10 +0,0 @@
-r docs.in
hypothesis
coverage
py
pytest
pytest-benchmark[histogram]
pytest-cov
pytest-icdiff
sortedcollections
sortedcontainers

View File

@ -1,53 +0,0 @@
# SHA1:16846ddbf5f5b10e61a010cea43aa0bdebf3b815
#
# This file is autogenerated by pip-compile-multi
# To update, run:
#
# pip-compile-multi
#
-r docs.txt
attrs==22.1.0
# via
# hypothesis
# pytest
coverage[toml]==6.5.0
# via
# -r requirements/tests.in
# pytest-cov
hypothesis==6.59.0
# via -r requirements/tests.in
icdiff==2.0.5
# via pytest-icdiff
iniconfig==1.1.1
# via pytest
pluggy==1.0.0
# via pytest
pprintpp==0.4.0
# via pytest-icdiff
py==1.11.0
# via -r requirements/tests.in
py-cpuinfo==9.0.0
# via pytest-benchmark
pygal==3.0.0
# via pytest-benchmark
pygaljs==1.0.2
# via pytest-benchmark
pytest==7.2.0
# via
# -r requirements/tests.in
# pytest-benchmark
# pytest-cov
# pytest-icdiff
pytest-benchmark[histogram]==4.0.0
# via -r requirements/tests.in
pytest-cov==4.0.0
# via -r requirements/tests.in
pytest-icdiff==0.6
# via -r requirements/tests.in
sortedcollections==2.1.0
# via -r requirements/tests.in
sortedcontainers==2.4.0
# via
# -r requirements/tests.in
# hypothesis
# sortedcollections

View File

@ -7,9 +7,4 @@
# https://packaging.python.org/guides/single-sourcing-package-version/#:~:text=%5Bmetadata%5D%0Aversion%20%3D%20attr%3A%20package.__version__
[metadata]
version = attr: bidict.__version__
# https://wheel.readthedocs.io/en/stable/user_guide.html#building-wheels
[bdist_wheel]
# No longer Python 2-compatible -> disable universal wheels:
universal = 0
version = attr: bidict.metadata.__version__

View File

@ -1,75 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2009-2022 Joshua Bronson. All rights reserved.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""A setuptools-based setup module.
Ref: https://github.com/pypa/sampleproject/blob/main/setup.py
"""
import sys
PY2_ERR = """
This version of bidict does not support Python 2.
Either use bidict 0.18.4,
the last release with Python 2 support,
or use Python 3.
Also ensure you are using pip >= 9.0.1 to install bidict.
See python3statement.org for more info.
"""
if sys.version_info < (3,):
sys.exit(PY2_ERR)
elif sys.version_info < (3, 7):
sys.exit('Python < 3.7 is not supported by this version of bidict.')
from pathlib import Path
from types import SimpleNamespace
cwd = Path(__file__).parent.resolve()
long_description = (cwd / 'README.rst').read_text(encoding='utf8')
metadata = SimpleNamespace()
exec((cwd / 'bidict' / 'metadata.py').read_text(encoding='utf8'), metadata.__dict__)
from setuptools import setup
setup(
name='bidict',
author=metadata.__author__,
author_email=metadata.__email__,
description=metadata.__description__,
long_description=long_description,
long_description_content_type='text/x-rst',
keywords=metadata.__keywords__,
url=metadata.__url__,
license=metadata.__license__,
packages=['bidict'],
include_package_data=True,
zip_safe=False, # Don't zip. (We're zip-safe but prefer not to.)
python_requires='>=3.7',
project_urls=metadata.__project_urls__,
classifiers=[
'Intended Audience :: Developers',
'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Software Development :: Libraries :: Python Modules',
'Typing :: Typed',
],
)

View File

@ -11,16 +11,11 @@ import bidict
METADATA_ATTRS = """
__author__
__maintainer__
__copyright__
__email__
__description__
__keywords__
__license__
__status__
__url__
__version__
__project_urls__
""".split()

View File

@ -6,16 +6,17 @@ envlist =
docs
skip_missing_interpreters = true
isolated_build = true
[testenv]
deps = -r requirements/tests.txt
deps = -r dev-deps/test.txt
commands = ./run_tests.py
[testenv:lint]
deps = -r requirements/lint.txt
deps = -r dev-deps/lint.txt
skip_install = true
commands = pre-commit run --all-files --verbose --show-diff-on-failure
[testenv:docs]
deps = -r requirements/docs.txt
deps = -r dev-deps/docs.txt
commands = sphinx-build -W --keep-going -b html -d {envtmpdir}/doctrees docs {envtmpdir}/html

View File

@ -9,13 +9,12 @@
set -euo pipefail
log() {
echo -e >&2 "$@"
>&2 echo -e "$@"
}
main() {
if ! type pre-commit || ! type pip-compile-multi; then
log "Error: pre-commit or pip-compile-multi not found." \
"\n Hint: pip install -r requirements/dev.txt"
if ! type pre-commit || ! type pip-compile; then
log "Error: pre-commit or pip-compile not found."
exit 1
fi
@ -29,8 +28,13 @@ main() {
exit 1
fi
pip-compile-multi
pip install -r requirements/dev.txt
# Not adding --generate-hashes due to https://github.com/jazzband/pip-tools/issues/1326
local -r pip_compile="pip-compile pyproject.toml --upgrade --resolver=backtracking --allow-unsafe"
${pip_compile} --extra=test -o dev-deps/test.txt
${pip_compile} --extra=docs -o dev-deps/docs.txt
${pip_compile} --extra=lint -o dev-deps/lint.txt
${pip_compile} --extra=dev -o dev-deps/dev.txt
pip install -U -r dev-deps/test.txt -r dev-deps/docs.txt -r dev-deps/lint.txt -r dev-deps/dev.txt
pre-commit autoupdate
pre-commit clean