diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..02879483 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,9 @@ +[run] +omit = + # leading `*/` for pytest-dev/pytest-cov#456 + */.tox/* +disable_warnings = + couldnt-parse + +[report] +show_missing = True diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..304196f8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +root = true + +[*] +charset = utf-8 +indent_style = tab +indent_size = 4 +insert_final_newline = true +end_of_line = lf + +[*.py] +indent_style = space +max_line_length = 88 + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 + +[*.rst] +indent_style = space diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..89ff3396 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" + allow: + - dependency-type: "all" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cb85ffe6..4d9b8a3e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,6 +2,22 @@ name: tests on: [push, pull_request] +permissions: + contents: read + +env: + # Environment variable to support color support (jaraco/skeleton#66) + FORCE_COLOR: 1 + + # Suppress noisy pip warnings + PIP_DISABLE_PIP_VERSION_CHECK: 'true' + PIP_NO_PYTHON_VERSION_WARNING: 'true' + PIP_NO_WARN_SCRIPT_LOCATION: 'true' + + # Ensure tests can sense settings about the environment + TOX_OVERRIDE: >- + testenv.pass_env+=GITHUB_*,FORCE_COLOR + concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true @@ -11,29 +27,66 @@ jobs: strategy: matrix: python: - # Build on pre-releases until stable, then stable releases. - # actions/setup-python#213 - - ~3.7.0-0 - - ~3.10.0-0 - - ~3.11.0-0 + - "3.8" + - "3.11" + - "3.12" platform: - ubuntu-latest - macos-latest - windows-latest include: - - platform: ubuntu-latest - python: 'pypy3.9' + - python: "3.9" + platform: ubuntu-latest + - python: "3.10" + platform: ubuntu-latest + - python: pypy3.9 + platform: ubuntu-latest runs-on: ${{ matrix.platform }} + continue-on-error: ${{ matrix.python == '3.12' }} steps: - uses: actions/checkout@v3 - name: Setup Python uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} + allow-prereleases: true - name: Install tox run: | python -m pip install tox - - name: Run tests + - name: Run + run: tox + + diffcov: + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.python == '3.12' }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.x + - name: Install tox + run: | + python -m pip install tox + - name: Evaluate coverage + run: tox + env: + TOXENV: diffcov + + docs: + runs-on: ubuntu-latest + env: + TOXENV: docs + steps: + - uses: actions/checkout@v3 + - name: Setup Python + uses: actions/setup-python@v4 + - name: Install tox + run: | + python -m pip install tox + - name: Run run: tox test_cygwin: @@ -103,8 +156,27 @@ jobs: env: VIRTUALENV_NO_SETUPTOOLS: null + check: # This job does nothing and is only used for the branch protection + if: always() + + needs: + - test + - docs + - test_cygwin + + runs-on: ubuntu-latest + + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} + release: - needs: test + permissions: + contents: write + needs: + - check if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') runs-on: ubuntu-latest @@ -113,11 +185,11 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: 3.11-dev - name: Install tox run: | python -m pip install tox - - name: Release + - name: Run run: tox -e release env: TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..af502010 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,5 @@ +repos: +- repo: https://github.com/psf/black + rev: 22.6.0 + hooks: + - id: black diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..053c7287 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,12 @@ +version: 2 +python: + install: + - path: . + extra_requirements: + - docs + +# required boilerplate readthedocs/readthedocs.org#10401 +build: + os: ubuntu-22.04 + tools: + python: "3" diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..1bb5a443 --- /dev/null +++ b/LICENSE @@ -0,0 +1,17 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/NEWS.rst b/NEWS.rst new file mode 100644 index 00000000..e69de29b diff --git a/README.rst b/README.rst index 588898bb..44c779da 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,26 @@ +.. image:: https://img.shields.io/pypi/v/distutils.svg + :target: https://pypi.org/project/distutils + +.. image:: https://img.shields.io/pypi/pyversions/distutils.svg + +.. image:: https://github.com/pypa/distutils/workflows/tests/badge.svg + :target: https://github.com/pypa/distutils/actions?query=workflow%3A%22tests%22 + :alt: tests + +.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json + :target: https://github.com/astral-sh/ruff + :alt: Ruff + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + :alt: Code style: Black + +.. .. image:: https://readthedocs.org/projects/PROJECT_RTD/badge/?version=latest +.. :target: https://PROJECT_RTD.readthedocs.io/en/latest/?badge=latest + +.. image:: https://img.shields.io/badge/skeleton-2023-informational + :target: https://blog.jaraco.com/skeleton + Python Module Distribution Utilities extracted from the Python Standard Library Synchronizing diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..d673f413 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,45 @@ +extensions = [ + 'sphinx.ext.autodoc', + 'jaraco.packaging.sphinx', +] + +master_doc = "index" +html_theme = "furo" + +# Link dates and other references in the changelog +extensions += ['rst.linker'] +link_files = { + '../NEWS.rst': dict( + using=dict(GH='https://github.com'), + replace=[ + dict( + pattern=r'(Issue #|\B#)(?P\d+)', + url='{package_url}/issues/{issue}', + ), + dict( + pattern=r'(?m:^((?Pv?\d+(\.\d+){1,2}))\n[-=]+\n)', + with_scm='{text}\n{rev[timestamp]:%d %b %Y}\n', + ), + dict( + pattern=r'PEP[- ](?P\d+)', + url='https://peps.python.org/pep-{pep_number:0>4}/', + ), + ], + ) +} + +# Be strict about any broken references +nitpicky = True + +# Include Python intersphinx mapping to prevent failures +# jaraco/skeleton#51 +extensions += ['sphinx.ext.intersphinx'] +intersphinx_mapping = { + 'python': ('https://docs.python.org/3', None), +} + +# Preserve authored syntax for defaults +autodoc_preserve_defaults = True + +# for distutils, disable nitpicky +nitpicky = False diff --git a/docs/history.rst b/docs/history.rst new file mode 100644 index 00000000..5bdc2320 --- /dev/null +++ b/docs/history.rst @@ -0,0 +1,8 @@ +:tocdepth: 2 + +.. _changes: + +History +******* + +.. include:: ../NEWS (links).rst diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..6b70ccf9 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,21 @@ +Welcome to |project| documentation! +=================================== + +.. sidebar-links:: + :home: + :pypi: + +.. toctree:: + :maxdepth: 1 + + history + distutils/index + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 00000000..b6f97276 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,5 @@ +[mypy] +ignore_missing_imports = True +# required to support namespace packages +# https://github.com/python/mypy/issues/14057 +explicit_package_bases = True diff --git a/pyproject.toml b/pyproject.toml index e6863cff..dce944df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,8 @@ +[build-system] +requires = ["setuptools>=56", "setuptools_scm[toml]>=3.4.1"] +build-backend = "setuptools.build_meta" + [tool.black] skip-string-normalization = true -[tool.pytest-enabler.black] -addopts = "--black" - -[tool.pytest-enabler.flake8] -addopts = "--flake8" - -[tool.pytest-enabler.cov] -addopts = "--cov" +[tool.setuptools_scm] diff --git a/pytest.ini b/pytest.ini index 3f8cc25f..73dad17e 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,18 +1,30 @@ [pytest] +norecursedirs=dist build .tox .eggs addopts=--doctest-modules filterwarnings= - # Suppress deprecation warning in flake8 - ignore:SelectableGroups dict interface is deprecated::flake8 + ## upstream + + # Ensure ResourceWarnings are emitted + default::ResourceWarning # shopkeep/pytest-black#55 ignore: is not using a cooperative constructor:pytest.PytestDeprecationWarning ignore:The \(fspath. py.path.local\) argument to BlackItem is deprecated.:pytest.PytestDeprecationWarning ignore:BlackItem is an Item subclass and should not be a collector:pytest.PytestWarning - # tholo/pytest-flake8#83 - ignore: is not using a cooperative constructor:pytest.PytestDeprecationWarning - ignore:The \(fspath. py.path.local\) argument to Flake8Item is deprecated.:pytest.PytestDeprecationWarning - ignore:Flake8Item is an Item subclass and should not be a collector:pytest.PytestWarning + # shopkeep/pytest-black#67 + ignore:'encoding' argument not specified::pytest_black + + # realpython/pytest-mypy#152 + ignore:'encoding' argument not specified::pytest_mypy + + # python/cpython#100750 + ignore:'encoding' argument not specified::platform + + # pypa/build#615 + ignore:'encoding' argument not specified::build.env + + ## end upstream # acknowledge that TestDistribution isn't a test ignore:cannot collect test class 'TestDistribution' diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..6fc62c4b --- /dev/null +++ b/setup.cfg @@ -0,0 +1,66 @@ +[metadata] +name = distutils +author = Jason R. Coombs +author_email = jaraco@jaraco.com +description = Distribution utilities formerly from standard library +long_description = file:README.rst +url = https://github.com/pypa/distutils +classifiers = + Development Status :: 5 - Production/Stable + Intended Audience :: Developers + License :: OSI Approved :: MIT License + Programming Language :: Python :: 3 + Programming Language :: Python :: 3 :: Only + +[options] +packages = find_namespace: +include_package_data = true +python_requires = >=3.8 +install_requires = + +[options.packages.find] +exclude = + build* + dist* + docs* + tests* + +[options.extras_require] +testing = + # upstream + pytest >= 6 + pytest-checkdocs >= 2.4 + pytest-black >= 0.3.7; \ + # workaround for jaraco/skeleton#22 + python_implementation != "PyPy" + pytest-cov + # disabled + #pytest-mypy >= 0.9.1; \ + # # workaround for jaraco/skeleton#22 + # python_implementation != "PyPy" + pytest-enabler >= 2.2 + pytest-ruff + + # local + pytest >= 7.4.3 #186 + jaraco.envs>=2.4 + jaraco.path + jaraco.text + path + docutils + pyfakefs + more_itertools + +docs = + # upstream + sphinx >= 3.5 + # workaround for sphinx/sphinx-doc#11662 + sphinx < 7.2.5 + jaraco.packaging >= 9.3 + rst.linker >= 1.9 + furo + sphinx-lint + + # local + +[options.entry_points] diff --git a/towncrier.toml b/towncrier.toml new file mode 100644 index 00000000..6fa480e4 --- /dev/null +++ b/towncrier.toml @@ -0,0 +1,2 @@ +[tool.towncrier] +title_format = "{version}" diff --git a/tox.ini b/tox.ini index 6a224b52..f2b0cbf4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,33 +1,62 @@ -[tox] -minversion = 3.25 -toxworkdir={env:TOX_WORK_DIR:.tox} - - [testenv] +description = perform primary checks (tests, style, types, coverage) deps = - pytest \ - # required for #186 - >= 7.4.3 +setenv = + PYTHONWARNDEFAULTENCODING = 1 + # pypa/distutils#99 + VIRTUALENV_NO_SETUPTOOLS = 1 +commands = + pytest {posargs} +usedevelop = True +extras = + testing - pytest-flake8 - # workaround for tholo/pytest-flake8#87 - flake8 < 5 +[testenv:diffcov] +description = run tests and check that diff from main is covered +deps = + diff-cover +commands = + pytest {posargs} --cov-report xml + diff-cover coverage.xml --compare-branch=origin/main --html-report diffcov.html + diff-cover coverage.xml --compare-branch=origin/main --fail-under=100 - pytest-black - pytest-cov - pytest-enabler >= 1.3 +[testenv:docs] +description = build the documentation +extras = + docs + testing +changedir = docs +commands = + python -m sphinx -W --keep-going . {toxinidir}/build/html + python -m sphinxlint \ + # workaround for sphinx-contrib/sphinx-lint#83 + --jobs 1 - jaraco.envs>=2.4 - jaraco.path - jaraco.text - path - docutils - pyfakefs - more_itertools +[testenv:finalize] +description = assemble changelog and tag a release +skip_install = True +deps = + towncrier + jaraco.develop >= 7.23 +pass_env = * commands = - pytest {posargs} -setenv = - PYTHONPATH = {toxinidir} - # pypa/distutils#99 - VIRTUALENV_NO_SETUPTOOLS = 1 + python -m jaraco.develop.finalize + + +[testenv:release] +description = publish the package to PyPI and GitHub skip_install = True +deps = + build + twine>=3 + jaraco.develop>=7.1 +pass_env = + TWINE_PASSWORD + GITHUB_TOKEN +setenv = + TWINE_USERNAME = {env:TWINE_USERNAME:__token__} +commands = + python -c "import shutil; shutil.rmtree('dist', ignore_errors=True)" + python -m build + python -m twine upload dist/* + python -m jaraco.develop.create-github-release