Skip to content

Commit

Permalink
Add a test for issue #410 and a property to ModelVisitor
Browse files Browse the repository at this point in the history
  • Loading branch information
brunato committed Aug 6, 2024
1 parent 90a7233 commit d5c22d8
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
34 changes: 34 additions & 0 deletions tests/validation/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,40 @@ def test_dynamic_schema_load(self):
self.assertIn("schemaLocation declaration after namespace start",
str(ctx.exception))

def test_issue_410(self):
schema = self.schema_class(dedent("""\
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="muclient">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="include"/>
<xs:choice>
<xs:element name="plugin"/>
<xs:element name="world"/>
<xs:element name="triggers"/>
<xs:element name="aliases"/>
<xs:element name="timers"/>
<xs:element name="macros"/>
<xs:element name="variables"/>
<xs:element name="colours"/>
<xs:element name="keypad"/>
<xs:element name="printing"/>
</xs:choice>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>"""))

xml_data = '<muclient></muclient>'
self.check_validity(schema, xml_data, True)

xml_data = '<muclient><include/></muclient>'
self.check_validity(schema, xml_data, True)

xml_data = '<muclient><world/><include/></muclient>'
self.check_validity(schema, xml_data, True)


class TestValidation11(TestValidation):
schema_class = XMLSchema11
Expand Down
21 changes: 21 additions & 0 deletions xmlschema/validators/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
plus a set of functions for manipulating encoded content.
"""
from collections import defaultdict, deque, Counter
from copy import copy
from operator import attrgetter
from typing import Any, Dict, Iterable, Iterator, List, \
MutableMapping, MutableSequence, Optional, Tuple, Union
Expand Down Expand Up @@ -206,6 +207,16 @@ def __init__(self, root: ModelGroupType) -> None:
def __repr__(self) -> str:
return '%s(root=%r)' % (self.__class__.__name__, self.root)

def __copy__(self) -> 'ModelVisitor':
model: 'ModelVisitor' = object.__new__(self.__class__)

for cls in self.__class__.__mro__:
if hasattr(cls, '__slots__'):
for attr in cls.__slots__:
setattr(model, attr, copy(getattr(self, attr)))

return model

def clear(self) -> None:
del self._groups[:]
self.occurs.clear()
Expand Down Expand Up @@ -240,9 +251,19 @@ def restart(self) -> None:
self._start()

def stop(self) -> Iterator[AdvanceYieldedType]:
"""Stop the model and returns the errors, if any."""
while self.element is not None:
yield from self.advance()

@property
def stoppable(self) -> bool:
"""Returns `True` if the model is stoppable from the current status without errors."""
model = copy(self)
for _ in model.stop():
return False
else:
return True

def iter_group(self) -> Iterator[ModelParticleType]:
"""Returns an iterator for the current model group."""
if self.group.model == 'all':
Expand Down

0 comments on commit d5c22d8

Please sign in to comment.