Switch back to using attr directive in setup.cfg version

As of setuptools 46.4.0, this extracts the attribute value statically
using the ast module, if possible. This allows it to work properly even
if the attribute is stored in a file that cannot be imported at setup
time (e. g. because of dependencies that might not be installed yet).
This commit is contained in:
dgelessus 2020-07-18 13:13:19 +02:00
parent d367a9238a
commit b595456a05
3 changed files with 3 additions and 43 deletions

View File

@ -1,6 +1,6 @@
[build-system]
requires = [
"setuptools >= 43.0.0",
"setuptools >= 46.4.0",
"wheel >= 0.32.0",
]
build-backend = "setuptools.build_meta"

View File

@ -1,12 +1,6 @@
[metadata]
name = rsrcfork
# The version is defined in setup.py,
# which extracts the value of the __version__ attribute from rsrcfork/__init__.py,
# so that the version number/string is only explicitly written in a single place.
# We cannot use "version = attr: rsrcfork.__version__" here,
# because the attr directive needs to import the module to read its attributes,
# which won't work if any of the module's import-time dependencies are not installed yet
# (as is usually the case when setup.cfg is first evaluated before installation).
version = attr: rsrcfork.__version__
url = https://github.com/dgelessus/python-rsrcfork
author = dgelessus
classifiers =

View File

@ -1,39 +1,5 @@
#!/usr/bin/env python3
import ast
import setuptools
def attr(file, name):
"""Read the constant value of a global variable from a Python file without importing/executing it.
The variable in question must be assigned a constant literal
(as understood by :func:`ast.literal_eval`)
in a simple assignment.
The variable *should* only be assigned once
(later assignments are silently ignored).
Based on https://github.com/pypa/setuptools/issues/1960#issue-547330414.
"""
with open(file, "rb") as f:
module = ast.parse(f.read())
for node in ast.iter_child_nodes(module):
if (
isinstance(node, ast.Assign)
and len(node.targets) == 1
and isinstance(node.targets[0], ast.Name)
and node.targets[0].id == name
):
return ast.literal_eval(node.value)
else:
raise ValueError(f"No simple assignment of variable {name!r} found in {file!r}")
setuptools.setup(
# Read the version number from the module source code without importing or executing it.
# This is necessary because at the time that setup.py is executed,
# the dependencies necessary to import rsrcfork may not be installed yet.
version=attr("rsrcfork/__init__.py", "__version__"),
)
setuptools.setup()