Skip to content

Commit 2498dd4

Browse files
authored
Switch project setup to pyproject.toml (#123)
Since we're hiring a new Python engineer hopefully soon, I thought it's time to get rid of some tech debt. This rewrites the project setup to use `pyproject.toml` instead of `setup.py`, as `pyproject.toml` is the modern, recommended way to specify project metadata, and `setup.py` is being deprecated. I've also updated the publication to PyPI to use the official GitHub action, and to use OIDC for authentication instead of an API token.
1 parent 9d7f405 commit 2498dd4

File tree

14 files changed

+134
-133
lines changed

14 files changed

+134
-133
lines changed

.flake8

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ filename =
33
./docs/*.py,
44
./scripts/*.py,
55
./src/*.py,
6-
./tests/*.py,
7-
./setup.py
6+
./tests/*.py
87
per-file-ignores =
98
docs/*: D
109
scripts/*: D

.github/workflows/release.yaml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,16 @@ jobs:
4141
name: Check whether the documentation is up to date
4242
uses: ./.github/workflows/check_docs.yaml
4343

44-
deploy:
44+
publish_to_pypi:
4545
name: Publish to PyPI
4646
needs: [lint_and_type_checks, unit_tests, integration_tests, check_docs]
4747
runs-on: ubuntu-latest
48+
permissions:
49+
contents: write
50+
id-token: write
51+
environment:
52+
name: pypi
53+
url: https://pypi.org/p/apify-client
4854

4955
steps:
5056
- name: Checkout repository
@@ -56,9 +62,7 @@ jobs:
5662
python-version: 3.8
5763

5864
- name: Install dependencies
59-
run: |
60-
python -m pip install --upgrade pip
61-
pip install --upgrade setuptools twine wheel
65+
run: make install-dev
6266

6367
- # Determine if this is a prerelease or latest release
6468
name: Determine release type
@@ -86,7 +90,7 @@ jobs:
8690
- # Check whether the released version is listed in CHANGELOG.md
8791
name: Check whether the released version is listed in the changelog
8892
if: steps.get-release-type.outputs.release_type != 'alpha'
89-
run: python ./scripts/check_version_in_changelog.py
93+
run: make check-changelog-entry
9094

9195
- # Check version consistency and increment pre-release version number for prereleases (must be the last step before build)
9296
name: Bump pre-release version
@@ -95,18 +99,15 @@ jobs:
9599

96100
- # Build a source distribution and a python3-only wheel
97101
name: Build distribution files
98-
run: python setup.py sdist bdist_wheel
102+
run: make build
99103

100104
- # Check whether the package description will render correctly on PyPI
101105
name: Check package rendering on PyPI
102-
run: python -m twine check dist/*
106+
run: make twine-check
103107

104108
- # Publish package to PyPI using their official GitHub action
105109
name: Publish package to PyPI
106-
run: python -m twine upload --non-interactive --disable-progress-bar dist/*
107-
env:
108-
TWINE_USERNAME: __token__
109-
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
110+
uses: pypa/gh-action-pypi-publish@release/v1
110111

111112
- # Tag the current commit with the version tag if this is not made from the release event (releases are tagged with the release process)
112113
name: Tag Version

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ Changelog
77

88
- added support for `is_status_message_terminal` flag in Actor run status message update
99

10+
### Internal changes
11+
12+
- switched from `setup.py` to `pyproject.toml` for specifying project setup
13+
1014
[1.0.0](../../releases/tag/v1.0.0) - 2023-03-13
1115
-----------------------------------------------
1216

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,18 @@ clean:
88

99
install-dev:
1010
python -m pip install --upgrade pip
11-
pip install --upgrade setuptools wheel
1211
pip install --no-cache-dir -e ".[dev]"
1312
pre-commit install
1413

14+
build:
15+
python -m build
16+
17+
publish:
18+
python -m twine upload dist/*
19+
20+
twine-check:
21+
python -m twine check dist/*
22+
1523
lint:
1624
python3 -m flake8
1725

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ To generate the documentation, just run `make docs`.
6161

6262
Publishing new versions to [PyPI](https://pypi.org/project/apify-client) happens automatically through GitHub Actions.
6363

64-
On each commit to the `master` branch, a new beta release is published, taking the version number from `src/apify_client/_version.py`
64+
On each commit to the `master` branch, a new beta release is published, taking the version number from `pyproject.toml`
6565
and automatically incrementing the beta version suffix by 1 from the last beta release published to PyPI.
6666

67-
A stable version is published when a new release is created using GitHub Releases, again taking the version number from `src/apify_client/_version.py`. The built package assets are automatically uploaded to the GitHub release.
67+
A stable version is published when a new release is created using GitHub Releases, again taking the version number from `pyproject.toml`. The built package assets are automatically uploaded to the GitHub release.
6868

69-
If there is already a stable version with the same version number as in `src/apify_client/_version.py` published to PyPI, the publish process fails,
69+
If there is already a stable version with the same version number as in `pyproject.toml` published to PyPI, the publish process fails,
7070
so don't forget to update the version number before releasing a new version.
7171
The release process also fails when the released version is not described in `CHANGELOG.md`,
7272
so don't forget to describe the changes in the new version there.

mypy.ini

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ files =
44
docs,
55
scripts,
66
src,
7-
tests,
8-
setup.py
7+
tests
98
check_untyped_defs = True
109
disallow_incomplete_defs = True
1110
disallow_untyped_calls = True

pyproject.toml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
[project]
2+
name = "apify_client"
3+
version = "1.1.0"
4+
description = "Apify API client for Python"
5+
readme = "README.md"
6+
license = {text = "Apache Software License"}
7+
authors = [
8+
{name = "Apify Technologies s.r.o.", email = "[email protected]" }
9+
]
10+
keywords = ["apify", "api", "client", "scraping", "automation"]
11+
12+
classifiers = [
13+
"Development Status :: 5 - Production/Stable",
14+
"Intended Audience :: Developers",
15+
"License :: OSI Approved :: Apache Software License",
16+
"Operating System :: OS Independent",
17+
"Programming Language :: Python :: 3.8",
18+
"Programming Language :: Python :: 3.9",
19+
"Programming Language :: Python :: 3.10",
20+
"Programming Language :: Python :: 3.11",
21+
"Topic :: Software Development :: Libraries",
22+
]
23+
24+
requires-python = ">=3.8"
25+
dependencies = [
26+
"httpx ~= 0.24.0"
27+
]
28+
29+
[project.optional-dependencies]
30+
dev = [
31+
"autopep8 ~= 2.0.2",
32+
"build ~= 0.10.0",
33+
"flake8 ~= 6.0.0",
34+
"flake8-bugbear ~= 23.3.23",
35+
"flake8-commas ~= 2.1.0",
36+
"flake8-comprehensions ~= 3.12.0",
37+
"flake8-datetimez ~= 20.10.0",
38+
"flake8-docstrings ~= 1.7.0",
39+
"flake8-isort ~= 6.0.0",
40+
"flake8-noqa ~= 1.3.1",
41+
"flake8-pytest-style ~= 1.7.2",
42+
"flake8-quotes ~= 3.3.2",
43+
"flake8-unused-arguments ~= 0.0.13",
44+
"isort ~= 5.12.0",
45+
"mypy ~= 1.2.0",
46+
"pep8-naming ~= 0.13.3",
47+
"pre-commit ~= 3.3.1",
48+
"pytest ~= 7.3.1",
49+
"pytest-asyncio ~= 0.21.0",
50+
"pytest-only ~= 2.0.0",
51+
"pytest-randomly ~= 3.12.0",
52+
"pytest-timeout ~= 2.1.0",
53+
"pytest-xdist ~= 3.2.1",
54+
"redbaron ~= 0.9.2",
55+
"sphinx ~= 6.1.3",
56+
"sphinx-autodoc-typehints ~= 1.22",
57+
"sphinx-markdown-builder == 0.5.4",
58+
"twine ~= 4.0.2",
59+
]
60+
61+
[project.urls]
62+
"Homepage" = "https://docs.apify.com/api/client/python/"
63+
"Documentation" = "https://docs.apify.com/api/client/python/"
64+
"Source" = "https://github.com/apify/apify-client-python"
65+
"Issue tracker" = "https://github.com/apify/apify-client-python/issues"
66+
"Apify Homepage" = "https://apify.com"
67+
68+
[build-system]
69+
requires = ["setuptools>=64.0.0", "wheel"]
70+
build-backend = "setuptools.build_meta"
71+
72+
[tool.setuptools.packages.find]
73+
where = ["src"]
74+
include = ["apify_client"]
75+
76+
[tool.setuptools.package-data]
77+
apify_client = ["py.typed"]

scripts/print_current_package_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
from utils import get_current_package_version
44

5-
# Print the current package version from the src/package_name/_version.py file to stdout
5+
# Print the current package version from the pyproject.toml file to stdout
66
if __name__ == '__main__':
77
print(get_current_package_version(), end='')

scripts/update_version_for_prerelease.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from utils import PACKAGE_NAME, get_current_package_version, set_current_package_version
99

1010
# Checks whether the current package version number was not already used in a published release,
11-
# and if not, modifies the package version number in src/package_name/_version.py
11+
# and if not, modifies the package version number in pyproject.toml
1212
# from a stable release version (X.Y.Z) to a prerelease version (X.Y.ZbN or X.Y.Z.aN or X.Y.Z.rcN)
1313
if __name__ == '__main__':
1414
if len(sys.argv) != 2:
@@ -55,6 +55,6 @@
5555
if prerelease_version > latest_prerelease:
5656
latest_prerelease = prerelease_version
5757

58-
# Write the latest prerelease version number to src/package_name/_version.py
58+
# Write the latest prerelease version number to pyproject.toml
5959
new_prerelease_version_number = f'{current_version}{prerelease_prefix}{latest_prerelease + 1}'
6060
set_current_package_version(new_prerelease_version_number)

scripts/utils.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,40 @@
33

44
PACKAGE_NAME = 'apify_client'
55
REPO_ROOT = pathlib.Path(__file__).parent.resolve() / '..'
6-
VERSION_FILE_PATH = REPO_ROOT / f'src/{PACKAGE_NAME}/_version.py'
6+
PYPROJECT_TOML_FILE_PATH = REPO_ROOT / 'pyproject.toml'
77

88

9-
# Load the current version number from src/package_name/_version.py
10-
# It is on a line in the format __version__ = 1.2.3
9+
# Load the current version number from pyproject.toml
10+
# It is on a line in the format `version = "1.2.3"`
1111
def get_current_package_version() -> str:
12-
with open(VERSION_FILE_PATH, 'r') as version_file:
13-
for line in version_file:
14-
if line.startswith('__version__'):
12+
with open(PYPROJECT_TOML_FILE_PATH, 'r') as pyproject_toml_file:
13+
for line in pyproject_toml_file:
14+
if line.startswith('version = '):
1515
delim = '"' if '"' in line else "'"
1616
version = line.split(delim)[1]
1717
return version
1818
else:
1919
raise RuntimeError('Unable to find version string.')
2020

2121

22-
# Write the given version number from src/package_name/_version.py
23-
# It replaces the version number on the line with the format __version__ = 1.2.3
22+
# Write the given version number from pyproject.toml
23+
# It replaces the version number on the line with the format `version = "1.2.3"`
2424
def set_current_package_version(version: str) -> None:
25-
with open(VERSION_FILE_PATH, 'r+') as version_file:
26-
updated_version_file_lines = []
25+
with open(PYPROJECT_TOML_FILE_PATH, 'r+') as pyproject_toml_file:
26+
updated_pyproject_toml_file_lines = []
2727
version_string_found = False
28-
for line in version_file:
29-
if line.startswith('__version__'):
28+
for line in pyproject_toml_file:
29+
if line.startswith('version = '):
3030
version_string_found = True
31-
line = f"__version__ = '{version}'"
32-
updated_version_file_lines.append(line)
31+
line = f'version = "{version}"'
32+
updated_pyproject_toml_file_lines.append(line)
3333

3434
if not version_string_found:
3535
raise RuntimeError('Unable to find version string.')
3636

37-
version_file.seek(0)
38-
version_file.write('\n'.join(updated_version_file_lines))
39-
version_file.truncate()
37+
pyproject_toml_file.seek(0)
38+
pyproject_toml_file.write('\n'.join(updated_pyproject_toml_file_lines))
39+
pyproject_toml_file.truncate()
4040

4141

4242
# Generate convert a docstring from a sync resource client method

0 commit comments

Comments
 (0)