.. 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"
}