diff --git a/lib/Rete/Network.py b/lib/Rete/Network.py index 6dc79c5..7e352e1 100644 --- a/lib/Rete/Network.py +++ b/lib/Rete/Network.py @@ -135,19 +135,6 @@ def __init__(self, items=None, skipBNodes=False): else: self._l = [] - def _hashRulePattern(self, item): - """ - Generates a unique hash for RDF triples and N3 builtin invokations. The - hash function consists of the hash of the terms concatenated in order - """ - if isinstance(item, tuple): - return reduce(lambda x, y: x + y, [ - i for i in item - if not self.skipBNodes or not isinstance(i, BNode) - ]) - elif isinstance(item, N3Builtin): - return reduce(lambda x, y: x + y, [item.argument, item.result]) - def __len__(self): return len(self._l) @@ -155,14 +142,22 @@ def __getslice__(self, beginIdx, endIdx): return HashablePatternList(self._l[beginIdx:endIdx]) def __hash__(self): - if self._l: - _concatPattern = [pattern and self._hashRulePattern(pattern) or "None" for pattern in self._l] - #nulify the impact of order in patterns - _concatPattern.sort() - return hash(reduce(lambda x, y: x + y, _concatPattern)) - else: - return hash(None) - + out = [] + for item in self._l: + if not item: + out.append('None') + elif isinstance(item, tuple): + out.extend([i for i in item + if not self.skipBNodes or not isinstance(i, BNode)]) + elif isinstance(item, N3Builtin): + out.extend([item.argument, item.result]) + else: + raise NotImplementedError("don't know how to hash %r" % item) + + #nulify the impact of order in patterns + out.sort() + return hash(tuple(out)) + def __add__(self, other): assert isinstance(other, HashablePatternList), other return HashablePatternList(self._l + other._l) diff --git a/test/test_network_pattern_list.py b/test/test_network_pattern_list.py new file mode 100644 index 0000000..85bf629 --- /dev/null +++ b/test/test_network_pattern_list.py @@ -0,0 +1,30 @@ +import unittest +import logging +logging.basicConfig(level=logging.DEBUG) + +from FuXi.Rete.Network import HashablePatternList +from rdflib import URIRef, Literal +import rdflib.term + +class TestHashablePatternList(unittest.TestCase): + def setUp(self): + super(TestHashablePatternList, self).setUp() + + self.oldWarning = rdflib.term._LOGGER.warning + def stopOnWarning(msg): + raise ValueError("this warning was logged: %s" % msg) + rdflib.term._LOGGER.warning = stopOnWarning + + def tearDown(self): + super(TestHashablePatternList, self).tearDown() + rdflib.term._LOGGER.warning = self.oldWarning + + def testCombineUriAndLiteral(self): + # This is a simplified version of input that happens in real usage with a rule like this: + # { ?c :p1 ?uri . } => { ?c :p2 (" " ?uri) . } . + hpl = HashablePatternList(items=[(URIRef('http://example.com/'),), + (Literal(' '),)]) + hash(hpl) + +if __name__ == '__main__': + unittest.main()