diff options
-rw-r--r-- | bsfs/graph/resolve.py | 10 | ||||
-rw-r--r-- | bsfs/query/validator.py | 31 | ||||
-rw-r--r-- | bsfs/schema/types.py | 16 | ||||
-rw-r--r-- | bsfs/triple_store/sparql/parse_filter.py | 15 | ||||
-rw-r--r-- | test/schema/test_types.py | 33 |
5 files changed, 52 insertions, 53 deletions
diff --git a/bsfs/graph/resolve.py b/bsfs/graph/resolve.py index 9b5f631..b671204 100644 --- a/bsfs/graph/resolve.py +++ b/bsfs/graph/resolve.py @@ -96,11 +96,11 @@ class Filter(): # parse child expression subrng = self._parse_predicate_expression(pred) # determine the next type - try: - if rng is None or subrng > rng: # pick most generic range - rng = subrng - except TypeError as err: - raise errors.ConsistencyError(f'ranges {subrng} and {rng} are not related') from err + if rng is None or subrng > rng: # pick most generic range + rng = subrng + # check range consistency + if not subrng <= rng and not subrng >= rng: + raise errors.ConsistencyError(f'ranges {subrng} and {rng} are not related') if not isinstance(rng, (bsc.Node, bsc.Literal)): raise errors.BackendError(f'the range of node {node} is undefined') return rng diff --git a/bsfs/query/validator.py b/bsfs/query/validator.py index 75b51ca..ecea951 100644 --- a/bsfs/query/validator.py +++ b/bsfs/query/validator.py @@ -113,25 +113,18 @@ class Filter(): for pred in node: # parse child expression subdom, subrng = self._parse_predicate_expression(pred) - try: - # determine overall domain - if dom is None or subdom < dom: # pick most specific domain - dom = subdom - # domains must be related across all child expressions - if not subdom <= dom and not subdom >= dom: - raise errors.ConsistencyError(f'domains {subdom} and {dom} are not related') - except TypeError as err: # compared literal vs. node - raise errors.ConsistencyError(f'domains {subdom} and {dom} are not of the same type') from err - - try: - # determine overall range - if rng is None or subrng > rng: # pick most generic range - rng = subrng - # ranges must be related across all child expressions - if not subrng <= rng and not subrng >= rng: - raise errors.ConsistencyError(f'ranges {subrng} and {rng} are not related') - except TypeError as err: # compared literal vs. node - raise errors.ConsistencyError(f'ranges {subrng} and {rng} are not of the same type') from err + # determine overall domain + if dom is None or subdom < dom: # pick most specific domain + dom = subdom + # domains must be related across all child expressions + if not subdom <= dom and not subdom >= dom: + raise errors.ConsistencyError(f'domains {subdom} and {dom} are not related') + # determine overall range + if rng is None or subrng > rng: # pick most generic range + rng = subrng + # ranges must be related across all child expressions + if not subrng <= rng and not subrng >= rng: + raise errors.ConsistencyError(f'ranges {subrng} and {rng} are not related') # OneOf guarantees at least one expression, dom and rng are always bsc.Vertex. # mypy does not realize this, hence we ignore the warning. return dom, rng # type: ignore [return-value] diff --git a/bsfs/schema/types.py b/bsfs/schema/types.py index 6257dee..95dc66a 100644 --- a/bsfs/schema/types.py +++ b/bsfs/schema/types.py @@ -150,8 +150,10 @@ class _Type(): def __lt__(self, other: typing.Any) -> bool: """Return True iff *self* is a true subclass of *other*.""" - if not isinstance(other, type(self)): + if not isinstance(other, _Type): return NotImplemented + if not isinstance(other, type(self)): # FIXME: necessary? + return False if self.uri == other.uri: # equivalence return False if self in other.parents(): # superclass @@ -163,8 +165,10 @@ class _Type(): def __le__(self, other: typing.Any) -> bool: """Return True iff *self* is equivalent or a subclass of *other*.""" - if not isinstance(other, type(self)): + if not isinstance(other, _Type): return NotImplemented + if not isinstance(other, type(self)): # FIXME: necessary? + return False if self.uri == other.uri: # equivalence return True if self in other.parents(): # superclass @@ -176,8 +180,10 @@ class _Type(): def __gt__(self, other: typing.Any) -> bool: """Return True iff *self* is a true superclass of *other*.""" - if not isinstance(other, type(self)): + if not isinstance(other, _Type): return NotImplemented + if not isinstance(other, type(self)): # FIXME: necessary? + return False if self.uri == other.uri: # equivalence return False if self in other.parents(): # superclass @@ -189,8 +195,10 @@ class _Type(): def __ge__(self, other: typing.Any) -> bool: """Return True iff *self* is eqiuvalent or a superclass of *other*.""" - if not isinstance(other, type(self)): + if not isinstance(other, _Type): return NotImplemented + if not isinstance(other, type(self)): # FIXME: necessary? + return False if self.uri == other.uri: # equivalence return True if self in other.parents(): # superclass diff --git a/bsfs/triple_store/sparql/parse_filter.py b/bsfs/triple_store/sparql/parse_filter.py index 18a3288..5d8a2d9 100644 --- a/bsfs/triple_store/sparql/parse_filter.py +++ b/bsfs/triple_store/sparql/parse_filter.py @@ -131,15 +131,12 @@ class Filter(): puri, subrng = self._parse_predicate_expression(node_type, pred) # track predicate uris suburi.add(puri) - try: - # check for more generic range - if rng is None or subrng > rng: - rng = subrng - # check range consistency - if not subrng <= rng and not subrng >= rng: - raise errors.ConsistencyError(f'ranges {subrng} and {rng} are not related') - except TypeError as err: # subrng and rng are not comparable - raise errors.ConsistencyError(f'ranges {subrng} and {rng} are not related') from err + # check for more generic range + if rng is None or subrng > rng: + rng = subrng + # check range consistency + if not subrng <= rng and not subrng >= rng: + raise errors.ConsistencyError(f'ranges {subrng} and {rng} are not related') # return joint predicate expression and next range # OneOf guarantees at least one expression, rng is always a bsc.Vertex. # mypy does not realize this, hence we ignore the warning. diff --git a/test/schema/test_types.py b/test/schema/test_types.py index 26da270..1eeafa1 100644 --- a/test/schema/test_types.py +++ b/test/schema/test_types.py @@ -140,30 +140,31 @@ class TestType(unittest.TestCase): self.assertFalse(bike >= bicycle) self.assertFalse(bike == bicycle) - # can compare types along the class hierarchy + # comparing different classes returns False ... + # ... when classes are hierarchically related class Foo(_Type): pass foo = Foo('Foo', bike) - self.assertTrue(foo < bike) - self.assertTrue(foo <= bike) + self.assertFalse(foo < bike) + self.assertFalse(foo <= bike) self.assertFalse(foo > bike) self.assertFalse(foo >= bike) # goes both ways self.assertFalse(bike < foo) self.assertFalse(bike <= foo) - self.assertTrue(bike > foo) - self.assertTrue(bike >= foo) - # cannot compare unrelated classes + self.assertFalse(bike > foo) + self.assertFalse(bike >= foo) + # ... when classes are unrelated class Bar(_Type): pass bar = Bar('Bar', bike) - self.assertRaises(TypeError, operator.lt, foo, bar) - self.assertRaises(TypeError, operator.le, foo, bar) - self.assertRaises(TypeError, operator.gt, foo, bar) - self.assertRaises(TypeError, operator.ge, foo, bar) + self.assertFalse(foo < bar) + self.assertFalse(foo <= bar) + self.assertFalse(foo > bar) + self.assertFalse(foo >= bar) # goes both ways - self.assertRaises(TypeError, operator.lt, bar, foo) - self.assertRaises(TypeError, operator.le, bar, foo) - self.assertRaises(TypeError, operator.gt, bar, foo) - self.assertRaises(TypeError, operator.ge, bar, foo) + self.assertFalse(bar < foo) + self.assertFalse(bar <= foo) + self.assertFalse(bar > foo) + self.assertFalse(bar >= foo) class TestPredicate(unittest.TestCase): @@ -262,7 +263,7 @@ class TestPredicate(unittest.TestCase): # range must be subtype of parent's range self.assertRaises(errors.ConsistencyError, tag.child, ns.bse.foo, range=n_root) self.assertRaises(errors.ConsistencyError, tag.child, ns.bse.foo, range=Node(ns.bsfs.Image, n_root)) - self.assertRaises(TypeError, tag.child, ns.bse.foo, range=Literal(ns.bsfs.Tag, l_root)) + self.assertRaises(errors.ConsistencyError, tag.child, ns.bse.foo, range=Literal(ns.bsfs.Tag, l_root)) # range can be subtyped from ROOT_VERTEX to Node or Literal self.assertEqual(n_root, root.child(ns.bse.foo, range=n_root).range) self.assertEqual(l_root, root.child(ns.bse.foo, range=l_root).range) @@ -370,7 +371,7 @@ class TestFeature(unittest.TestCase): # range must be subtype of parent's range self.assertRaises(errors.ConsistencyError, colors.child, ns.bse.foo, range=Literal(ns.bsfs.Literal, None)) self.assertRaises(errors.ConsistencyError, colors.child, ns.bse.foo, range=Literal(ns.bsfs.foo, Literal(ns.bsfs.Literal, None))) - self.assertRaises(TypeError, colors.child, ns.bse.foo, range=Node(ns.bsfs.Tag, n_root)) + self.assertRaises(errors.ConsistencyError, colors.child, ns.bse.foo, range=Node(ns.bsfs.Tag, n_root)) ## main ## |