Skip to content

Commit

Permalink
Merge pull request #47 from NNPDF/production_rule_bug
Browse files Browse the repository at this point in the history
Force fuzzyspec expansion to always resolve the ns
  • Loading branch information
Zaharid authored May 12, 2021
2 parents 7bb63b7 + e6482da commit c009824
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 56 deletions.
21 changes: 13 additions & 8 deletions src/reportengine/namespaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ def expand_fuzzyspec_partial(ns, fuzzyspec, currspec=None):
results = []
#ns = ChainMap(d)
key, remainder = fuzzyspec[0], fuzzyspec[1:]
if not key in ns:
yield key, currspec, ns
yield key, currspec, ns
val = ns[key]

if isinstance(val, Mapping):

cs_ = (*currspec, key)
Expand Down Expand Up @@ -129,12 +129,17 @@ def expand_fuzzyspec(ns, fuzzyspec, currspec=None):
"""Return all the nsspecs that spawn from the fuzzyspec.
Raise ElementNotFound if some part is missing."""
gen = expand_fuzzyspec_partial(ns, fuzzyspec, currspec)
try:
missing, nsspec, _ = gen.send(None)
except StopIteration as e:
return e.value
raise ElementNotFound("Could not resolve a fuzzyspec. "
"A key is missing: %s, at the level %r." % (missing, nsspec))
while True:
try:
key, nsspec, currns = gen.send(None)
except StopIteration as e:
return e.value
else:
if key not in currns:
raise ElementNotFound(
"Could not resolve a fuzzyspec. "
f"A key is missing: '{key}', at the level {nsspec}."
)


def collect_fuzzyspec(ns, key, fuzzyspec, currspec=None):
Expand Down
7 changes: 6 additions & 1 deletion src/reportengine/resourcebuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,11 +402,16 @@ def _process_requirement(self, name, nsspec, *, extraargs=None,

log.debug("Processing requirement: %s" % (name,))


ns = namespaces.resolve(self.rootns, nsspec)
if extraargs is None:
extraargs = ()


is_provider = self.is_provider_func(name)
if ( is_provider and isinstance(self.get_provider_func(name), collect)):
log.debug("Resolving collect node for %s", name)
yield from self._make_node(name, nsspec, extraargs, parents)
return
#First try to find the name in the namespace
try:
put_index, val = self.input_parser.resolve_key(name, ns, parents=parents, currspec=nsspec)
Expand Down
43 changes: 43 additions & 0 deletions src/reportengine/tests/test_complexinput.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,12 @@ def produce_matched_datasets_from_dataspecs(self, dataspecs):
res.sort(key=lambda x: (x['dataset_name']))
return res

def produce_dependent_namespace(self, pdf):
return {"pdfprop": pdf}

def produce_derived_prop(self, pdfprop):
return f"Derived: {pdfprop}"


@make_argcheck
def bad_check(pdf):
Expand All @@ -193,8 +199,15 @@ def report(self, template_text):
def plot_a_pdf(self, pdf):
return "PLOT OF " + str(pdf)

def prop_table(self, pdfprop):
return f"Table: {pdfprop}"

dataspecs_speclabel = collect('speclabel', ('datasepcs',),
element_default='label')

props_collection = collect("prop_table", ("dependent_namespace",))
resolved_collection = collect("derived_prop", ("dependent_namespace",))

@bad_check
def bad_plot(self, pdf):
return self.plot_a_pdf(pdf)
Expand Down Expand Up @@ -399,5 +412,35 @@ def test_namespace_production(self):
(('matched_datasets_from_dataspecs', 0), ('dataspecs', 1),))['dataset']
assert ds1 != ds2

def test_dependent_rules(self):
c = Config({"pdf": "a", "Ns": {"pdf": "b"}})
targets = [
FuzzyTarget("props_collection", (), (), ()),
FuzzyTarget("props_collection", ("Ns",), (), ()),
]
builder = resourcebuilder.ResourceBuilder(c, Providers(), targets)
builder.resolve_fuzzytargets()
builder.execute_sequential()
res1 = namespaces.resolve(builder.rootns, ())["props_collection"]
res2 = namespaces.resolve(builder.rootns, ('Ns',))["props_collection"]
assert res1 == ['Table: PDF: a']
assert res2 == ['Table: PDF: b']

