4 """The Versioneer - like a rocketeer, but for versions.
9 * like a rocketeer, but for versions!
10 * https://github.com/warner/python-versioneer
12 * License: Public Domain
13 * Compatible With: python2.6, 2.7, 3.3, 3.4, 3.5, and pypy
15 (https://pypip.in/version/versioneer/badge.svg?style=flat)
16 ](https://pypi.python.org/pypi/versioneer/)
18 (https://travis-ci.org/warner/python-versioneer.png?branch=master)
19 ](https://travis-ci.org/warner/python-versioneer)
21 This is a tool for managing a recorded version number in distutils-based
22 python projects. The goal is to remove the tedious and error-prone "update
23 the embedded version string" step from your release process. Making a new
24 release should be as easy as recording a new tag in your version-control
25 system, and maybe making new tarballs.
30 * `pip install versioneer` to somewhere to your $PATH
31 * add a `[versioneer]` section to your setup.cfg (see below)
32 * run `versioneer install` in your source tree, commit the results
34 ## Version Identifiers
36 Source trees come from a variety of places:
38 * a version-control system checkout (mostly used by developers)
39 * a nightly tarball, produced by build automation
40 * a snapshot tarball, produced by a web-based VCS browser, like github's
41 "tarball from tag" feature
42 * a release tarball, produced by "setup.py sdist", distributed through PyPI
44 Within each source tree, the version identifier (either a string or a number,
45 this tool is format-agnostic) can come from a variety of places:
47 * ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows
48 about recent "tags" and an absolute revision-id
49 * the name of the directory into which the tarball was unpacked
50 * an expanded VCS keyword ($Id$, etc)
51 * a `_version.py` created by some earlier build step
53 For released software, the version identifier is closely related to a VCS
54 tag. Some projects use tag names that include more than just the version
55 string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool
56 needs to strip the tag prefix to extract the version identifier. For
57 unreleased software (between tags), the version identifier should provide
58 enough information to help developers recreate the same tree, while also
59 giving them an idea of roughly how old the tree is (after version 1.2, before
60 version 1.3). Many VCS systems can report a description that captures this,
61 for example `git describe --tags --dirty --always` reports things like
62 "0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the
63 0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has
66 The version identifier is used for multiple purposes:
68 * to allow the module to self-identify its version: `myproject.__version__`
69 * to choose a name and prefix for a 'setup.py sdist' tarball
71 ## Theory of Operation
73 Versioneer works by adding a special `_version.py` file into your source
74 tree, where your `__init__.py` can import it. This `_version.py` knows how to
75 dynamically ask the VCS tool for version information at import time.
77 `_version.py` also contains `$Revision$` markers, and the installation
78 process marks `_version.py` to have this marker rewritten with a tag name
79 during the `git archive` command. As a result, generated tarballs will
80 contain enough information to get the proper version.
82 To allow `setup.py` to compute a version too, a `versioneer.py` is added to
83 the top level of your source tree, next to `setup.py` and the `setup.cfg`
84 that configures it. This overrides several distutils/setuptools commands to
85 compute the version when invoked, and changes `setup.py build` and `setup.py
86 sdist` to replace `_version.py` with a small static file that contains just
87 the generated version data.
91 First, decide on values for the following configuration variables:
93 * `VCS`: the version control system you use. Currently accepts "git".
95 * `style`: the style of version string to be produced. See "Styles" below for
96 details. Defaults to "pep440", which looks like
97 `TAG[+DISTANCE.gSHORTHASH[.dirty]]`.
99 * `versionfile_source`:
101 A project-relative pathname into which the generated version strings should
102 be written. This is usually a `_version.py` next to your project's main
103 `__init__.py` file, so it can be imported at runtime. If your project uses
104 `src/myproject/__init__.py`, this should be `src/myproject/_version.py`.
105 This file should be checked in to your VCS as usual: the copy created below
106 by `setup.py setup_versioneer` will include code that parses expanded VCS
107 keywords in generated tarballs. The 'build' and 'sdist' commands will
108 replace it with a copy that has just the calculated version string.
110 This must be set even if your project does not have any modules (and will
111 therefore never import `_version.py`), since "setup.py sdist" -based trees
112 still need somewhere to record the pre-calculated version strings. Anywhere
113 in the source tree should do. If there is a `__init__.py` next to your
114 `_version.py`, the `setup.py setup_versioneer` command (described below)
115 will append some `__version__`-setting assignments, if they aren't already
118 * `versionfile_build`:
120 Like `versionfile_source`, but relative to the build directory instead of
121 the source directory. These will differ when your setup.py uses
122 'package_dir='. If you have `package_dir={'myproject': 'src/myproject'}`,
123 then you will probably have `versionfile_build='myproject/_version.py'` and
124 `versionfile_source='src/myproject/_version.py'`.
126 If this is set to None, then `setup.py build` will not attempt to rewrite
127 any `_version.py` in the built tree. If your project does not have any
128 libraries (e.g. if it only builds a script), then you should use
129 `versionfile_build = None`. To actually use the computed version string,
130 your `setup.py` will need to override `distutils.command.build_scripts`
131 with a subclass that explicitly inserts a copy of
132 `versioneer.get_version()` into your script file. See
133 `test/demoapp-script-only/setup.py` for an example.
137 a string, like 'PROJECTNAME-', which appears at the start of all VCS tags.
138 If your tags look like 'myproject-1.2.0', then you should use
139 tag_prefix='myproject-'. If you use unprefixed tags like '1.2.0', this
140 should be an empty string, using either `tag_prefix=` or `tag_prefix=''`.
142 * `parentdir_prefix`:
144 a optional string, frequently the same as tag_prefix, which appears at the
145 start of all unpacked tarball filenames. If your tarball unpacks into
146 'myproject-1.2.0', this should be 'myproject-'. To disable this feature,
147 just omit the field from your `setup.cfg`.
149 This tool provides one script, named `versioneer`. That script has one mode,
150 "install", which writes a copy of `versioneer.py` into the current directory
151 and runs `versioneer.py setup` to finish the installation.
153 To versioneer-enable your project:
155 * 1: Modify your `setup.cfg`, adding a section named `[versioneer]` and
156 populating it with the configuration values you decided earlier (note that
157 the option names are not case-sensitive):
163 versionfile_source = src/myproject/_version.py
164 versionfile_build = myproject/_version.py
166 parentdir_prefix = myproject-
169 * 2: Run `versioneer install`. This will do the following:
171 * copy `versioneer.py` into the top of your source tree
172 * create `_version.py` in the right place (`versionfile_source`)
173 * modify your `__init__.py` (if one exists next to `_version.py`) to define
174 `__version__` (by calling a function from `_version.py`)
175 * modify your `MANIFEST.in` to include both `versioneer.py` and the
176 generated `_version.py` in sdist tarballs
178 `versioneer install` will complain about any problems it finds with your
179 `setup.py` or `setup.cfg`. Run it multiple times until you have fixed all
182 * 3: add a `import versioneer` to your setup.py, and add the following
183 arguments to the setup() call:
185 version=versioneer.get_version(),
186 cmdclass=versioneer.get_cmdclass(),
188 * 4: commit these changes to your VCS. To make sure you won't forget,
189 `versioneer install` will mark everything it touched for addition using
190 `git add`. Don't forget to add `setup.py` and `setup.cfg` too.
192 ## Post-Installation Usage
194 Once established, all uses of your tree from a VCS checkout should get the
195 current version string. All generated tarballs should include an embedded
196 version string (so users who unpack them will not need a VCS tool installed).
198 If you distribute your project through PyPI, then the release process should
199 boil down to two steps:
202 * 2: python setup.py register sdist upload
204 If you distribute it through github (i.e. users use github to generate
205 tarballs with `git archive`), the process is:
208 * 2: git push; git push --tags
210 Versioneer will report "0+untagged.NUMCOMMITS.gHASH" until your tree has at
211 least one tag in its history.
213 ## Version-String Flavors
215 Code which uses Versioneer can learn about its version string at runtime by
216 importing `_version` from your main `__init__.py` file and running the
217 `get_versions()` function. From the "outside" (e.g. in `setup.py`), you can
218 import the top-level `versioneer.py` and run `get_versions()`.
220 Both functions return a dictionary with different flavors of version
223 * `['version']`: A condensed version string, rendered using the selected
224 style. This is the most commonly used value for the project's version
225 string. The default "pep440" style yields strings like `0.11`,
226 `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section
227 below for alternative styles.
229 * `['full-revisionid']`: detailed revision identifier. For Git, this is the
230 full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac".
232 * `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that
233 this is only accurate if run in a VCS checkout, otherwise it is likely to
236 * `['error']`: if the version string could not be computed, this will be set
237 to a string describing the problem, otherwise it will be None. It may be
238 useful to throw an exception in setup.py if this is set, to avoid e.g.
239 creating tarballs with a version string of "unknown".
241 Some variants are more useful than others. Including `full-revisionid` in a
242 bug report should allow developers to reconstruct the exact code being tested
243 (or indicate the presence of local changes that should be shared with the
244 developers). `version` is suitable for display in an "about" box or a CLI
245 `--version` output: it can be easily compared against release notes and lists
246 of bugs fixed in various releases.
248 The installer adds the following text to your `__init__.py` to place a basic
249 version in `YOURPROJECT.__version__`:
251 from ._version import get_versions
252 __version__ = get_versions()['version']
257 The setup.cfg `style=` configuration controls how the VCS information is
258 rendered into a version string.
260 The default style, "pep440", produces a PEP440-compliant string, equal to the
261 un-prefixed tag name for actual releases, and containing an additional "local
262 version" section with more detail for in-between builds. For Git, this is
263 TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags
264 --dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the
265 tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and
266 that this commit is two revisions ("+2") beyond the "0.11" tag. For released
267 software (exactly equal to a known tag), the identifier will only contain the
268 stripped tag, e.g. "0.11".
270 Other styles are available. See details.md in the Versioneer source tree for
275 Versioneer tries to avoid fatal errors: if something goes wrong, it will tend
276 to return a version of "0+unknown". To investigate the problem, run `setup.py
277 version`, which will run the version-lookup code in a verbose mode, and will
278 display the full contents of `get_versions()` (including the `error` string,
279 which may help identify what went wrong).
281 ## Updating Versioneer
283 To upgrade your project to a new release of Versioneer, do the following:
285 * install the new Versioneer (`pip install -U versioneer` or equivalent)
286 * edit `setup.cfg`, if necessary, to include any new configuration settings
287 indicated by the release notes
288 * re-run `versioneer install` in your source tree, to replace
290 * commit any changed files
292 ### Upgrading to 0.16
296 ### Upgrading to 0.15
298 Starting with this version, Versioneer is configured with a `[versioneer]`
299 section in your `setup.cfg` file. Earlier versions required the `setup.py` to
300 set attributes on the `versioneer` module immediately after import. The new
301 version will refuse to run (raising an exception during import) until you
302 have provided the necessary `setup.cfg` section.
304 In addition, the Versioneer package provides an executable named
305 `versioneer`, and the installation process is driven by running `versioneer
306 install`. In 0.14 and earlier, the executable was named
307 `versioneer-installer` and was run without an argument.
309 ### Upgrading to 0.14
311 0.14 changes the format of the version string. 0.13 and earlier used
312 hyphen-separated strings like "0.11-2-g1076c97-dirty". 0.14 and beyond use a
313 plus-separated "local version" section strings, with dot-separated
314 components, like "0.11+2.g1076c97". PEP440-strict tools did not like the old
315 format, but should be ok with the new one.
317 ### Upgrading from 0.11 to 0.12
321 ### Upgrading from 0.10 to 0.11
323 You must add a `versioneer.VCS = "git"` to your `setup.py` before re-running
324 `setup.py setup_versioneer`. This will enable the use of additional
325 version-control systems (SVN, etc) in the future.
329 This tool is designed to make it easily extended to other version-control
330 systems: all VCS-specific components are in separate directories like
331 src/git/ . The top-level `versioneer.py` script is assembled from these
332 components by running make-versioneer.py . In the future, make-versioneer.py
333 will take a VCS name as an argument, and will construct a version of
334 `versioneer.py` that is specific to the given VCS. It might also take the
335 configuration arguments that are currently provided manually during
336 installation by editing setup.py . Alternatively, it might go the other
337 direction and include code from all supported VCS systems, reducing the
338 number of intermediate scripts.
343 To make Versioneer easier to embed, all its code is dedicated to the public
344 domain. The `_version.py` that it creates is also in the public domain.
345 Specifically, both are released under the Creative Commons "Public Domain
346 Dedication" license (CC0-1.0), as described in
347 https://creativecommons.org/publicdomain/zero/1.0/ .
351 from __future__ import print_function
355 import ConfigParser as configparser
364 class VersioneerConfig:
365 """Container for Versioneer configuration parameters."""
369 """Get the project root directory.
371 We require that all commands are run from the project root, i.e. the
372 directory that contains setup.py, setup.cfg, and versioneer.py .
374 root = os.path.realpath(os.path.abspath(os.getcwd()))
375 setup_py = os.path.join(root, "setup.py")
376 versioneer_py = os.path.join(root, "versioneer.py")
377 if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)):
378 # allow 'python path/to/setup.py COMMAND'
379 root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0])))
380 setup_py = os.path.join(root, "setup.py")
381 versioneer_py = os.path.join(root, "versioneer.py")
382 if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)):
383 err = ("Versioneer was unable to run the project root directory. "
384 "Versioneer requires setup.py to be executed from "
385 "its immediate directory (like 'python setup.py COMMAND'), "
386 "or in a way that lets it use sys.argv[0] to find the root "
387 "(like 'python path/to/setup.py COMMAND').")
388 raise VersioneerBadRootError(err)
390 # Certain runtime workflows (setup.py install/develop in a setuptools
391 # tree) execute all dependencies in a single python process, so
392 # "versioneer" may be imported multiple times, and python's shared
393 # module-import table will cache the first one. So we can't use
394 # os.path.dirname(__file__), as that will find whichever
395 # versioneer.py was first imported, even in later projects.
396 me = os.path.realpath(os.path.abspath(__file__))
397 if os.path.splitext(me)[0] != os.path.splitext(versioneer_py)[0]:
398 print("Warning: build in %s is using versioneer.py from %s"
399 % (os.path.dirname(me), versioneer_py))
405 def get_config_from_root(root):
406 """Read the project setup.cfg file to determine Versioneer config."""
407 # This might raise EnvironmentError (if setup.cfg is missing), or
408 # configparser.NoSectionError (if it lacks a [versioneer] section), or
409 # configparser.NoOptionError (if it lacks "VCS="). See the docstring at
410 # the top of versioneer.py for instructions on writing your setup.cfg .
411 setup_cfg = os.path.join(root, "setup.cfg")
412 parser = configparser.SafeConfigParser()
413 with open(setup_cfg, "r") as f:
415 VCS = parser.get("versioneer", "VCS") # mandatory
417 def get(parser, name):
418 if parser.has_option("versioneer", name):
419 return parser.get("versioneer", name)
421 cfg = VersioneerConfig()
423 cfg.style = get(parser, "style") or ""
424 cfg.versionfile_source = get(parser, "versionfile_source")
425 cfg.versionfile_build = get(parser, "versionfile_build")
426 cfg.tag_prefix = get(parser, "tag_prefix")
427 if cfg.tag_prefix in ("''", '""'):
429 cfg.parentdir_prefix = get(parser, "parentdir_prefix")
430 cfg.verbose = get(parser, "verbose")
434 class NotThisMethod(Exception):
435 """Exception raised if a method is not valid for the current scenario."""
437 # these dictionaries contain VCS-specific tools
442 def register_vcs_handler(vcs, method): # decorator
443 """Decorator to mark a method as the handler for a particular VCS."""
445 """Store f in HANDLERS[vcs][method]."""
446 if vcs not in HANDLERS:
448 HANDLERS[vcs][method] = f
453 def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
454 """Call the given command(s)."""
455 assert isinstance(commands, list)
459 dispcmd = str([c] + args)
460 # remember shell=False, so use git.cmd on windows, not just git
461 p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
462 stderr=(subprocess.PIPE if hide_stderr
465 except EnvironmentError:
466 e = sys.exc_info()[1]
467 if e.errno == errno.ENOENT:
470 print("unable to run %s" % dispcmd)
475 print("unable to find command, tried %s" % (commands,))
477 stdout = p.communicate()[0].strip()
478 if sys.version_info[0] >= 3:
479 stdout = stdout.decode()
480 if p.returncode != 0:
482 print("unable to run %s (error)" % dispcmd)
485 LONG_VERSION_PY['git'] = '''
486 # This file helps to compute a version number in source trees obtained from
487 # git-archive tarball (such as those provided by githubs download-from-tag
488 # feature). Distribution tarballs (built by setup.py sdist) and build
489 # directories (produced by setup.py build) will contain a much shorter file
490 # that just contains the computed version number.
492 # This file is released into the public domain. Generated by
493 # versioneer-0.16 (https://github.com/warner/python-versioneer)
495 """Git implementation of _version.py."""
505 """Get the keywords needed to look up the version information."""
506 # these strings will be replaced by git during git-archive.
507 # setup.py/versioneer.py will grep for the variable names, so they must
508 # each be defined on a line of their own. _version.py will just call
510 git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s"
511 git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s"
512 keywords = {"refnames": git_refnames, "full": git_full}
516 class VersioneerConfig:
517 """Container for Versioneer configuration parameters."""
521 """Create, populate and return the VersioneerConfig() object."""
522 # these strings are filled in when 'setup.py versioneer' creates
524 cfg = VersioneerConfig()
526 cfg.style = "%(STYLE)s"
527 cfg.tag_prefix = "%(TAG_PREFIX)s"
528 cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s"
529 cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s"
534 class NotThisMethod(Exception):
535 """Exception raised if a method is not valid for the current scenario."""
542 def register_vcs_handler(vcs, method): # decorator
543 """Decorator to mark a method as the handler for a particular VCS."""
545 """Store f in HANDLERS[vcs][method]."""
546 if vcs not in HANDLERS:
548 HANDLERS[vcs][method] = f
553 def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
554 """Call the given command(s)."""
555 assert isinstance(commands, list)
559 dispcmd = str([c] + args)
560 # remember shell=False, so use git.cmd on windows, not just git
561 p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
562 stderr=(subprocess.PIPE if hide_stderr
565 except EnvironmentError:
566 e = sys.exc_info()[1]
567 if e.errno == errno.ENOENT:
570 print("unable to run %%s" %% dispcmd)
575 print("unable to find command, tried %%s" %% (commands,))
577 stdout = p.communicate()[0].strip()
578 if sys.version_info[0] >= 3:
579 stdout = stdout.decode()
580 if p.returncode != 0:
582 print("unable to run %%s (error)" %% dispcmd)
587 def versions_from_parentdir(parentdir_prefix, root, verbose):
588 """Try to determine the version from the parent directory name.
590 Source tarballs conventionally unpack into a directory that includes
591 both the project name and a version string.
593 dirname = os.path.basename(root)
594 if not dirname.startswith(parentdir_prefix):
596 print("guessing rootdir is '%%s', but '%%s' doesn't start with "
597 "prefix '%%s'" %% (root, dirname, parentdir_prefix))
598 raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
599 return {"version": dirname[len(parentdir_prefix):],
600 "full-revisionid": None,
601 "dirty": False, "error": None}
604 @register_vcs_handler("git", "get_keywords")
605 def git_get_keywords(versionfile_abs):
606 """Extract version information from the given file."""
607 # the code embedded in _version.py can just fetch the value of these
608 # keywords. When used from setup.py, we don't want to import _version.py,
609 # so we do it with a regexp instead. This function is not used from
613 f = open(versionfile_abs, "r")
614 for line in f.readlines():
615 if line.strip().startswith("git_refnames ="):
616 mo = re.search(r'=\s*"(.*)"', line)
618 keywords["refnames"] = mo.group(1)
619 if line.strip().startswith("git_full ="):
620 mo = re.search(r'=\s*"(.*)"', line)
622 keywords["full"] = mo.group(1)
624 except EnvironmentError:
629 @register_vcs_handler("git", "keywords")
630 def git_versions_from_keywords(keywords, tag_prefix, verbose):
631 """Get version information from git keywords."""
633 raise NotThisMethod("no keywords at all, weird")
634 refnames = keywords["refnames"].strip()
635 if refnames.startswith("$Format"):
637 print("keywords are unexpanded, not using")
638 raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
639 refs = set([r.strip() for r in refnames.strip("()").split(",")])
640 # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
641 # just "foo-1.0". If we see a "tag: " prefix, prefer those.
643 tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
645 # Either we're using git < 1.8.3, or there really are no tags. We use
646 # a heuristic: assume all version tags have a digit. The old git %%d
647 # expansion behaves like git log --decorate=short and strips out the
648 # refs/heads/ and refs/tags/ prefixes that would let us distinguish
649 # between branches and tags. By ignoring refnames without digits, we
650 # filter out many common branch names like "release" and
651 # "stabilization", as well as "HEAD" and "master".
652 tags = set([r for r in refs if re.search(r'\d', r)])
654 print("discarding '%%s', no digits" %% ",".join(refs-tags))
656 print("likely tags: %%s" %% ",".join(sorted(tags)))
657 for ref in sorted(tags):
658 # sorting will prefer e.g. "2.0" over "2.0rc1"
659 if ref.startswith(tag_prefix):
660 r = ref[len(tag_prefix):]
662 print("picking %%s" %% r)
663 return {"version": r,
664 "full-revisionid": keywords["full"].strip(),
665 "dirty": False, "error": None
667 # no suitable tags, so version is "0+unknown", but full hex is still there
669 print("no suitable tags, using unknown + full revision id")
670 return {"version": "0+unknown",
671 "full-revisionid": keywords["full"].strip(),
672 "dirty": False, "error": "no suitable tags"}
675 @register_vcs_handler("git", "pieces_from_vcs")
676 def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
677 """Get version from 'git describe' in the root of the source tree.
679 This only gets called if the git-archive 'subst' keywords were *not*
680 expanded, and _version.py hasn't already been rewritten with a short
681 version string, meaning we're inside a checked out source tree.
683 if not os.path.exists(os.path.join(root, ".git")):
685 print("no .git in %%s" %% root)
686 raise NotThisMethod("no .git directory")
689 if sys.platform == "win32":
690 GITS = ["git.cmd", "git.exe"]
691 # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
692 # if there isn't one, this yields HEX[-dirty] (no NUM)
693 describe_out = run_command(GITS, ["describe", "--tags", "--dirty",
694 "--always", "--long",
695 "--match", "%%s*" %% tag_prefix],
697 # --long was added in git-1.5.5
698 if describe_out is None:
699 raise NotThisMethod("'git describe' failed")
700 describe_out = describe_out.strip()
701 full_out = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
703 raise NotThisMethod("'git rev-parse' failed")
704 full_out = full_out.strip()
707 pieces["long"] = full_out
708 pieces["short"] = full_out[:7] # maybe improved later
709 pieces["error"] = None
711 # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
712 # TAG might have hyphens.
713 git_describe = describe_out
715 # look for -dirty suffix
716 dirty = git_describe.endswith("-dirty")
717 pieces["dirty"] = dirty
719 git_describe = git_describe[:git_describe.rindex("-dirty")]
721 # now we have TAG-NUM-gHEX or HEX
723 if "-" in git_describe:
725 mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
727 # unparseable. Maybe git-describe is misbehaving?
728 pieces["error"] = ("unable to parse git-describe output: '%%s'"
733 full_tag = mo.group(1)
734 if not full_tag.startswith(tag_prefix):
736 fmt = "tag '%%s' doesn't start with prefix '%%s'"
737 print(fmt %% (full_tag, tag_prefix))
738 pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'"
739 %% (full_tag, tag_prefix))
741 pieces["closest-tag"] = full_tag[len(tag_prefix):]
743 # distance: number of commits since tag
744 pieces["distance"] = int(mo.group(2))
746 # commit: short hex revision ID
747 pieces["short"] = mo.group(3)
751 pieces["closest-tag"] = None
752 count_out = run_command(GITS, ["rev-list", "HEAD", "--count"],
754 pieces["distance"] = int(count_out) # total number of commits
759 def plus_or_dot(pieces):
760 """Return a + if we don't already have one, else return a ."""
761 if "+" in pieces.get("closest-tag", ""):
766 def render_pep440(pieces):
767 """Build up version string, with post-release "local version identifier".
769 Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
770 get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
773 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
775 if pieces["closest-tag"]:
776 rendered = pieces["closest-tag"]
777 if pieces["distance"] or pieces["dirty"]:
778 rendered += plus_or_dot(pieces)
779 rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"])
784 rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"],
791 def render_pep440_pre(pieces):
792 """TAG[.post.devDISTANCE] -- No -dirty.
795 1: no tags. 0.post.devDISTANCE
797 if pieces["closest-tag"]:
798 rendered = pieces["closest-tag"]
799 if pieces["distance"]:
800 rendered += ".post.dev%%d" %% pieces["distance"]
803 rendered = "0.post.dev%%d" %% pieces["distance"]
807 def render_pep440_post(pieces):
808 """TAG[.postDISTANCE[.dev0]+gHEX] .
810 The ".dev0" means dirty. Note that .dev0 sorts backwards
811 (a dirty tree will appear "older" than the corresponding clean one),
812 but you shouldn't be releasing software with -dirty anyways.
815 1: no tags. 0.postDISTANCE[.dev0]
817 if pieces["closest-tag"]:
818 rendered = pieces["closest-tag"]
819 if pieces["distance"] or pieces["dirty"]:
820 rendered += ".post%%d" %% pieces["distance"]
823 rendered += plus_or_dot(pieces)
824 rendered += "g%%s" %% pieces["short"]
827 rendered = "0.post%%d" %% pieces["distance"]
830 rendered += "+g%%s" %% pieces["short"]
834 def render_pep440_old(pieces):
835 """TAG[.postDISTANCE[.dev0]] .
837 The ".dev0" means dirty.
840 1: no tags. 0.postDISTANCE[.dev0]
842 if pieces["closest-tag"]:
843 rendered = pieces["closest-tag"]
844 if pieces["distance"] or pieces["dirty"]:
845 rendered += ".post%%d" %% pieces["distance"]
850 rendered = "0.post%%d" %% pieces["distance"]
856 def render_git_describe(pieces):
857 """TAG[-DISTANCE-gHEX][-dirty].
859 Like 'git describe --tags --dirty --always'.
862 1: no tags. HEX[-dirty] (note: no 'g' prefix)
864 if pieces["closest-tag"]:
865 rendered = pieces["closest-tag"]
866 if pieces["distance"]:
867 rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"])
870 rendered = pieces["short"]
876 def render_git_describe_long(pieces):
877 """TAG-DISTANCE-gHEX[-dirty].
879 Like 'git describe --tags --dirty --always -long'.
880 The distance/hash is unconditional.
883 1: no tags. HEX[-dirty] (note: no 'g' prefix)
885 if pieces["closest-tag"]:
886 rendered = pieces["closest-tag"]
887 rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"])
890 rendered = pieces["short"]
896 def render(pieces, style):
897 """Render the given version pieces into the requested style."""
899 return {"version": "unknown",
900 "full-revisionid": pieces.get("long"),
902 "error": pieces["error"]}
904 if not style or style == "default":
905 style = "pep440" # the default
907 if style == "pep440":
908 rendered = render_pep440(pieces)
909 elif style == "pep440-pre":
910 rendered = render_pep440_pre(pieces)
911 elif style == "pep440-post":
912 rendered = render_pep440_post(pieces)
913 elif style == "pep440-old":
914 rendered = render_pep440_old(pieces)
915 elif style == "git-describe":
916 rendered = render_git_describe(pieces)
917 elif style == "git-describe-long":
918 rendered = render_git_describe_long(pieces)
920 raise ValueError("unknown style '%%s'" %% style)
922 return {"version": rendered, "full-revisionid": pieces["long"],
923 "dirty": pieces["dirty"], "error": None}
927 """Get version information or return default if unable to do so."""
928 # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
929 # __file__, we can work backwards from there to the root. Some
930 # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
931 # case we can only use expanded keywords.
934 verbose = cfg.verbose
937 return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
939 except NotThisMethod:
943 root = os.path.realpath(__file__)
944 # versionfile_source is the relative path from the top of the source
945 # tree (where the .git directory might live) to this file. Invert
946 # this to find the root from __file__.
947 for i in cfg.versionfile_source.split('/'):
948 root = os.path.dirname(root)
950 return {"version": "0+unknown", "full-revisionid": None,
952 "error": "unable to find root of source tree"}
955 pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
956 return render(pieces, cfg.style)
957 except NotThisMethod:
961 if cfg.parentdir_prefix:
962 return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
963 except NotThisMethod:
966 return {"version": "0+unknown", "full-revisionid": None,
968 "error": "unable to compute version"}
972 @register_vcs_handler("git", "get_keywords")
973 def git_get_keywords(versionfile_abs):
974 """Extract version information from the given file."""
975 # the code embedded in _version.py can just fetch the value of these
976 # keywords. When used from setup.py, we don't want to import _version.py,
977 # so we do it with a regexp instead. This function is not used from
981 f = open(versionfile_abs, "r")
982 for line in f.readlines():
983 if line.strip().startswith("git_refnames ="):
984 mo = re.search(r'=\s*"(.*)"', line)
986 keywords["refnames"] = mo.group(1)
987 if line.strip().startswith("git_full ="):
988 mo = re.search(r'=\s*"(.*)"', line)
990 keywords["full"] = mo.group(1)
992 except EnvironmentError:
997 @register_vcs_handler("git", "keywords")
998 def git_versions_from_keywords(keywords, tag_prefix, verbose):
999 """Get version information from git keywords."""
1001 raise NotThisMethod("no keywords at all, weird")
1002 refnames = keywords["refnames"].strip()
1003 if refnames.startswith("$Format"):
1005 print("keywords are unexpanded, not using")
1006 raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
1007 refs = set([r.strip() for r in refnames.strip("()").split(",")])
1008 # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
1009 # just "foo-1.0". If we see a "tag: " prefix, prefer those.
1011 tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
1013 # Either we're using git < 1.8.3, or there really are no tags. We use
1014 # a heuristic: assume all version tags have a digit. The old git %d
1015 # expansion behaves like git log --decorate=short and strips out the
1016 # refs/heads/ and refs/tags/ prefixes that would let us distinguish
1017 # between branches and tags. By ignoring refnames without digits, we
1018 # filter out many common branch names like "release" and
1019 # "stabilization", as well as "HEAD" and "master".
1020 tags = set([r for r in refs if re.search(r'\d', r)])
1022 print("discarding '%s', no digits" % ",".join(refs-tags))
1024 print("likely tags: %s" % ",".join(sorted(tags)))
1025 for ref in sorted(tags):
1026 # sorting will prefer e.g. "2.0" over "2.0rc1"
1027 if ref.startswith(tag_prefix):
1028 r = ref[len(tag_prefix):]
1030 print("picking %s" % r)
1031 return {"version": r,
1032 "full-revisionid": keywords["full"].strip(),
1033 "dirty": False, "error": None
1035 # no suitable tags, so version is "0+unknown", but full hex is still there
1037 print("no suitable tags, using unknown + full revision id")
1038 return {"version": "0+unknown",
1039 "full-revisionid": keywords["full"].strip(),
1040 "dirty": False, "error": "no suitable tags"}
1043 @register_vcs_handler("git", "pieces_from_vcs")
1044 def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
1045 """Get version from 'git describe' in the root of the source tree.
1047 This only gets called if the git-archive 'subst' keywords were *not*
1048 expanded, and _version.py hasn't already been rewritten with a short
1049 version string, meaning we're inside a checked out source tree.
1051 if not os.path.exists(os.path.join(root, ".git")):
1053 print("no .git in %s" % root)
1054 raise NotThisMethod("no .git directory")
1057 if sys.platform == "win32":
1058 GITS = ["git.cmd", "git.exe"]
1059 # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
1060 # if there isn't one, this yields HEX[-dirty] (no NUM)
1061 describe_out = run_command(GITS, ["describe", "--tags", "--dirty",
1062 "--always", "--long",
1063 "--match", "%s*" % tag_prefix],
1065 # --long was added in git-1.5.5
1066 if describe_out is None:
1067 raise NotThisMethod("'git describe' failed")
1068 describe_out = describe_out.strip()
1069 full_out = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
1070 if full_out is None:
1071 raise NotThisMethod("'git rev-parse' failed")
1072 full_out = full_out.strip()
1075 pieces["long"] = full_out
1076 pieces["short"] = full_out[:7] # maybe improved later
1077 pieces["error"] = None
1079 # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
1080 # TAG might have hyphens.
1081 git_describe = describe_out
1083 # look for -dirty suffix
1084 dirty = git_describe.endswith("-dirty")
1085 pieces["dirty"] = dirty
1087 git_describe = git_describe[:git_describe.rindex("-dirty")]
1089 # now we have TAG-NUM-gHEX or HEX
1091 if "-" in git_describe:
1093 mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
1095 # unparseable. Maybe git-describe is misbehaving?
1096 pieces["error"] = ("unable to parse git-describe output: '%s'"
1101 full_tag = mo.group(1)
1102 if not full_tag.startswith(tag_prefix):
1104 fmt = "tag '%s' doesn't start with prefix '%s'"
1105 print(fmt % (full_tag, tag_prefix))
1106 pieces["error"] = ("tag '%s' doesn't start with prefix '%s'"
1107 % (full_tag, tag_prefix))
1109 pieces["closest-tag"] = full_tag[len(tag_prefix):]
1111 # distance: number of commits since tag
1112 pieces["distance"] = int(mo.group(2))
1114 # commit: short hex revision ID
1115 pieces["short"] = mo.group(3)
1119 pieces["closest-tag"] = None
1120 count_out = run_command(GITS, ["rev-list", "HEAD", "--count"],
1122 pieces["distance"] = int(count_out) # total number of commits
1127 def do_vcs_install(manifest_in, versionfile_source, ipy):
1128 """Git-specific installation logic for Versioneer.
1130 For Git, this means creating/changing .gitattributes to mark _version.py
1131 for export-time keyword substitution.
1134 if sys.platform == "win32":
1135 GITS = ["git.cmd", "git.exe"]
1136 files = [manifest_in, versionfile_source]
1141 if me.endswith(".pyc") or me.endswith(".pyo"):
1142 me = os.path.splitext(me)[0] + ".py"
1143 versioneer_file = os.path.relpath(me)
1145 versioneer_file = "versioneer.py"
1146 files.append(versioneer_file)
1149 f = open(".gitattributes", "r")
1150 for line in f.readlines():
1151 if line.strip().startswith(versionfile_source):
1152 if "export-subst" in line.strip().split()[1:]:
1155 except EnvironmentError:
1158 f = open(".gitattributes", "a+")
1159 f.write("%s export-subst\n" % versionfile_source)
1161 files.append(".gitattributes")
1162 run_command(GITS, ["add", "--"] + files)
1165 def versions_from_parentdir(parentdir_prefix, root, verbose):
1166 """Try to determine the version from the parent directory name.
1168 Source tarballs conventionally unpack into a directory that includes
1169 both the project name and a version string.
1171 dirname = os.path.basename(root)
1172 if not dirname.startswith(parentdir_prefix):
1174 print("guessing rootdir is '%s', but '%s' doesn't start with "
1175 "prefix '%s'" % (root, dirname, parentdir_prefix))
1176 raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
1177 return {"version": dirname[len(parentdir_prefix):],
1178 "full-revisionid": None,
1179 "dirty": False, "error": None}
1181 SHORT_VERSION_PY = """
1182 # This file was generated by 'versioneer.py' (0.16) from
1183 # revision-control system data, or from the parent directory name of an
1184 # unpacked source archive. Distribution tarballs contain a pre-generated copy
1192 ''' # END VERSION_JSON
1196 return json.loads(version_json)
1200 def versions_from_file(filename):
1201 """Try to determine the version from _version.py if present."""
1203 with open(filename) as f:
1205 except EnvironmentError:
1206 raise NotThisMethod("unable to read _version.py")
1207 mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON",
1208 contents, re.M | re.S)
1210 raise NotThisMethod("no version_json in _version.py")
1211 return json.loads(mo.group(1))
1214 def write_to_version_file(filename, versions):
1215 """Write the given version number to the given _version.py file."""
1217 contents = json.dumps(versions, sort_keys=True,
1218 indent=1, separators=(",", ": "))
1219 with open(filename, "w") as f:
1220 f.write(SHORT_VERSION_PY % contents)
1222 print("set %s to '%s'" % (filename, versions["version"]))
1225 def plus_or_dot(pieces):
1226 """Return a + if we don't already have one, else return a ."""
1227 if "+" in pieces.get("closest-tag", ""):
1232 def render_pep440(pieces):
1233 """Build up version string, with post-release "local version identifier".
1235 Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
1236 get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
1239 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
1241 if pieces["closest-tag"]:
1242 rendered = pieces["closest-tag"]
1243 if pieces["distance"] or pieces["dirty"]:
1244 rendered += plus_or_dot(pieces)
1245 rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
1247 rendered += ".dirty"
1250 rendered = "0+untagged.%d.g%s" % (pieces["distance"],
1253 rendered += ".dirty"
1257 def render_pep440_pre(pieces):
1258 """TAG[.post.devDISTANCE] -- No -dirty.
1261 1: no tags. 0.post.devDISTANCE
1263 if pieces["closest-tag"]:
1264 rendered = pieces["closest-tag"]
1265 if pieces["distance"]:
1266 rendered += ".post.dev%d" % pieces["distance"]
1269 rendered = "0.post.dev%d" % pieces["distance"]
1273 def render_pep440_post(pieces):
1274 """TAG[.postDISTANCE[.dev0]+gHEX] .
1276 The ".dev0" means dirty. Note that .dev0 sorts backwards
1277 (a dirty tree will appear "older" than the corresponding clean one),
1278 but you shouldn't be releasing software with -dirty anyways.
1281 1: no tags. 0.postDISTANCE[.dev0]
1283 if pieces["closest-tag"]:
1284 rendered = pieces["closest-tag"]
1285 if pieces["distance"] or pieces["dirty"]:
1286 rendered += ".post%d" % pieces["distance"]
1289 rendered += plus_or_dot(pieces)
1290 rendered += "g%s" % pieces["short"]
1293 rendered = "0.post%d" % pieces["distance"]
1296 rendered += "+g%s" % pieces["short"]
1300 def render_pep440_old(pieces):
1301 """TAG[.postDISTANCE[.dev0]] .
1303 The ".dev0" means dirty.
1306 1: no tags. 0.postDISTANCE[.dev0]
1308 if pieces["closest-tag"]:
1309 rendered = pieces["closest-tag"]
1310 if pieces["distance"] or pieces["dirty"]:
1311 rendered += ".post%d" % pieces["distance"]
1316 rendered = "0.post%d" % pieces["distance"]
1322 def render_git_describe(pieces):
1323 """TAG[-DISTANCE-gHEX][-dirty].
1325 Like 'git describe --tags --dirty --always'.
1328 1: no tags. HEX[-dirty] (note: no 'g' prefix)
1330 if pieces["closest-tag"]:
1331 rendered = pieces["closest-tag"]
1332 if pieces["distance"]:
1333 rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
1336 rendered = pieces["short"]
1338 rendered += "-dirty"
1342 def render_git_describe_long(pieces):
1343 """TAG-DISTANCE-gHEX[-dirty].
1345 Like 'git describe --tags --dirty --always -long'.
1346 The distance/hash is unconditional.
1349 1: no tags. HEX[-dirty] (note: no 'g' prefix)
1351 if pieces["closest-tag"]:
1352 rendered = pieces["closest-tag"]
1353 rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
1356 rendered = pieces["short"]
1358 rendered += "-dirty"
1362 def render(pieces, style):
1363 """Render the given version pieces into the requested style."""
1365 return {"version": "unknown",
1366 "full-revisionid": pieces.get("long"),
1368 "error": pieces["error"]}
1370 if not style or style == "default":
1371 style = "pep440" # the default
1373 if style == "pep440":
1374 rendered = render_pep440(pieces)
1375 elif style == "pep440-pre":
1376 rendered = render_pep440_pre(pieces)
1377 elif style == "pep440-post":
1378 rendered = render_pep440_post(pieces)
1379 elif style == "pep440-old":
1380 rendered = render_pep440_old(pieces)
1381 elif style == "git-describe":
1382 rendered = render_git_describe(pieces)
1383 elif style == "git-describe-long":
1384 rendered = render_git_describe_long(pieces)
1386 raise ValueError("unknown style '%s'" % style)
1388 return {"version": rendered, "full-revisionid": pieces["long"],
1389 "dirty": pieces["dirty"], "error": None}
1392 class VersioneerBadRootError(Exception):
1393 """The project root directory is unknown or missing key files."""
1396 def get_versions(verbose=False):
1397 """Get the project version from whatever source is available.
1399 Returns dict with two keys: 'version' and 'full'.
1401 if "versioneer" in sys.modules:
1402 # see the discussion in cmdclass.py:get_cmdclass()
1403 del sys.modules["versioneer"]
1406 cfg = get_config_from_root(root)
1408 assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg"
1409 handlers = HANDLERS.get(cfg.VCS)
1410 assert handlers, "unrecognized VCS '%s'" % cfg.VCS
1411 verbose = verbose or cfg.verbose
1412 assert cfg.versionfile_source is not None, \
1413 "please set versioneer.versionfile_source"
1414 assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix"
1416 versionfile_abs = os.path.join(root, cfg.versionfile_source)
1418 # extract version from first of: _version.py, VCS command (e.g. 'git
1419 # describe'), parentdir. This is meant to work for developers using a
1420 # source checkout, for users of a tarball created by 'setup.py sdist',
1421 # and for users of a tarball/zipball created by 'git archive' or github's
1422 # download-from-tag feature or the equivalent in other VCSes.
1424 get_keywords_f = handlers.get("get_keywords")
1425 from_keywords_f = handlers.get("keywords")
1426 if get_keywords_f and from_keywords_f:
1428 keywords = get_keywords_f(versionfile_abs)
1429 ver = from_keywords_f(keywords, cfg.tag_prefix, verbose)
1431 print("got version from expanded keyword %s" % ver)
1433 except NotThisMethod:
1437 ver = versions_from_file(versionfile_abs)
1439 print("got version from file %s %s" % (versionfile_abs, ver))
1441 except NotThisMethod:
1444 from_vcs_f = handlers.get("pieces_from_vcs")
1447 pieces = from_vcs_f(cfg.tag_prefix, root, verbose)
1448 ver = render(pieces, cfg.style)
1450 print("got version from VCS %s" % ver)
1452 except NotThisMethod:
1456 if cfg.parentdir_prefix:
1457 ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
1459 print("got version from parentdir %s" % ver)
1461 except NotThisMethod:
1465 print("unable to compute version")
1467 return {"version": "0+unknown", "full-revisionid": None,
1468 "dirty": None, "error": "unable to compute version"}
1472 """Get the short version string for this project."""
1473 return get_versions()["version"]
1477 """Get the custom setuptools/distutils subclasses used by Versioneer."""
1478 if "versioneer" in sys.modules:
1479 del sys.modules["versioneer"]
1480 # this fixes the "python setup.py develop" case (also 'install' and
1481 # 'easy_install .'), in which subdependencies of the main project are
1482 # built (using setup.py bdist_egg) in the same python process. Assume
1483 # a main project A and a dependency B, which use different versions
1484 # of Versioneer. A's setup.py imports A's Versioneer, leaving it in
1485 # sys.modules by the time B's setup.py is executed, causing B to run
1486 # with the wrong versioneer. Setuptools wraps the sub-dep builds in a
1487 # sandbox that restores sys.modules to it's pre-build state, so the
1488 # parent is protected against the child's "import versioneer". By
1489 # removing ourselves from sys.modules here, before the child build
1490 # happens, we protect the child from the parent's versioneer too.
1491 # Also see https://github.com/warner/python-versioneer/issues/52
1495 # we add "version" to both distutils and setuptools
1496 from distutils.core import Command
1498 class cmd_version(Command):
1499 description = "report generated version string"
1501 boolean_options = []
1503 def initialize_options(self):
1506 def finalize_options(self):
1510 vers = get_versions(verbose=True)
1511 print("Version: %s" % vers["version"])
1512 print(" full-revisionid: %s" % vers.get("full-revisionid"))
1513 print(" dirty: %s" % vers.get("dirty"))
1515 print(" error: %s" % vers["error"])
1516 cmds["version"] = cmd_version
1518 # we override "build_py" in both distutils and setuptools
1520 # most invocation pathways end up running build_py:
1521 # distutils/build -> build_py
1522 # distutils/install -> distutils/build ->..
1523 # setuptools/bdist_wheel -> distutils/install ->..
1524 # setuptools/bdist_egg -> distutils/install_lib -> build_py
1525 # setuptools/install -> bdist_egg ->..
1526 # setuptools/develop -> ?
1528 # we override different "build_py" commands for both environments
1529 if "setuptools" in sys.modules:
1530 from setuptools.command.build_py import build_py as _build_py
1532 from distutils.command.build_py import build_py as _build_py
1534 class cmd_build_py(_build_py):
1537 cfg = get_config_from_root(root)
1538 versions = get_versions()
1540 # now locate _version.py in the new build/ directory and replace
1541 # it with an updated value
1542 if cfg.versionfile_build:
1543 target_versionfile = os.path.join(self.build_lib,
1544 cfg.versionfile_build)
1545 print("UPDATING %s" % target_versionfile)
1546 write_to_version_file(target_versionfile, versions)
1547 cmds["build_py"] = cmd_build_py
1549 if "cx_Freeze" in sys.modules: # cx_freeze enabled?
1550 from cx_Freeze.dist import build_exe as _build_exe
1552 class cmd_build_exe(_build_exe):
1555 cfg = get_config_from_root(root)
1556 versions = get_versions()
1557 target_versionfile = cfg.versionfile_source
1558 print("UPDATING %s" % target_versionfile)
1559 write_to_version_file(target_versionfile, versions)
1561 _build_exe.run(self)
1562 os.unlink(target_versionfile)
1563 with open(cfg.versionfile_source, "w") as f:
1564 LONG = LONG_VERSION_PY[cfg.VCS]
1568 "TAG_PREFIX": cfg.tag_prefix,
1569 "PARENTDIR_PREFIX": cfg.parentdir_prefix,
1570 "VERSIONFILE_SOURCE": cfg.versionfile_source,
1572 cmds["build_exe"] = cmd_build_exe
1573 del cmds["build_py"]
1575 # we override different "sdist" commands for both environments
1576 if "setuptools" in sys.modules:
1577 from setuptools.command.sdist import sdist as _sdist
1579 from distutils.command.sdist import sdist as _sdist
1581 class cmd_sdist(_sdist):
1583 versions = get_versions()
1584 self._versioneer_generated_versions = versions
1585 # unless we update this, the command will keep using the old
1587 self.distribution.metadata.version = versions["version"]
1588 return _sdist.run(self)
1590 def make_release_tree(self, base_dir, files):
1592 cfg = get_config_from_root(root)
1593 _sdist.make_release_tree(self, base_dir, files)
1594 # now locate _version.py in the new base_dir directory
1595 # (remembering that it may be a hardlink) and replace it with an
1597 target_versionfile = os.path.join(base_dir, cfg.versionfile_source)
1598 print("UPDATING %s" % target_versionfile)
1599 write_to_version_file(target_versionfile,
1600 self._versioneer_generated_versions)
1601 cmds["sdist"] = cmd_sdist
1607 setup.cfg is missing the necessary Versioneer configuration. You need
1613 versionfile_source = src/myproject/_version.py
1614 versionfile_build = myproject/_version.py
1616 parentdir_prefix = myproject-
1618 You will also need to edit your setup.py to use the results:
1621 setup(version=versioneer.get_version(),
1622 cmdclass=versioneer.get_cmdclass(), ...)
1624 Please read the docstring in ./versioneer.py for configuration instructions,
1625 edit setup.cfg, and re-run the installer or 'python versioneer.py setup'.
1629 # See the docstring in versioneer.py for instructions. Note that you must
1630 # re-run 'versioneer.py setup' after changing this section, and commit the
1636 #versionfile_source =
1637 #versionfile_build =
1643 INIT_PY_SNIPPET = """
1644 from ._version import get_versions
1645 __version__ = get_versions()['version']
1651 """Main VCS-independent setup function for installing Versioneer."""
1654 cfg = get_config_from_root(root)
1655 except (EnvironmentError, configparser.NoSectionError,
1656 configparser.NoOptionError) as e:
1657 if isinstance(e, (EnvironmentError, configparser.NoSectionError)):
1658 print("Adding sample versioneer config to setup.cfg",
1660 with open(os.path.join(root, "setup.cfg"), "a") as f:
1661 f.write(SAMPLE_CONFIG)
1662 print(CONFIG_ERROR, file=sys.stderr)
1665 print(" creating %s" % cfg.versionfile_source)
1666 with open(cfg.versionfile_source, "w") as f:
1667 LONG = LONG_VERSION_PY[cfg.VCS]
1668 f.write(LONG % {"DOLLAR": "$",
1670 "TAG_PREFIX": cfg.tag_prefix,
1671 "PARENTDIR_PREFIX": cfg.parentdir_prefix,
1672 "VERSIONFILE_SOURCE": cfg.versionfile_source,
1675 ipy = os.path.join(os.path.dirname(cfg.versionfile_source),
1677 if os.path.exists(ipy):
1679 with open(ipy, "r") as f:
1681 except EnvironmentError:
1683 if INIT_PY_SNIPPET not in old:
1684 print(" appending to %s" % ipy)
1685 with open(ipy, "a") as f:
1686 f.write(INIT_PY_SNIPPET)
1688 print(" %s unmodified" % ipy)
1690 print(" %s doesn't exist, ok" % ipy)
1693 # Make sure both the top-level "versioneer.py" and versionfile_source
1694 # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so
1695 # they'll be copied into source distributions. Pip won't be able to
1696 # install the package without this.
1697 manifest_in = os.path.join(root, "MANIFEST.in")
1698 simple_includes = set()
1700 with open(manifest_in, "r") as f:
1702 if line.startswith("include "):
1703 for include in line.split()[1:]:
1704 simple_includes.add(include)
1705 except EnvironmentError:
1707 # That doesn't cover everything MANIFEST.in can do
1708 # (http://docs.python.org/2/distutils/sourcedist.html#commands), so
1709 # it might give some false negatives. Appending redundant 'include'
1710 # lines is safe, though.
1711 if "versioneer.py" not in simple_includes:
1712 print(" appending 'versioneer.py' to MANIFEST.in")
1713 with open(manifest_in, "a") as f:
1714 f.write("include versioneer.py\n")
1716 print(" 'versioneer.py' already in MANIFEST.in")
1717 if cfg.versionfile_source not in simple_includes:
1718 print(" appending versionfile_source ('%s') to MANIFEST.in" %
1719 cfg.versionfile_source)
1720 with open(manifest_in, "a") as f:
1721 f.write("include %s\n" % cfg.versionfile_source)
1723 print(" versionfile_source already in MANIFEST.in")
1725 # Make VCS-specific changes. For git, this means creating/changing
1726 # .gitattributes to mark _version.py for export-time keyword
1728 do_vcs_install(manifest_in, cfg.versionfile_source, ipy)
1732 def scan_setup_py():
1733 """Validate the contents of setup.py against Versioneer's expectations."""
1737 with open("setup.py", "r") as f:
1738 for line in f.readlines():
1739 if "import versioneer" in line:
1741 if "versioneer.get_cmdclass()" in line:
1742 found.add("cmdclass")
1743 if "versioneer.get_version()" in line:
1744 found.add("get_version")
1745 if "versioneer.VCS" in line:
1747 if "versioneer.versionfile_source" in line:
1751 print("Your setup.py appears to be missing some important items")
1752 print("(but I might be wrong). Please make sure it has something")
1753 print("roughly like the following:")
1755 print(" import versioneer")
1756 print(" setup( version=versioneer.get_version(),")
1757 print(" cmdclass=versioneer.get_cmdclass(), ...)")
1761 print("You should remove lines like 'versioneer.VCS = ' and")
1762 print("'versioneer.versionfile_source = ' . This configuration")
1763 print("now lives in setup.cfg, and should be removed from setup.py")
1768 if __name__ == "__main__":
1772 errors += scan_setup_py()