From b52de9543519938145032ee75132cc42c496b21c Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Wed, 5 Aug 2026 08:36:34 -0600 Subject: [PATCH] Produce dev-release wheels per PEP 440 --- py/client-ticking/setup.py | 29 ++++++++++++++++++++++++++--- py/client/setup.py | 29 ++++++++++++++++++++++++++--- py/embedded-server/setup.py | 29 ++++++++++++++++++++++++++--- py/server/setup.py | 29 ++++++++++++++++++++++++++--- 4 files changed, 104 insertions(+), 12 deletions(-) diff --git a/py/client-ticking/setup.py b/py/client-ticking/setup.py index 19fafabaae2..7a9cc5fefe0 100644 --- a/py/client-ticking/setup.py +++ b/py/client-ticking/setup.py @@ -4,6 +4,7 @@ import os import pathlib import platform +from datetime import datetime, timezone from Cython.Build import cythonize from packaging.version import parse as parse_version @@ -17,13 +18,35 @@ def _get_readme() -> str: return (HERE / "README.md").read_text(encoding="utf-8") +def _snapshot_date() -> str: + # Date-precision (UTC) timestamp used to build a PEP 440 dev pre-release for SNAPSHOTs. + # + # Reproducible builds: building the same source twice on different days would otherwise + # yield different versions (e.g. .dev20260805 vs .dev20260806), so the artifact would not + # be a deterministic function of the source. SOURCE_DATE_EPOCH is the cross-ecosystem + # standard (https://reproducible-builds.org/specs/source-date-epoch/) for pinning build + # time: an integer of seconds since the Unix epoch (UTC), conventionally the commit time + # (git log -1 --pretty=%ct). When set, we use it instead of the wall clock so rebuilds of + # the same commit produce an identical version; otherwise we fall back to "now". + epoch = os.environ.get("SOURCE_DATE_EPOCH") + when = ( + datetime.fromtimestamp(int(epoch), tz=timezone.utc) + if epoch + else datetime.now(tz=timezone.utc) + ) + return when.strftime("%Y%m%d") + + def _normalize_version(java_version): partitions = java_version.partition("-") regular_version = partitions[0] local_segment = partitions[2] - python_version = ( - f"{regular_version}+{local_segment}" if local_segment else regular_version - ) + if local_segment == "SNAPSHOT": + python_version = f"{regular_version}.dev{_snapshot_date()}" + elif local_segment: + python_version = f"{regular_version}+{local_segment}" + else: + python_version = regular_version return str(parse_version(python_version)) diff --git a/py/client/setup.py b/py/client/setup.py index 65abaad18c3..415df7a0f73 100644 --- a/py/client/setup.py +++ b/py/client/setup.py @@ -3,6 +3,7 @@ # import os import pathlib +from datetime import datetime, timezone from packaging.version import parse as parse_version from setuptools import find_namespace_packages, setup @@ -15,13 +16,35 @@ def _get_readme() -> str: return (here / "README.md").read_text(encoding="utf-8") +def _snapshot_date() -> str: + # Date-precision (UTC) timestamp used to build a PEP 440 dev pre-release for SNAPSHOTs. + # + # Reproducible builds: building the same source twice on different days would otherwise + # yield different versions (e.g. .dev20260805 vs .dev20260806), so the artifact would not + # be a deterministic function of the source. SOURCE_DATE_EPOCH is the cross-ecosystem + # standard (https://reproducible-builds.org/specs/source-date-epoch/) for pinning build + # time: an integer of seconds since the Unix epoch (UTC), conventionally the commit time + # (git log -1 --pretty=%ct). When set, we use it instead of the wall clock so rebuilds of + # the same commit produce an identical version; otherwise we fall back to "now". + epoch = os.environ.get("SOURCE_DATE_EPOCH") + when = ( + datetime.fromtimestamp(int(epoch), tz=timezone.utc) + if epoch + else datetime.now(tz=timezone.utc) + ) + return when.strftime("%Y%m%d") + + def _normalize_version(java_version): partitions = java_version.partition("-") regular_version = partitions[0] local_segment = partitions[2] - python_version = ( - f"{regular_version}+{local_segment}" if local_segment else regular_version - ) + if local_segment == "SNAPSHOT": + python_version = f"{regular_version}.dev{_snapshot_date()}" + elif local_segment: + python_version = f"{regular_version}+{local_segment}" + else: + python_version = regular_version return str(parse_version(python_version)) diff --git a/py/embedded-server/setup.py b/py/embedded-server/setup.py index 1a707e09a47..6296128d79c 100644 --- a/py/embedded-server/setup.py +++ b/py/embedded-server/setup.py @@ -3,6 +3,7 @@ # import os import pathlib +from datetime import datetime, timezone from packaging.version import parse as parse_version from setuptools import find_namespace_packages, setup @@ -15,13 +16,35 @@ def _get_readme() -> str: return (here / "README_PyPi.md").read_text(encoding="utf-8") +def _snapshot_date() -> str: + # Date-precision (UTC) timestamp used to build a PEP 440 dev pre-release for SNAPSHOTs. + # + # Reproducible builds: building the same source twice on different days would otherwise + # yield different versions (e.g. .dev20260805 vs .dev20260806), so the artifact would not + # be a deterministic function of the source. SOURCE_DATE_EPOCH is the cross-ecosystem + # standard (https://reproducible-builds.org/specs/source-date-epoch/) for pinning build + # time: an integer of seconds since the Unix epoch (UTC), conventionally the commit time + # (git log -1 --pretty=%ct). When set, we use it instead of the wall clock so rebuilds of + # the same commit produce an identical version; otherwise we fall back to "now". + epoch = os.environ.get("SOURCE_DATE_EPOCH") + when = ( + datetime.fromtimestamp(int(epoch), tz=timezone.utc) + if epoch + else datetime.now(tz=timezone.utc) + ) + return when.strftime("%Y%m%d") + + def _normalize_version(java_version) -> str: partitions = java_version.partition("-") regular_version = partitions[0] local_segment = partitions[2] - python_version = ( - f"{regular_version}+{local_segment}" if local_segment else regular_version - ) + if local_segment == "SNAPSHOT": + python_version = f"{regular_version}.dev{_snapshot_date()}" + elif local_segment: + python_version = f"{regular_version}+{local_segment}" + else: + python_version = regular_version return str(parse_version(python_version)) diff --git a/py/server/setup.py b/py/server/setup.py index d3d92a937e4..139e00909e8 100644 --- a/py/server/setup.py +++ b/py/server/setup.py @@ -3,6 +3,7 @@ # import os import pathlib +from datetime import datetime, timezone from packaging.version import parse as parse_version from setuptools import find_namespace_packages, setup @@ -15,13 +16,35 @@ def _get_readme() -> str: return (HERE / "README.md").read_text(encoding="utf-8") +def _snapshot_date() -> str: + # Date-precision (UTC) timestamp used to build a PEP 440 dev pre-release for SNAPSHOTs. + # + # Reproducible builds: building the same source twice on different days would otherwise + # yield different versions (e.g. .dev20260805 vs .dev20260806), so the artifact would not + # be a deterministic function of the source. SOURCE_DATE_EPOCH is the cross-ecosystem + # standard (https://reproducible-builds.org/specs/source-date-epoch/) for pinning build + # time: an integer of seconds since the Unix epoch (UTC), conventionally the commit time + # (git log -1 --pretty=%ct). When set, we use it instead of the wall clock so rebuilds of + # the same commit produce an identical version; otherwise we fall back to "now". + epoch = os.environ.get("SOURCE_DATE_EPOCH") + when = ( + datetime.fromtimestamp(int(epoch), tz=timezone.utc) + if epoch + else datetime.now(tz=timezone.utc) + ) + return when.strftime("%Y%m%d") + + def _normalize_version(java_version) -> str: partitions = java_version.partition("-") regular_version = partitions[0] local_segment = partitions[2] - python_version = ( - f"{regular_version}+{local_segment}" if local_segment else regular_version - ) + if local_segment == "SNAPSHOT": + python_version = f"{regular_version}.dev{_snapshot_date()}" + elif local_segment: + python_version = f"{regular_version}+{local_segment}" + else: + python_version = regular_version return str(parse_version(python_version))