def test_dependent_resolved(self):
c = Config({"pdf": "a", "Ns": {"pdf": "b"}})
targets = [
FuzzyTarget("resolved_collection", (), (), ()),
FuzzyTarget("resolved_collection", ("Ns",), (), ()),
]
builder = resourcebuilder.ResourceBuilder(c, Providers(), targets)
builder.resolve_fuzzytargets()
builder.execute_sequential()
res1 = namespaces.resolve(builder.rootns, ())["resolved_collection"]
res2 = namespaces.resolve(builder.rootns, ('Ns',))["resolved_collection"]
assert res1 == ['Derived: PDF: a']
assert res2 == ['Derived: PDF: b']



if __name__ == '__main__':
unittest.main()
63 changes: 16 additions & 47 deletions src/reportengine/tests/test_namespaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,52 +52,26 @@ def test_resolve(self):
def test_expand(self):
fuzzy = ('a', 'c')
ns = ChainMap(self.d)
gen = namespaces.expand_fuzzyspec_partial(ns, fuzzy)
#self.assertFalse(list(gen))
while True:
try:
next(gen)
except StopIteration as e:
self.assertEqual(e.value, [('a', ('c', 0)), ('a', ('c', 1))])
break
else:
self.fail()

fuzzy = ('a', 'x', 'c')
ns = ChainMap(self.d)
gen = namespaces.expand_fuzzyspec_partial(ns, fuzzy)
#self.assertFalse(list(gen))
var, spec, cns = next(gen)
cns[var] = 'not ok'
with self.assertRaises(TypeError):
next(gen)

fuzzy = ('a', 'xx', 'c')
ns = ChainMap(self.d)
gen = namespaces.expand_fuzzyspec_partial(ns, fuzzy)
#self.assertFalse(list(gen))
var, spec, cns = next(gen)
cns[var] = [{'ok': True}, {'ok':'yes'}, {'ok':1}]
with self.assertRaises(StopIteration) as ec:
next(gen)
specs = ec.exception.value
self.assertEqual(set(specs),
set(itertools.product('a', [('xx', 0), ('xx', 1,), ('xx', 2)],
[('c', 0), ('c', 1)]))
)
assert namespaces.expand_fuzzyspec(ns, fuzzy) == [
('a', ('c', 0)),
('a', ('c', 1)),
]


def test_nested_expand(self):
d = self.d
d['c'][0]['l3'] = [{'x':1},{'x':2}]
d['c'][1]['l3'] = [{'x':1},]
d['c'][0]['l3'] = [{'x': 1}, {'x': 2}]
d['c'][1]['l3'] = [
{'x': 1},
]
ns = ChainMap(d)
fuzzy = ('c', 'l3')
gen = namespaces.expand_fuzzyspec_partial(ns, fuzzy)
with self.assertRaises(StopIteration) as ec:
next(gen)
self.assertEqual(ec.exception.value,
[(('c', 0), ('l3', 0)), (('c', 0), ('l3', 1)), (('c', 1), ('l3', 0))]
)
res = namespaces.expand_fuzzyspec(ns, fuzzy)
assert res == [
(('c', 0), ('l3', 0)),
(('c', 0), ('l3', 1)),
(('c', 1), ('l3', 0)),
]

def test_identities(self):
a = {1:'a'}
Expand All @@ -118,12 +92,7 @@ def test_expand_identities(self):
l1cp = copy.deepcopy(l1)
d = {'root': root, 'l1':l1, 'l2':l2}

try:
next(namespaces.expand_fuzzyspec_partial(d, ('root', 'l1', 'l2')))
except StopIteration as e:
specs = e.value
else:
raise RuntimeError()
specs = namespaces.expand_fuzzyspec(d, ('root', 'l1', 'l2'))


self.assertEqual(len(specs), 3*3)
Expand Down

0 comments on commit c009824

Please sign in to comment.