From dadf22c1ce1501f8fef8d6f2adbf9f2eb9dd3eca Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Thu, 13 Jun 2024 15:04:35 -0500 Subject: [PATCH] PYTHON-4485 Use Hatch as Build Backend (#827) * PYTHON-4485 Use Hatch as Build Backend * lint * fix codeql * remove setup.py * rename test reqs * use fetch depth * fix benchmark * fix codeql --- .evergreen/benchmark-python.sh | 2 +- .github/workflows/codeql.yml | 6 ++- bindings/python/MANIFEST.in | 16 ------- bindings/python/build-manylinux-wheel.sh | 14 ++---- bindings/python/hatch_build.py | 36 +++++++++++++++ bindings/python/pymongocrypt/version.py | 2 +- bindings/python/pyproject.toml | 19 ++++---- bindings/python/release.sh | 2 +- ...requirements.txt => requirements-test.txt} | 0 bindings/python/setup.py | 46 ------------------- 10 files changed, 59 insertions(+), 84 deletions(-) delete mode 100644 bindings/python/MANIFEST.in create mode 100644 bindings/python/hatch_build.py rename bindings/python/{test-requirements.txt => requirements-test.txt} (100%) delete mode 100644 bindings/python/setup.py diff --git a/.evergreen/benchmark-python.sh b/.evergreen/benchmark-python.sh index 6c410c374..d44a7551c 100755 --- a/.evergreen/benchmark-python.sh +++ b/.evergreen/benchmark-python.sh @@ -24,7 +24,7 @@ cd bindings/python/ /opt/mongodbtoolchain/v4/bin/python3 -m venv venv . ./venv/bin/activate -python -m pip install --prefer-binary -r test-requirements.txt +python -m pip install --prefer-binary -r requirements-test.txt python -m pip install -e . export OUTPUT_FILE=results.json diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8154c15d4..91bcf73e7 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,7 +13,7 @@ on: jobs: analyze-python: name: Analyze Python - runs-on: "ubuntu-latest" + runs-on: "macos-latest" timeout-minutes: 360 permissions: # required for all workflows @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 - uses: actions/setup-python@v5 with: python-version: 3.x @@ -43,6 +45,8 @@ jobs: - name: Install package run: | cd bindings/python + export LIBMONGOCRYPT_VERSION=$(cat ./libmongocrypt-version.txt) + git fetch origin $LIBMONGOCRYPT_VERSION bash release.sh pip install dist/*.whl diff --git a/bindings/python/MANIFEST.in b/bindings/python/MANIFEST.in deleted file mode 100644 index 994cd2114..000000000 --- a/bindings/python/MANIFEST.in +++ /dev/null @@ -1,16 +0,0 @@ -include README.rst -include LICENSE -include pyproject.toml -include *requirements.txt -include sbom.json -include CHANGELOG.rst -recursive-include pymongocrypt *.py -recursive-include requirements *.txt -exclude build-manylinux-wheel.sh -exclude *.sh -exclude libmongocrypt-version.txt -exclude RELEASE.rst -exclude strip_header.py -exclude synchro.py -prune test -prune .evergreen diff --git a/bindings/python/build-manylinux-wheel.sh b/bindings/python/build-manylinux-wheel.sh index ee09bceb3..e93b55054 100755 --- a/bindings/python/build-manylinux-wheel.sh +++ b/bindings/python/build-manylinux-wheel.sh @@ -1,13 +1,7 @@ #!/bin/bash -ex cd /python -/opt/python/cp37-cp37m/bin/python -m build --wheel - -# Audit wheels and write manylinux tag -for whl in dist/*none-any.whl; do - # Skip already built manylinux wheels. - if [[ "$whl" != *"manylinux"* ]]; then - auditwheel repair $whl -w dist - rm $whl - fi -done +mkdir /tmp/wheelhouse +/opt/python/cp38-cp38/bin/python -m build --wheel --outdir /tmp/wheelhouse +# Audit wheels and repair manylinux tags +auditwheel repair /tmp/wheelhouse/*.whl -w dist diff --git a/bindings/python/hatch_build.py b/bindings/python/hatch_build.py new file mode 100644 index 000000000..1ea6c29cd --- /dev/null +++ b/bindings/python/hatch_build.py @@ -0,0 +1,36 @@ +"""A custom hatch build hook for pymongo.""" +from __future__ import annotations + +import os +import sys +from pathlib import Path + +from hatchling.builders.hooks.plugin.interface import BuildHookInterface + + +class CustomHook(BuildHookInterface): + """The pymongocrypt build hook.""" + + def initialize(self, version, build_data): + """Initialize the hook.""" + if self.target_name == "sdist": + return + + # Ensure wheel is marked as binary. + # On linux, we use auditwheel to set the name. + if sys.platform == "darwin": + os.environ["MACOSX_DEPLOYMENT_TARGET"] = "11.0" + build_data["tag"] = "py3-none-macosx_11_0_universal2" + patt = ".dylib" + elif os.name == "nt": + build_data["tag"] = "py3-none-win_amd64" + patt = ".dll" + else: + patt = ".so" + + here = Path(__file__).parent.resolve() + dpath = here / "pymongocrypt" + for fpath in dpath.glob(f"*{patt}"): + relpath = os.path.relpath(fpath, here) + build_data["artifacts"].append(relpath) + build_data["force_include"][relpath] = relpath diff --git a/bindings/python/pymongocrypt/version.py b/bindings/python/pymongocrypt/version.py index adde7c46c..9f1171f47 100644 --- a/bindings/python/pymongocrypt/version.py +++ b/bindings/python/pymongocrypt/version.py @@ -12,6 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "2.0.0.dev0" +__version__ = "1.10.0.dev0" _MIN_LIBMONGOCRYPT_VERSION = "1.8.0" diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 67d57f952..a4d8835e8 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -1,6 +1,6 @@ [build-system] -requires = ["setuptools>=63.0", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["hatchling>1.24","hatch-requirements-txt>=0.4.1"] +build-backend = "hatchling.build" [project] name = "pymongocrypt" @@ -42,14 +42,17 @@ classifiers = [ [project.urls] Homepage = "https://github.com/mongodb/libmongocrypt/tree/master/bindings/python" -[tool.setuptools.dynamic] -version = {attr = "pymongocrypt.version.__version__"} +[tool.hatch.version] +path = "pymongocrypt/version.py" -[tool.setuptools.packages.find] -include = ["pymongocrypt", "pymongocrypt.asynchronous", "pymongocrypt.synchronous"] +# Used to call hatch_build.py +[tool.hatch.build.hooks.custom] -[tool.setuptools.package-data] -pymongocrypt=['*.dll', '*.so', '*.dylib'] +[tool.hatch.metadata.hooks.requirements_txt] +files = ["requirements.txt"] + +[tool.hatch.metadata.hooks.requirements_txt.optional-dependencies] +test = ["requirements-test.txt"] [tool.ruff.lint] select = [ diff --git a/bindings/python/release.sh b/bindings/python/release.sh index 546c6a9e9..a48f24b65 100755 --- a/bindings/python/release.sh +++ b/bindings/python/release.sh @@ -117,7 +117,7 @@ if [ $(command -v docker) ]; then if [ "Linux" = "$(uname -s)" ]; then $PYTHON -m venv .venv . .venv/bin/activate - test_dist dist/*.whl + test_dist dist/*linux*.whl fi # Build the manylinux_2_28 aarch64 wheel. diff --git a/bindings/python/test-requirements.txt b/bindings/python/requirements-test.txt similarity index 100% rename from bindings/python/test-requirements.txt rename to bindings/python/requirements-test.txt diff --git a/bindings/python/setup.py b/bindings/python/setup.py deleted file mode 100644 index 49b1ee4ac..000000000 --- a/bindings/python/setup.py +++ /dev/null @@ -1,46 +0,0 @@ -import sys - -from setuptools import setup - -# Make our Windows and macOS wheels platform specific because we embed -# libmongocrypt. On Linux we ship manylinux2010 wheels which cannot do this or -# else auditwheel raises the following error: -# RuntimeError: Invalid binary wheel, found the following shared -# library/libraries in purelib folder: -# libmongocrypt.so -# The wheel has to be platlib compliant in order to be repaired by auditwheel. -cmdclass = {} -if sys.platform in ("win32", "darwin"): - try: - from wheel.bdist_wheel import bdist_wheel as _bdist_wheel - - class bdist_wheel(_bdist_wheel): - def finalize_options(self): - _bdist_wheel.finalize_options(self) - self.root_is_pure = False - - def get_tag(self): - python, abi, plat = _bdist_wheel.get_tag(self) - # Our python source is py3 compatible. - python, abi = "py3", "none" - return python, abi, plat - - cmdclass["bdist_wheel"] = bdist_wheel - except ImportError: - # Version of wheel is too old, use None to fail a bdist_wheel attempt. - cmdclass["bdist_wheel"] = None - - -def parse_reqs_file(fname): - with open(fname) as fid: - lines = [li.strip() for li in fid.readlines()] - return [li for li in lines if li and not li.startswith("#")] - - -extras_require = dict(test=parse_reqs_file("test-requirements.txt")) - -setup( - cmdclass=cmdclass, - install_requires=parse_reqs_file("requirements.txt"), - extras_require=extras_require, -)