Skip to content

Commit

Permalink
python: switch to static versioning for simplicity
Browse files Browse the repository at this point in the history
We tried to derive versions from Git.  But since we release off of
a branch, this meant that all non-branch builds would have version
0.0.0.  This breaks things like Polars that rely on checking the
installed version.

Instead, since we already bump versions as part of the release
process, just hardcode the version and drop most of miniver.

Fixes #1363.
  • Loading branch information
lidavidm committed Jan 2, 2024
1 parent e8224bf commit 385fe63
Show file tree
Hide file tree
Showing 17 changed files with 36 additions and 896 deletions.
1 change: 0 additions & 1 deletion .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,6 @@ jobs:
BUILD_ALL: "0"
BUILD_DRIVER_MANAGER: "1"
BUILD_DRIVER_POSTGRESQL: "1"
SETUPTOOLS_SCM_PRETEND_VERSION: "0.9.0"
run: |
./ci/scripts/python_build.sh "$(pwd)" "$(pwd)/build"
Expand Down
6 changes: 6 additions & 0 deletions dev/release/utils-prepare.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ update_versions() {
local version=${base_version}
local conda_version=${base_version}
local docs_version=${base_version}
local py_version=${base_version}
local r_version=${base_version}
;;
snapshot)
local version=${next_version}-SNAPSHOT
local conda_version=${next_version}
local docs_version="${next_version} (dev)"
local py_version="${next_version}dev"
local r_version="${base_version}.9000"
;;
esac
Expand Down Expand Up @@ -70,6 +72,10 @@ update_versions() {
rm "${ADBC_DIR}/glib/meson.build.bak"
git add "${ADBC_DIR}/glib/meson.build"

sed -i.bak -E "s/version = \".+\"/version = \"${py_version}\"/g" "${ADBC_DIR}"/python/adbc_*/adbc_*/_static_version.py
rm "${ADBC_DIR}"/python/adbc_*/adbc_*/_static_version.py.bak
git add "${ADBC_DIR}"/python/adbc_*/adbc_*/_static_version.py

sed -i.bak -E "s/VERSION = \".+\"/VERSION = \"${version}\"/g" "${ADBC_DIR}/ruby/lib/adbc/version.rb"
rm "${ADBC_DIR}/ruby/lib/adbc/version.rb.bak"
git add "${ADBC_DIR}/ruby/lib/adbc/version.rb"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,8 @@
# Generated by miniver (CC0).

# This file is part of 'miniver': https://github.com/jbweston/miniver
#
# This file will be overwritten by setup.py when a source or binary
# distribution is made. The magic value "__use_git__" is interpreted by
# _version.py.

version = "__use_git__"
version = "0.9.0dev"

# These values are only set if the distribution was created with 'git archive'
# NOTE: must add an export-subst to .gitattributes!
Expand Down
172 changes: 2 additions & 170 deletions python/adbc_driver_flightsql/adbc_driver_flightsql/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,9 @@
# under the License.

# Generated by miniver (CC0).

import os
import re

# This file is part of 'miniver': https://github.com/jbweston/miniver
#
from collections import namedtuple

Version = namedtuple("Version", ("release", "dev", "labels"))
import os

# No public API
__all__ = []
Expand All @@ -34,9 +28,6 @@
package_name = os.path.basename(package_root)

STATIC_VERSION_FILE = "_static_version.py"
TAG_RELEASE_FORMAT = re.compile(
r"^apache-arrow-adbc-([0-9]+\.[0-9]+\.[0-9]+)(?:-rc[0-9]+)?$"
)


def get_version(version_file=STATIC_VERSION_FILE):
Expand All @@ -45,15 +36,7 @@ def get_version(version_file=STATIC_VERSION_FILE):
return override
version_info = get_static_version_info(version_file)
version = version_info["version"]
if version == "__use_git__":
version = get_version_from_git()
if not version:
version = get_version_from_git_archive(version_info)
if not version:
version = Version("unknown", None, None)
return pep440_format(version)
else:
return version
return version


def get_static_version_info(version_file=STATIC_VERSION_FILE):
Expand All @@ -63,158 +46,7 @@ def get_static_version_info(version_file=STATIC_VERSION_FILE):
return version_info


def version_is_from_git(version_file=STATIC_VERSION_FILE):
return get_static_version_info(version_file)["version"] == "__use_git__"


def pep440_format(version_info):
release, dev, labels = version_info

version_parts = [release]
if dev:
if release.endswith("-dev") or release.endswith(".dev"):
version_parts.append(dev)
else: # prefer PEP440 over strict adhesion to semver
version_parts.append(".dev{}".format(dev))

if labels:
version_parts.append("+")
version_parts.append(".".join(labels))

return "".join(version_parts)


def get_version_from_git():
import subprocess

# git describe --first-parent does not take into account tags from branches
# that were merged-in. The '--long' flag gets us the 'dev' version and
# git hash, '--always' returns the git hash even if there are no tags.
for opts in [["--first-parent"], []]:
try:
p = subprocess.Popen(
["git", "describe", "--long", "--always"] + opts,
cwd=package_root,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
except OSError:
return
if p.wait() == 0:
break
else:
return

description = (
p.communicate()[0]
.decode()
.strip("v") # Tags can have a leading 'v', but the version should not
.rstrip("\n")
.rsplit("-", 2) # Split the latest tag, commits since tag, and hash
)

try:
release, dev, git = description
release = TAG_RELEASE_FORMAT.match(release).group(1)
except (AttributeError, ValueError):
# Invalid tag; or no tags, only the git hash
# prepend 'g' to match with format returned by 'git describe'
git = "g{}".format(*description)
# XXX: assume version if not given
release = "0.0.0"
dev = None

labels = []
if dev == "0":
dev = None
else:
labels.append(git)

try:
p = subprocess.Popen(["git", "diff", "--quiet"], cwd=package_root)
except OSError:
labels.append("confused") # This should never happen.
else:
if p.wait() == 1:
labels.append("dirty")

return Version(release, dev, labels)


# TODO: change this logic when there is a git pretty-format
# that gives the same output as 'git describe'.
# Currently we can only tell the tag the current commit is
# pointing to, or its hash (with no version info)
# if it is not tagged.
def get_version_from_git_archive(version_info):
try:
refnames = version_info["refnames"]
git_hash = version_info["git_hash"]
except KeyError:
# These fields are not present if we are running from an sdist.
# Execution should never reach here, though
return None

if git_hash.startswith("$Format") or refnames.startswith("$Format"):
# variables not expanded during 'git archive'
return None

VTAG = "tag: "
refs = set(r.strip() for r in refnames.split(","))
version_tags = set(r[len(VTAG) :] for r in refs if r.startswith(VTAG))
if version_tags:
release, *_ = sorted(version_tags) # prefer e.g. "2.0" over "2.0rc1"
release = TAG_RELEASE_FORMAT.match(release).group(1)
return Version(release, dev=None, labels=None)
else:
return Version("unknown", dev=None, labels=["g{}".format(git_hash)])


__version__ = get_version()


# The following section defines a 'get_cmdclass' function
# that can be used from setup.py. The '__version__' module
# global is used (but not modified).


def _write_version(fname):
# This could be a hard link, so try to delete it first. Is there any way
# to do this atomically together with opening?
try:
os.remove(fname)
except OSError:
pass
with open(fname, "w") as f:
f.write(
"# This file has been created by setup.py.\n"
"version = '{}'\n".format(__version__)
)


def get_cmdclass(pkg_source_path):
from setuptools.command.build_py import build_py as build_py_orig
from setuptools.command.sdist import sdist as sdist_orig

class _build_py(build_py_orig):
def run(self):
super().run()

src_marker = "".join(["src", os.path.sep])

if pkg_source_path.startswith(src_marker):
path = pkg_source_path[len(src_marker) :]
else:
path = pkg_source_path
_write_version(os.path.join(self.build_lib, path, STATIC_VERSION_FILE))

class _sdist(sdist_orig):
def make_release_tree(self, base_dir, files):
super().make_release_tree(base_dir, files)
_write_version(os.path.join(base_dir, pkg_source_path, STATIC_VERSION_FILE))

return dict(sdist=_sdist, build_py=_build_py)


if __name__ == "__main__":
print("Version: ", get_version())
7 changes: 3 additions & 4 deletions python/adbc_driver_flightsql/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
# Resolve Version (miniver)


def get_version_and_cmdclass(pkg_path):
def get_version(pkg_path):
"""
Load version.py module without importing the whole package.
Expand All @@ -60,15 +60,14 @@ def get_version_and_cmdclass(pkg_path):
spec = spec_from_file_location("version", os.path.join(pkg_path, "_version.py"))
module = module_from_spec(spec)
spec.loader.exec_module(module)
return module.__version__, module.get_cmdclass(pkg_path)
return module.__version__


version, cmdclass = get_version_and_cmdclass("adbc_driver_flightsql")
version = get_version("adbc_driver_flightsql")

# ------------------------------------------------------------
# Setup

setup(
cmdclass=cmdclass,
version=version,
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,8 @@
# Generated by miniver (CC0).

# This file is part of 'miniver': https://github.com/jbweston/miniver
#
# This file will be overwritten by setup.py when a source or binary
# distribution is made. The magic value "__use_git__" is interpreted by
# _version.py.

version = "__use_git__"
version = "0.9.0dev"

# These values are only set if the distribution was created with 'git archive'
# NOTE: must add an export-subst to .gitattributes!
Expand Down
Loading

0 comments on commit 385fe63

Please sign in to comment.