8 * like a rocketeer, but for versions!
9 * https://github.com/warner/python-versioneer
11 * License: Public Domain
12 * Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, and pypy
14 (https://pypip.in/version/versioneer/badge.svg?style=flat)
15 ](https://pypi.python.org/pypi/versioneer/)
17 (https://travis-ci.org/warner/python-versioneer.png?branch=master)
18 ](https://travis-ci.org/warner/python-versioneer)
20 This is a tool for managing a recorded version number in distutils-based
21 python projects. The goal is to remove the tedious and error-prone "update
22 the embedded version string" step from your release process. Making a new
23 release should be as easy as recording a new tag in your version-control
24 system, and maybe making new tarballs.
29 * `pip install versioneer` to somewhere to your $PATH
30 * add a `[versioneer]` section to your setup.cfg (see below)
31 * run `versioneer install` in your source tree, commit the results
33 ## Version Identifiers
35 Source trees come from a variety of places:
37 * a version-control system checkout (mostly used by developers)
38 * a nightly tarball, produced by build automation
39 * a snapshot tarball, produced by a web-based VCS browser, like github's
40 "tarball from tag" feature
41 * a release tarball, produced by "setup.py sdist", distributed through PyPI
43 Within each source tree, the version identifier (either a string or a number,
44 this tool is format-agnostic) can come from a variety of places:
46 * ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows
47 about recent "tags" and an absolute revision-id
48 * the name of the directory into which the tarball was unpacked
49 * an expanded VCS keyword ($Id$, etc)
50 * a `_version.py` created by some earlier build step
52 For released software, the version identifier is closely related to a VCS
53 tag. Some projects use tag names that include more than just the version
54 string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool
55 needs to strip the tag prefix to extract the version identifier. For
56 unreleased software (between tags), the version identifier should provide
57 enough information to help developers recreate the same tree, while also
58 giving them an idea of roughly how old the tree is (after version 1.2, before
59 version 1.3). Many VCS systems can report a description that captures this,
60 for example `git describe --tags --dirty --always` reports things like
61 "0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the
62 0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has
65 The version identifier is used for multiple purposes:
67 * to allow the module to self-identify its version: `myproject.__version__`
68 * to choose a name and prefix for a 'setup.py sdist' tarball
70 ## Theory of Operation
72 Versioneer works by adding a special `_version.py` file into your source
73 tree, where your `__init__.py` can import it. This `_version.py` knows how to
74 dynamically ask the VCS tool for version information at import time.
76 `_version.py` also contains `$Revision$` markers, and the installation
77 process marks `_version.py` to have this marker rewritten with a tag name
78 during the `git archive` command. As a result, generated tarballs will
79 contain enough information to get the proper version.
81 To allow `setup.py` to compute a version too, a `versioneer.py` is added to
82 the top level of your source tree, next to `setup.py` and the `setup.cfg`
83 that configures it. This overrides several distutils/setuptools commands to
84 compute the version when invoked, and changes `setup.py build` and `setup.py
85 sdist` to replace `_version.py` with a small static file that contains just
86 the generated version data.
90 First, decide on values for the following configuration variables:
92 * `VCS`: the version control system you use. Currently accepts "git".
94 * `style`: the style of version string to be produced. See "Styles" below for
95 details. Defaults to "pep440", which looks like
96 `TAG[+DISTANCE.gSHORTHASH[.dirty]]`.
98 * `versionfile_source`:
100 A project-relative pathname into which the generated version strings should
101 be written. This is usually a `_version.py` next to your project's main
102 `__init__.py` file, so it can be imported at runtime. If your project uses
103 `src/myproject/__init__.py`, this should be `src/myproject/_version.py`.
104 This file should be checked in to your VCS as usual: the copy created below
105 by `setup.py setup_versioneer` will include code that parses expanded VCS
106 keywords in generated tarballs. The 'build' and 'sdist' commands will
107 replace it with a copy that has just the calculated version string.
109 This must be set even if your project does not have any modules (and will
110 therefore never import `_version.py`), since "setup.py sdist" -based trees
111 still need somewhere to record the pre-calculated version strings. Anywhere
112 in the source tree should do. If there is a `__init__.py` next to your
113 `_version.py`, the `setup.py setup_versioneer` command (described below)
114 will append some `__version__`-setting assignments, if they aren't already
117 * `versionfile_build`:
119 Like `versionfile_source`, but relative to the build directory instead of
120 the source directory. These will differ when your setup.py uses
121 'package_dir='. If you have `package_dir={'myproject': 'src/myproject'}`,
122 then you will probably have `versionfile_build='myproject/_version.py'` and
123 `versionfile_source='src/myproject/_version.py'`.
125 If this is set to None, then `setup.py build` will not attempt to rewrite
126 any `_version.py` in the built tree. If your project does not have any
127 libraries (e.g. if it only builds a script), then you should use
128 `versionfile_build = None` and override `distutils.command.build_scripts`
129 to explicitly insert a copy of `versioneer.get_version()` into your
134 a string, like 'PROJECTNAME-', which appears at the start of all VCS tags.
135 If your tags look like 'myproject-1.2.0', then you should use
136 tag_prefix='myproject-'. If you use unprefixed tags like '1.2.0', this
137 should be an empty string.
139 * `parentdir_prefix`:
141 a optional string, frequently the same as tag_prefix, which appears at the
142 start of all unpacked tarball filenames. If your tarball unpacks into
143 'myproject-1.2.0', this should be 'myproject-'. To disable this feature,
144 just omit the field from your `setup.cfg`.
146 This tool provides one script, named `versioneer`. That script has one mode,
147 "install", which writes a copy of `versioneer.py` into the current directory
148 and runs `versioneer.py setup` to finish the installation.
150 To versioneer-enable your project:
152 * 1: Modify your `setup.cfg`, adding a section named `[versioneer]` and
153 populating it with the configuration values you decided earlier (note that
154 the option names are not case-sensitive):
160 versionfile_source = src/myproject/_version.py
161 versionfile_build = myproject/_version.py
163 parentdir_prefix = myproject-
166 * 2: Run `versioneer install`. This will do the following:
168 * copy `versioneer.py` into the top of your source tree
169 * create `_version.py` in the right place (`versionfile_source`)
170 * modify your `__init__.py` (if one exists next to `_version.py`) to define
171 `__version__` (by calling a function from `_version.py`)
172 * modify your `MANIFEST.in` to include both `versioneer.py` and the
173 generated `_version.py` in sdist tarballs
175 `versioneer install` will complain about any problems it finds with your
176 `setup.py` or `setup.cfg`. Run it multiple times until you have fixed all
179 * 3: add a `import versioneer` to your setup.py, and add the following
180 arguments to the setup() call:
182 version=versioneer.get_version(),
183 cmdclass=versioneer.get_cmdclass(),
185 * 4: commit these changes to your VCS. To make sure you won't forget,
186 `versioneer install` will mark everything it touched for addition using
187 `git add`. Don't forget to add `setup.py` and `setup.cfg` too.
189 ## Post-Installation Usage
191 Once established, all uses of your tree from a VCS checkout should get the
192 current version string. All generated tarballs should include an embedded
193 version string (so users who unpack them will not need a VCS tool installed).
195 If you distribute your project through PyPI, then the release process should
196 boil down to two steps:
199 * 2: python setup.py register sdist upload
201 If you distribute it through github (i.e. users use github to generate
202 tarballs with `git archive`), the process is:
205 * 2: git push; git push --tags
207 Versioneer will report "0+untagged.NUMCOMMITS.gHASH" until your tree has at
208 least one tag in its history.
210 ## Version-String Flavors
212 Code which uses Versioneer can learn about its version string at runtime by
213 importing `_version` from your main `__init__.py` file and running the
214 `get_versions()` function. From the "outside" (e.g. in `setup.py`), you can
215 import the top-level `versioneer.py` and run `get_versions()`.
217 Both functions return a dictionary with different flavors of version
220 * `['version']`: A condensed version string, rendered using the selected
221 style. This is the most commonly used value for the project's version
222 string. The default "pep440" style yields strings like `0.11`,
223 `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section
224 below for alternative styles.
226 * `['full-revisionid']`: detailed revision identifier. For Git, this is the
227 full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac".
229 * `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that
230 this is only accurate if run in a VCS checkout, otherwise it is likely to
233 * `['error']`: if the version string could not be computed, this will be set
234 to a string describing the problem, otherwise it will be None. It may be
235 useful to throw an exception in setup.py if this is set, to avoid e.g.
236 creating tarballs with a version string of "unknown".
238 Some variants are more useful than others. Including `full-revisionid` in a
239 bug report should allow developers to reconstruct the exact code being tested
240 (or indicate the presence of local changes that should be shared with the
241 developers). `version` is suitable for display in an "about" box or a CLI
242 `--version` output: it can be easily compared against release notes and lists
243 of bugs fixed in various releases.
245 The installer adds the following text to your `__init__.py` to place a basic
246 version in `YOURPROJECT.__version__`:
248 from ._version import get_versions
249 __version__ = get_versions()['version']
254 The setup.cfg `style=` configuration controls how the VCS information is
255 rendered into a version string.
257 The default style, "pep440", produces a PEP440-compliant string, equal to the
258 un-prefixed tag name for actual releases, and containing an additional "local
259 version" section with more detail for in-between builds. For Git, this is
260 TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags
261 --dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the
262 tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and
263 that this commit is two revisions ("+2") beyond the "0.11" tag. For released
264 software (exactly equal to a known tag), the identifier will only contain the
265 stripped tag, e.g. "0.11".
267 Other styles are available. See details.md in the Versioneer source tree for
272 Versioneer tries to avoid fatal errors: if something goes wrong, it will tend
273 to return a version of "0+unknown". To investigate the problem, run `setup.py
274 version`, which will run the version-lookup code in a verbose mode, and will
275 display the full contents of `get_versions()` (including the `error` string,
276 which may help identify what went wrong).
278 ## Updating Versioneer
280 To upgrade your project to a new release of Versioneer, do the following:
282 * install the new Versioneer (`pip install -U versioneer` or equivalent)
283 * edit `setup.cfg`, if necessary, to include any new configuration settings
284 indicated by the release notes
285 * re-run `versioneer install` in your source tree, to replace
287 * commit any changed files
289 ### Upgrading to 0.15
291 Starting with this version, Versioneer is configured with a `[versioneer]`
292 section in your `setup.cfg` file. Earlier versions required the `setup.py` to
293 set attributes on the `versioneer` module immediately after import. The new
294 version will refuse to run (raising an exception during import) until you
295 have provided the necessary `setup.cfg` section.
297 In addition, the Versioneer package provides an executable named
298 `versioneer`, and the installation process is driven by running `versioneer
299 install`. In 0.14 and earlier, the executable was named
300 `versioneer-installer` and was run without an argument.
302 ### Upgrading to 0.14
304 0.14 changes the format of the version string. 0.13 and earlier used
305 hyphen-separated strings like "0.11-2-g1076c97-dirty". 0.14 and beyond use a
306 plus-separated "local version" section strings, with dot-separated
307 components, like "0.11+2.g1076c97". PEP440-strict tools did not like the old
308 format, but should be ok with the new one.
310 ### Upgrading from 0.11 to 0.12
314 ### Upgrading from 0.10 to 0.11
316 You must add a `versioneer.VCS = "git"` to your `setup.py` before re-running
317 `setup.py setup_versioneer`. This will enable the use of additional
318 version-control systems (SVN, etc) in the future.
322 This tool is designed to make it easily extended to other version-control
323 systems: all VCS-specific components are in separate directories like
324 src/git/ . The top-level `versioneer.py` script is assembled from these
325 components by running make-versioneer.py . In the future, make-versioneer.py
326 will take a VCS name as an argument, and will construct a version of
327 `versioneer.py` that is specific to the given VCS. It might also take the
328 configuration arguments that are currently provided manually during
329 installation by editing setup.py . Alternatively, it might go the other
330 direction and include code from all supported VCS systems, reducing the
331 number of intermediate scripts.
336 To make Versioneer easier to embed, all its code is hereby released into the
337 public domain. The `_version.py` that it creates is also in the public
342 from __future__
import print_function
346 import ConfigParser
as configparser
355 class VersioneerConfig
:
360 # we require that all commands are run from the project root, i.e. the
361 # directory that contains setup.py, setup.cfg, and versioneer.py .
362 root
= os
.path
.realpath(os
.path
.abspath(os
.getcwd()))
363 setup_py
= os
.path
.join(root
, "setup.py")
364 versioneer_py
= os
.path
.join(root
, "versioneer.py")
365 if not (os
.path
.exists(setup_py
) or os
.path
.exists(versioneer_py
)):
366 # allow 'python path/to/setup.py COMMAND'
367 root
= os
.path
.dirname(os
.path
.realpath(os
.path
.abspath(sys
.argv
[0])))
368 setup_py
= os
.path
.join(root
, "setup.py")
369 versioneer_py
= os
.path
.join(root
, "versioneer.py")
370 if not (os
.path
.exists(setup_py
) or os
.path
.exists(versioneer_py
)):
371 err
= ("Versioneer was unable to run the project root directory. "
372 "Versioneer requires setup.py to be executed from "
373 "its immediate directory (like 'python setup.py COMMAND'), "
374 "or in a way that lets it use sys.argv[0] to find the root "
375 "(like 'python path/to/setup.py COMMAND').")
376 raise VersioneerBadRootError(err
)
378 # Certain runtime workflows (setup.py install/develop in a setuptools
379 # tree) execute all dependencies in a single python process, so
380 # "versioneer" may be imported multiple times, and python's shared
381 # module-import table will cache the first one. So we can't use
382 # os.path.dirname(__file__), as that will find whichever
383 # versioneer.py was first imported, even in later projects.
384 me
= os
.path
.realpath(os
.path
.abspath(__file__
))
385 if os
.path
.splitext(me
)[0] != os
.path
.splitext(versioneer_py
)[0]:
386 print("Warning: build in %s is using versioneer.py from %s"
387 % (os
.path
.dirname(me
), versioneer_py
))
393 def get_config_from_root(root
):
394 # This might raise EnvironmentError (if setup.cfg is missing), or
395 # configparser.NoSectionError (if it lacks a [versioneer] section), or
396 # configparser.NoOptionError (if it lacks "VCS="). See the docstring at
397 # the top of versioneer.py for instructions on writing your setup.cfg .
398 setup_cfg
= os
.path
.join(root
, "setup.cfg")
399 parser
= configparser
.SafeConfigParser()
400 with
open(setup_cfg
, "r") as f
:
402 VCS
= parser
.get("versioneer", "VCS") # mandatory
404 def get(parser
, name
):
405 if parser
.has_option("versioneer", name
):
406 return parser
.get("versioneer", name
)
408 cfg
= VersioneerConfig()
410 cfg
.style
= get(parser
, "style") or ""
411 cfg
.versionfile_source
= get(parser
, "versionfile_source")
412 cfg
.versionfile_build
= get(parser
, "versionfile_build")
413 cfg
.tag_prefix
= get(parser
, "tag_prefix")
414 cfg
.parentdir_prefix
= get(parser
, "parentdir_prefix")
415 cfg
.verbose
= get(parser
, "verbose")
419 class NotThisMethod(Exception):
422 # these dictionaries contain VCS-specific tools
427 def register_vcs_handler(vcs
, method
): # decorator
429 if vcs
not in HANDLERS
:
431 HANDLERS
[vcs
][method
] = f
436 def run_command(commands
, args
, cwd
=None, verbose
=False, hide_stderr
=False):
437 assert isinstance(commands
, list)
441 dispcmd
= str([c
] + args
)
442 # remember shell=False, so use git.cmd on windows, not just git
443 p
= subprocess
.Popen([c
] + args
, cwd
=cwd
, stdout
=subprocess
.PIPE
,
444 stderr
=(subprocess
.PIPE
if hide_stderr
447 except EnvironmentError:
448 e
= sys
.exc_info()[1]
449 if e
.errno
== errno
.ENOENT
:
452 print("unable to run %s" % dispcmd
)
457 print("unable to find command, tried %s" % (commands
,))
459 stdout
= p
.communicate()[0].strip()
460 if sys
.version_info
[0] >= 3:
461 stdout
= stdout
.decode()
462 if p
.returncode
!= 0:
464 print("unable to run %s (error)" % dispcmd
)
467 LONG_VERSION_PY
['git'] = '''
468 # This file helps to compute a version number in source trees obtained from
469 # git-archive tarball (such as those provided by githubs download-from-tag
470 # feature). Distribution tarballs (built by setup.py sdist) and build
471 # directories (produced by setup.py build) will contain a much shorter file
472 # that just contains the computed version number.
474 # This file is released into the public domain. Generated by
475 # versioneer-0.15 (https://github.com/warner/python-versioneer)
485 # these strings will be replaced by git during git-archive.
486 # setup.py/versioneer.py will grep for the variable names, so they must
487 # each be defined on a line of their own. _version.py will just call
489 git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s"
490 git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s"
491 keywords = {"refnames": git_refnames, "full": git_full}
495 class VersioneerConfig:
500 # these strings are filled in when 'setup.py versioneer' creates
502 cfg = VersioneerConfig()
504 cfg.style = "%(STYLE)s"
505 cfg.tag_prefix = "%(TAG_PREFIX)s"
506 cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s"
507 cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s"
512 class NotThisMethod(Exception):
520 def register_vcs_handler(vcs, method): # decorator
522 if vcs not in HANDLERS:
524 HANDLERS[vcs][method] = f
529 def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
530 assert isinstance(commands, list)
534 dispcmd = str([c] + args)
535 # remember shell=False, so use git.cmd on windows, not just git
536 p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
537 stderr=(subprocess.PIPE if hide_stderr
540 except EnvironmentError:
541 e = sys.exc_info()[1]
542 if e.errno == errno.ENOENT:
545 print("unable to run %%s" %% dispcmd)
550 print("unable to find command, tried %%s" %% (commands,))
552 stdout = p.communicate()[0].strip()
553 if sys.version_info[0] >= 3:
554 stdout = stdout.decode()
555 if p.returncode != 0:
557 print("unable to run %%s (error)" %% dispcmd)
562 def versions_from_parentdir(parentdir_prefix, root, verbose):
563 # Source tarballs conventionally unpack into a directory that includes
564 # both the project name and a version string.
565 dirname = os.path.basename(root)
566 if not dirname.startswith(parentdir_prefix):
568 print("guessing rootdir is '%%s', but '%%s' doesn't start with "
569 "prefix '%%s'" %% (root, dirname, parentdir_prefix))
570 raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
571 return {"version": dirname[len(parentdir_prefix):],
572 "full-revisionid": None,
573 "dirty": False, "error": None}
576 @register_vcs_handler("git", "get_keywords")
577 def git_get_keywords(versionfile_abs):
578 # the code embedded in _version.py can just fetch the value of these
579 # keywords. When used from setup.py, we don't want to import _version.py,
580 # so we do it with a regexp instead. This function is not used from
584 f = open(versionfile_abs, "r")
585 for line in f.readlines():
586 if line.strip().startswith("git_refnames ="):
587 mo = re.search(r'=\s*"(.*)"', line)
589 keywords["refnames"] = mo.group(1)
590 if line.strip().startswith("git_full ="):
591 mo = re.search(r'=\s*"(.*)"', line)
593 keywords["full"] = mo.group(1)
595 except EnvironmentError:
600 @register_vcs_handler("git", "keywords")
601 def git_versions_from_keywords(keywords, tag_prefix, verbose):
603 raise NotThisMethod("no keywords at all, weird")
604 refnames = keywords["refnames"].strip()
605 if refnames.startswith("$Format"):
607 print("keywords are unexpanded, not using")
608 raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
609 refs = set([r.strip() for r in refnames.strip("()").split(",")])
610 # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
611 # just "foo-1.0". If we see a "tag: " prefix, prefer those.
613 tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
615 # Either we're using git < 1.8.3, or there really are no tags. We use
616 # a heuristic: assume all version tags have a digit. The old git %%d
617 # expansion behaves like git log --decorate=short and strips out the
618 # refs/heads/ and refs/tags/ prefixes that would let us distinguish
619 # between branches and tags. By ignoring refnames without digits, we
620 # filter out many common branch names like "release" and
621 # "stabilization", as well as "HEAD" and "master".
622 tags = set([r for r in refs if re.search(r'\d', r)])
624 print("discarding '%%s', no digits" %% ",".join(refs-tags))
626 print("likely tags: %%s" %% ",".join(sorted(tags)))
627 for ref in sorted(tags):
628 # sorting will prefer e.g. "2.0" over "2.0rc1"
629 if ref.startswith(tag_prefix):
630 r = ref[len(tag_prefix):]
632 print("picking %%s" %% r)
633 return {"version": r,
634 "full-revisionid": keywords["full"].strip(),
635 "dirty": False, "error": None
637 # no suitable tags, so version is "0+unknown", but full hex is still there
639 print("no suitable tags, using unknown + full revision id")
640 return {"version": "0+unknown",
641 "full-revisionid": keywords["full"].strip(),
642 "dirty": False, "error": "no suitable tags"}
645 @register_vcs_handler("git", "pieces_from_vcs")
646 def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
647 # this runs 'git' from the root of the source tree. This only gets called
648 # if the git-archive 'subst' keywords were *not* expanded, and
649 # _version.py hasn't already been rewritten with a short version string,
650 # meaning we're inside a checked out source tree.
652 if not os.path.exists(os.path.join(root, ".git")):
654 print("no .git in %%s" %% root)
655 raise NotThisMethod("no .git directory")
658 if sys.platform == "win32":
659 GITS = ["git.cmd", "git.exe"]
660 # if there is a tag, this yields TAG-NUM-gHEX[-dirty]
661 # if there are no tags, this yields HEX[-dirty] (no NUM)
662 describe_out = run_command(GITS, ["describe", "--tags", "--dirty",
663 "--always", "--long"],
665 # --long was added in git-1.5.5
666 if describe_out is None:
667 raise NotThisMethod("'git describe' failed")
668 describe_out = describe_out.strip()
669 full_out = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
671 raise NotThisMethod("'git rev-parse' failed")
672 full_out = full_out.strip()
675 pieces["long"] = full_out
676 pieces["short"] = full_out[:7] # maybe improved later
677 pieces["error"] = None
679 # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
680 # TAG might have hyphens.
681 git_describe = describe_out
683 # look for -dirty suffix
684 dirty = git_describe.endswith("-dirty")
685 pieces["dirty"] = dirty
687 git_describe = git_describe[:git_describe.rindex("-dirty")]
689 # now we have TAG-NUM-gHEX or HEX
691 if "-" in git_describe:
693 mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
695 # unparseable. Maybe git-describe is misbehaving?
696 pieces["error"] = ("unable to parse git-describe output: '%%s'"
701 full_tag = mo.group(1)
702 if not full_tag.startswith(tag_prefix):
704 fmt = "tag '%%s' doesn't start with prefix '%%s'"
705 print(fmt %% (full_tag, tag_prefix))
706 pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'"
707 %% (full_tag, tag_prefix))
709 pieces["closest-tag"] = full_tag[len(tag_prefix):]
711 # distance: number of commits since tag
712 pieces["distance"] = int(mo.group(2))
714 # commit: short hex revision ID
715 pieces["short"] = mo.group(3)
719 pieces["closest-tag"] = None
720 count_out = run_command(GITS, ["rev-list", "HEAD", "--count"],
722 pieces["distance"] = int(count_out) # total number of commits
727 def plus_or_dot(pieces):
728 if "+" in pieces.get("closest-tag", ""):
733 def render_pep440(pieces):
734 # now build up version string, with post-release "local version
735 # identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
736 # get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
739 # 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
741 if pieces["closest-tag"]:
742 rendered = pieces["closest-tag"]
743 if pieces["distance"] or pieces["dirty"]:
744 rendered += plus_or_dot(pieces)
745 rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"])
750 rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"],
757 def render_pep440_pre(pieces):
758 # TAG[.post.devDISTANCE] . No -dirty
761 # 1: no tags. 0.post.devDISTANCE
763 if pieces["closest-tag"]:
764 rendered = pieces["closest-tag"]
765 if pieces["distance"]:
766 rendered += ".post.dev%%d" %% pieces["distance"]
769 rendered = "0.post.dev%%d" %% pieces["distance"]
773 def render_pep440_post(pieces):
774 # TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that
775 # .dev0 sorts backwards (a dirty tree will appear "older" than the
776 # corresponding clean one), but you shouldn't be releasing software with
780 # 1: no tags. 0.postDISTANCE[.dev0]
782 if pieces["closest-tag"]:
783 rendered = pieces["closest-tag"]
784 if pieces["distance"] or pieces["dirty"]:
785 rendered += ".post%%d" %% pieces["distance"]
788 rendered += plus_or_dot(pieces)
789 rendered += "g%%s" %% pieces["short"]
792 rendered = "0.post%%d" %% pieces["distance"]
795 rendered += "+g%%s" %% pieces["short"]
799 def render_pep440_old(pieces):
800 # TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty.
803 # 1: no tags. 0.postDISTANCE[.dev0]
805 if pieces["closest-tag"]:
806 rendered = pieces["closest-tag"]
807 if pieces["distance"] or pieces["dirty"]:
808 rendered += ".post%%d" %% pieces["distance"]
813 rendered = "0.post%%d" %% pieces["distance"]
819 def render_git_describe(pieces):
820 # TAG[-DISTANCE-gHEX][-dirty], like 'git describe --tags --dirty
824 # 1: no tags. HEX[-dirty] (note: no 'g' prefix)
826 if pieces["closest-tag"]:
827 rendered = pieces["closest-tag"]
828 if pieces["distance"]:
829 rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"])
832 rendered = pieces["short"]
838 def render_git_describe_long(pieces):
839 # TAG-DISTANCE-gHEX[-dirty], like 'git describe --tags --dirty
840 # --always -long'. The distance/hash is unconditional.
843 # 1: no tags. HEX[-dirty] (note: no 'g' prefix)
845 if pieces["closest-tag"]:
846 rendered = pieces["closest-tag"]
847 rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"])
850 rendered = pieces["short"]
856 def render(pieces, style):
858 return {"version": "unknown",
859 "full-revisionid": pieces.get("long"),
861 "error": pieces["error"]}
863 if not style or style == "default":
864 style = "pep440" # the default
866 if style == "pep440":
867 rendered = render_pep440(pieces)
868 elif style == "pep440-pre":
869 rendered = render_pep440_pre(pieces)
870 elif style == "pep440-post":
871 rendered = render_pep440_post(pieces)
872 elif style == "pep440-old":
873 rendered = render_pep440_old(pieces)
874 elif style == "git-describe":
875 rendered = render_git_describe(pieces)
876 elif style == "git-describe-long":
877 rendered = render_git_describe_long(pieces)
879 raise ValueError("unknown style '%%s'" %% style)
881 return {"version": rendered, "full-revisionid": pieces["long"],
882 "dirty": pieces["dirty"], "error": None}
886 # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
887 # __file__, we can work backwards from there to the root. Some
888 # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
889 # case we can only use expanded keywords.
892 verbose = cfg.verbose
895 return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
897 except NotThisMethod:
901 root = os.path.realpath(__file__)
902 # versionfile_source is the relative path from the top of the source
903 # tree (where the .git directory might live) to this file. Invert
904 # this to find the root from __file__.
905 for i in cfg.versionfile_source.split('/'):
906 root = os.path.dirname(root)
908 return {"version": "0+unknown", "full-revisionid": None,
910 "error": "unable to find root of source tree"}
913 pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
914 return render(pieces, cfg.style)
915 except NotThisMethod:
919 if cfg.parentdir_prefix:
920 return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
921 except NotThisMethod:
924 return {"version": "0+unknown", "full-revisionid": None,
926 "error": "unable to compute version"}
930 @register_vcs_handler("git", "get_keywords")
931 def git_get_keywords(versionfile_abs
):
932 # the code embedded in _version.py can just fetch the value of these
933 # keywords. When used from setup.py, we don't want to import _version.py,
934 # so we do it with a regexp instead. This function is not used from
938 f
= open(versionfile_abs
, "r")
939 for line
in f
.readlines():
940 if line
.strip().startswith("git_refnames ="):
941 mo
= re
.search(r
'=\s*"(.*)"', line
)
943 keywords
["refnames"] = mo
.group(1)
944 if line
.strip().startswith("git_full ="):
945 mo
= re
.search(r
'=\s*"(.*)"', line
)
947 keywords
["full"] = mo
.group(1)
949 except EnvironmentError:
954 @register_vcs_handler("git", "keywords")
955 def git_versions_from_keywords(keywords
, tag_prefix
, verbose
):
957 raise NotThisMethod("no keywords at all, weird")
958 refnames
= keywords
["refnames"].strip()
959 if refnames
.startswith("$Format"):
961 print("keywords are unexpanded, not using")
962 raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
963 refs
= set([r
.strip() for r
in refnames
.strip("()").split(",")])
964 # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
965 # just "foo-1.0". If we see a "tag: " prefix, prefer those.
967 tags
= set([r
[len(TAG
):] for r
in refs
if r
.startswith(TAG
)])
969 # Either we're using git < 1.8.3, or there really are no tags. We use
970 # a heuristic: assume all version tags have a digit. The old git %d
971 # expansion behaves like git log --decorate=short and strips out the
972 # refs/heads/ and refs/tags/ prefixes that would let us distinguish
973 # between branches and tags. By ignoring refnames without digits, we
974 # filter out many common branch names like "release" and
975 # "stabilization", as well as "HEAD" and "master".
976 tags
= set([r
for r
in refs
if re
.search(r
'\d', r
)])
978 print("discarding '%s', no digits" % ",".join(refs
-tags
))
980 print("likely tags: %s" % ",".join(sorted(tags
)))
981 for ref
in sorted(tags
):
982 # sorting will prefer e.g. "2.0" over "2.0rc1"
983 if ref
.startswith(tag_prefix
):
984 r
= ref
[len(tag_prefix
):]
986 print("picking %s" % r
)
987 return {"version": r
,
988 "full-revisionid": keywords
["full"].strip(),
989 "dirty": False, "error": None
991 # no suitable tags, so version is "0+unknown", but full hex is still there
993 print("no suitable tags, using unknown + full revision id")
994 return {"version": "0+unknown",
995 "full-revisionid": keywords
["full"].strip(),
996 "dirty": False, "error": "no suitable tags"}
999 @register_vcs_handler("git", "pieces_from_vcs")
1000 def git_pieces_from_vcs(tag_prefix
, root
, verbose
, run_command
=run_command
):
1001 # this runs 'git' from the root of the source tree. This only gets called
1002 # if the git-archive 'subst' keywords were *not* expanded, and
1003 # _version.py hasn't already been rewritten with a short version string,
1004 # meaning we're inside a checked out source tree.
1006 if not os
.path
.exists(os
.path
.join(root
, ".git")):
1008 print("no .git in %s" % root
)
1009 raise NotThisMethod("no .git directory")
1012 if sys
.platform
== "win32":
1013 GITS
= ["git.cmd", "git.exe"]
1014 # if there is a tag, this yields TAG-NUM-gHEX[-dirty]
1015 # if there are no tags, this yields HEX[-dirty] (no NUM)
1016 describe_out
= run_command(GITS
, ["describe", "--tags", "--dirty",
1017 "--always", "--long"],
1019 # --long was added in git-1.5.5
1020 if describe_out
is None:
1021 raise NotThisMethod("'git describe' failed")
1022 describe_out
= describe_out
.strip()
1023 full_out
= run_command(GITS
, ["rev-parse", "HEAD"], cwd
=root
)
1024 if full_out
is None:
1025 raise NotThisMethod("'git rev-parse' failed")
1026 full_out
= full_out
.strip()
1029 pieces
["long"] = full_out
1030 pieces
["short"] = full_out
[:7] # maybe improved later
1031 pieces
["error"] = None
1033 # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
1034 # TAG might have hyphens.
1035 git_describe
= describe_out
1037 # look for -dirty suffix
1038 dirty
= git_describe
.endswith("-dirty")
1039 pieces
["dirty"] = dirty
1041 git_describe
= git_describe
[:git_describe
.rindex("-dirty")]
1043 # now we have TAG-NUM-gHEX or HEX
1045 if "-" in git_describe
:
1047 mo
= re
.search(r
'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe
)
1049 # unparseable. Maybe git-describe is misbehaving?
1050 pieces
["error"] = ("unable to parse git-describe output: '%s'"
1055 full_tag
= mo
.group(1)
1056 if not full_tag
.startswith(tag_prefix
):
1058 fmt
= "tag '%s' doesn't start with prefix '%s'"
1059 print(fmt
% (full_tag
, tag_prefix
))
1060 pieces
["error"] = ("tag '%s' doesn't start with prefix '%s'"
1061 % (full_tag
, tag_prefix
))
1063 pieces
["closest-tag"] = full_tag
[len(tag_prefix
):]
1065 # distance: number of commits since tag
1066 pieces
["distance"] = int(mo
.group(2))
1068 # commit: short hex revision ID
1069 pieces
["short"] = mo
.group(3)
1073 pieces
["closest-tag"] = None
1074 count_out
= run_command(GITS
, ["rev-list", "HEAD", "--count"],
1076 pieces
["distance"] = int(count_out
) # total number of commits
1081 def do_vcs_install(manifest_in
, versionfile_source
, ipy
):
1083 if sys
.platform
== "win32":
1084 GITS
= ["git.cmd", "git.exe"]
1085 files
= [manifest_in
, versionfile_source
]
1090 if me
.endswith(".pyc") or me
.endswith(".pyo"):
1091 me
= os
.path
.splitext(me
)[0] + ".py"
1092 versioneer_file
= os
.path
.relpath(me
)
1094 versioneer_file
= "versioneer.py"
1095 files
.append(versioneer_file
)
1098 f
= open(".gitattributes", "r")
1099 for line
in f
.readlines():
1100 if line
.strip().startswith(versionfile_source
):
1101 if "export-subst" in line
.strip().split()[1:]:
1104 except EnvironmentError:
1107 f
= open(".gitattributes", "a+")
1108 f
.write("%s export-subst\n" % versionfile_source
)
1110 files
.append(".gitattributes")
1111 run_command(GITS
, ["add", "--"] + files
)
1114 def versions_from_parentdir(parentdir_prefix
, root
, verbose
):
1115 # Source tarballs conventionally unpack into a directory that includes
1116 # both the project name and a version string.
1117 dirname
= os
.path
.basename(root
)
1118 if not dirname
.startswith(parentdir_prefix
):
1120 print("guessing rootdir is '%s', but '%s' doesn't start with "
1121 "prefix '%s'" % (root
, dirname
, parentdir_prefix
))
1122 raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
1123 return {"version": dirname
[len(parentdir_prefix
):],
1124 "full-revisionid": None,
1125 "dirty": False, "error": None}
1127 SHORT_VERSION_PY
= """
1128 # This file was generated by 'versioneer.py' (0.15) from
1129 # revision-control system data, or from the parent directory name of an
1130 # unpacked source archive. Distribution tarballs contain a pre-generated copy
1138 ''' # END VERSION_JSON
1142 return json.loads(version_json)
1146 def versions_from_file(filename
):
1148 with
open(filename
) as f
:
1150 except EnvironmentError:
1151 raise NotThisMethod("unable to read _version.py")
1152 mo
= re
.search(r
"version_json = '''\n(.*)''' # END VERSION_JSON",
1153 contents
, re
.M | re
.S
)
1155 raise NotThisMethod("no version_json in _version.py")
1156 return json
.loads(mo
.group(1))
1159 def write_to_version_file(filename
, versions
):
1161 contents
= json
.dumps(versions
, sort_keys
=True,
1162 indent
=1, separators
=(",", ": "))
1163 with
open(filename
, "w") as f
:
1164 f
.write(SHORT_VERSION_PY
% contents
)
1166 print("set %s to '%s'" % (filename
, versions
["version"]))
1169 def plus_or_dot(pieces
):
1170 if "+" in pieces
.get("closest-tag", ""):
1175 def render_pep440(pieces
):
1176 # now build up version string, with post-release "local version
1177 # identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
1178 # get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
1181 # 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
1183 if pieces
["closest-tag"]:
1184 rendered
= pieces
["closest-tag"]
1185 if pieces
["distance"] or pieces
["dirty"]:
1186 rendered
+= plus_or_dot(pieces
)
1187 rendered
+= "%d.g%s" % (pieces
["distance"], pieces
["short"])
1189 rendered
+= ".dirty"
1192 rendered
= "0+untagged.%d.g%s" % (pieces
["distance"],
1195 rendered
+= ".dirty"
1199 def render_pep440_pre(pieces
):
1200 # TAG[.post.devDISTANCE] . No -dirty
1203 # 1: no tags. 0.post.devDISTANCE
1205 if pieces
["closest-tag"]:
1206 rendered
= pieces
["closest-tag"]
1207 if pieces
["distance"]:
1208 rendered
+= ".post.dev%d" % pieces
["distance"]
1211 rendered
= "0.post.dev%d" % pieces
["distance"]
1215 def render_pep440_post(pieces
):
1216 # TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that
1217 # .dev0 sorts backwards (a dirty tree will appear "older" than the
1218 # corresponding clean one), but you shouldn't be releasing software with
1222 # 1: no tags. 0.postDISTANCE[.dev0]
1224 if pieces
["closest-tag"]:
1225 rendered
= pieces
["closest-tag"]
1226 if pieces
["distance"] or pieces
["dirty"]:
1227 rendered
+= ".post%d" % pieces
["distance"]
1230 rendered
+= plus_or_dot(pieces
)
1231 rendered
+= "g%s" % pieces
["short"]
1234 rendered
= "0.post%d" % pieces
["distance"]
1237 rendered
+= "+g%s" % pieces
["short"]
1241 def render_pep440_old(pieces
):
1242 # TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty.
1245 # 1: no tags. 0.postDISTANCE[.dev0]
1247 if pieces
["closest-tag"]:
1248 rendered
= pieces
["closest-tag"]
1249 if pieces
["distance"] or pieces
["dirty"]:
1250 rendered
+= ".post%d" % pieces
["distance"]
1255 rendered
= "0.post%d" % pieces
["distance"]
1261 def render_git_describe(pieces
):
1262 # TAG[-DISTANCE-gHEX][-dirty], like 'git describe --tags --dirty
1266 # 1: no tags. HEX[-dirty] (note: no 'g' prefix)
1268 if pieces
["closest-tag"]:
1269 rendered
= pieces
["closest-tag"]
1270 if pieces
["distance"]:
1271 rendered
+= "-%d-g%s" % (pieces
["distance"], pieces
["short"])
1274 rendered
= pieces
["short"]
1276 rendered
+= "-dirty"
1280 def render_git_describe_long(pieces
):
1281 # TAG-DISTANCE-gHEX[-dirty], like 'git describe --tags --dirty
1282 # --always -long'. The distance/hash is unconditional.
1285 # 1: no tags. HEX[-dirty] (note: no 'g' prefix)
1287 if pieces
["closest-tag"]:
1288 rendered
= pieces
["closest-tag"]
1289 rendered
+= "-%d-g%s" % (pieces
["distance"], pieces
["short"])
1292 rendered
= pieces
["short"]
1294 rendered
+= "-dirty"
1298 def render(pieces
, style
):
1300 return {"version": "unknown",
1301 "full-revisionid": pieces
.get("long"),
1303 "error": pieces
["error"]}
1305 if not style
or style
== "default":
1306 style
= "pep440" # the default
1308 if style
== "pep440":
1309 rendered
= render_pep440(pieces
)
1310 elif style
== "pep440-pre":
1311 rendered
= render_pep440_pre(pieces
)
1312 elif style
== "pep440-post":
1313 rendered
= render_pep440_post(pieces
)
1314 elif style
== "pep440-old":
1315 rendered
= render_pep440_old(pieces
)
1316 elif style
== "git-describe":
1317 rendered
= render_git_describe(pieces
)
1318 elif style
== "git-describe-long":
1319 rendered
= render_git_describe_long(pieces
)
1321 raise ValueError("unknown style '%s'" % style
)
1323 return {"version": rendered
, "full-revisionid": pieces
["long"],
1324 "dirty": pieces
["dirty"], "error": None}
1327 class VersioneerBadRootError(Exception):
1331 def get_versions(verbose
=False):
1332 # returns dict with two keys: 'version' and 'full'
1334 if "versioneer" in sys
.modules
:
1335 # see the discussion in cmdclass.py:get_cmdclass()
1336 del sys
.modules
["versioneer"]
1339 cfg
= get_config_from_root(root
)
1341 assert cfg
.VCS
is not None, "please set [versioneer]VCS= in setup.cfg"
1342 handlers
= HANDLERS
.get(cfg
.VCS
)
1343 assert handlers
, "unrecognized VCS '%s'" % cfg
.VCS
1344 verbose
= verbose
or cfg
.verbose
1345 assert cfg
.versionfile_source
is not None, \
1346 "please set versioneer.versionfile_source"
1347 assert cfg
.tag_prefix
is not None, "please set versioneer.tag_prefix"
1349 versionfile_abs
= os
.path
.join(root
, cfg
.versionfile_source
)
1351 # extract version from first of: _version.py, VCS command (e.g. 'git
1352 # describe'), parentdir. This is meant to work for developers using a
1353 # source checkout, for users of a tarball created by 'setup.py sdist',
1354 # and for users of a tarball/zipball created by 'git archive' or github's
1355 # download-from-tag feature or the equivalent in other VCSes.
1357 get_keywords_f
= handlers
.get("get_keywords")
1358 from_keywords_f
= handlers
.get("keywords")
1359 if get_keywords_f
and from_keywords_f
:
1361 keywords
= get_keywords_f(versionfile_abs
)
1362 ver
= from_keywords_f(keywords
, cfg
.tag_prefix
, verbose
)
1364 print("got version from expanded keyword %s" % ver
)
1366 except NotThisMethod
:
1370 ver
= versions_from_file(versionfile_abs
)
1372 print("got version from file %s %s" % (versionfile_abs
, ver
))
1374 except NotThisMethod
:
1377 from_vcs_f
= handlers
.get("pieces_from_vcs")
1380 pieces
= from_vcs_f(cfg
.tag_prefix
, root
, verbose
)
1381 ver
= render(pieces
, cfg
.style
)
1383 print("got version from VCS %s" % ver
)
1385 except NotThisMethod
:
1389 if cfg
.parentdir_prefix
:
1390 ver
= versions_from_parentdir(cfg
.parentdir_prefix
, root
, verbose
)
1392 print("got version from parentdir %s" % ver
)
1394 except NotThisMethod
:
1398 print("unable to compute version")
1400 return {"version": "0+unknown", "full-revisionid": None,
1401 "dirty": None, "error": "unable to compute version"}
1405 return get_versions()["version"]
1409 if "versioneer" in sys
.modules
:
1410 del sys
.modules
["versioneer"]
1411 # this fixes the "python setup.py develop" case (also 'install' and
1412 # 'easy_install .'), in which subdependencies of the main project are
1413 # built (using setup.py bdist_egg) in the same python process. Assume
1414 # a main project A and a dependency B, which use different versions
1415 # of Versioneer. A's setup.py imports A's Versioneer, leaving it in
1416 # sys.modules by the time B's setup.py is executed, causing B to run
1417 # with the wrong versioneer. Setuptools wraps the sub-dep builds in a
1418 # sandbox that restores sys.modules to it's pre-build state, so the
1419 # parent is protected against the child's "import versioneer". By
1420 # removing ourselves from sys.modules here, before the child build
1421 # happens, we protect the child from the parent's versioneer too.
1422 # Also see https://github.com/warner/python-versioneer/issues/52
1426 # we add "version" to both distutils and setuptools
1427 from distutils
.core
import Command
1429 class cmd_version(Command
):
1430 description
= "report generated version string"
1432 boolean_options
= []
1434 def initialize_options(self
):
1437 def finalize_options(self
):
1441 vers
= get_versions(verbose
=True)
1442 print("Version: %s" % vers
["version"])
1443 print(" full-revisionid: %s" % vers
.get("full-revisionid"))
1444 print(" dirty: %s" % vers
.get("dirty"))
1446 print(" error: %s" % vers
["error"])
1447 cmds
["version"] = cmd_version
1449 # we override "build_py" in both distutils and setuptools
1451 # most invocation pathways end up running build_py:
1452 # distutils/build -> build_py
1453 # distutils/install -> distutils/build ->..
1454 # setuptools/bdist_wheel -> distutils/install ->..
1455 # setuptools/bdist_egg -> distutils/install_lib -> build_py
1456 # setuptools/install -> bdist_egg ->..
1457 # setuptools/develop -> ?
1459 from distutils
.command
.build_py
import build_py
as _build_py
1461 class cmd_build_py(_build_py
):
1464 cfg
= get_config_from_root(root
)
1465 versions
= get_versions()
1467 # now locate _version.py in the new build/ directory and replace
1468 # it with an updated value
1469 if cfg
.versionfile_build
:
1470 target_versionfile
= os
.path
.join(self
.build_lib
,
1471 cfg
.versionfile_build
)
1472 print("UPDATING %s" % target_versionfile
)
1473 write_to_version_file(target_versionfile
, versions
)
1474 cmds
["build_py"] = cmd_build_py
1476 if "cx_Freeze" in sys
.modules
: # cx_freeze enabled?
1477 from cx_Freeze
.dist
import build_exe
as _build_exe
1479 class cmd_build_exe(_build_exe
):
1482 cfg
= get_config_from_root(root
)
1483 versions
= get_versions()
1484 target_versionfile
= cfg
.versionfile_source
1485 print("UPDATING %s" % target_versionfile
)
1486 write_to_version_file(target_versionfile
, versions
)
1488 _build_exe
.run(self
)
1489 os
.unlink(target_versionfile
)
1490 with
open(cfg
.versionfile_source
, "w") as f
:
1491 LONG
= LONG_VERSION_PY
[cfg
.VCS
]
1495 "TAG_PREFIX": cfg
.tag_prefix
,
1496 "PARENTDIR_PREFIX": cfg
.parentdir_prefix
,
1497 "VERSIONFILE_SOURCE": cfg
.versionfile_source
,
1499 cmds
["build_exe"] = cmd_build_exe
1500 del cmds
["build_py"]
1502 # we override different "sdist" commands for both environments
1503 if "setuptools" in sys
.modules
:
1504 from setuptools
.command
.sdist
import sdist
as _sdist
1506 from distutils
.command
.sdist
import sdist
as _sdist
1508 class cmd_sdist(_sdist
):
1510 versions
= get_versions()
1511 self
._versioneer
_generated
_versions
= versions
1512 # unless we update this, the command will keep using the old
1514 self
.distribution
.metadata
.version
= versions
["version"]
1515 return _sdist
.run(self
)
1517 def make_release_tree(self
, base_dir
, files
):
1519 cfg
= get_config_from_root(root
)
1520 _sdist
.make_release_tree(self
, base_dir
, files
)
1521 # now locate _version.py in the new base_dir directory
1522 # (remembering that it may be a hardlink) and replace it with an
1524 target_versionfile
= os
.path
.join(base_dir
, cfg
.versionfile_source
)
1525 print("UPDATING %s" % target_versionfile
)
1526 write_to_version_file(target_versionfile
,
1527 self
._versioneer
_generated
_versions
)
1528 cmds
["sdist"] = cmd_sdist
1534 setup.cfg is missing the necessary Versioneer configuration. You need
1540 versionfile_source = src/myproject/_version.py
1541 versionfile_build = myproject/_version.py
1543 parentdir_prefix = myproject-
1545 You will also need to edit your setup.py to use the results:
1548 setup(version=versioneer.get_version(),
1549 cmdclass=versioneer.get_cmdclass(), ...)
1551 Please read the docstring in ./versioneer.py for configuration instructions,
1552 edit setup.cfg, and re-run the installer or 'python versioneer.py setup'.
1556 # See the docstring in versioneer.py for instructions. Note that you must
1557 # re-run 'versioneer.py setup' after changing this section, and commit the
1563 #versionfile_source =
1564 #versionfile_build =
1570 INIT_PY_SNIPPET
= """
1571 from ._version import get_versions
1572 __version__ = get_versions()['version']
1580 cfg
= get_config_from_root(root
)
1581 except (EnvironmentError, configparser
.NoSectionError
,
1582 configparser
.NoOptionError
) as e
:
1583 if isinstance(e
, (EnvironmentError, configparser
.NoSectionError
)):
1584 print("Adding sample versioneer config to setup.cfg",
1586 with
open(os
.path
.join(root
, "setup.cfg"), "a") as f
:
1587 f
.write(SAMPLE_CONFIG
)
1588 print(CONFIG_ERROR
, file=sys
.stderr
)
1591 print(" creating %s" % cfg
.versionfile_source
)
1592 with
open(cfg
.versionfile_source
, "w") as f
:
1593 LONG
= LONG_VERSION_PY
[cfg
.VCS
]
1594 f
.write(LONG
% {"DOLLAR": "$",
1596 "TAG_PREFIX": cfg
.tag_prefix
,
1597 "PARENTDIR_PREFIX": cfg
.parentdir_prefix
,
1598 "VERSIONFILE_SOURCE": cfg
.versionfile_source
,
1601 ipy
= os
.path
.join(os
.path
.dirname(cfg
.versionfile_source
),
1603 if os
.path
.exists(ipy
):
1605 with
open(ipy
, "r") as f
:
1607 except EnvironmentError:
1609 if INIT_PY_SNIPPET
not in old
:
1610 print(" appending to %s" % ipy
)
1611 with
open(ipy
, "a") as f
:
1612 f
.write(INIT_PY_SNIPPET
)
1614 print(" %s unmodified" % ipy
)
1616 print(" %s doesn't exist, ok" % ipy
)
1619 # Make sure both the top-level "versioneer.py" and versionfile_source
1620 # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so
1621 # they'll be copied into source distributions. Pip won't be able to
1622 # install the package without this.
1623 manifest_in
= os
.path
.join(root
, "MANIFEST.in")
1624 simple_includes
= set()
1626 with
open(manifest_in
, "r") as f
:
1628 if line
.startswith("include "):
1629 for include
in line
.split()[1:]:
1630 simple_includes
.add(include
)
1631 except EnvironmentError:
1633 # That doesn't cover everything MANIFEST.in can do
1634 # (http://docs.python.org/2/distutils/sourcedist.html#commands), so
1635 # it might give some false negatives. Appending redundant 'include'
1636 # lines is safe, though.
1637 if "versioneer.py" not in simple_includes
:
1638 print(" appending 'versioneer.py' to MANIFEST.in")
1639 with
open(manifest_in
, "a") as f
:
1640 f
.write("include versioneer.py\n")
1642 print(" 'versioneer.py' already in MANIFEST.in")
1643 if cfg
.versionfile_source
not in simple_includes
:
1644 print(" appending versionfile_source ('%s') to MANIFEST.in" %
1645 cfg
.versionfile_source
)
1646 with
open(manifest_in
, "a") as f
:
1647 f
.write("include %s\n" % cfg
.versionfile_source
)
1649 print(" versionfile_source already in MANIFEST.in")
1651 # Make VCS-specific changes. For git, this means creating/changing
1652 # .gitattributes to mark _version.py for export-time keyword
1654 do_vcs_install(manifest_in
, cfg
.versionfile_source
, ipy
)
1658 def scan_setup_py():
1662 with
open("setup.py", "r") as f
:
1663 for line
in f
.readlines():
1664 if "import versioneer" in line
:
1666 if "versioneer.get_cmdclass()" in line
:
1667 found
.add("cmdclass")
1668 if "versioneer.get_version()" in line
:
1669 found
.add("get_version")
1670 if "versioneer.VCS" in line
:
1672 if "versioneer.versionfile_source" in line
:
1676 print("Your setup.py appears to be missing some important items")
1677 print("(but I might be wrong). Please make sure it has something")
1678 print("roughly like the following:")
1680 print(" import versioneer")
1681 print(" setup( version=versioneer.get_version(),")
1682 print(" cmdclass=versioneer.get_cmdclass(), ...)")
1686 print("You should remove lines like 'versioneer.VCS = ' and")
1687 print("'versioneer.versionfile_source = ' . This configuration")
1688 print("now lives in setup.cfg, and should be removed from setup.py")
1693 if __name__
== "__main__":
1697 errors
+= scan_setup_py()