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

PYTHON-4451 Use Hatch as Build Backend #1644

Merged
merged 24 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .evergreen/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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())"
Expand Down
2 changes: 1 addition & 1 deletion .evergreen/utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
6 changes: 2 additions & 4 deletions .github/workflows/test-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,10 @@ jobs:
- name: Run linters
run: |
tox -m lint-manual
- name: Check Manifest
Copy link
Contributor

Choose a reason for hiding this comment

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

No manifest file!

Copy link
Contributor

Choose a reason for hiding this comment

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

I read the Why Hatch? page. I'm starting to get it. Very nice.

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: |
Expand Down
33 changes: 0 additions & 33 deletions MANIFEST.in

This file was deleted.

6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
36 changes: 36 additions & 0 deletions hatch_build.py
Original file line number Diff line number Diff line change
@@ -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
27 changes: 20 additions & 7 deletions pymongo/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_string() -> str:
if isinstance(version_tuple[-1], str):
return ".".join(map(str, version_tuple[:-1])) + version_tuple[-1]
return ".".join(map(str, version_tuple))
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__: str = get_version_string()
version_tuple = get_version_tuple(__version__)
version = __version__


def get_version_string() -> str:
return __version__
32 changes: 22 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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", "pymongo"]
[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"
Expand Down Expand Up @@ -168,6 +179,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
Expand Down
26 changes: 1 addition & 25 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,32 +136,8 @@ def build_extension(self, ext):
)
ext_modules = []


Copy link
Contributor

Choose a reason for hiding this comment

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

You were able to get rid of all this because of the way that requirements.txt is handled? That's awesome!

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
9 changes: 9 additions & 0 deletions test/test_pymongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,22 @@
from test import unittest

import pymongo
from pymongo._version import get_version_tuple


class TestPyMongo(unittest.TestCase):
def test_mongo_client_alias(self):
# Testing that pymongo module imports mongo_client.MongoClient
self.assertEqual(pymongo.MongoClient, pymongo.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()
8 changes: 8 additions & 0 deletions tools/fail_if_no_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@
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":
Expand Down
13 changes: 0 additions & 13 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -71,8 +68,6 @@ commands =
description = run tests using run-tests.sh Evergreen script
passenv = *
extras = test
deps =
setuptools
allowlist_externals =
bash
commands =
Expand Down Expand Up @@ -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
Expand Down
Loading