diff --git a/generate_version.py b/generate_version.py deleted file mode 100644 index 7dc1bdcf329d0..0000000000000 --- a/generate_version.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python3 - -# Note: This file has to live next to setup.py or versioneer will not work -import argparse -import os -import sys - -import versioneer - -sys.path.insert(0, "") - - -def write_version_info(path) -> None: - version = None - git_version = None - - try: - import _version_meson - - version = _version_meson.__version__ - git_version = _version_meson.__git_version__ - except ImportError: - version = versioneer.get_version() - git_version = versioneer.get_versions()["full-revisionid"] - if os.environ.get("MESON_DIST_ROOT"): - path = os.path.join(os.environ.get("MESON_DIST_ROOT"), path) - with open(path, "w", encoding="utf-8") as file: - file.write(f'__version__="{version}"\n') - file.write(f'__git_version__="{git_version}"\n') - - -def main() -> None: - parser = argparse.ArgumentParser() - parser.add_argument( - "-o", - "--outfile", - type=str, - help="Path to write version info to", - required=False, - ) - parser.add_argument( - "--print", - default=False, - action="store_true", - help="Whether to print out the version", - required=False, - ) - args = parser.parse_args() - - if args.outfile: - if not args.outfile.endswith(".py"): - raise ValueError( - f"Output file must be a Python file. " - f"Got: {args.outfile} as filename instead" - ) - - write_version_info(args.outfile) - - if args.print: - try: - import _version_meson - - version = _version_meson.__version__ - except ImportError: - version = versioneer.get_version() - print(version) - - -main() diff --git a/meson.build b/meson.build index 06623a305ab54..4281083f7c55b 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,9 @@ project( 'pandas', 'c', 'cpp', 'cython', - version: run_command(['generate_version.py', '--print'], check: true).stdout().strip(), + version: run_command( + ['python', 'pandas/_build_utils/gitversion.py'], + check: true).stdout().strip(), license: 'BSD-3', meson_version: '>=1.2.1', default_options: [ @@ -15,8 +17,6 @@ project( fs = import('fs') py = import('python').find_installation(pure: false) tempita = files('generate_pxi.py') -versioneer = files('generate_version.py') - add_project_arguments('-DNPY_NO_DEPRECATED_API=0', language : 'c') add_project_arguments('-DNPY_NO_DEPRECATED_API=0', language : 'cpp') @@ -27,23 +27,6 @@ add_project_arguments('-DNPY_NO_DEPRECATED_API=0', language : 'cpp') add_project_arguments('-DNPY_TARGET_VERSION=NPY_1_21_API_VERSION', language : 'c') add_project_arguments('-DNPY_TARGET_VERSION=NPY_1_21_API_VERSION', language : 'cpp') - -if fs.exists('_version_meson.py') - py.install_sources('_version_meson.py', subdir: 'pandas') -else - custom_target('write_version_file', - output: '_version_meson.py', - command: [ - py, versioneer, '-o', '@OUTPUT@' - ], - build_by_default: true, - build_always_stale: true, - install: true, - install_dir: py.get_install_dir() / 'pandas' - ) - meson.add_dist_script(py, versioneer, '-o', '_version_meson.py') -endif - # Needed by pandas.test() when it looks for the pytest ini options py.install_sources( 'pyproject.toml', diff --git a/pandas/__init__.py b/pandas/__init__.py index f7ae91dd847f7..d055bd99ebfe8 100644 --- a/pandas/__init__.py +++ b/pandas/__init__.py @@ -171,22 +171,7 @@ from pandas.util._tester import test -# use the closest tagged version if possible -_built_with_meson = False -try: - from pandas._version_meson import ( # pyright: ignore [reportMissingImports] - __version__, - __git_version__, - ) - - _built_with_meson = True -except ImportError: - from pandas._version import get_versions - - v = get_versions() - __version__ = v.get("closest-tag", v["version"]) - __git_version__ = v.get("full-revisionid") - del get_versions, v +# If a version with git hash was stored, use that instead # module level doc-string diff --git a/pandas/_build_utils/gitversion.py b/pandas/_build_utils/gitversion.py new file mode 100755 index 0000000000000..363b10ce84f76 --- /dev/null +++ b/pandas/_build_utils/gitversion.py @@ -0,0 +1,90 @@ +# This file is vendored from NumPy. See NUMPY_LICENSE.txt + +#!/usr/bin/env python3 +import os +import textwrap + + +def init_version(): + init = os.path.join(os.path.dirname(__file__), "../../pyproject.toml") + with open(init) as fid: + data = fid.readlines() + + version_line = next(line for line in data if line.startswith("version =")) + + version = version_line.strip().split(" = ")[1] + version = version.replace('"', "").replace("'", "") + + return version + + +def git_version(version): + # Append last commit date and hash to dev version information, + # if available + + import os.path + import subprocess + + git_hash = "" + try: + p = subprocess.Popen( + ["git", "log", "-1", '--format="%H %aI"'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=os.path.dirname(__file__), + ) + except FileNotFoundError: + pass + else: + out, err = p.communicate() + if p.returncode == 0: + git_hash, git_date = ( + out.decode("utf-8") + .strip() + .replace('"', "") + .split("T")[0] + .replace("-", "") + .split() + ) + + # Only attach git tag to development versions + if "dev" in version: + version += f"+git{git_date}.{git_hash[:7]}" + + return version, git_hash + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("--write", help="Save version to this file") + parser.add_argument( + "--meson-dist", + help="Output path is relative to MESON_DIST_ROOT", + action="store_true", + ) + args = parser.parse_args() + + version, git_hash = git_version(init_version()) + + template = textwrap.dedent(f""" + version = "{version}" + __version__ = version + """) + + if args.write: + outfile = args.write + if args.meson_dist: + outfile = os.path.join(os.environ.get("MESON_DIST_ROOT", ""), outfile) + + # Print human readable output path + relpath = os.path.relpath(outfile) + if relpath.startswith("."): + relpath = outfile + + with open(outfile, "w") as f: + print(f"Saving version to {relpath}") + f.write(template) + else: + print(version) diff --git a/pandas/_version.py b/pandas/_version.py deleted file mode 100644 index 7bd9da2bb1cfa..0000000000000 --- a/pandas/_version.py +++ /dev/null @@ -1,692 +0,0 @@ -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. -# Generated by versioneer-0.28 -# https://github.com/python-versioneer/python-versioneer - -"""Git implementation of _version.py.""" - -import errno -import functools -import os -import re -import subprocess -import sys -from typing import Callable - - -def get_keywords(): - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "$Format:%d$" - git_full = "$Format:%H$" - git_date = "$Format:%ci$" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_config(): - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "pep440" - cfg.tag_prefix = "v" - cfg.parentdir_prefix = "pandas-" - cfg.versionfile_source = "pandas/_version.py" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY: dict[str, str] = {} -HANDLERS: dict[str, dict[str, Callable]] = {} - - -def register_vcs_handler(vcs, method): # decorator - """Create decorator to mark a method as the handler of a VCS.""" - - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - process = None - - popen_kwargs = {} - if sys.platform == "win32": - # This hides the console window if pythonw.exe is used - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - popen_kwargs["startupinfo"] = startupinfo - - for command in commands: - dispcmd = str([command] + args) - try: - # remember shell=False, so use git.cmd on windows, not just git - process = subprocess.Popen( - [command] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - **popen_kwargs, - ) - break - except OSError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print(f"unable to run {dispcmd}") - print(e) - return None, None - else: - if verbose: - print(f"unable to find command, tried {commands}") - return None, None - stdout = process.communicate()[0].strip().decode() - if process.returncode != 0: - if verbose: - print(f"unable to run {dispcmd} (error)") - print(f"stdout was {stdout}") - return None, process.returncode - return stdout, process.returncode - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for _ in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print( - f"Tried directories {rootdirs!s} \ - but none started with prefix {parentdir_prefix}" - ) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - with open(versionfile_abs, encoding="utf-8") as fobj: - for line in fobj: - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - except OSError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if "refnames" not in keywords: - raise NotThisMethod("Short version file found") - date = keywords.get("date") - if date is not None: - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = {r.strip() for r in refnames.strip("()").split(",")} - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = {r[len(TAG) :] for r in refs if r.startswith(TAG)} - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = {r for r in refs if re.search(r"\d", r)} - if verbose: - print(f"discarding '{','.join(refs - tags)}', no digits") - if verbose: - print(f"likely tags: {','.join(sorted(tags))}") - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] - # Filter out refs that exactly match prefix or that don't start - # with a number once the prefix is stripped (mostly a concern - # when prefix is '') - if not re.match(r"\d", r): - continue - if verbose: - print(f"picking {r}") - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - # GIT_DIR can interfere with correct operation of Versioneer. - # It may be intended to be passed to the Versioneer-versioned project, - # but that should not change where we get our version from. - env = os.environ.copy() - env.pop("GIT_DIR", None) - runner = functools.partial(runner, env=env) - - _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose) - if rc != 0: - if verbose: - print(f"Directory {root} not under git control") - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = runner( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - f"{tag_prefix}[[:digit:]]*", - ], - cwd=root, - ) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) - # --abbrev-ref was added in git-1.6.3 - if rc != 0 or branch_name is None: - raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") - branch_name = branch_name.strip() - - if branch_name == "HEAD": - # If we aren't exactly on a branch, pick a branch which represents - # the current commit. If all else fails, we are on a branchless - # commit. - branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) - # --contains was added in git-1.5.4 - if rc != 0 or branches is None: - raise NotThisMethod("'git branch --contains' returned error") - branches = branches.split("\n") - - # Remove the first line if we're running detached - if "(" in branches[0]: - branches.pop(0) - - # Strip off the leading "* " from the list of branches. - branches = [branch[2:] for branch in branches] - if "master" in branches: - branch_name = "master" - elif not branches: - branch_name = None - else: - # Pick the first branch that is returned. Good or bad. - branch_name = branches[0] - - pieces["branch"] = branch_name - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) - if not mo: - # unparsable. Maybe git-describe is misbehaving? - pieces["error"] = f"unable to parse git-describe output: '{describe_out}'" - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ( - f"tag '{full_tag}' doesn't start with prefix '{tag_prefix}'" - ) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) - pieces["distance"] = len(out.split()) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces) -> str: - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += f"{pieces['distance']}.g{pieces['short']}" - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = f"0+untagged.{pieces['distance']}.g{pieces['short']}" - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_branch(pieces): - """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . - - The ".dev0" means not master branch. Note that .dev0 sorts backwards - (a feature branch will appear "older" than the master branch). - - Exceptions: - 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += f"{pieces['distance']}.g{pieces['short']}" - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0" - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += f"+untagged.{pieces['distance']}.g{pieces['short']}" - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def pep440_split_post(ver): - """Split pep440 version string at the post-release segment. - - Returns the release segments before the post-release and the - post-release version number (or -1 if no post-release segment is present). - """ - vc = str.split(ver, ".post") - return vc[0], int(vc[1] or 0) if len(vc) == 2 else None - - -def render_pep440_pre(pieces): - """TAG[.postN.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post0.devDISTANCE - """ - if pieces["closest-tag"]: - if pieces["distance"]: - # update the post release segment - tag_version, post_version = pep440_split_post(pieces["closest-tag"]) - rendered = tag_version - if post_version is not None: - rendered += f".post{post_version + 1}.dev{pieces['distance']}" - else: - rendered += f".post0.dev{pieces['distance']}" - else: - # no commits, use the tag as the version - rendered = pieces["closest-tag"] - else: - # exception #1 - rendered = f"0.post0.dev{pieces['distance']}" - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += f".post{pieces['distance']}" - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += f"g{pieces['short']}" - else: - # exception #1 - rendered = f"0.post{pieces['distance']}" - if pieces["dirty"]: - rendered += ".dev0" - rendered += f"+g{pieces['short']}" - return rendered - - -def render_pep440_post_branch(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . - - The ".dev0" means not master branch. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += f".post{pieces['distance']}" - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += f"g{pieces['short']}" - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = f"0.post{pieces['distance']}" - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += f"+g{pieces['short']}" - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += f"0.post{pieces['distance']}" - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = f"0.post{pieces['distance']}" - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += f"-{pieces['distance']}-g{pieces['short']}" - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += f"-{pieces['distance']}-g{pieces['short']}" - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-branch": - rendered = render_pep440_branch(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-post-branch": - rendered = render_pep440_post_branch(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError(f"unknown style '{style}'") - - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } - - -def get_versions(): - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for _ in cfg.versionfile_source.split("/"): - root = os.path.dirname(root) - except NameError: - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None, - } - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } diff --git a/pandas/meson.build b/pandas/meson.build index 435103a954d86..9e5f250f5d3d8 100644 --- a/pandas/meson.build +++ b/pandas/meson.build @@ -22,6 +22,33 @@ inc_pd = include_directories('_libs/include') fs.copyfile('__init__.py') +pd_dir = py.get_install_dir() / 'pandas' + +# Generate version.py for sdist +meson.add_dist_script( + ['_build_utils/gitversion.py', '--meson-dist', '--write', + 'pandas/version.py'] +) +if not fs.exists('version.py') + generate_version = custom_target( + 'generate-version', + install: true, + build_always_stale: true, + build_by_default: true, + output: 'version.py', + input: '_build_utils/gitversion.py', + command: [py, '@INPUT@', '--write', '@OUTPUT@'], + install_dir: pd_dir, + install_tag: 'python-runtime' + ) +else + # When building from sdist, version.py exists and should be included + py.install_sources( + ['version.py'], + subdir : 'pandas' + ) +endif + subdir('_libs') subdirs_list = [ @@ -45,7 +72,6 @@ endforeach top_level_py_list = [ '__init__.py', '_typing.py', - '_version.py', 'conftest.py', 'testing.py' ] diff --git a/pyproject.toml b/pyproject.toml index f96fbee4a5818..ad4752b2692eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,9 +19,7 @@ build-backend = "mesonpy" [project] name = 'pandas' -dynamic = [ - 'version' -] +version = "3.0.0.dev0" description = 'Powerful data structures for data analysis, time series, and statistics' readme = 'README.md' authors = [