Skip to content

Commit

Permalink
Switch build backend to Hatchling (#3233)
Browse files Browse the repository at this point in the history
This implements PEP 621, obviating the need for `setup.py`, `setup.cfg`,
and `MANIFEST.in`. The build backend Hatchling (of which I am a
maintainer in the PyPA) is now used as that is the default in the
official Python packaging tutorial. Hatchling is available on all the
major distribution channels such as Debian, Fedora, and many more.

## Python support

The earliest supported Python 3 version of Hatchling is 3.7, therefore
I've also set that as the minimum here. Python 3.6 is EOL and other
build backends like flit-core and setuptools also dropped support.
Python 3.6 accounted for 3-4% of downloads in the last month.

## Plugins 

Configuration is now completely static with the help of 3 plugins:

### Readme

hynek's hatch-fancy-pypi-readme allows for the dynamic construction of
the readme which was previously coded up in `setup.py`. Now it's simply:

```toml
[tool.hatch.metadata.hooks.fancy-pypi-readme]
content-type = "text/markdown"
fragments = [
  { path = "README.md" },
  { path = "CHANGES.md" },
]
```

### Versioning

hatch-vcs is currently just a wrapper around setuptools-scm (which
despite the legacy naming is actually now decoupled from setuptools):

```toml
[tool.hatch.version]
source = "vcs"

[tool.hatch.build.hooks.vcs]
version-file = "src/_black_version.py"
template = '''
version = "{version}"
'''
```

### mypyc

hatch-mypyc offers many benefits over the existing approach:

- No need to manually select files for inclusion
- Avoids the need for the current CI workaround for mypyc/mypyc#946
- Intermediate artifacts (like `build/`) from setuptools and mypyc
  itself no longer clutter the project directory
- Runtime dependencies required at build time no longer need to be
  manually redeclared as this is a built-in option of Hatchling

Co-authored-by: Richard Si <63936253+ichard26@users.noreply.github.com>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
  • Loading branch information
3 people committed Sep 25, 2022
1 parent 4b4680a commit 468ceaf
Show file tree
Hide file tree
Showing 13 changed files with 140 additions and 195 deletions.
14 changes: 0 additions & 14 deletions .github/mypyc-requirements.txt

This file was deleted.

12 changes: 5 additions & 7 deletions .github/workflows/diff_shades.yml
Expand Up @@ -3,10 +3,10 @@ name: diff-shades
on:
push:
branches: [main]
paths: ["src/**", "setup.*", "pyproject.toml", ".github/workflows/*"]
paths: ["src/**", "pyproject.toml", ".github/workflows/*"]

pull_request:
paths: ["src/**", "setup.*", "pyproject.toml", ".github/workflows/*"]
paths: ["src/**", "pyproject.toml", ".github/workflows/*"]

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
Expand Down Expand Up @@ -41,6 +41,7 @@ jobs:
needs: configure
runs-on: ubuntu-latest
env:
HATCH_BUILD_HOOKS_ENABLE: "1"
# Clang is less picky with the C code it's given than gcc (and may
# generate faster binaries too).
CC: clang-12
Expand All @@ -64,7 +65,6 @@ jobs:
run: |
python -m pip install https://github.com/ichard26/diff-shades/archive/stable.zip
python -m pip install click packaging urllib3
python -m pip install -r .github/mypyc-requirements.txt
# After checking out old revisions, this might not exist so we'll use a copy.
cat scripts/diff_shades_gha_helper.py > helper.py
git config user.name "diff-shades-gha"
Expand All @@ -83,8 +83,7 @@ jobs:
GITHUB_TOKEN: ${{ github.token }}
run: >
${{ matrix.baseline-setup-cmd }}
&& python setup.py --use-mypyc bdist_wheel
&& python -m pip install dist/*.whl && rm build dist -r
&& python -m pip install .
- name: Analyze baseline revision
if: steps.baseline-cache.outputs.cache-hit != 'true'
Expand All @@ -97,8 +96,7 @@ jobs:
GITHUB_TOKEN: ${{ github.token }}
run: >
${{ matrix.target-setup-cmd }}
&& python setup.py --use-mypyc bdist_wheel
&& python -m pip install dist/*.whl
&& python -m pip install .
- name: Analyze target revision
run: >
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/fuzz.yml
Expand Up @@ -22,7 +22,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
python-version: ["3.7", "3.8", "3.9", "3.10"]

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/pypi_upload.yml
Expand Up @@ -61,8 +61,6 @@ jobs:
uses: pypa/cibuildwheel@v2.10.0
env:
CIBW_ARCHS_MACOS: "${{ matrix.macos_arch }}"
# This isn't supported in pyproject.toml which makes sense (but is annoying).
CIBW_PROJECT_REQUIRES_PYTHON: ">=3.6.2"

- name: Upload wheels as workflow artifacts
uses: actions/upload-artifact@v2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Expand Up @@ -31,7 +31,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "pypy-3.7", "pypy-3.8"]
python-version: ["3.7", "3.8", "3.9", "3.10", "pypy-3.7", "pypy-3.8"]
os: [ubuntu-latest, macOS-latest, windows-latest]

steps:
Expand Down
5 changes: 5 additions & 0 deletions CHANGES.md
Expand Up @@ -6,6 +6,9 @@

<!-- Include any especially major or disruptive changes here -->

- Runtime support for Python 3.6 has been removed. Formatting 3.6 code will still be
supported until further notice.

### Stable style

<!-- Changes that affect Black's stable style -->
Expand All @@ -28,6 +31,8 @@

<!-- Changes to how Black is packaged, such as dependency requirements -->

- Hatchling is now used as the build backend. This will not have any effect for users
who install Black with its wheels from PyPI. (#3233)
- Faster compiled wheels are now available for CPython 3.11 (#3276)

### Parser
Expand Down
1 change: 0 additions & 1 deletion MANIFEST.in

This file was deleted.

6 changes: 4 additions & 2 deletions docs/faq.md
Expand Up @@ -86,15 +86,17 @@ disabled-by-default counterpart W504. E203 should be disabled while changes are

## Which Python versions does Black support?

Currently the runtime requires Python 3.6-3.10. Formatting is supported for files
containing syntax from Python 3.3 to 3.10. We promise to support at least all Python
Currently the runtime requires Python 3.7-3.11. Formatting is supported for files
containing syntax from Python 3.3 to 3.11. We promise to support at least all Python
versions that have not reached their end of life. This is the case for both running
_Black_ and formatting code.

Support for formatting Python 2 code was removed in version 22.0. While we've made no
plans to stop supporting older Python 3 minor versions immediately, their support might
also be removed some time in the future without a deprecation period.

Runtime support for 3.6 was removed in version 22.9.0.

## Why does my linter or typechecker complain after I format my code?

Some linters and other tools use magical comments (e.g., `# noqa`, `# type: ignore`) to
Expand Down
7 changes: 4 additions & 3 deletions docs/usage_and_configuration/the_basics.md
Expand Up @@ -204,9 +204,10 @@ code in compliance with many other _Black_ formatted projects.

[PEP 518](https://www.python.org/dev/peps/pep-0518/) defines `pyproject.toml` as a
configuration file to store build system requirements for Python projects. With the help
of tools like [Poetry](https://python-poetry.org/) or
[Flit](https://flit.readthedocs.io/en/latest/) it can fully replace the need for
`setup.py` and `setup.cfg` files.
of tools like [Poetry](https://python-poetry.org/),
[Flit](https://flit.readthedocs.io/en/latest/), or
[Hatch](https://hatch.pypa.io/latest/) it can fully replace the need for `setup.py` and
`setup.cfg` files.

### Where _Black_ looks for the file

Expand Down
135 changes: 117 additions & 18 deletions pyproject.toml
Expand Up @@ -7,7 +7,7 @@

[tool.black]
line-length = 88
target-version = ['py36', 'py37', 'py38']
target-version = ['py37', 'py38']
include = '\.pyi?$'
extend-exclude = '''
/(
Expand All @@ -26,18 +26,128 @@ preview = true
# NOTE: You don't need this in your own Black configuration.

[build-system]
requires = ["setuptools>=45.0", "setuptools_scm[toml]>=6.3.1", "wheel"]
build-backend = "setuptools.build_meta"
requires = ["hatchling>=1.8.0", "hatch-vcs", "hatch-fancy-pypi-readme"]
build-backend = "hatchling.build"

[project]
name = "black"
description = "The uncompromising code formatter."
license = "MIT"
requires-python = ">=3.7"
authors = [
{ name = "Łukasz Langa", email = "lukasz@langa.pl" },
]
keywords = [
"automation",
"autopep8",
"formatter",
"gofmt",
"pyfmt",
"rustfmt",
"yapf",
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"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",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance",
]
dependencies = [
"click>=8.0.0",
"mypy_extensions>=0.4.3",
"pathspec>=0.9.0",
"platformdirs>=2",
"tomli>=1.1.0; python_full_version < '3.11.0a7'",
"typed-ast>=1.4.2; python_version < '3.8' and implementation_name == 'cpython'",
"typing_extensions>=3.10.0.0; python_version < '3.10'",
]
dynamic = ["readme", "version"]

[project.optional-dependencies]
colorama = ["colorama>=0.4.3"]
uvloop = ["uvloop>=0.15.2"]
d = [
"aiohttp>=3.7.4",
]
jupyter = [
"ipython>=7.8.0",
"tokenize-rt>=3.2.0",
]

[project.scripts]
black = "black:patched_main"
blackd = "blackd:patched_main [d]"

[project.urls]
Changelog = "https://github.com/psf/black/blob/main/CHANGES.md"
Homepage = "https://github.com/psf/black"

[tool.hatch.metadata.hooks.fancy-pypi-readme]
content-type = "text/markdown"
fragments = [
{ path = "README.md" },
{ path = "CHANGES.md" },
]

[tool.hatch.version]
source = "vcs"

[tool.hatch.build.hooks.vcs]
version-file = "src/_black_version.py"
template = '''
version = "{version}"
'''

[tool.hatch.build.targets.sdist]
exclude = ["/profiling"]

[tool.hatch.build.targets.wheel]
only-include = ["src"]
sources = ["src"]

[tool.hatch.build.targets.wheel.hooks.mypyc]
enable-by-default = false
dependencies = [
"hatch-mypyc>=0.13.0",
"mypy==0.971",
# Required stubs to be removed when the packages support PEP 561 themselves
"types-typed-ast>=1.4.2",
]
require-runtime-dependencies = true
exclude = [
# There's no good reason for blackd to be compiled.
"/src/blackd",
# Not performance sensitive, so save bytes + compilation time:
"/src/blib2to3/__init__.py",
"/src/blib2to3/pgen2/__init__.py",
"/src/black/output.py",
"/src/black/concurrency.py",
"/src/black/files.py",
"/src/black/report.py",
# Breaks the test suite when compiled (and is also useless):
"/src/black/debug.py",
# Compiled modules can't be run directly and that's a problem here:
"/src/black/__main__.py",
]
options = { debug_level = "0" }

[tool.cibuildwheel]
build-verbosity = 1
# So these are the environments we target:
# - Python: CPython 3.6+ only
# - Python: CPython 3.7+ only
# - Architecture (64-bit only): amd64 / x86_64, universal2, and arm64
# - OS: Linux (no musl), Windows, and macOS
build = "cp3*-*"
skip = ["*-manylinux_i686", "*-musllinux_*", "*-win32", "pp-*"]
before-build = ["pip install -r .github/mypyc-requirements.txt"]
# This is the bare minimum needed to run the test suite. Pulling in the full
# test_requirements.txt would download a bunch of other packages not necessary
# here and would slow down the testing step a fair bit.
Expand All @@ -49,7 +159,7 @@ test-extras = ["d"," jupyter"]
test-skip = ["*-macosx_arm64", "*-macosx_universal2:arm64"]

[tool.cibuildwheel.environment]
BLACK_USE_MYPYC = "1"
HATCH_BUILD_HOOKS_ENABLE = "1"
MYPYC_OPT_LEVEL = "3"
MYPYC_DEBUG_LEVEL = "0"
# The dependencies required to build wheels with mypyc aren't specified in
Expand All @@ -61,28 +171,17 @@ AIOHTTP_NO_EXTENSIONS = "1"

[tool.cibuildwheel.linux]
before-build = [
"pip install -r .github/mypyc-requirements.txt",
"yum install -y clang gcc",
]

[tool.cibuildwheel.linux.environment]
BLACK_USE_MYPYC = "1"
HATCH_BUILD_HOOKS_ENABLE = "1"
MYPYC_OPT_LEVEL = "3"
MYPYC_DEBUG_LEVEL = "0"
PIP_NO_BUILD_ISOLATION = "no"
# Black needs Clang to compile successfully on Linux.
CC = "clang"
AIOHTTP_NO_EXTENSIONS = "1"

[tool.cibuildwheel.windows]
# For some reason, (compiled) mypyc is failing to start up with "ImportError: DLL load
# failed: A dynamic link library (DLL) initialization routine failed." on Windows for
# at least 3.6. Let's just use interpreted mypy[c].
# See also: https://github.com/mypyc/mypyc/issues/819.
before-build = [
"pip install -r .github/mypyc-requirements.txt --no-binary mypy"
]

[tool.isort]
atomic = true
profile = "black"
Expand Down
3 changes: 0 additions & 3 deletions setup.cfg

This file was deleted.

0 comments on commit 468ceaf

Please sign in to comment.