Skip to content

Commit edc3000

Browse files
committed
Fix #73 - Infinite recursion in validate()
1 parent 7e3e3ff commit edc3000

3 files changed

Lines changed: 35 additions & 9 deletions

File tree

pipeline/src/base.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,21 @@ def validate(self, ignore=None):
161161
162162
Returns a dict containing information about any validation failures.
163163
"""
164+
return self._validate(ignore=ignore)
165+
166+
def _validate(self, ignore=None, seen=None):
167+
# this is implemented as an internal method so that the
168+
# "seen" set, needed to avoid possible infinite recursion,
169+
# can be hidden from the public interface.
170+
if seen is None:
171+
seen = set()
164172
failures = defaultdict(list)
165173
for property in self.properties:
166174
value = getattr(self, property.name, None)
167-
for key, values in property.validate(value, ignore=ignore).items():
168-
failures[key] += values
175+
if id(value) not in seen:
176+
seen.add(id(value))
177+
for key, values in property.validate(value, ignore=ignore, seen=seen).items():
178+
failures[key] += values
169179
return failures
170180

171181
@property

pipeline/src/properties.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,16 @@ def types(self):
100100
def is_link(self) -> bool:
101101
return issubclass(self.types[0], Node)
102102

103-
def validate(self, value, ignore=None):
103+
def validate(self, value, ignore=None, seen=None):
104104
"""
105105
Check whether `value` satisfies all constraints.
106106
107107
Arguments:
108108
value: the value to be checked
109109
ignore: an optional list of check types that should be ignored
110110
("required", "type", "multiplicity")
111+
seen: for internal use: contains a set with Python object ids that have
112+
already been encountered in the validation tree.
111113
112114
Returns a dict containing information about any validation failures.
113115
"""
@@ -131,11 +133,10 @@ def validate(self, value, ignore=None):
131133
else:
132134
item_type = f"value contains {type(item)}"
133135
failures["type"].append(
134-
f"{self.name}: Expected {', '.join(t.__name__ for t in self.types)}, " +
135-
item_type
136+
f"{self.name}: Expected {', '.join(t.__name__ for t in self.types)}, " + item_type
136137
)
137138
elif isinstance(item, (Node, IRI)):
138-
failures.update(item.validate(ignore=ignore))
139+
failures.update(item._validate(ignore=ignore, seen=seen))
139140
if self.min_items:
140141
if len(value) < self.min_items and "multiplicity" not in ignore:
141142
failures["multiplicity"].append(
@@ -167,11 +168,10 @@ def validate(self, value, ignore=None):
167168
else:
168169
value_type = f"value contains {type(value)}"
169170
failures["type"].append(
170-
f"{self.name}: Expected {', '.join(t.__name__ for t in self.types)}, " +
171-
value_type
171+
f"{self.name}: Expected {', '.join(t.__name__ for t in self.types)}, " + value_type
172172
)
173173
elif isinstance(value, (Node, IRI)):
174-
failures.update(value.validate(ignore=ignore))
174+
failures.update(value._validate(ignore=ignore, seen=seen))
175175
# todo: check formatting, multiline
176176
return failures
177177

pipeline/tests/test_regressions.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,19 @@ def test_issue0056():
254254
assert failures["multiplicity"] == ['digital_identifier does not accept multiple values, but contains 2']
255255
data = dataset.to_jsonld()
256256
json.dumps(data) # this should not raise an Exception
257+
258+
259+
def test_issue0073():
260+
# https://github.com/openMetadataInitiative/openMINDS_Python/issues/73
261+
# Infinite recursion in validate()
262+
ds1 = omcore.DatasetVersion(
263+
short_name="ds1",
264+
is_alternative_version_of=None
265+
)
266+
ds2 = omcore.DatasetVersion(
267+
short_name="ds2",
268+
is_alternative_version_of=ds1
269+
)
270+
ds1.is_alternative_version_of = ds2
271+
272+
failures = ds1.validate()

0 commit comments

Comments
 (0)