From fdd87015cb2aa5e95d40b26b00c8ae2e94f307db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20N=C3=B6the?= Date: Fri, 15 May 2020 15:34:17 +0200 Subject: [PATCH 1/4] Use setuptools_scm for versioning --- .gitignore | 1 + MANIFEST.in | 4 -- ctapipe/__init__.py | 5 +- ctapipe/version.py | 172 -------------------------------------------- pyproject.toml | 2 +- setup.py | 28 +++++--- 6 files changed, 21 insertions(+), 191 deletions(-) delete mode 100644 ctapipe/version.py diff --git a/.gitignore b/.gitignore index 8c24a15b540..2192e28a02a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ __pycache__ # ignore version cache file (generated automatically when setup.py is run) ctapipe/_version_cache.py +ctapipe/version.py # Ignore .c files by default to avoid including generated code. If you want to # add a non-generated .c extension, use `git add -f filename.c`. diff --git a/MANIFEST.in b/MANIFEST.in index 5c119e6656b..f0fdd0876e4 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,11 +3,7 @@ include CHANGES.rst include setup.cfg -recursive-include *.pyx *.c *.pxd recursive-include docs * -recursive-include licenses * -recursive-include cextern * -recursive-include scripts * prune build prune docs/_build diff --git a/ctapipe/__init__.py b/ctapipe/__init__.py index 1346ad4e041..93196fa1e56 100644 --- a/ctapipe/__init__.py +++ b/ctapipe/__init__.py @@ -2,7 +2,6 @@ """ ctapipe - CTA Python pipeline experimental version """ +from .version import __version__ -from . import version - -__version__ = version.get_version(pep440=False) +__all__ = ['__version__'] diff --git a/ctapipe/version.py b/ctapipe/version.py deleted file mode 100644 index d8f2b6d0687..00000000000 --- a/ctapipe/version.py +++ /dev/null @@ -1,172 +0,0 @@ -""" -Get version identification from git. - - -The update_release_version() function writes the current version to the -VERSION file. This function should be called before packaging a release version. - -Use the get_version() function to get the version string, including the latest -commit, from git. -If git is not available the VERSION file will be read. - -Heres an example of such a version string: - - v0.2.0.post58+git57440dc - - -This code was taken from here: -https://github.com/aebrahim/python-git-version - -Combining ideas from -http://blogs.nopcode.org/brainstorm/2013/05/20/pragmatic-python-versioning-via-setuptools-and-git-tags/ -and Python Versioneer -https://github.com/warner/python-versioneer -but being much more lightwheight - -""" -from subprocess import check_output, CalledProcessError -from os import path, name, devnull, environ, listdir - -__all__ = ("get_version",) - -CURRENT_DIRECTORY = path.dirname(path.abspath(__file__)) -VERSION_FILE = path.join(CURRENT_DIRECTORY, "_version_cache.py") - -GIT_COMMAND = "git" - -if name == "nt": - - def find_git_on_windows(): - """find the path to the git executable on windows""" - # first see if git is in the path - try: - check_output(["where", "/Q", "git"]) - # if this command succeeded, git is in the path - return "git" - # catch the exception thrown if git was not found - except CalledProcessError: - pass - # There are several locations git.exe may be hiding - possible_locations = [] - # look in program files for msysgit - if "PROGRAMFILES(X86)" in environ: - possible_locations.append( - "%s/Git/cmd/git.exe" % environ["PROGRAMFILES(X86)"] - ) - if "PROGRAMFILES" in environ: - possible_locations.append("%s/Git/cmd/git.exe" % environ["PROGRAMFILES"]) - # look for the github version of git - if "LOCALAPPDATA" in environ: - github_dir = "%s/GitHub" % environ["LOCALAPPDATA"] - if path.isdir(github_dir): - for subdir in listdir(github_dir): - if not subdir.startswith("PortableGit"): - continue - possible_locations.append( - "%s/%s/bin/git.exe" % (github_dir, subdir) - ) - for possible_location in possible_locations: - if path.isfile(possible_location): - return possible_location - # git was not found - return "git" - - GIT_COMMAND = find_git_on_windows() - - -def get_git_describe_version(abbrev=7): - """return the string output of git desribe""" - try: - with open(devnull, "w") as fnull: - arguments = [GIT_COMMAND, "describe", "--tags", "--abbrev=%d" % abbrev] - return ( - check_output(arguments, cwd=CURRENT_DIRECTORY, stderr=fnull) - .decode("ascii") - .strip() - ) - except (OSError, CalledProcessError): - return None - - -def format_git_describe(git_str, pep440=False): - """format the result of calling 'git describe' as a python version""" - - if "-" not in git_str: # currently at a tag - formatted_str = git_str - else: - # formatted as version-N-githash - # want to convert to version.postN-githash - git_str = git_str.replace("-", ".post", 1) - if pep440: # does not allow git hash afterwards - formatted_str = git_str.split("-")[0] - else: - formatted_str = git_str.replace("-g", "+git") - - # need to remove the "v" to have a proper python version - if formatted_str.startswith("v"): - formatted_str = formatted_str[1:] - - return formatted_str - - -def read_release_version(): - """Read version information from VERSION file""" - try: - from ._version_cache import version - - if len(version) == 0: - version = None - return version - except ImportError: - return "unknown" - - -def update_release_version(pep440=False): - """Release versions are stored in a file called VERSION. - This method updates the version stored in the file. - This function should be called when creating new releases. - It is called by setup.py when building a package. - - - pep440: bool - When True, this function returns a version string suitable for - a release as defined by PEP 440. When False, the githash (if - available) will be appended to the version string. - - """ - version = get_version(pep440=pep440) - with open(VERSION_FILE, "w") as outfile: - outfile.write(f"version='{version}'") - outfile.write("\n") - - -def get_version(pep440=False): - """Tracks the version number. - - pep440: bool - When True, this function returns a version string suitable for - a release as defined by PEP 440. When False, the githash (if - available) will be appended to the version string. - - The file VERSION holds the version information. If this is not a git - repository, then it is reasonable to assume that the version is not - being incremented and the version returned will be the release version as - read from the file. - - However, if the script is located within an active git repository, - git-describe is used to get the version information. - - The file VERSION will need to be changed manually. - """ - - raw_git_version = get_git_describe_version() - if not raw_git_version: # not a git repository - return read_release_version() - - git_version = format_git_describe(raw_git_version, pep440=pep440) - - return git_version - - -if __name__ == "__main__": - print(get_version()) diff --git a/pyproject.toml b/pyproject.toml index 23e7414db6b..df02cd11de6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools >= 40.6.0", "wheel"] +requires = ["setuptools >= 40.6.0", "wheel", "setuptools_scm[toml]>=3.4"] build-backend = "setuptools.build_meta" [tool.black] diff --git a/setup.py b/setup.py index dfb3d877085..9383363644e 100755 --- a/setup.py +++ b/setup.py @@ -3,16 +3,8 @@ # import ah_bootstrap from setuptools import setup, find_packages - -import sys import os -# pep 517 builds do not have cwd in PATH by default -sys.path.insert(0, os.path.dirname(__file__)) -# Get the long and version description from the package's docstring -import ctapipe # noqa - - # Define entry points for command-line scripts # TODO: this shuold be automated (e.g. look for main functions and # rename _ to -, and prepend 'ctapipe' @@ -48,11 +40,21 @@ "graphviz", ] -ctapipe.version.update_release_version() + +VERSION_TEMPLATE = """ +# DO NOT MANUALLY EDIT THIS FILE, IT IS AUTOGENERATED BY SETUP +# Note that we need to fall back to the hard-coded version if either +# setuptools_scm can't be imported or setuptools_scm can't determine the +# version, so we catch the generic 'Exception'. +try: + from setuptools_scm import get_version + __version__ = get_version(root='..', relative_to=__file__) +except Exception: + __version__ = '{version}' +""".lstrip() setup( packages=find_packages(), - version=ctapipe.version.get_version(pep440=True), python_requires=">=3.7", install_requires=[ "astropy>=3,<5", @@ -79,8 +81,12 @@ "tests": tests_require, "docs": docs_require, }, + use_scm_version={ + 'write_to': os.path.join('ctapipe', 'version.py'), + 'write_to_template': VERSION_TEMPLATE, + }, tests_require=tests_require, - setup_requires=["pytest_runner"], + setup_requires=['pytest_runner', 'setuptools_scm'], classifiers=[ "Intended Audience :: Science/Research", "License :: OSI Approved :: BSD License", From e3b2162888cc263b7f3f4fee9bca22ef67778056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20N=C3=B6the?= Date: Mon, 9 Nov 2020 11:46:44 +0100 Subject: [PATCH 2/4] Use astropys approach for setuptools_scm --- .gitignore | 2 +- MANIFEST.in | 1 + ctapipe/_dev_version.py | 9 +++++++++ ctapipe/version.py | 21 +++++++++++++++++++++ setup.py | 20 ++------------------ 5 files changed, 34 insertions(+), 19 deletions(-) create mode 100644 ctapipe/_dev_version.py create mode 100644 ctapipe/version.py diff --git a/.gitignore b/.gitignore index 2192e28a02a..d56d8474a83 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ __pycache__ # ignore version cache file (generated automatically when setup.py is run) ctapipe/_version_cache.py -ctapipe/version.py +ctapipe/_version.py # Ignore .c files by default to avoid including generated code. If you want to # add a non-generated .c extension, use `git add -f filename.c`. diff --git a/MANIFEST.in b/MANIFEST.in index f0fdd0876e4..2b59b72313c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -8,5 +8,6 @@ recursive-include docs * prune build prune docs/_build prune docs/api +prune ctapipe/_dev_version.py global-exclude *.pyc *.o diff --git a/ctapipe/_dev_version.py b/ctapipe/_dev_version.py new file mode 100644 index 00000000000..6aafeda4735 --- /dev/null +++ b/ctapipe/_dev_version.py @@ -0,0 +1,9 @@ +# Try to use setuptools_scm to get the current version; this is only used +# in development installations from the git repository. +# see ctapipe/version.py for details +try: + from setuptools_scm import get_version + + version = get_version(root="..", relative_to=__file__) +except Exception: + raise ImportError("setuptools_scm broken or not installed") diff --git a/ctapipe/version.py b/ctapipe/version.py new file mode 100644 index 00000000000..6f33825a034 --- /dev/null +++ b/ctapipe/version.py @@ -0,0 +1,21 @@ +# this is adapted from https://github.com/astropy/astropy/blob/master/astropy/version.py +# see https://github.com/astropy/astropy/pull/10774 for a discussion on why this needed. + +try: + try: + from ._dev_version import version + except ImportError: + from ._version import version +except Exception: + import warnings + + warnings.warn( + "Could not determine ctapipe version; this indicates a broken installation." + " Install ctapipe from PyPI, using conda or from a local git repository." + " Installing github's autogenerated source release tarballs " + " does not include version information and should be avoided." + ) + del warnings + version = "0.0.0" + +__version__ = version diff --git a/setup.py b/setup.py index 9383363644e..bbb9f078ebd 100755 --- a/setup.py +++ b/setup.py @@ -40,19 +40,6 @@ "graphviz", ] - -VERSION_TEMPLATE = """ -# DO NOT MANUALLY EDIT THIS FILE, IT IS AUTOGENERATED BY SETUP -# Note that we need to fall back to the hard-coded version if either -# setuptools_scm can't be imported or setuptools_scm can't determine the -# version, so we catch the generic 'Exception'. -try: - from setuptools_scm import get_version - __version__ = get_version(root='..', relative_to=__file__) -except Exception: - __version__ = '{version}' -""".lstrip() - setup( packages=find_packages(), python_requires=">=3.7", @@ -81,12 +68,9 @@ "tests": tests_require, "docs": docs_require, }, - use_scm_version={ - 'write_to': os.path.join('ctapipe', 'version.py'), - 'write_to_template': VERSION_TEMPLATE, - }, + use_scm_version={"write_to": os.path.join("ctapipe", "_version.py")}, tests_require=tests_require, - setup_requires=['pytest_runner', 'setuptools_scm'], + setup_requires=["pytest_runner", "setuptools_scm"], classifiers=[ "Intended Audience :: Science/Research", "License :: OSI Approved :: BSD License", From 4cf0f999f6d34925c82d4a2891e0fb16ffab1ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20N=C3=B6the?= Date: Mon, 9 Nov 2020 11:54:52 +0100 Subject: [PATCH 3/4] Require setuptools_scm at runtime for dev --- ctapipe/_dev_version.py | 4 ++-- setup.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ctapipe/_dev_version.py b/ctapipe/_dev_version.py index 6aafeda4735..a27274d7e08 100644 --- a/ctapipe/_dev_version.py +++ b/ctapipe/_dev_version.py @@ -5,5 +5,5 @@ from setuptools_scm import get_version version = get_version(root="..", relative_to=__file__) -except Exception: - raise ImportError("setuptools_scm broken or not installed") +except Exception as e: + raise ImportError(f"setuptools_scm broken or not installed: {e}") diff --git a/setup.py b/setup.py index bbb9f078ebd..47b1c35870b 100755 --- a/setup.py +++ b/setup.py @@ -61,6 +61,7 @@ "traitlets~=5.0,>=5.0.5", "zstandard", "h5py", # needed for astropy hdf5 io + "setuptools_scm>=3.4", ], # here are optional dependencies (as "tag" : "dependency spec") extras_require={ From aba3e0fb242201dfc6df9d7352b42f80d630eb2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20N=C3=B6the?= Date: Mon, 9 Nov 2020 11:59:21 +0100 Subject: [PATCH 4/4] Fix file exclude in manifest --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 2b59b72313c..dd4aaffc0d2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -8,6 +8,6 @@ recursive-include docs * prune build prune docs/_build prune docs/api -prune ctapipe/_dev_version.py +exclude ctapipe/_dev_version.py global-exclude *.pyc *.o