[reprotest] 01/01: utils: Add AttributeReplacer and move AttributeFunctor here
Ximin Luo
infinity0 at debian.org
Wed Sep 27 19:27:09 UTC 2017
This is an automated email from the git hooks/post-receive script.
infinity0 pushed a commit to branch master
in repository reprotest.
commit c2bd30c304c0181168ab2ec03a88e17967848aa7
Author: Ximin Luo <infinity0 at debian.org>
Date: Wed Sep 27 21:25:43 2017 +0200
utils: Add AttributeReplacer and move AttributeFunctor here
---
reprotest/__init__.py | 5 ++---
reprotest/build.py | 8 +++++---
reprotest/presets.py | 7 +------
reprotest/utils.py | 41 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 49 insertions(+), 12 deletions(-)
diff --git a/reprotest/__init__.py b/reprotest/__init__.py
index a5972e2..551b2d5 100644
--- a/reprotest/__init__.py
+++ b/reprotest/__init__.py
@@ -8,7 +8,6 @@ import contextlib
import logging
import os
import random
-import re
import shlex
import shutil
import subprocess
@@ -280,7 +279,7 @@ class TestArgs(collections.namedtuple('_Test',
raise ValueError("already built '%s'" % name)
names_seen.add(name)
- var = var._replace(spec=var.spec.apply_dynamic_defaults(source_root))
+ var = var.replace.spec.apply_dynamic_defaults(source_root)
bctx = BuildContext(testbed.scratch, result_dir, source_root, name, var)
build = bctx.make_build_commands(
@@ -377,7 +376,7 @@ def check_auto(test_args, testbed_args, build_variations=Variations.of(Variation
varnames = VariationSpec.all_names()
random.shuffle(varnames)
for v in varnames:
- var_test = var_cur.replace_spec(**{v: var_x1.spec[v]})
+ var_test = var_cur.replace.spec._replace(**{v: var_x1.spec[v]})
if is_reproducible(v, var_test):
# vary it for the next test as well, it's OK to vary it
var_cur = var_test
diff --git a/reprotest/build.py b/reprotest/build.py
index 976495c..be22ff6 100644
--- a/reprotest/build.py
+++ b/reprotest/build.py
@@ -15,6 +15,7 @@ import types
from reprotest import _shell_ast
from reprotest import mdiffconf
+from reprotest.utils import AttributeReplacer
def tool_required(*tools):
@@ -455,15 +456,16 @@ class Variations(collections.namedtuple('_Variations', 'spec verbosity')):
def of(cls, *specs, zero=VariationSpec.empty(), verbosity=0):
return [cls(spec, verbosity) for spec in [zero] + list(specs)]
- def replace_spec(self, *args, **kwargs):
- return self._replace(spec=self.spec._replace(*args, **kwargs))
+ @property
+ def replace(self):
+ return AttributeReplacer(self, [])
if __name__ == "__main__":
import sys
d = VariationSpec()
for s in sys.argv[1:]:
- d = d.append(s)
+ d = d.extend([s])
print(s)
print(">>>", d)
print("result", d.apply_dynamic_defaults("."))
diff --git a/reprotest/presets.py b/reprotest/presets.py
index 9f4f340..ca2a0e5 100644
--- a/reprotest/presets.py
+++ b/reprotest/presets.py
@@ -6,12 +6,7 @@ import os
import shlex
import subprocess
-
-class AttributeFunctor(collections.namedtuple('_AttributeFunctor', 'x f')):
- def __getattr__(self, name):
- return lambda *args: self.x._replace(**{
- name: self.f(getattr(self.x, name), *args)
- })
+from reprotest.utils import AttributeFunctor
class ReprotestPreset(collections.namedtuple('_ReprotestPreset',
diff --git a/reprotest/utils.py b/reprotest/utils.py
new file mode 100644
index 0000000..83a8417
--- /dev/null
+++ b/reprotest/utils.py
@@ -0,0 +1,41 @@
+# Licensed under the GPL: https://www.gnu.org/licenses/gpl-3.0.en.html
+# For details: reprotest/debian/copyright
+
+import collections
+import functools
+
+
+class AttributeFunctor(collections.namedtuple('_AttributeFunctor', 'x f')):
+ """Functor for applying functions to attributes of namedtuples."""
+ def __getattr__(self, name):
+ return lambda *args: self.x._replace(**{
+ name: self.f(getattr(self.x, name), *args)
+ })
+
+
+class AttributeReplacer(object):
+ """Proxy for setting attributes deeply on trees of namedtuples."""
+ __slots__ = ['top', 'attrs']
+
+ def __init__(self, top, attrs):
+ self.top = top
+ self.attrs = attrs
+
+ def rgetattr(self, attrs):
+ return functools.reduce(getattr, attrs, self.top)
+
+ def __getattr__(self, name):
+ attr = self.rgetattr(self.attrs + [name])
+ return self.__class__(self.top, self.attrs + [name])
+
+ def __call__(self, *args, **kwargs):
+ f = self.rgetattr(self.attrs)
+ if not callable(f):
+ raise TypeError("not callable: %s of %s" % (self.attrs, self.top))
+ result = f(*args, **kwargs)
+ parents = [(self.rgetattr(self.attrs[:i]), self.attrs[i])
+ for i in range(len(self.attrs))]
+ return functools.reduce(
+ lambda v, p: p[0]._replace(**{p[1]: v}),
+ reversed(parents[:-1]), result)
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/reprotest.git
More information about the Reproducible-commits
mailing list