summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonny Pfannschmidt <opensource@ronnypfannschmidt.de>2019-05-26 08:22:32 +0200
committerRonny Pfannschmidt <opensource@ronnypfannschmidt.de>2019-05-26 08:22:32 +0200
commit26836886a4b719bbec8e4aaaa9fbe59f3d89b808 (patch)
tree343e0d03bee8bcea1410c5d328ed404cc5719c83
parent34a99d7b23c6a0b7f36a42fffab1f1302d9aed1d (diff)
parent94667297ccd7e8d445077e63b3cf2fd5e1c99d01 (diff)
downloadsetuptools-scm-26836886a4b719bbec8e4aaaa9fbe59f3d89b808.tar.gz
Merge branch 'master' into feature-git-worktree-193
-rw-r--r--.travis.yml37
-rw-r--r--CHANGELOG.rst24
-rw-r--r--README.rst317
-rw-r--r--setup.py2
-rw-r--r--src/setuptools_scm/__init__.py36
-rw-r--r--src/setuptools_scm/config.py11
-rw-r--r--src/setuptools_scm/file_finder_git.py26
-rw-r--r--src/setuptools_scm/hacks.py5
-rw-r--r--src/setuptools_scm/integration.py8
-rw-r--r--src/setuptools_scm/utils.py3
-rw-r--r--testing/conftest.py2
-rw-r--r--testing/test_basic_api.py16
-rw-r--r--testing/test_git.py14
-rw-r--r--testing/test_regressions.py6
-rw-r--r--tox.ini4
15 files changed, 321 insertions, 190 deletions
diff --git a/.travis.yml b/.travis.yml
index 79ebf42..75c3c0e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -22,6 +22,9 @@ python:
- '3.4'
- '3.5'
- '3.6'
+- '3.7'
+- '3.8-dev'
+dist: xenial # needed for 3.7+
env:
- TOXENV=py-test
@@ -62,40 +65,28 @@ jobs:
<<: *pypi
distributions: "sdist bdist_wheel"
- - <<: *deploy
+ - &bdist_egg
+ <<: *deploy
name: "python eggs 2.7"
python: '2.7'
deploy:
<<: *pypi
distributions: "bdist_egg"
- - <<: *deploy
+ - <<: *bdist_egg
name: "python eggs 3.4"
python: '3.4'
- deploy:
- <<: *pypi
- distributions: "bdist_egg"
-
-
- - <<: *deploy
+ - <<: *bdist_egg
name: "python eggs 3.5"
python: '3.5'
- deploy:
- <<: *pypi
- distributions: "bdist_egg"
-
- - <<: *deploy
+ - <<: *bdist_egg
name: "python eggs 3.6"
python: '3.6'
- deploy:
- <<: *pypi
- distributions: "bdist_egg"
-
- # - <<: *eggs
- # name: "python eggs 3.7"
- # python: '3.7'
- # deploy:
- # <<: *pypi
- # distributions: "bdist_egg"
+ - <<: *bdist_egg
+ name: "python eggs 3.7"
+ python: '3.7'
+ - <<: *bdist_egg
+ name: "python eggs 3.8"
+ python: '3.8-dev'
cache:
directories:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index f0b299d..c6a1968 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,3 +1,27 @@
+* fix #305 - ensure the git file finder closes filedescriptors even when errors happen
+
+v3.3.3
+======
+
+* add eggs for python3.7 and 3.8 to the deploy
+
+v3.3.2
+======
+
+
+* fix #335 - fix python3.8 support and add builds for up to python3.8
+
+v3.3.1
+======
+
+* fix #333 (regression from #198) - use a specific fallback root when calling fallbacks. Remove old
+ hack that resets the root when fallback entrypoints are present.
+
+v3.3.0
+======
+
+* fix #198 by adding the ``fallback_version`` option, which sets the version to be used when everything else fails.
+
v3.2.0
======
diff --git a/README.rst b/README.rst
index dc7a4d7..9f6f105 100644
--- a/README.rst
+++ b/README.rst
@@ -1,61 +1,119 @@
setuptools_scm
===============
-:code:`setuptools_scm` handles managing your python package versions
-in scm metadata instead of declaring them as the version argument
-or in a scm managed file.
+``setuptools_scm`` handles managing your Python package versions
+in SCM metadata instead of declaring them as the version argument
+or in a SCM managed file.
-It also handles file finders for the supported scm's.
+It also handles file finders for the supported SCMs.
.. image:: https://travis-ci.org/pypa/setuptools_scm.svg?branch=master
:target: https://travis-ci.org/pypa/setuptools_scm
-Setup.py usage
---------------
+``setup.py`` usage
+------------------
+
+To use ``setuptools_scm`` just modify your project's ``setup.py`` file
+like this:
+
+* Add ``setuptools_scm`` to the ``setup_requires`` parameter.
+* Add the ``use_scm_version`` parameter and set it to ``True``.
+
+For example:
+
+.. code:: python
+
+ from setuptools import setup
+ setup(
+ ...,
+ use_scm_version=True,
+ setup_requires=['setuptools_scm'],
+ ...,
+ )
-To use setuptools_scm just modify your project's setup.py file like this:
+Arguments to ``get_version()`` (see below) may be passed as a dictionary to
+``use_scm_version``. For example:
-1. Add :code:`'setuptools_scm'` to the :code:`setup_requires` parameter
-2. Add the :code:`use_scm_version` parameter and set it to ``True``
+.. code:: python
- E.g.:
+ from setuptools import setup
+ setup(
+ ...,
+ use_scm_version = {"root": "..", "relative_to": __file__},
+ setup_requires=['setuptools_scm'],
+ ...,
+ )
- .. code:: python
+Once configured, you can access the version number in your package via
+``pkg_resources`` (`PEP-0396 <https://www.python.org/dev/peps/pep-0396>`_). For
+example:
- from setuptools import setup
- setup(
- ...,
- use_scm_version=True,
- setup_requires=['setuptools_scm'],
- ...,
- )
+.. code:: python
- Arguments to ``get_version()`` (see below) may be passed as a
- dictionary to ``use_scm_version``. For example:
+ from pkg_resources import get_distribution, DistributionNotFound
+ try:
+ __version__ = get_distribution(__name__).version
+ except DistributionNotFound:
+ # package is not installed
+ pass
- .. code:: python
+You can also confirm the version number locally via ``setup.py``:
- from setuptools import setup
- setup(
- ...,
- use_scm_version = {"root": "..", "relative_to": __file__},
- setup_requires=['setuptools_scm'],
- ...,
- )
+.. code-block:: shell
+ $ python setup.py --version
-3. Access the version number in your package via :code:`pkg_resources`
+.. note::
- E.g. (`PEP-0396 <https://www.python.org/dev/peps/pep-0396>`_):
+ If you see unusual version numbers for packages but ``python setup.py
+ --version`` reports the expected version number, ensure ``[egg_info]`` is
+ not defined in ``setup.cfg``.
- .. code:: python
- from pkg_resources import get_distribution, DistributionNotFound
- try:
- __version__ = get_distribution(__name__).version
- except DistributionNotFound:
- # package is not installed
- pass
+``setup.cfg``
+-------------
+
+If using `setuptools 30.3.0
+<https://setuptools.readthedocs.io/en/latest/setuptools.html#configuring-setup-using-setup-cfg-files>`_
+or greater, you can store ``setup_requires`` configuration in ``setup.cfg``.
+However, ``use_scm_version`` must still be placed in ``setup.py``. For example:
+
+.. code:: python
+
+ # setup.py
+ from setuptools import setup
+ setup(
+ use_scm_version=True,
+ )
+
+.. code:: ini
+
+ # setup.cfg
+ [metadata]
+ ...
+
+ [options]
+ setup_requires =
+ setuptools_scm
+ ...
+
+.. important::
+
+ Ensure neither the ``[metadata]`` ``version`` option nor the ``[egg_info]``
+ section are defined, as these will interfere with ``setuptools_scm``.
+
+You may also need to define a ``pyproject.toml`` file (`PEP-0518
+<https://www.python.org/dev/peps/pep-0518>`_) to ensure you have the required
+version of ``setuptools``:
+
+.. code:: ini
+
+ # pyproject.toml
+ [build-system]
+ requires = ["setuptools>=30.3.0", "wheel", "setuptools_scm"]
+
+For more information, refer to the `setuptools issue #1002
+<https://github.com/pypa/setuptools/issues/1002>`_.
Programmatic usage
@@ -69,13 +127,13 @@ than the project's root, you can use:
from setuptools_scm import get_version
version = get_version(root='..', relative_to=__file__)
-See `setup.py Usage`_ above for how to use this within setup.py.
+See `setup.py Usage`_ above for how to use this within ``setup.py``.
-Usage from sphinx
+Usage from Sphinx
-----------------
-It is discouraged to use setuptools_scm from sphinx itself,
+It is discouraged to use ``setuptools_scm`` from Sphinx itself,
instead use ``pkg_resources`` after editable/real installation:
.. code:: python
@@ -86,25 +144,24 @@ instead use ``pkg_resources`` after editable/real installation:
# for example take major/minor
version = '.'.join(release.split('.')[:2])
-The underlying reason is, that services like readthedocs sometimes change
-the workingdirectory for good reasons and using the installed metadata prevents
-using needless volatile data there.
+The underlying reason is, that services like *Read the Docs* sometimes change
+the working directory for good reasons and using the installed metadata
+prevents using needless volatile data there.
Notable Plugins
----------------
`setuptools_scm_git_archive <https://pypi.python.org/pypi/setuptools_scm_git_archive>`_
-provides partial support for obtaining versions from git archives
-that belong to tagged versions. The only reason for not including
-it in setuptools-scm itself is git/github not supporting
-sufficient metadata for untagged/followup commits,
-which is preventing a consistent UX.
+ Provides partial support for obtaining versions from git archives that
+ belong to tagged versions. The only reason for not including it in
+ ``setuptools_scm`` itself is Git/GitHub not supporting sufficient metadata
+ for untagged/followup commits, which is preventing a consistent UX.
Default versioning scheme
--------------------------
-In the standard configuration setuptools_scm takes a look at 3 things:
+In the standard configuration ``setuptools_scm`` takes a look at three things:
1. latest tag (with a version number)
2. the distance to this tag (e.g. number of revisions since latest tag)
@@ -112,19 +169,19 @@ In the standard configuration setuptools_scm takes a look at 3 things:
and uses roughly the following logic to render the version:
-:code:`no distance and clean`:
- :code:`{tag}`
-:code:`distance and clean`:
- :code:`{next_version}.dev{distance}+{scm letter}{revision hash}`
-:code:`no distance and not clean`:
- :code:`{tag}+dYYYMMMDD`
-:code:`distance and not clean`:
- :code:`{next_version}.dev{distance}+{scm letter}{revision hash}.dYYYMMMDD`
+no distance and clean:
+ ``{tag}``
+distance and clean:
+ ``{next_version}.dev{distance}+{scm letter}{revision hash}``
+no distance and not clean:
+ ``{tag}+dYYYMMMDD``
+distance and not clean:
+ ``{next_version}.dev{distance}+{scm letter}{revision hash}.dYYYMMMDD``
-The next version is calculated by adding ``1`` to the last numeric component
-of the tag.
+The next version is calculated by adding ``1`` to the last numeric component of
+the tag.
-For git projects, the version relies on `git describe <https://git-scm.com/docs/git-describe>`_,
+For Git projects, the version relies on `git describe <https://git-scm.com/docs/git-describe>`_,
so you will see an additional ``g`` prepended to the ``{revision hash}``.
Semantic Versioning (SemVer)
@@ -132,30 +189,30 @@ Semantic Versioning (SemVer)
Due to the default behavior it's necessary to always include a
patch version (the ``3`` in ``1.2.3``), or else the automatic guessing
-will increment the wrong part of the semver (e.g. tag ``2.0`` results in
+will increment the wrong part of the SemVer (e.g. tag ``2.0`` results in
``2.1.devX`` instead of ``2.0.1.devX``). So please make sure to tag
accordingly.
.. note::
- Future versions of setuptools_scm will switch to
- `SemVer <http://semver.org/>`_ by default hiding the the old behavior
- as an configurable option.
+ Future versions of ``setuptools_scm`` will switch to `SemVer
+ <http://semver.org/>`_ by default hiding the the old behavior as an
+ configurable option.
Builtin mechanisms for obtaining version numbers
--------------------------------------------------
-1. the scm itself (git/hg)
-2. :code:`.hg_archival` files (mercurial archives)
-3. PKG-INFO
+1. the SCM itself (git/hg)
+2. ``.hg_archival`` files (mercurial archives)
+3. ``PKG-INFO``
.. note::
- git archives are not supported due to git shortcomings
+ Git archives are not supported due to Git shortcomings
-Configuration Parameters
+Configuration parameters
------------------------
In order to configure the way ``use_scm_version`` works you can provide
@@ -164,21 +221,21 @@ a mapping with options instead of a boolean value.
The currently supported configuration keys are:
:root:
- Relative path to cwd, used for finding the scm root, defaults to :code:`.`
+ Relative path to cwd, used for finding the SCM root; defaults to ``.``
:version_scheme:
- Configures how the local version number is constructed.
- Either an entrypoint name or a callable.
+ Configures how the local version number is constructed; either an
+ entrypoint name or a callable.
:local_scheme:
- Configures how the local component of the version is constructed.
- Either an entrypoint name or a callable.
+ Configures how the local component of the version is constructed; either an
+ entrypoint name or a callable.
:write_to:
A path to a file that gets replaced with a file containing the current
- version. It is ideal for creating a version.py file within the package,
- typically used to avoid using `pkg_resources.get_distribution` (which adds
- some overhead).
+ version. It is ideal for creating a ``version.py`` file within the
+ package, typically used to avoid using `pkg_resources.get_distribution`
+ (which adds some overhead).
.. warning::
@@ -188,38 +245,44 @@ The currently supported configuration keys are:
:write_to_template:
A newstyle format string that is given the current version as
- the :code:`version` keyword argument for formatting.
+ the ``version`` keyword argument for formatting.
:relative_to:
A file from which the root can be resolved.
Typically called by a script or module that is not in the root of the
- repository to point setuptools_scm at the root of the repository by
+ repository to point ``setuptools_scm`` at the root of the repository by
supplying ``__file__``.
-:parse:
- A function that will be used instead of the discovered SCM for parsing the
- version.
- Use with caution, this is a function for advanced use, and you should be
- familiar with the setuptools_scm internals to use it.
-
:tag_regex:
- A python regex string to extract the version part from any SCM tag.
- The regex needs to contain three named groups prefix, version and suffix,
- where `version` captures the actual version information.
+ A Python regex string to extract the version part from any SCM tag.
+ The regex needs to contain three named groups prefix, version and suffix,
+ where ``version`` captures the actual version information.
- defaults to the value of ``setuptools_scm.config.DEFAULT_TAG_REGEX``
- (see `config.py <src/setuptools_scm/config.py>`_).
+ Defaults to the value of ``setuptools_scm.config.DEFAULT_TAG_REGEX``
+ (see `config.py <src/setuptools_scm/config.py>`_).
+
+:fallback_version:
+ A version string that will be used if no other method for detecting the
+ version worked (e.g., when using a tarball with no metadata). If this is
+ unset (the default), setuptools_scm will error if it fails to detect the
+ version.
+
+:parse:
+ A function that will be used instead of the discovered SCM for parsing the
+ version.
+ Use with caution, this is a function for advanced use, and you should be
+ familiar with the ``setuptools_scm`` internals to use it.
:git_describe_command:
- This command will be used instead the default `git describe` command.
- Use with caution, this is a function for advanced use, and you should be
- familiar with the setuptools_scm internals to use it.
+ This command will be used instead the default ``git describe`` command.
+ Use with caution, this is a function for advanced use, and you should be
+ familiar with the ``setuptools_scm`` internals to use it.
- The default value is set by ``setuptools_scm.git.DEFAULT_DESCRIBE``
- (see `git.py <src/setuptools_scm/git.py>`_).
+ Defaults to the value set by ``setuptools_scm.git.DEFAULT_DESCRIBE``
+ (see `git.py <src/setuptools_scm/git.py>`_).
-To use setuptools_scm in other Python code you can use the
-``get_version`` function:
+To use ``setuptools_scm`` in other Python code you can use the ``get_version``
+function:
.. code:: python
@@ -229,13 +292,12 @@ To use setuptools_scm in other Python code you can use the
It optionally accepts the keys of the ``use_scm_version`` parameter as
keyword arguments.
-Example configuration in `setup.py` format:
+Example configuration in ``setup.py`` format:
.. code:: python
from setuptools import setup
-
setup(
use_scm_version={
'write_to': 'version.txt',
@@ -243,51 +305,52 @@ Example configuration in `setup.py` format:
}
)
-Environment Variables
+Environment variables
---------------------
:SETUPTOOLS_SCM_PRETEND_VERSION:
- when defined and not empty,
- its used as the primary source for the version number
- in which case it will be a unparsed string
+ when defined and not empty,
+ its used as the primary source for the version number
+ in which case it will be a unparsed string
+
:SETUPTOOLS_SCM_DEBUG:
- when defined and not empty,
- a lot of debug information will be printed as part of setuptools_scm operating
+ when defined and not empty,
+ a lot of debug information will be printed as part of ``setuptools_scm``
+ operating
Extending setuptools_scm
------------------------
-setuptools_scm ships with a few setuptools entrypoints based hooks to extend
-its default capabilities.
+``setuptools_scm`` ships with a few ``setuptools`` entrypoints based hooks to
+extend its default capabilities.
Adding a new SCM
~~~~~~~~~~~~~~~~
-setuptools_scm provides 2 entrypoints for adding new SCMs
+``setuptools_scm`` provides two entrypoints for adding new SCMs:
``setuptools_scm.parse_scm``
A function used to parse the metadata of the current workdir
using the name of the control directory/file of your SCM as the
entrypoint's name. E.g. for the built-in entrypoint for git the
- entrypoint is named :code:`.git` and references
- :code:`'setuptools_scm.git:parse'`.
+ entrypoint is named ``.git`` and references ``setuptools_scm.git:parse``
- The return value MUST be a :code:`setuptools.version.ScmVersion` instance
- created by the function :code:`setuptools_scm.version:meta`.
+ The return value MUST be a ``setuptools.version.ScmVersion`` instance
+ created by the function ``setuptools_scm.version:meta``.
``setuptools_scm.files_command``
- Either a string containing a shell command that prints all SCM managed
- files in its current working directory or a callable, that given a
- pathname will return that list.
+ Either a string containing a shell command that prints all SCM managed
+ files in its current working directory or a callable, that given a
+ pathname will return that list.
- Also use then name of your SCM control directory as name of the entrypoint.
+ Also use then name of your SCM control directory as name of the entrypoint.
Version number construction
~~~~~~~~~~~~~~~~~~~~~~~~~~~
``setuptools_scm.version_scheme``
Configures how the version number is constructed given a
- :code:`setuptools.version.ScmVersion` instance and should return a string
+ ``setuptools.version.ScmVersion`` instance and should return a string
representing the version.
Available implementations:
@@ -297,25 +360,25 @@ Version number construction
``setuptools_scm.local_scheme``
Configures how the local part of a version is rendered given a
- :code:`setuptools.version.ScmVersion` instance and should return a string
+ ``setuptools.version.ScmVersion`` instance and should return a string
representing the local version.
Available implementations:
:node-and-date: adds the node on dev versions and the date on dirty
workdir (default)
- :node-and-timestamp: like :code:`node-and-date` but with a timestamp of
- the form :code:`{:%Y%m%d%H%M%S}` instead
- :dirty-tag: adds :code:`+dirty` if the current workdir has changes
+ :node-and-timestamp: like ``node-and-date`` but with a timestamp of
+ the form ``{:%Y%m%d%H%M%S}`` instead
+ :dirty-tag: adds ``+dirty`` if the current workdir has changes
-Importing in setup.py
-~~~~~~~~~~~~~~~~~~~~~
+Importing in ``setup.py``
+~~~~~~~~~~~~~~~~~~~~~~~~~
-To support usage in :code:`setup.py` passing a callable into use_scm_version
+To support usage in ``setup.py`` passing a callable into ``use_scm_version``
is supported.
-Within that callable, setuptools_scm is available for import.
+Within that callable, ``setuptools_scm`` is available for import.
The callable must return the configuration.
@@ -354,8 +417,8 @@ some environments require a test prior to install,
Code of Conduct
---------------
-Everyone interacting in the setuptools_scm project's codebases, issue trackers,
-chat rooms, and mailing lists is expected to follow the
+Everyone interacting in the ``setuptools_scm`` project's codebases, issue
+trackers, chat rooms, and mailing lists is expected to follow the
`PyPA Code of Conduct`_.
.. _PyPA Code of Conduct: https://www.pypa.io/en/latest/code-of-conduct/
diff --git a/setup.py b/setup.py
index d38527a..2eb533b 100644
--- a/setup.py
+++ b/setup.py
@@ -76,6 +76,7 @@ arguments = dict(
.hg_archival.txt = setuptools_scm.hg:parse_archival
PKG-INFO = setuptools_scm.hacks:parse_pkginfo
pip-egg-info = setuptools_scm.hacks:parse_pip_egg_info
+ setup.py = setuptools_scm.hacks:fallback_version
[setuptools_scm.files_command]
.hg = setuptools_scm.file_finder_hg:hg_find_files
@@ -103,6 +104,7 @@ arguments = dict(
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
+ "Programming Language :: Python :: 3.7",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Version Control",
"Topic :: System :: Software Distribution",
diff --git a/src/setuptools_scm/__init__.py b/src/setuptools_scm/__init__.py
index f49cce4..f3886ed 100644
--- a/src/setuptools_scm/__init__.py
+++ b/src/setuptools_scm/__init__.py
@@ -31,12 +31,12 @@ def version_from_scm(root):
config = Configuration()
config.root = root
# TODO: Is it API?
- return _version_from_entrypoint(config, "setuptools_scm.parse_scm")
+ return _version_from_entrypoints(config)
-def _call_entrypoint_fn(config, fn):
+def _call_entrypoint_fn(root, config, fn):
if function_has_arg(fn, "config"):
- return fn(config.absolute_root, config=config)
+ return fn(root, config=config)
else:
warnings.warn(
"parse functions are required to provide a named argument"
@@ -44,12 +44,18 @@ def _call_entrypoint_fn(config, fn):
category=PendingDeprecationWarning,
stacklevel=2,
)
- return fn(config.absolute_root)
+ return fn(root)
-def _version_from_entrypoint(config, entrypoint):
- for ep in iter_matching_entrypoints(config.absolute_root, entrypoint):
- version = _call_entrypoint_fn(config, ep.load())
+def _version_from_entrypoints(config, fallback=False):
+ if fallback:
+ entrypoint = "setuptools_scm.parse_scm_fallback"
+ root = config.fallback_root
+ else:
+ entrypoint = "setuptools_scm.parse_scm"
+ root = config.absolute_root
+ for ep in iter_matching_entrypoints(root, entrypoint):
+ version = _call_entrypoint_fn(root, config, ep.load())
if version:
return version
@@ -81,20 +87,16 @@ def _do_parse(config):
return meta(tag=pretended, preformatted=True, config=config)
if config.parse:
- parse_result = _call_entrypoint_fn(config, config.parse)
+ parse_result = _call_entrypoint_fn(config.absolute_root, config, config.parse)
if isinstance(parse_result, string_types):
raise TypeError(
"version parse result was a string\nplease return a parsed version"
)
- version = parse_result or _version_from_entrypoint(
- config, "setuptools_scm.parse_scm_fallback"
- )
+ version = parse_result or _version_from_entrypoints(config, fallback=True)
else:
# include fallbacks after dropping them from the main entrypoint
- version = _version_from_entrypoint(
- config, "setuptools_scm.parse_scm"
- ) or _version_from_entrypoint(
- config, "setuptools_scm.parse_scm_fallback"
+ version = _version_from_entrypoints(config) or _version_from_entrypoints(
+ config, fallback=True
)
if version:
@@ -120,6 +122,8 @@ def get_version(
write_to_template=None,
relative_to=None,
tag_regex=None,
+ fallback_version=None,
+ fallback_root=".",
parse=None,
git_describe_command=None,
):
@@ -132,12 +136,14 @@ def get_version(
config = Configuration()
config.root = root
+ config.fallback_root = fallback_root
config.version_scheme = version_scheme
config.local_scheme = local_scheme
config.write_to = write_to
config.write_to_template = write_to_template
config.relative_to = relative_to
config.tag_regex = tag_regex
+ config.fallback_version = fallback_version
config.parse = parse
config.git_describe_command = git_describe_command
diff --git a/src/setuptools_scm/config.py b/src/setuptools_scm/config.py
index 796dd0b..38f79ae 100644
--- a/src/setuptools_scm/config.py
+++ b/src/setuptools_scm/config.py
@@ -44,6 +44,7 @@ class Configuration(object):
local_scheme = None
write_to = None
write_to_template = None
+ fallback_version = None
_relative_to = None
parse = None
_tag_regex = None
@@ -59,11 +60,21 @@ class Configuration(object):
self.local_scheme = "node-and-date"
self.write_to = ""
self.write_to_template = None
+ self.fallback_version = None
+ self.fallback_root = "."
self.parse = None
self.tag_regex = DEFAULT_TAG_REGEX
self.git_describe_command = None
@property
+ def fallback_root(self):
+ return self._fallback_root
+
+ @fallback_root.setter
+ def fallback_root(self, value):
+ self._fallback_root = os.path.abspath(value)
+
+ @property
def absolute_root(self):
return self._absolute_root
diff --git a/src/setuptools_scm/file_finder_git.py b/src/setuptools_scm/file_finder_git.py
index b7b55ed..5cda162 100644
--- a/src/setuptools_scm/file_finder_git.py
+++ b/src/setuptools_scm/file_finder_git.py
@@ -28,16 +28,16 @@ def _git_toplevel(path):
def _git_interpret_archive(fd, toplevel):
- tf = tarfile.open(fileobj=fd, mode="r|*")
- git_files = set()
- git_dirs = {toplevel}
- for member in tf.getmembers():
- name = os.path.normcase(member.name).replace("/", os.path.sep)
- if member.type == tarfile.DIRTYPE:
- git_dirs.add(name)
- else:
- git_files.add(name)
- return git_files, git_dirs
+ with tarfile.open(fileobj=fd, mode="r|*") as tf:
+ git_files = set()
+ git_dirs = {toplevel}
+ for member in tf.getmembers():
+ name = os.path.normcase(member.name).replace("/", os.path.sep)
+ if member.type == tarfile.DIRTYPE:
+ git_dirs.add(name)
+ else:
+ git_files.add(name)
+ return git_files, git_dirs
def _git_ls_files_and_dirs(toplevel):
@@ -46,7 +46,11 @@ def _git_ls_files_and_dirs(toplevel):
cmd = ["git", "archive", "--prefix", toplevel + os.path.sep, "HEAD"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, cwd=toplevel)
try:
- return _git_interpret_archive(proc.stdout, toplevel)
+ try:
+ return _git_interpret_archive(proc.stdout, toplevel)
+ finally:
+ # ensure we avoid ressource warnings by cleaning up the pocess
+ proc.wait()
except Exception:
if proc.wait() != 0:
log.exception("listing git files failed - pretending there aren't any")
diff --git a/src/setuptools_scm/hacks.py b/src/setuptools_scm/hacks.py
index a4ca586..1ef0bb4 100644
--- a/src/setuptools_scm/hacks.py
+++ b/src/setuptools_scm/hacks.py
@@ -22,3 +22,8 @@ def parse_pip_egg_info(root, config=None):
if not items:
return
return parse_pkginfo(os.path.join(pipdir, items[0]), config=config)
+
+
+def fallback_version(root, config=None):
+ if config.fallback_version is not None:
+ return meta(config.fallback_version, preformatted=True, config=config)
diff --git a/src/setuptools_scm/integration.py b/src/setuptools_scm/integration.py
index 737e84f..e18b3e5 100644
--- a/src/setuptools_scm/integration.py
+++ b/src/setuptools_scm/integration.py
@@ -2,7 +2,6 @@ from pkg_resources import iter_entry_points
from .version import _warn_if_setuptools_outdated
from .utils import do
-from .discover import iter_matching_entrypoints
from . import get_version
@@ -14,12 +13,7 @@ def version_keyword(dist, keyword, value):
value = {}
if getattr(value, "__call__", None):
value = value()
- # this piece of code is a hack to counter the mistake in root finding
- matching_fallbacks = iter_matching_entrypoints(
- ".", "setuptools_scm.parse_scm_fallback"
- )
- if any(matching_fallbacks):
- value.pop("root", None)
+
dist.metadata.version = get_version(**value)
diff --git a/src/setuptools_scm/utils.py b/src/setuptools_scm/utils.py
index 7e4e9f5..5b59005 100644
--- a/src/setuptools_scm/utils.py
+++ b/src/setuptools_scm/utils.py
@@ -100,7 +100,8 @@ def function_has_arg(fn, argname):
if PY2:
argspec = inspect.getargspec(fn).args
else:
- argspec = inspect.getfullargspec(fn).args
+
+ argspec = inspect.signature(fn).parameters
return argname in argspec
diff --git a/testing/conftest.py b/testing/conftest.py
index fb81953..0d34731 100644
--- a/testing/conftest.py
+++ b/testing/conftest.py
@@ -63,7 +63,7 @@ class Wd(object):
__tracebackhide__ = True
from setuptools_scm import get_version
- version = get_version(root=str(self.cwd), **kw)
+ version = get_version(root=str(self.cwd), fallback_root=str(self.cwd), **kw)
print(version)
return version
diff --git a/testing/test_basic_api.py b/testing/test_basic_api.py
index c032d23..f342e23 100644
--- a/testing/test_basic_api.py
+++ b/testing/test_basic_api.py
@@ -1,4 +1,5 @@
import os
+import sys
import py
import pytest
@@ -22,8 +23,9 @@ def test_data_from_mime(tmpdir):
assert res == {"name": "test", "revision": "1"}
-def test_version_from_pkginfo(wd):
+def test_version_from_pkginfo(wd, monkeypatch):
wd.write("PKG-INFO", "Version: 0.1")
+
assert wd.version == "0.1"
# replicate issue 167
@@ -56,6 +58,18 @@ def test_root_parameter_pass_by(monkeypatch, tmpdir):
setuptools_scm.get_version(root=tmpdir.strpath)
+def test_fallback(tmpdir, monkeypatch):
+ monkeypatch.delenv("SETUPTOOLS_SCM_DEBUG")
+ p = tmpdir.ensure("sub/package", dir=1)
+ p.join("setup.py").write(
+ """from setuptools import setup
+setup(use_scm_version={"fallback_version": "12.34"})
+"""
+ )
+ res = do((sys.executable, "setup.py", "--version"), p)
+ assert res == "12.34"
+
+
@pytest.mark.parametrize(
"version", ["1.0", "1.2.3.dev1+ge871260", "1.2.3.dev15+ge871260.d20180625", "2345"]
)
diff --git a/testing/test_git.py b/testing/test_git.py
index 1ada360..9307850 100644
--- a/testing/test_git.py
+++ b/testing/test_git.py
@@ -1,4 +1,5 @@
import sys
+
from setuptools_scm import integration
from setuptools_scm.utils import do
from setuptools_scm import git
@@ -30,6 +31,19 @@ def test_parse_describe_output(given, tag, number, node, dirty):
assert parsed == (tag, number, node, dirty)
+def test_root_relative_to(tmpdir, wd, monkeypatch):
+ monkeypatch.delenv("SETUPTOOLS_SCM_DEBUG")
+ p = wd.cwd.ensure("sub/package", dir=1)
+ p.join("setup.py").write(
+ """from setuptools import setup
+setup(use_scm_version={"root": "../..",
+ "relative_to": __file__})
+"""
+ )
+ res = do((sys.executable, "setup.py", "--version"), p)
+ assert res == "0.1.dev0"
+
+
@pytest.mark.issue("https://github.com/pypa/setuptools_scm/issues/298")
def test_file_finder_no_history(wd, caplog):
file_list = git_find_files(str(wd.cwd))
diff --git a/testing/test_regressions.py b/testing/test_regressions.py
index 702cbf2..f3b0fc6 100644
--- a/testing/test_regressions.py
+++ b/testing/test_regressions.py
@@ -29,7 +29,7 @@ def test_pkginfo_noscmroot(tmpdir, monkeypatch):
do("git init", p.dirpath())
res = do((sys.executable, "setup.py", "--version"), p)
- assert res == "1.0"
+ assert res == "0.1.dev0"
def test_pip_egg_info(tmpdir, monkeypatch):
@@ -43,10 +43,10 @@ def test_pip_egg_info(tmpdir, monkeypatch):
)
with pytest.raises(LookupError):
- get_version(root=p.strpath)
+ get_version(root=p.strpath, fallback_root=p.strpath)
p.ensure("pip-egg-info/random.egg-info/PKG-INFO").write("Version: 1.0")
- assert get_version(root=p.strpath) == "1.0"
+ assert get_version(root=p.strpath, fallback_root=p.strpath) == "1.0"
@pytest.mark.issue(164)
diff --git a/tox.ini b/tox.ini
index 121beb5..129f9b4 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,8 +1,10 @@
[tox]
-envlist=py{27,34,35,36,37}-test,flake8,check_readme,py{27,36}-selfcheck
+envlist=py{27,34,35,36,37,38}-test,flake8,check_readme,py{27,37}-selfcheck
[pytest]
filterwarnings=error
+markers=
+ issue(id): reference to github issue
[flake8]
max-complexity = 10