Commit 6de971f1 authored by John T. Wodder II's avatar John T. Wodder II

Implement a "literal_attr:" config directive

parent 9887350a
from __future__ import absolute_import, unicode_literals
import ast
import io
import os
import sys
......@@ -316,15 +317,22 @@ class ConfigHandler:
Examples:
attr: package.attr
attr: package.module.attr
literal_attr: package.attr
literal_attr: package.module.attr
:param str value:
:rtype: str
"""
attr_directive = 'attr:'
if not value.startswith(attr_directive):
literal_attr_directive = 'literal_attr:'
if value.startswith(attr_directive):
directive = attr_directive
elif value.startswith(literal_attr_directive):
directive = literal_attr_directive
else:
return value
attrs_path = value.replace(attr_directive, '').strip().split('.')
attrs_path = value.replace(directive, '').strip().split('.')
attr_name = attrs_path.pop()
module_name = '.'.join(attrs_path)
......@@ -344,14 +352,50 @@ class ConfigHandler:
elif '' in package_dir:
# A custom parent directory was specified for all root modules
parent_path = os.path.join(os.getcwd(), package_dir[''])
if directive == attr_directive:
sys.path.insert(0, parent_path)
try:
module = import_module(module_name)
value = getattr(module, attr_name)
finally:
sys.path = sys.path[1:]
elif directive == literal_attr_directive:
fpath = os.path.join(parent_path, *module_name.split('.'))
if os.path.exists(fpath + '.py'):
fpath += '.py'
elif os.path.isdir(fpath):
fpath = os.path.join(fpath, '__init__.py')
else:
raise DistutilsOptionError(
'Could not find module ' + module_name
)
with open(fpath, 'rb') as fp:
src = fp.read()
found = False
top_level = ast.parse(src)
for statement in top_level.body:
if isinstance(statement, ast.Assign):
for target in statement.targets:
if isinstance(target, ast.Name) \
and target.id == attr_name:
value = ast.literal_eval(statement.value)
found = True
elif isinstance(target, ast.Tuple) \
and any(isinstance(t, ast.Name) and t.id==attr_name
for t in target.elts):
stmnt_value = ast.literal_eval(statement.value)
for t,v in zip(target.elts, stmnt_value):
if isinstance(t, ast.Name) \
and t.id == attr_name:
value = v
found = True
if not found:
raise DistutilsOptionError(
'No literal assignment to {!r} found in file'
.format(attr_name)
)
return value
@classmethod
......
......@@ -300,6 +300,37 @@ class TestMetadata:
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '2016.11.26'
def test_literal_version(self, tmpdir):
_, config = fake_env(
tmpdir,
'[metadata]\n'
'version = literal_attr: fake_package.VERSION\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1.2.3'
config.write(
'[metadata]\n'
'version = literal_attr: fake_package.VERSION_MAJOR\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1'
subpack = tmpdir.join('fake_package').mkdir('subpackage')
subpack.join('__init__.py').write('')
subpack.join('submodule.py').write(
'import third_party_module\n'
'VERSION = (2016, 11, 26)'
)
config.write(
'[metadata]\n'
'version = attr: fake_package.subpackage.submodule.VERSION\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '2016.11.26'
def test_version_file(self, tmpdir):
_, config = fake_env(
......@@ -332,6 +363,17 @@ class TestMetadata:
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1.2.3'
config.write(
'[metadata]\n'
'version = literal_attr: fake_package_simple.VERSION\n'
'[options]\n'
'package_dir =\n'
' = src\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1.2.3'
def test_version_with_package_dir_rename(self, tmpdir):
_, config = fake_env(
......@@ -347,6 +389,17 @@ class TestMetadata:
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1.2.3'
config.write(
'[metadata]\n'
'version = literal_attr: fake_package_rename.VERSION\n'
'[options]\n'
'package_dir =\n'
' fake_package_rename = fake_dir\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1.2.3'
def test_version_with_package_dir_complex(self, tmpdir):
_, config = fake_env(
......@@ -362,6 +415,17 @@ class TestMetadata:
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1.2.3'
config.write(
'[metadata]\n'
'version = literal_attr: fake_package_complex.VERSION\n'
'[options]\n'
'package_dir =\n'
' fake_package_complex = src/fake_dir\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1.2.3'
def test_unknown_meta_item(self, tmpdir):
fake_env(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment