PYTHON-4451 Use Hatch as Build Backend (#1644)
This commit is contained in:
parent
d6bf0e1e78
commit
2b030018e5
@ -158,6 +158,7 @@ if [ -n "$TEST_ENCRYPTION" ] || [ -n "$TEST_FLE_AZURE_AUTO" ] || [ -n "$TEST_FLE
|
||||
if [ ! -d "libmongocrypt_git" ]; then
|
||||
git clone https://github.com/mongodb/libmongocrypt.git libmongocrypt_git
|
||||
fi
|
||||
python -m pip install -U setuptools
|
||||
python -m pip install ./libmongocrypt_git/bindings/python
|
||||
python -c "import pymongocrypt; print('pymongocrypt version: '+pymongocrypt.__version__)"
|
||||
python -c "import pymongocrypt; print('libmongocrypt version: '+pymongocrypt.libmongocrypt_version())"
|
||||
|
||||
@ -66,7 +66,7 @@ createvirtualenv () {
|
||||
|
||||
export PIP_QUIET=1
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade setuptools tox
|
||||
python -m pip install --upgrade tox
|
||||
}
|
||||
|
||||
# Usage:
|
||||
|
||||
6
.github/workflows/test-python.yml
vendored
6
.github/workflows/test-python.yml
vendored
@ -31,12 +31,10 @@ jobs:
|
||||
- name: Run linters
|
||||
run: |
|
||||
tox -m lint-manual
|
||||
- name: Check Manifest
|
||||
run: |
|
||||
tox -m manifest
|
||||
- name: Run compilation
|
||||
run: |
|
||||
pip install -e .
|
||||
export PYMONGO_C_EXT_MUST_BUILD=1
|
||||
pip install -v -e .
|
||||
python tools/fail_if_no_c.py
|
||||
- name: Run typecheck
|
||||
run: |
|
||||
|
||||
34
MANIFEST.in
34
MANIFEST.in
@ -1,34 +0,0 @@
|
||||
include README.md
|
||||
include LICENSE
|
||||
include THIRD-PARTY-NOTICES
|
||||
include *.ini
|
||||
include sbom.json
|
||||
include requirements.txt
|
||||
exclude .coveragerc
|
||||
exclude .git-blame-ignore-revs
|
||||
exclude .pre-commit-config.yaml
|
||||
exclude .readthedocs.yaml
|
||||
exclude CONTRIBUTING.md
|
||||
exclude RELEASE.md
|
||||
recursive-include doc *.rst
|
||||
recursive-include doc *.py
|
||||
recursive-include doc *.conf
|
||||
recursive-include doc *.css
|
||||
recursive-include doc *.js
|
||||
recursive-include doc *.png
|
||||
include doc/Makefile
|
||||
include doc/_templates/layout.html
|
||||
include doc/make.bat
|
||||
include doc/static/periodic-executor-refs.dot
|
||||
recursive-include requirements *.txt
|
||||
recursive-include tools *.py
|
||||
recursive-include tools *.sh
|
||||
include tools/README.rst
|
||||
include green_framework_test.py
|
||||
recursive-include test *.pem
|
||||
recursive-include test *.py
|
||||
recursive-include test *.json
|
||||
recursive-include bson *.h
|
||||
prune test/mod_wsgi_test
|
||||
prune test/lambda
|
||||
prune .evergreen
|
||||
@ -78,12 +78,6 @@ PyMongo can be installed with [pip](http://pypi.python.org/pypi/pip):
|
||||
python -m pip install pymongo
|
||||
```
|
||||
|
||||
Or `easy_install` from [setuptools](http://pypi.python.org/pypi/setuptools):
|
||||
|
||||
```bash
|
||||
python -m easy_install pymongo
|
||||
```
|
||||
|
||||
You can also download the project source and do:
|
||||
|
||||
```bash
|
||||
|
||||
36
hatch_build.py
Normal file
36
hatch_build.py
Normal file
@ -0,0 +1,36 @@
|
||||
"""A custom hatch build hook for pymongo."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
||||
|
||||
|
||||
class CustomHook(BuildHookInterface):
|
||||
"""The pymongo build hook."""
|
||||
|
||||
def initialize(self, version, build_data):
|
||||
"""Initialize the hook."""
|
||||
if self.target_name == "sdist":
|
||||
return
|
||||
here = Path(__file__).parent.resolve()
|
||||
sys.path.insert(0, str(here))
|
||||
|
||||
subprocess.check_call([sys.executable, "setup.py", "build_ext", "-i"])
|
||||
|
||||
# Ensure wheel is marked as binary and contains the binary files.
|
||||
build_data["infer_tag"] = True
|
||||
build_data["pure_python"] = False
|
||||
if os.name == "nt":
|
||||
patt = ".pyd"
|
||||
else:
|
||||
patt = ".so"
|
||||
for pkg in ["bson", "pymongo"]:
|
||||
dpath = here / pkg
|
||||
for fpath in dpath.glob(f"*{patt}"):
|
||||
relpath = os.path.relpath(fpath, here)
|
||||
build_data["artifacts"].append(relpath)
|
||||
build_data["force_include"][relpath] = relpath
|
||||
@ -15,16 +15,29 @@
|
||||
"""Current version of PyMongo."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Tuple, Union
|
||||
import re
|
||||
from typing import List, Tuple, Union
|
||||
|
||||
version_tuple: Tuple[Union[int, str], ...] = (4, 8, 0, ".dev0")
|
||||
__version__ = "4.8.0.dev1"
|
||||
|
||||
|
||||
def get_version_tuple(version: str) -> Tuple[Union[int, str], ...]:
|
||||
pattern = r"(?P<major>\d+).(?P<minor>\d+).(?P<patch>\d+)(?P<rest>.*)"
|
||||
match = re.match(pattern, version)
|
||||
if match:
|
||||
parts: List[Union[int, str]] = [int(match[part]) for part in ["major", "minor", "patch"]]
|
||||
if match["rest"]:
|
||||
parts.append(match["rest"])
|
||||
elif re.match(r"\d+.\d+", version):
|
||||
parts = [int(part) for part in version.split(".")]
|
||||
else:
|
||||
raise ValueError("Could not parse version")
|
||||
return tuple(parts)
|
||||
|
||||
|
||||
version_tuple = get_version_tuple(__version__)
|
||||
version = __version__
|
||||
|
||||
|
||||
def get_version_string() -> str:
|
||||
if isinstance(version_tuple[-1], str):
|
||||
return ".".join(map(str, version_tuple[:-1])) + version_tuple[-1]
|
||||
return ".".join(map(str, version_tuple))
|
||||
|
||||
|
||||
__version__: str = get_version_string()
|
||||
version = __version__
|
||||
return __version__
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=63.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
requires = ["hatchling>1.24","setuptools>=65.0","hatch-requirements-txt>=0.4.1"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "pymongo"
|
||||
@ -45,16 +45,27 @@ Documentation = "https://pymongo.readthedocs.io"
|
||||
Source = "https://github.com/mongodb/mongo-python-driver"
|
||||
Tracker = "https://jira.mongodb.org/projects/PYTHON/issues"
|
||||
|
||||
[tool.setuptools.dynamic]
|
||||
version = {attr = "pymongo._version.__version__"}
|
||||
# Used to call hatch_build.py
|
||||
[tool.hatch.build.hooks.custom]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = ["bson","gridfs", "gridfs.asynchronous", "gridfs.synchronous", "pymongo", "pymongo.asynchronous", "pymongo.synchronous"]
|
||||
[tool.hatch.version]
|
||||
path = "pymongo/_version.py"
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
bson=["py.typed", "*.pyi"]
|
||||
pymongo=["py.typed", "*.pyi"]
|
||||
gridfs=["py.typed", "*.pyi"]
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["bson","gridfs", "pymongo"]
|
||||
|
||||
[tool.hatch.metadata.hooks.requirements_txt]
|
||||
files = ["requirements.txt"]
|
||||
|
||||
[tool.hatch.metadata.hooks.requirements_txt.optional-dependencies]
|
||||
aws = ["requirements/aws.txt"]
|
||||
docs = ["requirements/docs.txt"]
|
||||
encryption = ["requirements/encryption.txt"]
|
||||
gssapi = ["requirements/gssapi.txt"]
|
||||
ocsp = ["requirements/ocsp.txt"]
|
||||
snappy = ["requirements/snappy.txt"]
|
||||
test = ["requirements/test.txt"]
|
||||
zstd = ["requirements/zstd.txt"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
minversion = "7"
|
||||
@ -179,6 +190,7 @@ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?)|dummy.*)$"
|
||||
"UP031", "F401", "B023", "F811"]
|
||||
"tools/*.py" = ["T201"]
|
||||
"green_framework_test.py" = ["T201"]
|
||||
"hatch_build.py" = ["S"]
|
||||
|
||||
[tool.coverage.run]
|
||||
branch = true
|
||||
|
||||
26
setup.py
26
setup.py
@ -136,32 +136,8 @@ by this python implementation.\n
|
||||
)
|
||||
ext_modules = []
|
||||
|
||||
|
||||
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("#")]
|
||||
|
||||
|
||||
dependencies = parse_reqs_file("requirements.txt")
|
||||
|
||||
extras_require = dict(
|
||||
aws=parse_reqs_file("requirements/aws.txt"),
|
||||
encryption=parse_reqs_file("requirements/encryption.txt"),
|
||||
gssapi=parse_reqs_file("requirements/gssapi.txt"),
|
||||
ocsp=parse_reqs_file("requirements/ocsp.txt"),
|
||||
snappy=parse_reqs_file("requirements/snappy.txt"),
|
||||
# PYTHON-3423 Removed in 4.3 but kept here to avoid pip warnings.
|
||||
srv=[],
|
||||
tls=[],
|
||||
# PYTHON-2133 Removed in 4.0 but kept here to avoid pip warnings.
|
||||
zstd=parse_reqs_file("requirements/zstd.txt"),
|
||||
test=parse_reqs_file("requirements/test.txt"),
|
||||
)
|
||||
|
||||
setup(
|
||||
cmdclass={"build_ext": custom_build_ext},
|
||||
install_requires=dependencies,
|
||||
extras_require=extras_require,
|
||||
ext_modules=ext_modules,
|
||||
packages=["bson", "pymongo", "gridfs"],
|
||||
) # type:ignore
|
||||
|
||||
@ -22,6 +22,7 @@ sys.path[0:0] = [""]
|
||||
from test import unittest
|
||||
|
||||
import pymongo
|
||||
from pymongo._version import get_version_tuple
|
||||
|
||||
|
||||
class TestPyMongo(unittest.TestCase):
|
||||
@ -29,6 +30,14 @@ class TestPyMongo(unittest.TestCase):
|
||||
# Testing that pymongo module imports mongo_client.MongoClient
|
||||
self.assertEqual(pymongo.MongoClient, pymongo.synchronous.mongo_client.MongoClient)
|
||||
|
||||
def test_get_version_tuple(self):
|
||||
self.assertEqual(get_version_tuple("4.8.0.dev1"), (4, 8, 0, ".dev1"))
|
||||
self.assertEqual(get_version_tuple("4.8.1"), (4, 8, 1))
|
||||
self.assertEqual(get_version_tuple("5.0.0rc1"), (5, 0, 0, "rc1"))
|
||||
self.assertEqual(get_version_tuple("5.0"), (5, 0))
|
||||
with self.assertRaises(ValueError):
|
||||
get_version_tuple("5")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@ -29,6 +29,14 @@ import bson # noqa: E402
|
||||
import pymongo # noqa: E402
|
||||
|
||||
if not pymongo.has_c() or not bson.has_c():
|
||||
try:
|
||||
from pymongo import _cmessage # type:ignore[attr-defined] # noqa: F401
|
||||
except Exception as e:
|
||||
print(e)
|
||||
try:
|
||||
from bson import _cbson # type:ignore[attr-defined] # noqa: F401
|
||||
except Exception as e:
|
||||
print(e)
|
||||
sys.exit("could not load C extensions")
|
||||
|
||||
if os.environ.get("ENSURE_UNIVERSAL2") == "1":
|
||||
|
||||
13
tox.ini
13
tox.ini
@ -31,8 +31,6 @@ envlist =
|
||||
doc-test,
|
||||
# Linkcheck sphinx docs
|
||||
linkcheck
|
||||
# Check the sdist integrity.
|
||||
manifest
|
||||
|
||||
labels = # Use labels and -m instead of -e so that tox -m <label> fails instantly if the label does not exist
|
||||
test = test
|
||||
@ -51,7 +49,6 @@ labels = # Use labels and -m instead of -e so that tox -m <label> fails instantl
|
||||
linkcheck = linkcheck
|
||||
test-mockupdb = test-mockupdb
|
||||
aws-secrets = aws-secrets
|
||||
manifest = manifest
|
||||
|
||||
[testenv]
|
||||
package = editable
|
||||
@ -71,8 +68,6 @@ commands =
|
||||
description = run tests using run-tests.sh Evergreen script
|
||||
passenv = *
|
||||
extras = test
|
||||
deps =
|
||||
setuptools
|
||||
allowlist_externals =
|
||||
bash
|
||||
commands =
|
||||
@ -184,14 +179,6 @@ allowlist_externals =
|
||||
commands =
|
||||
{[testenv:test]commands} ./test/mockupdb
|
||||
|
||||
[testenv:manifest]
|
||||
description = ensure the sdist manifest is correct
|
||||
skip_install = true
|
||||
deps =
|
||||
check-manifest
|
||||
commands =
|
||||
python -m check_manifest -v
|
||||
|
||||
[testenv:setup-encryption]
|
||||
description = set up encryption assets and servers
|
||||
skip_install = true
|
||||
|
||||
Loading…
Reference in New Issue
Block a user