Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use setuptools_scm for dynamic versioning #7627

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion .ci/build.sh
Expand Up @@ -6,5 +6,4 @@ python3 -m coverage erase
if [ $(uname) == "Darwin" ]; then
export CPPFLAGS="-I/usr/local/miniconda/include";
fi
make clean
make install-coverage
3 changes: 3 additions & 0 deletions .github/workflows/test-cygwin.yml
Expand Up @@ -47,6 +47,8 @@ jobs:

- name: Checkout Pillow
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install Cygwin
uses: cygwin/cygwin-install-action@v4
Expand All @@ -55,6 +57,7 @@ jobs:
packages: >
gcc-g++
ghostscript
git
ImageMagick
jpeg
libfreetype-devel
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test-docker.yml
Expand Up @@ -70,6 +70,8 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Build system information
run: python3 .github/workflows/system-info.py
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/test-mingw.yml
Expand Up @@ -45,6 +45,8 @@ jobs:
steps:
- name: Checkout Pillow
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up shell
run: echo "C:\msys64\usr\bin\" >> $env:GITHUB_PATH
Expand All @@ -63,12 +65,13 @@ jobs:
mingw-w64-x86_64-libtiff \
mingw-w64-x86_64-libwebp \
mingw-w64-x86_64-openjpeg2 \
mingw-w64-x86_64-python-pyqt6 \
mingw-w64-x86_64-python3-cffi \
mingw-w64-x86_64-python3-numpy \
mingw-w64-x86_64-python3-olefile \
mingw-w64-x86_64-python3-pip \
mingw-w64-x86_64-python3-setuptools \
mingw-w64-x86_64-python-pyqt6
mingw-w64-x86_64-tools-git

python3 -m pip install pyroma pytest pytest-cov pytest-timeout

Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test-valgrind.yml
Expand Up @@ -40,6 +40,8 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Build system information
run: python3 .github/workflows/system-info.py
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test-windows.yml
Expand Up @@ -41,6 +41,8 @@ jobs:
steps:
- name: Checkout Pillow
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Checkout cached dependencies
uses: actions/checkout@v4
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Expand Up @@ -60,6 +60,8 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -92,3 +92,6 @@ Tests/images/sunraster

# pyinstaller
*.spec

