read-version


Nameread-version JSON
Version 0.3.2 PyPI version JSON
download
home_pagehttps://github.com/jwodder/read_version
SummaryExtract your project's __version__ variable
upload_time2021-07-25 18:01:56
maintainer
docs_urlNone
authorJohn Thorvald Wodder II
requires_python~=3.6
licenseMIT
keywords packaging setuptools version
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            .. image:: https://www.repostatus.org/badges/latest/inactive.svg
   :target: https://www.repostatus.org/#inactive
   :alt: Project Status: Inactive – The project has reached a stable, usable
         state but is no longer being actively developed; support/maintenance
         will be provided as time allows.

.. image:: https://github.com/jwodder/read_version/workflows/Test/badge.svg?branch=master
    :target: https://github.com/jwodder/read_version/actions?workflow=Test
    :alt: CI Status

.. image:: https://codecov.io/gh/jwodder/read_version/branch/master/graph/badge.svg
    :target: https://codecov.io/gh/jwodder/read_version

.. image:: https://img.shields.io/pypi/pyversions/read_version.svg
    :target: https://pypi.org/project/read_version/

.. image:: https://img.shields.io/github/license/jwodder/read_version.svg
    :target: https://opensource.org/licenses/MIT
    :alt: MIT License

`GitHub <https://github.com/jwodder/read_version>`_
| `PyPI <https://pypi.org/project/read_version/>`_
| `Issues <https://github.com/jwodder/read_version/issues>`_
| `Changelog <https://github.com/jwodder/read_version/blob/master/CHANGELOG.md>`_

**Note:** As of the release of setuptools 46.4.0, setuptools natively supports
using the ``attr:`` directive in ``setup.cfg`` to set the project version based
on static analysis of the project source.  This makes the bulk of
``read_version``'s use cases obsolete, and so it will not receive further
development.

When creating a ``setup.py`` for a new project, do you find yourself always
writing the same block of code for parsing ``__version__`` from your project's
source?  Something like this?

::

    with open(join(dirname(__file__), 'package_name', '__init__.py')) as fp:
        for line in fp:
            m = re.search(r'^\s*__version__\s*=\s*([\'"])([^\'"]+)\1\s*$', line)
            if m:
                version = m.group(2)
                break
        else:
            raise RuntimeError('Unable to find own __version__ string')

    setup(
        version = version,
        ...
    )

Someone needs to put all that into a reusable package, am I right?  Well,
someone did, and this is that package.  It exports a single function that does
the above, perfect for importing into your ``setup.py``, and *(New in v0.2.0!)*
this package even lets you map Python variables to supported metadata fields
via your ``pyproject.toml``.

Installation
============
``read_version`` requires Python 3.6 or higher.  Just use `pip
<https://pip.pypa.io>`_ for Python 3 (You have pip, right?) to install
``read_version`` and its dependencies::

    python3 -m pip install read_version

``read_version`` also has a ``toml`` extra that provides support for
reading configuration from ``pyproject.toml``.  Install it with::

    python3 -m pip install "read_version[toml]"


Usage
=====

The Functional Way
------------------

1. Install ``read_version`` in your development environment.

2. Add a ``pyproject.toml`` file to your project declaring ``read_version`` as
   a build dependency.  (This is needed so that other people can build your
   package from source; see `PEP 518
   <https://www.python.org/dev/peps/pep-0518/>`_ for more information.)  The
   contents of the file should look like::

        [build-system]
        requires = [
            "read_version ~= 0.3.0",
            "setuptools",
            "wheel"
        ]
        build-backend = "setuptools.build_meta"

3. In your ``setup.py``, get rid of your boilerplate ``__version__``-finding
   code and replace it with::

        from read_version import read_version

        setup(
            version = read_version('packagename', '__init__.py'),
            ...
        )

4. Build your project and double-check that the version is set to the correct
   value.

5. Done!

The Declarative Way
-------------------

*New in version 0.2.0!*

