
13 changed files with 2215 additions and 111 deletions
@ -1,2 +1,5 @@
|
||||
@echo off |
||||
%PYTHON% setup.py install --quiet |
||||
|
||||
conda remove jinja2 --quiet |
||||
conda install jinja2 --quiet |
||||
%PYTHON% setup.py install |
||||
|
@ -1,2 +1,3 @@
|
||||
#!/bin/bash |
||||
$PYTHON setup.py install --quiet |
||||
#!/bin/sh |
||||
|
||||
$PYTHON setup.py install |
||||
|
@ -0,0 +1,460 @@
|
||||
|
||||
# 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.15 (https://github.com/warner/python-versioneer) |
||||
|
||||
import errno |
||||
import os |
||||
import re |
||||
import subprocess |
||||
import sys |
||||
|
||||
|
||||
def get_keywords(): |
||||
# 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$" |
||||
keywords = {"refnames": git_refnames, "full": git_full} |
||||
return keywords |
||||
|
||||
|
||||
class VersioneerConfig: |
||||
pass |
||||
|
||||
|
||||
def get_config(): |
||||
# 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): |
||||
pass |
||||
|
||||
|
||||
LONG_VERSION_PY = {} |
||||
HANDLERS = {} |
||||
|
||||
|
||||
def register_vcs_handler(vcs, method): # decorator |
||||
def decorate(f): |
||||
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): |
||||
assert isinstance(commands, list) |
||||
p = None |
||||
for c in commands: |
||||
try: |
||||
dispcmd = str([c] + args) |
||||
# remember shell=False, so use git.cmd on windows, not just git |
||||
p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE, |
||||
stderr=(subprocess.PIPE if hide_stderr |
||||
else None)) |
||||
break |
||||
except EnvironmentError: |
||||
e = sys.exc_info()[1] |
||||
if e.errno == errno.ENOENT: |
||||
continue |
||||
if verbose: |
||||
print("unable to run %s" % dispcmd) |
||||
print(e) |
||||
return None |
||||
else: |
||||
if verbose: |
||||
print("unable to find command, tried %s" % (commands,)) |
||||
return None |
||||
stdout = p.communicate()[0].strip() |
||||
if sys.version_info[0] >= 3: |
||||
stdout = stdout.decode() |
||||
if p.returncode != 0: |
||||
if verbose: |
||||
print("unable to run %s (error)" % dispcmd) |
||||
return None |
||||
return stdout |
||||
|
||||
|
||||
def versions_from_parentdir(parentdir_prefix, root, verbose): |
||||
# Source tarballs conventionally unpack into a directory that includes |
||||
# both the project name and a version string. |
||||
dirname = os.path.basename(root) |
||||
if not dirname.startswith(parentdir_prefix): |
||||
if verbose: |
||||
print("guessing rootdir is '%s', but '%s' doesn't start with " |
||||
"prefix '%s'" % (root, dirname, parentdir_prefix)) |
||||
raise NotThisMethod("rootdir doesn't start with parentdir_prefix") |
||||
return {"version": dirname[len(parentdir_prefix):], |
||||
"full-revisionid": None, |
||||
"dirty": False, "error": None} |
||||
|
||||
|
||||
@register_vcs_handler("git", "get_keywords") |
||||
def git_get_keywords(versionfile_abs): |
||||
# 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: |
||||
f = open(versionfile_abs, "r") |
||||
for line in f.readlines(): |
||||
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) |
||||
f.close() |
||||
except EnvironmentError: |
||||
pass |
||||
return keywords |
||||
|
||||
|
||||
@register_vcs_handler("git", "keywords") |
||||
def git_versions_from_keywords(keywords, tag_prefix, verbose): |
||||
if not keywords: |
||||
raise NotThisMethod("no keywords at all, weird") |
||||
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 = set([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 = set([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 = set([r for r in refs if re.search(r'\d', r)]) |
||||
if verbose: |
||||
print("discarding '%s', no digits" % ",".join(refs-tags)) |
||||
if verbose: |
||||
print("likely tags: %s" % ",".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):] |
||||
if verbose: |
||||
print("picking %s" % r) |
||||
return {"version": r, |
||||
"full-revisionid": keywords["full"].strip(), |
||||
"dirty": False, "error": None |
||||
} |
||||
# 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"} |
||||
|
||||
|
||||
@register_vcs_handler("git", "pieces_from_vcs") |
||||
def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): |
||||
# this runs 'git' from 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. |
||||
|
||||
if not os.path.exists(os.path.join(root, ".git")): |
||||
if verbose: |
||||
print("no .git in %s" % root) |
||||
raise NotThisMethod("no .git directory") |
||||
|
||||
GITS = ["git"] |
||||
if sys.platform == "win32": |
||||
GITS = ["git.cmd", "git.exe"] |
||||
# if there is a tag, this yields TAG-NUM-gHEX[-dirty] |
||||
# if there are no tags, this yields HEX[-dirty] (no NUM) |
||||
describe_out = run_command(GITS, ["describe", "--tags", "--dirty", |
||||
"--always", "--long"], |
||||
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 = run_command(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 |
||||
|
||||
# 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: |
||||
# unparseable. Maybe git-describe is misbehaving? |
||||
pieces["error"] = ("unable to parse git-describe output: '%s'" |
||||
% 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"] = ("tag '%s' doesn't start with prefix '%s'" |
||||
% (full_tag, 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 |
||||
count_out = run_command(GITS, ["rev-list", "HEAD", "--count"], |
||||
cwd=root) |
||||
pieces["distance"] = int(count_out) # total number of commits |
||||
|
||||
return pieces |
||||
|
||||
|
||||
def plus_or_dot(pieces): |
||||
if "+" in pieces.get("closest-tag", ""): |
||||
return "." |
||||
return "+" |
||||
|
||||
|
||||
def render_pep440(pieces): |
||||
# now 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 += "%d.g%s" % (pieces["distance"], pieces["short"]) |
||||
if pieces["dirty"]: |
||||
rendered += ".dirty" |
||||
else: |
||||
# exception #1 |
||||
rendered = "0+untagged.%d.g%s" % (pieces["distance"], |
||||
pieces["short"]) |
||||
if pieces["dirty"]: |
||||
rendered += ".dirty" |
||||
return rendered |
||||
|
||||
|
||||
def render_pep440_pre(pieces): |
||||
# TAG[.post.devDISTANCE] . No -dirty |
||||
|
||||
# exceptions: |
||||
# 1: no tags. 0.post.devDISTANCE |
||||
|
||||
if pieces["closest-tag"]: |
||||
rendered = pieces["closest-tag"] |
||||
if pieces["distance"]: |
||||
rendered += ".post.dev%d" % pieces["distance"] |
||||
else: |
||||
# exception #1 |
||||
rendered = "0.post.dev%d" % 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 += ".post%d" % pieces["distance"] |
||||
if pieces["dirty"]: |
||||
rendered += ".dev0" |
||||
rendered += plus_or_dot(pieces) |
||||
rendered += "g%s" % pieces["short"] |
||||
else: |
||||
# exception #1 |
||||
rendered = "0.post%d" % pieces["distance"] |
||||
if pieces["dirty"]: |
||||
rendered += ".dev0" |
||||
rendered += "+g%s" % pieces["short"] |
||||
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 += ".post%d" % pieces["distance"] |
||||
if pieces["dirty"]: |
||||
rendered += ".dev0" |
||||
else: |
||||
# exception #1 |
||||
rendered = "0.post%d" % 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 += "-%d-g%s" % (pieces["distance"], 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 += "-%d-g%s" % (pieces["distance"], pieces["short"]) |
||||
else: |
||||
# exception #1 |
||||
rendered = pieces["short"] |
||||
if pieces["dirty"]: |
||||
rendered += "-dirty" |
||||
return rendered |
||||
|
||||
|
||||
def render(pieces, style): |
||||
if pieces["error"]: |
||||
return {"version": "unknown", |
||||
"full-revisionid": pieces.get("long"), |
||||
"dirty": None, |
||||
"error": pieces["error"]} |
||||
|
||||
if not style or style == "default": |
||||
style = "pep440" # the default |
||||
|
||||
if style == "pep440": |
||||
rendered = render_pep440(pieces) |
||||
elif style == "pep440-pre": |
||||
rendered = render_pep440_pre(pieces) |
||||
elif style == "pep440-post": |
||||
rendered = render_pep440_post(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("unknown style '%s'" % style) |
||||
|
||||
return {"version": rendered, "full-revisionid": pieces["long"], |
||||
"dirty": pieces["dirty"], "error": None} |
||||
|
||||
|
||||
def get_versions(): |
||||
# 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 i 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"} |
||||
|
||||
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"} |
@ -0,0 +1,12 @@
|
||||
|
||||
# See the docstring in versioneer.py for instructions. Note that you must |
||||
# re-run 'versioneer.py setup' after changing this section, and commit the |
||||
# resulting files. |
||||
|
||||
[versioneer] |
||||
VCS = git |
||||
style = pep440 |
||||
versionfile_source = pandas/_version.py |
||||
versionfile_build = pandas/_version.py |
||||
tag_prefix = v |
||||
parentdir_prefix = pandas- |
@ -0,0 +1,1699 @@
|
||||
|
||||
# Version: 0.15 |
||||
|
||||
""" |
||||
The Versioneer |
||||
============== |
||||
|
||||
* like a rocketeer, but for versions! |
||||
* https://github.com/warner/python-versioneer |
||||
* Brian Warner |
||||
* License: Public Domain |
||||
* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, and pypy |
||||
* [![Latest Version] |
||||
(https://pypip.in/version/versioneer/badge.svg?style=flat) |
||||
](https://pypi.python.org/pypi/versioneer/) |
||||
* [![Build Status] |
||||
(https://travis-ci.org/warner/python-versioneer.png?branch=master) |
||||
](https://travis-ci.org/warner/python-versioneer) |
||||
|
||||
This is a tool for managing a recorded version number in distutils-based |
||||
python projects. The goal is to remove the tedious and error-prone "update |
||||
the embedded version string" step from your release process. Making a new |
||||
release should be as easy as recording a new tag in your version-control |
||||
system, and maybe making new tarballs. |
||||
|
||||
|
||||
## Quick Install |
||||
|
||||
* `pip install versioneer` to somewhere to your $PATH |
||||
* add a `[versioneer]` section to your setup.cfg (see below) |
||||
* run `versioneer install` in your source tree, commit the results |
||||
|
||||
## Version Identifiers |
||||
|
||||
Source trees come from a variety of places: |
||||
|
||||
* a version-control system checkout (mostly used by developers) |
||||
* a nightly tarball, produced by build automation |
||||
* a snapshot tarball, produced by a web-based VCS browser, like github's |
||||
"tarball from tag" feature |
||||
* a release tarball, produced by "setup.py sdist", distributed through PyPI |
||||
|
||||
Within each source tree, the version identifier (either a string or a number, |
||||
this tool is format-agnostic) can come from a variety of places: |
||||
|
||||
* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows |
||||
about recent "tags" and an absolute revision-id |
||||
* the name of the directory into which the tarball was unpacked |
||||
* an expanded VCS keyword ($Id$, etc) |
||||
* a `_version.py` created by some earlier build step |
||||
|
||||
For released software, the version identifier is closely related to a VCS |
||||
tag. Some projects use tag names that include more than just the version |
||||
string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool |
||||
needs to strip the tag prefix to extract the version identifier. For |
||||
unreleased software (between tags), the version identifier should provide |
||||
enough information to help developers recreate the same tree, while also |
||||
giving them an idea of roughly how old the tree is (after version 1.2, before |
||||
version 1.3). Many VCS systems can report a description that captures this, |
||||
for example `git describe --tags --dirty --always` reports things like |
||||
"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the |
||||
0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has |
||||
uncommitted changes. |
||||
|
||||
The version identifier is used for multiple purposes: |
||||
|
||||
* to allow the module to self-identify its version: `myproject.__version__` |
||||
* to choose a name and prefix for a 'setup.py sdist' tarball |
||||
|
||||
## Theory of Operation |
||||
|
||||
Versioneer works by adding a special `_version.py` file into your source |
||||
tree, where your `__init__.py` can import it. This `_version.py` knows how to |
||||
dynamically ask the VCS tool for version information at import time. |
||||
|
||||
`_version.py` also contains `$Revision$` markers, and the installation |
||||
process marks `_version.py` to have this marker rewritten with a tag name |
||||
during the `git archive` command. As a result, generated tarballs will |
||||
contain enough information to get the proper version. |
||||
|
||||
To allow `setup.py` to compute a version too, a `versioneer.py` is added to |
||||
the top level of your source tree, next to `setup.py` and the `setup.cfg` |
||||
that configures it. This overrides several distutils/setuptools commands to |
||||
compute the version when invoked, and changes `setup.py build` and `setup.py |
||||
sdist` to replace `_version.py` with a small static file that contains just |
||||
the generated version data. |
||||
|
||||
## Installation |
||||
|
||||
First, decide on values for the following configuration variables: |
||||
|
||||
* `VCS`: the version control system you use. Currently accepts "git". |
||||
|
||||
* `style`: the style of version string to be produced. See "Styles" below for |
||||
details. Defaults to "pep440", which looks like |
||||
`TAG[+DISTANCE.gSHORTHASH[.dirty]]`. |
||||
|
||||
* `versionfile_source`: |
||||
|
||||
A project-relative pathname into which the generated version strings should |
||||
be written. This is usually a `_version.py` next to your project's main |
||||
`__init__.py` file, so it can be imported at runtime. If your project uses |
||||
`src/myproject/__init__.py`, this should be `src/myproject/_version.py`. |
||||
This file should be checked in to your VCS as usual: the copy created below |
||||
by `setup.py setup_versioneer` will include code that parses expanded VCS |
||||
keywords in generated tarballs. The 'build' and 'sdist' commands will |
||||
replace it with a copy that has just the calculated version string. |
||||
|
||||
This must be set even if your project does not have any modules (and will |
||||
therefore never import `_version.py`), since "setup.py sdist" -based trees |
||||
still need somewhere to record the pre-calculated version strings. Anywhere |
||||
in the source tree should do. If there is a `__init__.py` next to your |
||||
`_version.py`, the `setup.py setup_versioneer` command (described below) |
||||
will append some `__version__`-setting assignments, if they aren't already |
||||
present. |
||||
|
||||
* `versionfile_build`: |
||||
|
||||
Like `versionfile_source`, but relative to the build directory instead of |
||||
the source directory. These will differ when your setup.py uses |
||||
'package_dir='. If you have `package_dir={'myproject': 'src/myproject'}`, |
||||
then you will probably have `versionfile_build='myproject/_version.py'` and |
||||
`versionfile_source='src/myproject/_version.py'`. |
||||
|
||||
If this is set to None, then `setup.py build` will not attempt to rewrite |
||||
any `_version.py` in the built tree. If your project does not have any |
||||
libraries (e.g. if it only builds a script), then you should use |
||||
`versionfile_build = None` and override `distutils.command.build_scripts` |
||||
to explicitly insert a copy of `versioneer.get_version()` into your |
||||
generated script. |
||||
|
||||
* `tag_prefix`: |
||||
|
||||
a string, like 'PROJECTNAME-', which appears at the start of all VCS tags. |
||||
If your tags look like 'myproject-1.2.0', then you should use |
||||
tag_prefix='myproject-'. If you use unprefixed tags like '1.2.0', this |
||||
should be an empty string. |
||||
|
||||
* `parentdir_prefix`: |
||||
|
||||
a optional string, frequently the same as tag_prefix, which appears at the |
||||
start of all unpacked tarball filenames. If your tarball unpacks into |
||||
'myproject-1.2.0', this should be 'myproject-'. To disable this feature, |
||||
just omit the field from your `setup.cfg`. |
||||
|
||||
This tool provides one script, named `versioneer`. That script has one mode, |
||||
"install", which writes a copy of `versioneer.py` into the current directory |
||||
and runs `versioneer.py setup` to finish the installation. |
||||
|
||||
To versioneer-enable your project: |
||||
|
||||
* 1: Modify your `setup.cfg`, adding a section named `[versioneer]` and |
||||
populating it with the configuration values you decided earlier (note that |
||||
the option names are not case-sensitive): |
||||
|
||||
```` |
||||
[versioneer] |
||||
VCS = git |
||||
style = pep440 |
||||
versionfile_source = src/myproject/_version.py |
||||
versionfile_build = myproject/_version.py |
||||
tag_prefix = "" |
||||
parentdir_prefix = myproject- |
||||
```` |
||||
|
||||
* 2: Run `versioneer install`. This will do the following: |
||||
|
||||
* copy `versioneer.py` into the top of your source tree |
||||
* create `_version.py` in the right place (`versionfile_source`) |
||||
* modify your `__init__.py` (if one exists next to `_version.py`) to define |
||||
`__version__` (by calling a function from `_version.py`) |
||||
* modify your `MANIFEST.in` to include both `versioneer.py` and the |
||||
generated `_version.py` in sdist tarballs |
||||
|
||||
`versioneer install` will complain about any problems it finds with your |
||||
`setup.py` or `setup.cfg`. Run it multiple times until you have fixed all |
||||
the problems. |
||||
|
||||
* 3: add a `import versioneer` to your setup.py, and add the following |
||||
arguments to the setup() call: |
||||
|
||||
version=versioneer.get_version(), |
||||
cmdclass=versioneer.get_cmdclass(), |
||||
|
||||
* 4: commit these changes to your VCS. To make sure you won't forget, |
||||
`versioneer install` will mark everything it touched for addition using |
||||
`git add`. Don't forget to add `setup.py` and `setup.cfg` too. |
||||
|
||||
## Post-Installation Usage |
||||
|
||||
Once established, all uses of your tree from a VCS checkout should get the |
||||
current version string. All generated tarballs should include an embedded |
||||
version string (so users who unpack them will not need a VCS tool installed). |
||||
|
||||
If you distribute your project through PyPI, then the release process should |
||||
boil down to two steps: |
||||
|
||||
* 1: git tag 1.0 |
||||
* 2: python setup.py register sdist upload |
||||
|
||||
If you distribute it through github (i.e. users use github to generate |
||||
tarballs with `git archive`), the process is: |
||||
|
||||
* 1: git tag 1.0 |
||||
* 2: git push; git push --tags |
||||
|
||||
Versioneer will report "0+untagged.NUMCOMMITS.gHASH" until your tree has at |
||||
least one tag in its history. |
||||
|
||||
## Version-String Flavors |
||||
|
||||
Code which uses Versioneer can learn about its version string at runtime by |
||||
importing `_version` from your main `__init__.py` file and running the |
||||
`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can |
||||
import the top-level `versioneer.py` and run `get_versions()`. |
||||
|
||||
Both functions return a dictionary with different flavors of version |
||||
information: |
||||
|
||||
* `['version']`: A condensed version string, rendered using the selected |
||||
style. This is the most commonly used value for the project's version |
||||
string. The default "pep440" style yields strings like `0.11`, |
||||
`0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section |
||||
below for alternative styles. |
||||
|
||||
* `['full-revisionid']`: detailed revision identifier. For Git, this is the |
||||
full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". |
||||
|
||||
* `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that |
||||
this is only accurate if run in a VCS checkout, otherwise it is likely to |
||||
be False or None |
||||
|
||||
* `['error']`: if the version string could not be computed, this will be set |
||||
to a string describing the problem, otherwise it will be None. It may be |
||||
useful to throw an exception in setup.py if this is set, to avoid e.g. |
||||
creating tarballs with a version string of "unknown". |
||||
|
||||
Some variants are more useful than others. Including `full-revisionid` in a |
||||
bug report should allow developers to reconstruct the exact code being tested |
||||
(or indicate the presence of local changes that should be shared with the |
||||
developers). `version` is suitable for display in an "about" box or a CLI |
||||
`--version` output: it can be easily compared against release notes and lists |
||||
of bugs fixed in various releases. |
||||
|
||||
The installer adds the following text to your `__init__.py` to place a basic |
||||
version in `YOURPROJECT.__version__`: |
||||
|
||||
from ._version import get_versions |
||||
__version__ = get_versions()['version'] |
||||
del get_versions |
||||
|
||||
## Styles |
||||
|
||||
The setup.cfg `style=` configuration controls how the VCS information is |
||||
rendered into a version string. |
||||
|
||||
The default style, "pep440", produces a PEP440-compliant string, equal to the |
||||
un-prefixed tag name for actual releases, and containing an additional "local |
||||
version" section with more detail for in-between builds. For Git, this is |
||||
TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags |
||||
--dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the |
||||
tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and |
||||
that this commit is two revisions ("+2") beyond the "0.11" tag. For released |
||||
software (exactly equal to a known tag), the identifier will only contain the |
||||
stripped tag, e.g. "0.11". |
||||
|
||||
Other styles are available. See details.md in the Versioneer source tree for |
||||
descriptions. |
||||
|
||||
## Debugging |
||||
|
||||
Versioneer tries to avoid fatal errors: if something goes wrong, it will tend |
||||
to return a version of "0+unknown". To investigate the problem, run `setup.py |
||||
version`, which will run the version-lookup code in a verbose mode, and will |
||||
display the full contents of `get_versions()` (including the `error` string, |
||||
which may help identify what went wrong). |
||||
|
||||
## Updating Versioneer |
||||
|
||||
To upgrade your project to a new release of Versioneer, do the following: |
||||
|
||||
* install the new Versioneer (`pip install -U versioneer` or equivalent) |
||||
* edit `setup.cfg`, if necessary, to include any new configuration settings |
||||
indicated by the release notes |
||||
* re-run `versioneer install` in your source tree, to replace |
||||
`SRC/_version.py` |
||||
* commit any changed files |
||||
|
||||
### Upgrading to 0.15 |
||||
|
||||
Starting with this version, Versioneer is configured with a `[versioneer]` |
||||
section in your `setup.cfg` file. Earlier versions required the `setup.py` to |
||||
set attributes on the `versioneer` module immediately after import. The new |
||||
version will refuse to run (raising an exception during import) until you |
||||
have provided the necessary `setup.cfg` section. |
||||
|
||||
In addition, the Versioneer package provides an executable named |
||||
`versioneer`, and the installation process is driven by running `versioneer |
||||
install`. In 0.14 and earlier, the executable was named |
||||
`versioneer-installer` and was run without an argument. |
||||
|
||||
### Upgrading to 0.14 |
||||
|
||||
0.14 changes the format of the version string. 0.13 and earlier used |
||||
hyphen-separated strings like "0.11-2-g1076c97-dirty". 0.14 and beyond use a |
||||
plus-separated "local version" section strings, with dot-separated |
||||
components, like "0.11+2.g1076c97". PEP440-strict tools did not like the old |
||||
format, but should be ok with the new one. |
||||
|
||||
### Upgrading from 0.11 to 0.12 |
||||
|
||||
Nothing special. |
||||
|
||||
### Upgrading from 0.10 to 0.11 |
||||
|
||||
You must add a `versioneer.VCS = "git"` to your `setup.py` before re-running |
||||
`setup.py setup_versioneer`. This will enable the use of additional |
||||
version-control systems (SVN, etc) in the future. |
||||
|
||||
## Future Directions |
||||
|
||||
This tool is designed to make it easily extended to other version-control |
||||
systems: all VCS-specific components are in separate directories like |
||||
src/git/ . The top-level `versioneer.py` script is assembled from these |
||||
components by running make-versioneer.py . In the future, make-versioneer.py |
||||
will take a VCS name as an argument, and will construct a version of |
||||
`versioneer.py` that is specific to the given VCS. It might also take the |
||||
configuration arguments that are currently provided manually during |
||||
installation by editing setup.py . Alternatively, it might go the other |
||||
direction and include code from all supported VCS systems, reducing the |
||||
number of intermediate scripts. |
||||
|
||||
|
||||
## License |
||||
|
||||
To make Versioneer easier to embed, all its code is hereby released into the |
||||
public domain. The `_version.py` that it creates is also in the public |
||||
domain. |
||||
|
||||
""" |
||||
|
||||
from __future__ import print_function |
||||
try: |
||||
import configparser |
||||
except ImportError: |
||||
import ConfigParser as configparser |
||||
import errno |
||||
import json |
||||
import os |
||||
import re |
||||
import subprocess |
||||
import sys |
||||
|
||||
|
||||
class VersioneerConfig: |
||||
pass |
||||
|
||||
|
||||
def get_root(): |
||||
# we require that all commands are run from the project root, i.e. the |
||||
# directory that contains setup.py, setup.cfg, and versioneer.py . |
||||
root = os.path.realpath(os.path.abspath(os.getcwd())) |
||||
setup_py = os.path.join(root, "setup.py") |
||||
versioneer_py = os.path.join(root, "versioneer.py") |
||||
if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): |
||||
# allow 'python path/to/setup.py COMMAND' |
||||
root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) |
||||
setup_py = os.path.join(root, "setup.py") |
||||
versioneer_py = os.path.join(root, "versioneer.py") |
||||
if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): |
||||
err = ("Versioneer was unable to run the project root directory. " |
||||
"Versioneer requires setup.py to be executed from " |
||||
"its immediate directory (like 'python setup.py COMMAND'), " |
||||
"or in a way that lets it use sys.argv[0] to find the root " |
||||
"(like 'python path/to/setup.py COMMAND').") |
||||
raise VersioneerBadRootError(err) |
||||
try: |
||||
# Certain runtime workflows (setup.py install/develop in a setuptools |
||||
# tree) execute all dependencies in a single python process, so |
||||
# "versioneer" may be imported multiple times, and python's shared |
||||
# module-import table will cache the first one. So we can't use |
||||
# os.path.dirname(__file__), as that will find whichever |
||||
# versioneer.py was first imported, even in later projects. |
||||
me = os.path.realpath(os.path.abspath(__file__)) |
||||
if os.path.splitext(me)[0] != os.path.splitext(versioneer_py)[0]: |
||||
print("Warning: build in %s is using versioneer.py from %s" |
||||
% (os.path.dirname(me), versioneer_py)) |
||||
except NameError: |
||||
pass |
||||
return root |
||||
|
||||
|
||||
def get_config_from_root(root): |
||||
# This might raise EnvironmentError (if setup.cfg is missing), or |
||||
# configparser.NoSectionError (if it lacks a [versioneer] section), or |
||||
# configparser.NoOptionError (if it lacks "VCS="). See the docstring at |
||||
# the top of versioneer.py for instructions on writing your setup.cfg . |
||||
setup_cfg = os.path.join(root, "setup.cfg") |
||||
parser = configparser.SafeConfigParser() |
||||
with open(setup_cfg, "r") as f: |
||||
parser.readfp(f) |
||||
VCS = parser.get("versioneer", "VCS") # mandatory |
||||
|
||||
def get(parser, name): |
||||
if parser.has_option("versioneer", name): |
||||
return parser.get("versioneer", name) |
||||
return None |
||||
cfg = VersioneerConfig() |
||||
cfg.VCS = VCS |
||||
cfg.style = get(parser, "style") or "" |
||||
cfg.versionfile_source = get(parser, "versionfile_source") |
||||
cfg.versionfile_build = get(parser, "versionfile_build") |
||||
cfg.tag_prefix = get(parser, "tag_prefix") |
||||
cfg.parentdir_prefix = get(parser, "parentdir_prefix") |
||||
cfg.verbose = get(parser, "verbose") |
||||
return cfg |
||||
|
||||
|
||||
class NotThisMethod(Exception): |
||||
pass |
||||
|
||||
# these dictionaries contain VCS-specific tools |
||||
LONG_VERSION_PY = {} |
||||
HANDLERS = {} |
||||
|
||||
|
||||
def register_vcs_handler(vcs, method): # decorator |
||||
def decorate(f): |
||||
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): |
||||
assert isinstance(commands, list) |
||||
p = None |
||||
for c in commands: |
||||
try: |
||||
dispcmd = str([c] + args) |
||||
# remember shell=False, so use git.cmd on windows, not just git |
||||
p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE, |
||||
stderr=(subprocess.PIPE if hide_stderr |
||||
else None)) |
||||
break |
||||
except EnvironmentError: |
||||
e = sys.exc_info()[1] |
||||
if e.errno == errno.ENOENT: |
||||
continue |
||||
if verbose: |
||||
print("unable to run %s" % dispcmd) |
||||
print(e) |
||||
return None |
||||
else: |
||||
if verbose: |
||||
print("unable to find command, tried %s" % (commands,)) |
||||
return None |
||||
stdout = p.communicate()[0].strip() |
||||
if sys.version_info[0] >= 3: |
||||
stdout = stdout.decode() |
||||
if p.returncode != 0: |
||||
if verbose: |
||||
print("unable to run %s (error)" % dispcmd) |
||||
return None |
||||
return stdout |
||||
LONG_VERSION_PY['git'] = ''' |
||||
# 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.15 (https://github.com/warner/python-versioneer) |
||||
|
||||
import errno |
||||
import os |
||||
import re |
||||
import subprocess |
||||
import sys |
||||
|
||||
|
||||
def get_keywords(): |
||||
# 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 = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" |
||||
git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" |
||||
keywords = {"refnames": git_refnames, "full": git_full} |
||||
return keywords |
||||
|
||||
|
||||
class VersioneerConfig: |
||||
pass |
||||
|
||||
|
||||
def get_config(): |
||||
# these strings are filled in when 'setup.py versioneer' creates |
||||
# _version.py |
||||
cfg = VersioneerConfig() |
||||
cfg.VCS = "git" |
||||
cfg.style = "%(STYLE)s" |
||||
cfg.tag_prefix = "%(TAG_PREFIX)s" |
||||
cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" |
||||
cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" |
||||
cfg.verbose = False |
||||
return cfg |
||||
|
||||
|
||||
class NotThisMethod(Exception): |
||||
pass |
||||
|
||||
|
||||
LONG_VERSION_PY = {} |
||||
HANDLERS = {} |
||||
|
||||
|
||||
def register_vcs_handler(vcs, method): # decorator |
||||
def decorate(f): |
||||
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): |
||||
assert isinstance(commands, list) |
||||
p = None |
||||
for c in commands: |
||||
try: |
||||
dispcmd = str([c] + args) |
||||
# remember shell=False, so use git.cmd on windows, not just git |
||||
p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE, |
||||
stderr=(subprocess.PIPE if hide_stderr |
||||
else None)) |
||||
break |
||||
except EnvironmentError: |
||||
e = sys.exc_info()[1] |
||||
if e.errno == errno.ENOENT: |
||||
continue |
||||
if verbose: |
||||
print("unable to run %%s" %% dispcmd) |
||||
print(e) |
||||
return None |
||||
else: |
||||
if verbose: |
||||
print("unable to find command, tried %%s" %% (commands,)) |
||||
return None |
||||
stdout = p.communicate()[0].strip() |
||||
if sys.version_info[0] >= 3: |
||||
stdout = stdout.decode() |
||||
if p.returncode != 0: |
||||
if verbose: |
||||
print("unable to run %%s (error)" %% dispcmd) |
||||
return None |
||||
return stdout |
||||
|
||||