# Generated by setuptools_scm
src/PIL/_version.py
5 changes: 5 additions & 0 deletions pyproject.toml
Expand Up @@ -2,6 +2,7 @@
build-backend = "backend"
requires = [
"setuptools>=67.8",
"setuptools_scm>=8",
]
backend-path = [
"_custom_build",
Expand Down Expand Up @@ -86,6 +87,10 @@ package-dir = {"" = "src"}
[tool.setuptools.dynamic]
version = {attr = "PIL.__version__"}

[tool.setuptools_scm]
local_scheme = "no-local-version"
version_file = "src/PIL/_version.py"

[tool.cibuildwheel]
before-all = ".github/workflows/wheels-dependencies.sh"
build-verbosity = 1
Expand Down
8 changes: 4 additions & 4 deletions setup.py
Expand Up @@ -7,6 +7,7 @@
# Final rating: 10/10
# Your cheese is so fresh most people think it's a cream: Mascarpone
# ------------------------------
from __future__ import annotations

import os
import re
Expand All @@ -27,7 +28,6 @@ def get_version():
return locals()["__version__"]


PILLOW_VERSION = get_version()
FREETYPE_ROOT = None
HARFBUZZ_ROOT = None
FRIBIDI_ROOT = None
Expand All @@ -44,7 +44,7 @@ def get_version():

atexit.register(
lambda: warnings.warn(
f"Pillow {PILLOW_VERSION} does not support Python "
f"Pillow {get_version()} does not support Python "
f"{sys.version_info.major}.{sys.version_info.minor} and does not provide "
"prebuilt Windows binaries. We do not recommend building from source on "
"Windows.",
Expand Down Expand Up @@ -847,7 +847,7 @@ def build_extensions(self):
if struct.unpack("h", b"\0\1")[0] == 1:
defs.append(("WORDS_BIGENDIAN", None))

defs.append(("PILLOW_VERSION", f'"{PILLOW_VERSION}"'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comment considering this is still in progress: I don't see why it is necessary to remove PILLOW_VERSION as a Python variable - we're still defining PILLOW_VERSION as the same value for C, so I don't see the change as creating any distinction in meaning.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When doing it globally we get aFileNotFoundError: [Errno 2] No such file or directory: 'src/PIL/_version.py', I presume because when opening setup.py to begin the build, the build hasn't had a chance to generate the file yet.

Details
❯ pip install -e .
Found existing alias for "pip install -e .". You should use: "pie"
Obtaining file:///Users/hugo/github/Pillow
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... error
  error: subprocess-exited-with-error

  × Getting requirements to build editable did not run successfully.
  │ exit code: 1
  ╰─> [22 lines of output]
      Traceback (most recent call last):
        File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 353, in <module>
          main()
        File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 335, in main
          json_out['return_val'] = hook(**hook_input['kwargs'])
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 132, in get_requires_for_build_editable
          return hook(config_settings)
                 ^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/p6/lf2s1s5d4kb335g2n1td8z8c0000gn/T/pip-build-env-5qxfgm5i/overlay/lib/python3.12/site-packages/setuptools/build_meta.py", line 441, in get_requires_for_build_editable
          return self.get_requires_for_build_wheel(config_settings)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/p6/lf2s1s5d4kb335g2n1td8z8c0000gn/T/pip-build-env-5qxfgm5i/overlay/lib/python3.12/site-packages/setuptools/build_meta.py", line 325, in get_requires_for_build_wheel
          return self._get_build_requires(config_settings, requirements=['wheel'])
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/p6/lf2s1s5d4kb335g2n1td8z8c0000gn/T/pip-build-env-5qxfgm5i/overlay/lib/python3.12/site-packages/setuptools/build_meta.py", line 295, in _get_build_requires
          self.run_setup()
        File "/private/var/folders/p6/lf2s1s5d4kb335g2n1td8z8c0000gn/T/pip-build-env-5qxfgm5i/overlay/lib/python3.12/site-packages/setuptools/build_meta.py", line 311, in run_setup
          exec(code, locals())
        File "<string>", line 31, in <module>
        File "<string>", line 26, in get_version
      FileNotFoundError: [Errno 2] No such file or directory: 'src/PIL/_version.py'
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
error: subprocess-exited-with-error

× Getting requirements to build editable did not run successfully.
│ exit code: 1
╰─> See above for output.

note: This error originates from a subprocess, and is likely not a problem with pip.

defs.append(("PILLOW_VERSION", f'"{get_version()}"'))

self._update_extension("PIL._imaging", libs, defs)

Expand Down Expand Up @@ -912,7 +912,7 @@ def summary_report(self, feature):
print("-" * 68)
print("PIL SETUP SUMMARY")
print("-" * 68)
print(f"version Pillow {PILLOW_VERSION}")
print(f"version Pillow {get_version()}")
v = sys.version.split("[")
print(f"platform {sys.platform} {v[0].strip()}")
for v in v[1:]:
Expand Down
6 changes: 5 additions & 1 deletion src/PIL/Image.py
Expand Up @@ -23,6 +23,7 @@
#
# See the README file for information on usage and redistribution.
#
from __future__ import annotations

import atexit
import builtins
Expand Down Expand Up @@ -81,7 +82,10 @@ class DecompressionBombError(Exception):
# and should be considered private and subject to change.
from . import _imaging as core

if __version__ != getattr(core, "PILLOW_VERSION", None):
# if __version__ != getattr(core, "PILLOW_VERSION", None):
if not hasattr(core, "PILLOW_VERSION") or re.sub(
"dev[0-9]+", "dev0", __version__
) != re.sub("dev[0-9]+", "dev0", core.PILLOW_VERSION):
msg = (
"The _imaging extension was built for another version of Pillow or PIL:\n"
f"Core version: {getattr(core, 'PILLOW_VERSION', None)}\n"
Expand Down
2 changes: 0 additions & 2 deletions src/PIL/_version.py
Copy link

@webknjaz webknjaz Dec 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hugovk I recommend adding a src/PIL/_version.pyi file so that the type checkers wouldn't be confused with a missing import. Example: https://github.com/sphinx-contrib/sphinxcontrib-towncrier/blob/750485e/src/sphinxcontrib/towncrier/_scm_version.pyi.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The discussion to add that file began with sphinx-contrib/sphinxcontrib-towncrier#33 (comment), where you quoted an error. I'm guessing that error came from mypy?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

This file was deleted.