1. Install ``read_version`` in your development environment with the ``toml``
   extra::

    pip install 'read_version[toml]'

   You will also need version 42.0.0 or later of ``setuptools``::

    pip install -U 'setuptools>=42'

2. Add a ``pyproject.toml`` file to your project declaring
   ``read_version[toml]`` as a build dependency and also requiring version
   42.0.0 or later of ``setuptools``.  The relevant section of the file should
   look like::

        [build-system]
        requires = [
            "read_version[toml] ~= 0.3.0",
            "setuptools >= 42.0.0",
            "wheel"
        ]
        build-backend = "setuptools.build_meta"

3. Get rid of your boilerplate ``__version__``-finding code in your
   ``setup.py``.  Instead, add a ``tool.read_version`` table to your
   ``pyproject.toml`` file, and for each metadata field that you want to be
   read from a variable in a Python source file, add an entry to this table of
   the form ``FIELD = "dotted.file.path:varname"``, where:

   - ``FIELD`` is replaced by the lowercase name of the field.  Supported
     fields are:

     - ``author``
     - ``author_email``
     - ``description`` (Note that this is the short description or summary, not
       the long description!)
     - ``keywords`` (It is recommended to use a list of strings as the value or
       else ``setuptools`` might mangle it)
     - ``license``
     - ``maintainer``
     - ``maintainer_email``
     - ``url``
     - ``version``

     Entries with unsupported or unknown field names are ignored.

   - ``dotted.file.path`` is replaced by the path (relative to the project
     root) to the file containing the variable, with path components separated
     by dots and the ``.py`` at the end of the last path component dropped

   - ``varname`` is replaced by the name of the variable to read

   Examples::

        [tool.read_version]

        # Set the project's version to the value of __version__ in foobar.py:
        version = "foobar:__version__"

        # Set the project's author to the value of author_name in
        # foobar/__init__.py
        author = "foobar.__init__:author_name"

        # Set the project's license to the value of LICENSE in
        # src/foobar/about.py:
        license = "src.foobar.about:LICENSE"

   If this syntax doesn't work for you — say, because one of your path
   components contains a period or colon in its name, or because the file
   doesn't have a ``.py`` extension — or if you want to set a default value for
   when the variable isn't found, then make ``tool.read_version.FIELD`` into a
   table, like so::

        # Set the project's version to the value of __version__ in
        # foo.bar/__init__.pyq:
        [tool.read_version.version]
        path = ["foo.bar", "__init__.pyq"]
        variable = "__version__"

        # Set the project's author_email to the value of EMAIL in foobar.py.
        # If the variable isn't found, use the value "me@example.com" instead
        # of erroring
        [tool.read_version.author_email]
        path = ["foobar.py"]
        variable = "EMAIL"
        default = "me@example.com"

   ``tool.read_version.FIELD`` tables may contain the following keys:

   :path: *(Required)* The path to the source file containing the variable to
          read, relative to the project root, as a list of path components
   :variable: *(Required)* The name of the Python variable to get the value
              from
   :default: *(Optional)* If the variable cannot be found in the source file,
             use the given value instead; if the variable cannot be found and
             ``default`` is not set, an error will occur

4. Build your project and double-check that the metadata has all the relevant
   fields set to their correct values.

5. Done!

API
===
``read_version`` exports a single function, also named ``read_version``, whose
signature is::

    read_version(*filepath, variable='__version__', default=NOTHING)

``read_version()`` takes one or more file path components pointing to a Python
source file to parse.  The path components will be joined together with
``os.path.join()``, and then, if the path isn't absolute, the path to the
directory containing the script calling ``read_version()`` will be prepended to
the path.  (No more ``join(dirname(__file__), ...)`` boilerplate needed!)
``read_version()`` then parses the given Python file and searches through the
parse tree for any assignments to a variable named ``__version__``, returning
the last value assigned.

The ``variable`` keyword argument can be set to the name of a variable other
than ``__version__`` to search for assignments to a different variable instead.
Setting it to ``"__doc__"`` causes the function to return the module docstring.

