diff options
-rw-r--r-- | .travis.yml | 37 | ||||
-rw-r--r-- | CHANGELOG.rst | 24 | ||||
-rw-r--r-- | README.rst | 317 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | src/setuptools_scm/__init__.py | 36 | ||||
-rw-r--r-- | src/setuptools_scm/config.py | 11 | ||||
-rw-r--r-- | src/setuptools_scm/file_finder_git.py | 26 | ||||
-rw-r--r-- | src/setuptools_scm/hacks.py | 5 | ||||
-rw-r--r-- | src/setuptools_scm/integration.py | 8 | ||||
-rw-r--r-- | src/setuptools_scm/utils.py | 3 | ||||
-rw-r--r-- | testing/conftest.py | 2 | ||||
-rw-r--r-- | testing/test_basic_api.py | 16 | ||||
-rw-r--r-- | testing/test_git.py | 14 | ||||
-rw-r--r-- | testing/test_regressions.py | 6 | ||||
-rw-r--r-- | tox.ini | 4 |
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 ====== @@ -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/ @@ -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) @@ -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 |