Skip to content

Commit

Permalink
feat: migrate from setuptools to hatch
Browse files Browse the repository at this point in the history
The official Python packaging guide recommends hatch over setuptools.
Beyond that official recommendation, getting rid of setuptools allows us
to resolve issue #956 on mypy-checking of plugins in editable mode.

Close #956.
  • Loading branch information
regisb committed Nov 22, 2024
1 parent 1a7c096 commit 6b1a8c9
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 105 deletions.
7 changes: 2 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,8 @@ jobs:
python-version: 3.9
cache: 'pip'
cache-dependency-path: requirements/dev.txt
- name: Upgrade pip and setuptools
# https://pypi.org/project/pip/
# https://pypi.org/project/setuptools/
# https://pypi.org/project/wheel/
run: python -m pip install --upgrade pip setuptools==65.6.3 wheel
- name: Install Hatch
uses: pypa/hatch@install
- name: Print info about the current python installation
run: make ci-info
- name: Install requirements
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ jobs:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: requirements/dev.txt
- name: Upgrade pip
run: python -m pip install --upgrade pip setuptools
- name: Install dependencies
run: pip install -r requirements/dev.txt
run: pip install -e .[dev]
- name: Static code analysis
run: make test-lint
- name: Python unit tests
Expand Down
37 changes: 37 additions & 0 deletions .hatch_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# https://hatch.pypa.io/latest/how-to/config/dynamic-metadata/
import os
import typing as t

from hatchling.metadata.plugin.interface import MetadataHookInterface

HERE = os.path.dirname(__file__)


class MetaDataHook(MetadataHookInterface):
def update(self, metadata: dict[str, t.Any]) -> None:
about = load_about()
metadata["version"] = about["__package_version__"]
metadata["dependencies"] = load_requirements("base.in")
metadata["optional-dependencies"] = {
"dev": load_requirements("dev.txt"),
"full": load_requirements("plugins.txt"),
}


def load_about() -> dict[str, str]:
about: dict[str, str] = {}
with open(os.path.join(HERE, "tutor", "__about__.py"), "rt", encoding="utf-8") as f:
exec(f.read(), about) # pylint: disable=exec-used
return about


def load_requirements(filename: str) -> list[str]:
requirements = []
with open(
os.path.join(HERE, "requirements", filename), "rt", encoding="utf-8"
) as f:
for line in f:
line = line.strip()
if line != "" and not line.startswith("#"):
requirements.append(line)
return requirements
5 changes: 0 additions & 5 deletions MANIFEST.in

This file was deleted.

8 changes: 3 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@ docs: ## Build HTML documentation
$(MAKE) -C docs

compile-requirements: ## Compile requirements files
pip-compile ${COMPILE_OPTS} --output-file=requirements/base.txt
pip-compile ${COMPILE_OPTS} requirements/base.in
pip-compile ${COMPILE_OPTS} requirements/dev.in
pip-compile ${COMPILE_OPTS} --extra=docs --output-file=requirements/docs.txt
pip-compile ${COMPILE_OPTS} requirements/docs.in

upgrade-requirements: ## Upgrade requirements files
$(MAKE) compile-requirements COMPILE_OPTS="--upgrade"

build-pythonpackage: build-pythonpackage-tutor ## Build Python packages ready to upload to pypi

build-pythonpackage-tutor: ## Build the "tutor" python package for upload to pypi
build-pythonpackage: ## Build the "tutor" python package for upload to pypi
python -m build --sdist

push-pythonpackage: ## Push python package to pypi
Expand Down
35 changes: 22 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# https://packaging.python.org/en/latest/tutorials/packaging-projects/
# https://setuptools.pypa.io/en/latest/userguide/quickstart.html
# https://hatch.pypa.io/latest/config/build/

