Skip to content

Commit

Permalink
Merge branch 'development' into feature/docs_and_annotation
Browse files Browse the repository at this point in the history
# Conflicts:
#	ebmlite/core.py
#	ebmlite/util.py
  • Loading branch information
logicalzero committed Nov 2, 2023
2 parents 164990b + 64f9e07 commit 19211b1
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 52 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:

steps:

- uses: actions/setup-python@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- run: python -m pip install --upgrade pip
Expand Down
20 changes: 7 additions & 13 deletions ebmlite/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,14 +603,8 @@ def _isValidChild(cls, elId: int) -> bool:
if not cls.children:
return False

if cls._childIds:
return elId in cls._childIds
else:
# The set of valid child IDs hasn't been created yet.
cls._childIds = set(cls.children)
if cls.schema is not None:
cls._childIds.update(cls.schema.globals)
return elId in cls._childIds
return elId in cls.children or elId in cls.schema.globals


@property
def size(self) -> int:
Expand Down Expand Up @@ -1124,7 +1118,7 @@ def __init__(self,
self.elementInfo = {} # Raw element schema attributes, keyed by ID

self.globals = {} # Elements valid for any parent, by ID
self.children = {} # Valid root elements, by ID
self.children = set() # Valid root elements, by ID

# Parse, using the correct method for the schema format.
schema = ET.parse(source)
Expand Down Expand Up @@ -1215,7 +1209,7 @@ def _parseSchema(self, el, parent=None):
for chEl in el:
self._parseSchema(chEl, cls)

def addElement(self,
def addElement(self,
eid: int,
ename: str,
baseClass,
Expand Down Expand Up @@ -1320,7 +1314,7 @@ def _getInt(d, k, default):
{'id': eid, 'name': ename, 'schema': self,
'mandatory': mandatory, 'multiple': multiple,
'precache': precache, 'length': length,
'children': dict(), '__doc__': docs,
'children': set(), '__doc__': docs,
'__slots__': baseClass.__slots__})

self.elements[eid] = eclass
Expand All @@ -1332,8 +1326,8 @@ def _getInt(d, k, default):

parent = parent or self
if parent.children is None:
parent.children = {}
parent.children[eid] = eclass
parent.children = set()
parent.children.add(eid)

return eclass

Expand Down
29 changes: 28 additions & 1 deletion ebmlite/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
__credits__ = "David Randall Stokes, Connor Flanigan, Becker Awqatty, Derek Witt"

__all__ = ['createID', 'validateID', 'toXml', 'xml2ebml', 'loadXml', 'pprint',
'printSchemata']
'printSchemata', 'flatiter']

import ast
from io import BytesIO
Expand Down Expand Up @@ -505,3 +505,30 @@ def printSchemata(paths: Optional[List[str]] = None,
finally:
if newfile:
out.close()


#===============================================================================
#
#===============================================================================


def flatiter(element, depth=None):
""" Recursively crawl an EBML document or element, depth-first,
yielding all elements (or elements down to a given depth).
:param element: The EBML `Document` or `Element` to iterate.
:param depth: The maximum recursion depth. `None` or a value less
than zero will fully recurse without limit.
"""
depth = -1 if depth is None else depth

def _flatiter(el, d, first):
if not first:
yield el
if abs(d) > 0 and isinstance(el, core.MasterElement):
for ch in el:
for grandchild in _flatiter(ch, d-1, False):
yield grandchild

for child in _flatiter(element, depth, True):
yield child
53 changes: 16 additions & 37 deletions tests/test_general.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
@author: dstokes
"""

from itertools import zip_longest
import os.path
import unittest
from xml.dom.minidom import parseString
Expand Down Expand Up @@ -66,18 +67,11 @@ def testMkv(self):
xmlDoc2 = util.loadXml(xmlFile2, schema)

# Compare each element from the XML
xmlEls1 = [xmlDoc1]
xmlEls2 = [xmlDoc2]
while len(xmlEls1) > 0:
self.assertEqual(xmlEls1[0], xmlEls2[0], 'Element '
+ repr(xmlEls1[0])
+ ' was not converted properly')
for x in list(xmlEls1.pop(0).children.values()):
if issubclass(x, core.Element):
xmlEls1.append(x)
for x in list(xmlEls2.pop(0).children.values()):
if issubclass(x, core.Element):
xmlEls2.append(x)
for el1, el2 in zip_longest(util.flatiter(xmlDoc1),
util.flatiter(xmlDoc2),
fillvalue=None):
self.assertEqual(el1, el2,
'Element {!r} was not converted properly'.format(el1))


def testIde(self):
Expand Down Expand Up @@ -121,19 +115,11 @@ def testIde(self):
xmlDoc2 = util.loadXml(xmlFile2, schema)

# Compare each element from the XML
xmlEls1 = [xmlDoc1]
xmlEls2 = [xmlDoc2]
while len(xmlEls1) > 0:
self.assertEqual(xmlEls1[0], xmlEls2[0], 'Element '
+ repr(xmlEls1[0])
+ ' was not converted properly')
for x in list(xmlEls1.pop(0).children.values()):
if issubclass(x, core.Element):
xmlEls1.append(x)
for x in list(xmlEls2.pop(0).children.values()):
if issubclass(x, core.Element):
xmlEls2.append(x)

for el1, el2 in zip_longest(util.flatiter(xmlDoc1),
util.flatiter(xmlDoc2),
fillvalue=None):
self.assertEqual(el1, el2,
'Element {!r} was not converted properly'.format(el1))


def testPPrint(self):
Expand Down Expand Up @@ -298,18 +284,11 @@ def testMkv(self):
xmlDoc2 = util.loadXml(xmlFile2, schema)

# Compare each element from the XML
xmlEls1 = [xmlDoc1]
xmlEls2 = [xmlDoc2]
while len(xmlEls1) > 0:
self.assertEqual(xmlEls1[0], xmlEls2[0], 'Element '
+ repr(xmlEls1[0])
+ ' was not converted properly')
for x in list(xmlEls1.pop(0).children.values()):
if issubclass(x, core.Element):
xmlEls1.append(x)
for x in list(xmlEls2.pop(0).children.values()):
if issubclass(x, core.Element):
xmlEls2.append(x)
for el1, el2 in zip_longest(util.flatiter(xmlDoc1),
util.flatiter(xmlDoc2),
fillvalue=None):
self.assertEqual(el1, el2,
'Element {!r} was not converted properly'.format(el1))


if __name__ == "__main__":
Expand Down
28 changes: 28 additions & 0 deletions tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@

@pytest.mark.script_launch_mode('subprocess')
def test_ebml2xml(script_runner):

# This test can only run if the library has been installed,
# e.g., in a GitHub action. Bail if not.
# TODO: This is a hack and should be redone.
if os.getenv("GITHUB_ACTIONS") != "true":
return

path_base = os.path.join(".", "tests", "video-4{ext}")
path_in = path_base.format(ext=".ebml")
path_out = path_base.format(ext=".ebml.xml")
Expand Down Expand Up @@ -56,6 +63,13 @@ def assert_elements_are_equiv(e1, e2):

@pytest.mark.script_launch_mode('subprocess')
def test_xml2ebml(script_runner):

# This test can only run if the library has been installed,
# e.g., in a GitHub action. Bail if not.
# TODO: This is a hack and should be redone.
if os.getenv("GITHUB_ACTIONS") != "true":
return

path_base = os.path.join(".", "tests", "video-4{ext}")
path_in = path_base.format(ext=".xml")
path_out = path_base.format(ext=".xml.ebml")
Expand Down Expand Up @@ -84,6 +98,13 @@ def test_xml2ebml(script_runner):

@pytest.mark.script_launch_mode('subprocess')
def test_view(script_runner):

# This test can only run if the library has been installed,
# e.g., in a GitHub action. Bail if not.
# TODO: This is a hack and should be redone.
if os.getenv("GITHUB_ACTIONS") != "true":
return

path_base = os.path.join(".", "tests", "video-4{ext}")
path_in = path_base.format(ext=".ebml")
path_out = path_base.format(ext=".xml.txt")
Expand Down Expand Up @@ -112,6 +133,13 @@ def test_view(script_runner):

@pytest.mark.script_launch_mode('subprocess')
def test_list_schemata(script_runner):

# This test can only run if the library has been installed,
# e.g., in a GitHub action. Bail if not.
# TODO: This is a hack and should be redone.
if os.getenv("GITHUB_ACTIONS") != "true":
return

core.SCHEMA_PATH = [os.path.dirname(schemata.__file__)]
path_out = os.path.join(".", "tests", "list-schemata.txt")

Expand Down

0 comments on commit 19211b1

Please sign in to comment.