If no assignments to the variable are found, a ``ValueError`` is raised.  To
instead return a default value when this happens, set the ``default`` keyword
argument.


Restrictions
============
``read_variable`` only finds assignments that occur at the top level of the
module, outside of any blocks.

Only assignments of literal values are supported; assignments to the
searched-for variable involving more complicated expressions will cause an
error to be raised.



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/jwodder/read_version",
    "name": "read-version",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "~=3.6",
    "maintainer_email": "",
    "keywords": "packaging,setuptools,version",
    "author": "John Thorvald Wodder II",
    "author_email": "read-version@varonathe.org",
    "download_url": "https://files.pythonhosted.org/packages/9c/2f/e6ed7dd2e34706b7b04f08204f425ea16deb949f4374e5e445fd20a7702f/read_version-0.3.2.tar.gz",
    "platform": "",
    "description": ".. image:: https://www.repostatus.org/badges/latest/inactive.svg\n   :target: https://www.repostatus.org/#inactive\n   :alt: Project Status: Inactive \u2013 The project has reached a stable, usable\n         state but is no longer being actively developed; support/maintenance\n         will be provided as time allows.\n\n.. image:: https://github.com/jwodder/read_version/workflows/Test/badge.svg?branch=master\n    :target: https://github.com/jwodder/read_version/actions?workflow=Test\n    :alt: CI Status\n\n.. image:: https://codecov.io/gh/jwodder/read_version/branch/master/graph/badge.svg\n    :target: https://codecov.io/gh/jwodder/read_version\n\n.. image:: https://img.shields.io/pypi/pyversions/read_version.svg\n    :target: https://pypi.org/project/read_version/\n\n.. image:: https://img.shields.io/github/license/jwodder/read_version.svg\n    :target: https://opensource.org/licenses/MIT\n    :alt: MIT License\n\n`GitHub <https://github.com/jwodder/read_version>`_\n| `PyPI <https://pypi.org/project/read_version/>`_\n| `Issues <https://github.com/jwodder/read_version/issues>`_\n| `Changelog <https://github.com/jwodder/read_version/blob/master/CHANGELOG.md>`_\n\n**Note:** As of the release of setuptools 46.4.0, setuptools natively supports\nusing the ``attr:`` directive in ``setup.cfg`` to set the project version based\non static analysis of the project source.  This makes the bulk of\n``read_version``'s use cases obsolete, and so it will not receive further\ndevelopment.\n\nWhen creating a ``setup.py`` for a new project, do you find yourself always\nwriting the same block of code for parsing ``__version__`` from your project's\nsource?  Something like this?\n\n::\n\n    with open(join(dirname(__file__), 'package_name', '__init__.py')) as fp:\n        for line in fp:\n            m = re.search(r'^\\s*__version__\\s*=\\s*([\\'\"])([^\\'\"]+)\\1\\s*$', line)\n            if m:\n                version = m.group(2)\n                break\n        else:\n            raise RuntimeError('Unable to find own __version__ string')\n\n    setup(\n        version = version,\n        ...\n    )\n\nSomeone needs to put all that into a reusable package, am I right?  Well,\nsomeone did, and this is that package.  It exports a single function that does\nthe above, perfect for importing into your ``setup.py``, and *(New in v0.2.0!)*\nthis package even lets you map Python variables to supported metadata fields\nvia your ``pyproject.toml``.\n\nInstallation\n============\n``read_version`` requires Python 3.6 or higher.  Just use `pip\n<https://pip.pypa.io>`_ for Python 3 (You have pip, right?) to install\n``read_version`` and its dependencies::\n\n    python3 -m pip install read_version\n\n``read_version`` also has a ``toml`` extra that provides support for\nreading configuration from ``pyproject.toml``.  Install it with::\n\n    python3 -m pip install \"read_version[toml]\"\n\n\nUsage\n=====\n\nThe Functional Way\n------------------\n\n1. Install ``read_version`` in your development environment.\n\n2. Add a ``pyproject.toml`` file to your project declaring ``read_version`` as\n   a build dependency.  (This is needed so that other people can build your\n   package from source; see `PEP 518\n   <https://www.python.org/dev/peps/pep-0518/>`_ for more information.)  The\n   contents of the file should look like::\n\n        [build-system]\n        requires = [\n            \"read_version ~= 0.3.0\",\n            \"setuptools\",\n            \"wheel\"\n        ]\n        build-backend = \"setuptools.build_meta\"\n\n3. In your ``setup.py``, get rid of your boilerplate ``__version__``-finding\n   code and replace it with::\n\n        from read_version import read_version\n\n        setup(\n            version = read_version('packagename', '__init__.py'),\n            ...\n        )\n\n4. Build your project and double-check that the version is set to the correct\n   value.\n\n5. Done!\n\nThe Declarative Way\n-------------------\n\n*New in version 0.2.0!*\n\n1. Install ``read_version`` in your development environment with the ``toml``\n   extra::\n\n    pip install 'read_version[toml]'\n\n   You will also need version 42.0.0 or later of ``setuptools``::\n\n    pip install -U 'setuptools>=42'\n\n2. Add a ``pyproject.toml`` file to your project declaring\n   ``read_version[toml]`` as a build dependency and also requiring version\n   42.0.0 or later of ``setuptools``.  The relevant section of the file should\n   look like::\n\n        [build-system]\n        requires = [\n            \"read_version[toml] ~= 0.3.0\",\n            \"setuptools >= 42.0.0\",\n            \"wheel\"\n        ]\n        build-backend = \"setuptools.build_meta\"\n\n3. Get rid of your boilerplate ``__version__``-finding code in your\n   ``setup.py``.  Instead, add a ``tool.read_version`` table to your\n   ``pyproject.toml`` file, and for each metadata field that you want to be\n   read from a variable in a Python source file, add an entry to this table of\n   the form ``FIELD = \"dotted.file.path:varname\"``, where:\n\n   - ``FIELD`` is replaced by the lowercase name of the field.  Supported\n     fields are:\n\n     - ``author``\n     - ``author_email``\n     - ``description`` (Note that this is the short description or summary, not\n       the long description!)\n     - ``keywords`` (It is recommended to use a list of strings as the value or\n       else ``setuptools`` might mangle it)\n     - ``license``\n     - ``maintainer``\n     - ``maintainer_email``\n     - ``url``\n     - ``version``\n\n     Entries with unsupported or unknown field names are ignored.\n\n   - ``dotted.file.path`` is replaced by the path (relative to the project\n     root) to the file containing the variable, with path components separated\n     by dots and the ``.py`` at the end of the last path component dropped\n\n   - ``varname`` is replaced by the name of the variable to read\n\n   Examples::\n\n        [tool.read_version]\n\n        # Set the project's version to the value of __version__ in foobar.py:\n        version = \"foobar:__version__\"\n\n        # Set the project's author to the value of author_name in\n        # foobar/__init__.py\n        author = \"foobar.__init__:author_name\"\n\n        # Set the project's license to the value of LICENSE in\n        # src/foobar/about.py:\n        license = \"src.foobar.about:LICENSE\"\n\n   If this syntax doesn't work for you \u2014 say, because one of your path\n   components contains a period or colon in its name, or because the file\n   doesn't have a ``.py`` extension \u2014 or if you want to set a default value for\n   when the variable isn't found, then make ``tool.read_version.FIELD`` into a\n   table, like so::\n\n        # Set the project's version to the value of __version__ in\n        # foo.bar/__init__.pyq:\n        [tool.read_version.version]\n        path = [\"foo.bar\", \"__init__.pyq\"]\n        variable = \"__version__\"\n\n        # Set the project's author_email to the value of EMAIL in foobar.py.\n        # If the variable isn't found, use the value \"me@example.com\" instead\n        # of erroring\n        [tool.read_version.author_email]\n        path = [\"foobar.py\"]\n        variable = \"EMAIL\"\n        default = \"me@example.com\"\n\n   ``tool.read_version.FIELD`` tables may contain the following keys:\n\n   :path: *(Required)* The path to the source file containing the variable to\n          read, relative to the project root, as a list of path components\n   :variable: *(Required)* The name of the Python variable to get the value\n              from\n   :default: *(Optional)* If the variable cannot be found in the source file,\n             use the given value instead; if the variable cannot be found and\n             ``default`` is not set, an error will occur\n\n4. Build your project and double-check that the metadata has all the relevant\n   fields set to their correct values.\n\n5. Done!\n\nAPI\n===\n``read_version`` exports a single function, also named ``read_version``, whose\nsignature is::\n\n    read_version(*filepath, variable='__version__', default=NOTHING)\n\n``read_version()`` takes one or more file path components pointing to a Python\nsource file to parse.  The path components will be joined together with\n``os.path.join()``, and then, if the path isn't absolute, the path to the\ndirectory containing the script calling ``read_version()`` will be prepended to\nthe path.  (No more ``join(dirname(__file__), ...)`` boilerplate needed!)\n``read_version()`` then parses the given Python file and searches through the\nparse tree for any assignments to a variable named ``__version__``, returning\nthe last value assigned.\n\nThe ``variable`` keyword argument can be set to the name of a variable other\nthan ``__version__`` to search for assignments to a different variable instead.\nSetting it to ``\"__doc__\"`` causes the function to return the module docstring.\n\nIf no assignments to the variable are found, a ``ValueError`` is raised.  To\ninstead return a default value when this happens, set the ``default`` keyword\nargument.\n\n\nRestrictions\n============\n``read_variable`` only finds assignments that occur at the top level of the\nmodule, outside of any blocks.\n\nOnly assignments of literal values are supported; assignments to the\nsearched-for variable involving more complicated expressions will cause an\nerror to be raised.\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Extract your project's __version__ variable",
    "version": "0.3.2",
    "project_urls": {
        "Bug Tracker": "https://github.com/jwodder/read_version/issues",
        "Homepage": "https://github.com/jwodder/read_version",
        "Source Code": "https://github.com/jwodder/read_version"
    },
    "split_keywords": [
        "packaging",
        "setuptools",
        "version"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "65bbc203ddde5f133b4dfe1f5f431168991698438da8f5915ea8cd26655bcceb",
                "md5": "a3dc57e56b5bc5c5a6a9f6da26bca861",
                "sha256": "e34c9890aa653b129a862120841b0823da57535d5ac4934253d5087e79b00b1d"
            },
            "downloads": -1,
            "filename": "read_version-0.3.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a3dc57e56b5bc5c5a6a9f6da26bca861",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "~=3.6",
            "size": 8603,
            "upload_time": "2021-07-25T18:01:55",
            "upload_time_iso_8601": "2021-07-25T18:01:55.069170Z",
            "url": "https://files.pythonhosted.org/packages/65/bb/c203ddde5f133b4dfe1f5f431168991698438da8f5915ea8cd26655bcceb/read_version-0.3.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9c2fe6ed7dd2e34706b7b04f08204f425ea16deb949f4374e5e445fd20a7702f",
                "md5": "0be44e6819eb039c86cf55a413733645",
                "sha256": "3f2d30852bce9174b244f7f29aaebf4e79904c6ed51a19716325015ff306ce3f"
            },
            "downloads": -1,
            "filename": "read_version-0.3.2.tar.gz",
            "has_sig": false,
            "md5_digest": "0be44e6819eb039c86cf55a413733645",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "~=3.6",
            "size": 17377,
            "upload_time": "2021-07-25T18:01:56",
            "upload_time_iso_8601": "2021-07-25T18:01:56.504916Z",
            "url": "https://files.pythonhosted.org/packages/9c/2f/e6ed7dd2e34706b7b04f08204f425ea16deb949f4374e5e445fd20a7702f/read_version-0.3.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2021-07-25 18:01:56",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "jwodder",
    "github_project": "read_version",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "read-version"
}
        
Elapsed time: 0.33411s