[project]
dynamic = ["version", "dependencies", "optional-dependencies"]
name = "tutor"
license = {file = "LICENSE.txt"}
authors = [
Expand All @@ -22,6 +21,8 @@ classifiers = [
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
# these fields will be set by hatch_build.py
dynamic = ["version", "dependencies", "optional-dependencies"]

[project.scripts]
tutor = "tutor.commands.cli:main"
Expand All @@ -35,17 +36,25 @@ Issues = "https://github.com/overhangio/tutor/issues"
Changelog = "https://github.com/overhangio/tutor/blob/master/CHANGELOG.md"
Community = "https://discuss.openedx.org/tag/tutor"

# Setuptools-specific configuration
[build-system]
requires = ["setuptools", "wheel"]

[tool.setuptools.dynamic]
version = {attr = "tutor.__about__.__package_version__"}
dependencies = {file = ["requirements/base.in"] }
# hatch-specific configuration
[tool.hatch.metadata.hooks.custom]
path = ".hatch_build.py"

[tool.setuptools.dynamic.optional-dependencies]
dev = {file = ["requirements/dev.txt"]}
full = {file = ["requirements/plugins.txt"]}
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.setuptools.packages.find]
[tool.hatch.build.targets.sdist]
# Disable strict naming, otherwise twine is not able to detect name/version
strict-naming = false
include = [
"/tutor",
"requirements/base.in",
"requirements/plugins.txt",
"requirements/dev.txt",
]
exclude = ["tests*"]

[tool.hatch.metadata]
# Allow github dependencies in plugins.txt
allow-direct-references = true
26 changes: 13 additions & 13 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:
#
# pip-compile --output-file=requirements/base.txt
# pip-compile requirements/base.in
#
appdirs==1.4.4
# via tutor (pyproject.toml)
# via -r requirements/base.in
cachetools==5.5.0
# via google-auth
certifi==2024.8.30
Expand All @@ -15,47 +15,47 @@ certifi==2024.8.30
charset-normalizer==3.4.0
# via requests
click==8.1.7
# via tutor (pyproject.toml)
# via -r requirements/base.in
durationpy==0.9
# via kubernetes
google-auth==2.35.0
# via kubernetes
idna==3.10
# via requests
importlib-metadata==8.5.0
# via tutor (pyproject.toml)
# via -r requirements/base.in
importlib-resources==6.4.5
# via tutor (pyproject.toml)
# via -r requirements/base.in
jinja2==3.1.4
# via tutor (pyproject.toml)
# via -r requirements/base.in
kubernetes==31.0.0
# via tutor (pyproject.toml)
# via -r requirements/base.in
markupsafe==3.0.2
# via jinja2
mypy==1.13.0
# via tutor (pyproject.toml)
# via -r requirements/base.in
mypy-extensions==1.0.0
# via mypy
oauthlib==3.2.2
# via
# kubernetes
# requests-oauthlib
packaging==24.1
# via tutor (pyproject.toml)
packaging==24.2
# via -r requirements/base.in
pyasn1==0.6.1
# via
# pyasn1-modules
# rsa
pyasn1-modules==0.4.1
# via google-auth
pycryptodome==3.21.0
# via tutor (pyproject.toml)
# via -r requirements/base.in
python-dateutil==2.9.0.post0
# via kubernetes
pyyaml==6.0.2
# via
# -r requirements/base.in
# kubernetes
# tutor (pyproject.toml)
requests==2.32.3
# via
# kubernetes
Expand All @@ -70,8 +70,8 @@ six==1.16.0
# python-dateutil
typing-extensions==4.12.2
# via
# -r requirements/base.in
# mypy
# tutor (pyproject.toml)
urllib3==2.2.3
# via
# kubernetes
Expand Down
1 change: 0 additions & 1 deletion requirements/dev.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@ docutils<0.19.0
# Types packages
types-docutils
types-PyYAML
types-setuptools
43 changes: 15 additions & 28 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
#
# This file is autogenerated by pip-compile with Python 3.9
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:
#
# pip-compile requirements/dev.in
#
altgraph==0.17.4
# via
# macholib
# pyinstaller
# via pyinstaller
appdirs==1.4.4
# via -r requirements/base.txt
astroid==3.3.5
# via pylint
attrs==24.2.0
# via scriv
backports-tarfile==1.2.0
# via jaraco-context
black==24.10.0
# via -r requirements/dev.in
build==1.2.2.post1
Expand All @@ -29,6 +25,8 @@ certifi==2024.8.30
# -r requirements/base.txt
# kubernetes
# requests
cffi==1.17.1
# via cryptography
charset-normalizer==3.4.0
# via
# -r requirements/base.txt
Expand All @@ -44,6 +42,8 @@ click-log==0.4.0
# via scriv
coverage==7.6.4
# via -r requirements/dev.in
cryptography==43.0.3
# via secretstorage
dill==0.3.9
# via pylint
docutils==0.18.1
Expand All @@ -65,10 +65,6 @@ idna==3.10
importlib-metadata==8.5.0
# via
# -r requirements/base.txt
# build
# keyring
# pyinstaller
# pyinstaller-hooks-contrib
# twine
importlib-resources==6.4.5
# via -r requirements/base.txt
Expand All @@ -80,6 +76,10 @@ jaraco-context==6.0.1
# via keyring
jaraco-functools==4.1.0
# via keyring
jeepney==0.8.0
# via
# keyring
# secretstorage
jinja2==3.1.4
# via
# -r requirements/base.txt
Expand All @@ -88,8 +88,6 @@ keyring==25.5.0
# via twine
kubernetes==31.0.0
# via -r requirements/base.txt
macholib==1.16.3
# via pyinstaller
markdown-it-py==3.0.0
# via
# rich
Expand Down Expand Up @@ -120,7 +118,7 @@ oauthlib==3.2.2
# -r requirements/base.txt
# kubernetes
# requests-oauthlib
packaging==24.1
packaging==24.2
# via
# -r requirements/base.txt
# black
Expand All @@ -146,6 +144,8 @@ pyasn1-modules==0.4.1
# via
# -r requirements/base.txt
# google-auth
pycparser==2.22
# via cffi
pycryptodome==3.21.0
# via -r requirements/base.txt
pygments==2.18.0
Expand Down Expand Up @@ -196,19 +196,13 @@ rsa==4.9
# google-auth
scriv==1.5.1
# via -r requirements/dev.in
secretstorage==3.3.3
# via keyring
six==1.16.0
# via
# -r requirements/base.txt
# kubernetes
# python-dateutil
tomli==2.0.2
# via
# -r requirements/base.txt
# black
# build
# mypy
# pip-tools
# pylint
tomlkit==0.13.2
# via pylint
twine==5.1.1
Expand All @@ -217,16 +211,10 @@ types-docutils==0.21.0.20241005
# via -r requirements/dev.in
types-pyyaml==6.0.12.20240917
# via -r requirements/dev.in
types-setuptools==75.2.0.20241025
# via -r requirements/dev.in
typing-extensions==4.12.2
# via
# -r requirements/base.txt
# astroid
# black
# mypy
# pylint
# rich
urllib3==2.2.3
# via
# -r requirements/base.txt
Expand All @@ -243,7 +231,6 @@ zipp==3.20.2
# via
# -r requirements/base.txt
# importlib-metadata
# importlib-resources

# The following packages are considered to be unsafe in a requirements file:
# pip
Expand Down
Loading

0 comments on commit 6b1a8c9

Please sign in to comment.