Skip to content

Commit 04571eb

Browse files
Merge pull request #44 from dfxml-working-group/update_testing_and_schema_version
Update testing and schema version
2 parents 5b96f4d + d99ca5b commit 04571eb

File tree

5 files changed

+33
-28
lines changed

5 files changed

+33
-28
lines changed

.github/workflows/continuous-integration.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ jobs:
1515
python-version: [3.8, 3.9]
1616
steps:
1717
- name: Checkout
18-
uses: actions/checkout@v2
18+
uses: actions/checkout@v4
1919

2020
- name: Set up Python ${{ matrix.python-version }}
21-
uses: actions/setup-python@v1
21+
uses: actions/setup-python@v5
2222
with:
2323
python-version: ${{ matrix.python-version }}
2424

dfxml/objects.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def _read_differential_annotations(annodict, element, annoset):
157157
annoset.add(_d[an])
158158
#_logger.debug("annoset, after: %r." % annoset)
159159

160-
def _qsplit(tagname):
160+
def _qsplit(tagname: str) -> typing.Tuple[typing.Optional[str], str]:
161161
"""Requires string input. Returns namespace and local tag name as a pair. I could've sworn this was a basic implementation gimme, but ET.QName ain't it."""
162162
_typecheck(tagname, str)
163163
if tagname[0] == "{":
@@ -2369,7 +2369,7 @@ def compare_to_other(self, other, ignore_original=False) -> typing.Set[str]:
23692369
diffs.add(prop)
23702370
return diffs
23712371

2372-
def populate_from_Element(self, e):
2372+
def populate_from_Element(self, e: ET.Element) -> None:
23732373
global _warned_elements
23742374
_typecheck(e, (ET.Element, ET.ElementTree))
23752375
#_logger.debug("e = %r" % e)
@@ -2412,23 +2412,33 @@ def populate_from_Element(self, e):
24122412
#_logger.debug("getattr(self, %r) = %r" % (ctn, getattr(self, ctn)))
24132413
elif cns not in [dfxml.XMLNS_DFXML, ""]:
24142414
# Put all non-DFXML-namespace elements into the externals list.
2415+
_logger.debug("ce.tag = %r.", ce.tag)
24152416
self.externals.append(ce)
24162417
else:
24172418
if (cns, ctn, VolumeObject) not in _warned_elements:
24182419
_warned_elements.add((cns, ctn, VolumeObject))
24192420
_logger.warning("Unsure what to do with this element in a VolumeObject: %r" % ce)
24202421

2421-
def pop_poststream_elements(self, volume_element):
2422+
def pop_poststream_elements(self, volume_element: ET.Element) -> typing.List[ET.Element]:
24222423
"""
24232424
This function is a utility function for the two whole-object serialization methods, print_dfxml (to string) and to_Element (to ET.Element).
24242425
24252426
This function will mutate the input argument volume_element, removing the 'poststream' elements. volume_element is expected to be the element created by self.to_partial_Element.
24262427
24272428
Returns a list of child elements in DFXML Schema order. List might be empty.
24282429
2429-
This subroutine implements a re-serialization implementation decision: elements in extension namespaces can appear at the beginning or end of the volume XML child list, per the DFXML Schema. All of the externals are put into the beginning of the element in to_partial_Element. Hence, error will be the last child.
2430+
This subroutine implements a re-serialization implementation decision: elements in extension namespaces can appear only at the end of the volume XML child list, per the DFXML Schema. All of the externals are put into the end of the element in to_partial_Element.
24302431
"""
2431-
retval = []
2432+
retval: typing.List[ET.Element] = []
2433+
2434+
# Find all non-DFXML-namespaced elements by working from back of list of child elements, stopping when list is empty, or when a DFXML-namespaced element is encountered.
2435+
while len(volume_element) > 0:
2436+
if _qsplit(volume_element[-1].tag)[0] in [None, dfxml.XMLNS_DFXML, ""]:
2437+
break
2438+
else:
2439+
# (ET.Element does not have pop().)
2440+
retval.insert(0, volume_element[-1])
2441+
del(volume_element[-1])
24322442

24332443
errorel = None
24342444
if not (self.error is None or self.error == ""):
@@ -2438,12 +2448,8 @@ def pop_poststream_elements(self, volume_element):
24382448
# (ET.Element does not have pop().)
24392449
errorel = volume_element[-1]
24402450
del(volume_element[-1])
2441-
else:
2442-
# This branch of code should only be reached in unit testing, as it depends on the output of self.to_partial_Element.
2443-
if volume_element.find("error"):
2444-
raise ValueError("Inconsistent serialization state: Partial volume XML element has an immediate child named 'error', but not as the last child as expected from the schema.")
24452451
if not errorel is None:
2446-
retval.append(errorel)
2452+
retval.insert(0, errorel)
24472453

24482454
return retval
24492455

@@ -2494,7 +2500,7 @@ def print_dfxml(self, output_fh=sys.stdout):
24942500

24952501
output_fh.write("\n")
24962502

2497-
def to_Element(self):
2503+
def to_Element(self) -> ET.Element:
24982504
outel = self.to_partial_Element()
24992505

25002506
poststream_elements = self.pop_poststream_elements(outel)
@@ -2515,7 +2521,7 @@ def to_Element(self):
25152521

25162522
return outel
25172523

2518-
def to_partial_Element(self):
2524+
def to_partial_Element(self) -> ET.Element:
25192525
"""Returns the volume element with its properties, except for the child fileobjects. Properties are appended in DFXML schema order."""
25202526
outel = ET.Element("volume")
25212527

@@ -2530,13 +2536,10 @@ def to_partial_Element(self):
25302536
if len(annos_whittle_set) > 0:
25312537
_logger.warning("Failed to export some differential annotations: %r." % annos_whittle_set)
25322538

2533-
for e in self.externals:
2534-
outel.append(e)
2535-
25362539
if self.byte_runs:
25372540
outel.append(self.byte_runs.to_Element())
25382541

2539-
def _append_el(prop, value):
2542+
def _append_el(prop: str, value: typing.Any) -> None:
25402543
tmpel = ET.Element(prop)
25412544
_keep = False
25422545
if not value is None:
@@ -2549,7 +2552,7 @@ def _append_el(prop, value):
25492552
if _keep:
25502553
outel.append(tmpel)
25512554

2552-
def _append_str(prop):
2555+
def _append_str(prop: str) -> None:
25532556
value = getattr(self, prop)
25542557
_append_el(prop, value)
25552558

@@ -2589,9 +2592,11 @@ def _append_bool(prop):
25892592
outel.append(tmpel)
25902593

25912594
# Output the error property (which will be popped and re-appended after the file list in to_Element).
2592-
# The error should come last because of the two spots extended elements can be placed; this is to simplify the file-listing VolumeObject.to_Element() method.
25932595
_append_str("error")
25942596

2597+
for e in self.externals:
2598+
outel.append(e)
2599+
25952600
if len(diffs_whittle_set) > 0:
25962601
_logger.warning("Did not annotate all of the differing properties of this volume. Remaining properties: %r." % diffs_whittle_set)
25972602

@@ -2649,12 +2654,12 @@ def error(self, val):
26492654
self._error = _strcast(val)
26502655

26512656
@property
2652-
def externals(self):
2657+
def externals(self) -> OtherNSElementList:
26532658
"""(This property behaves the same as FileObject.externals.)"""
26542659
return self._externals
26552660

26562661
@externals.setter
2657-
def externals(self, val):
2662+
def externals(self, val: OtherNSElementList) -> None:
26582663
_typecheck(val, OtherNSElementList)
26592664
self._externals = val
26602665

@@ -3427,7 +3432,7 @@ def populate_from_Element(self, e):
34273432
getattr(self, ctn).populate_from_Element(ce)
34283433
elif ctn in FileObject._class_properties:
34293434
setattr(self, ctn, ce.text)
3430-
elif cns not in [dfxml.XMLNS_DFXML, ""]:
3435+
elif cns not in [None, dfxml.XMLNS_DFXML, ""]:
34313436
# Put all non-DFXML-namespace elements into the externals list.
34323437
self.externals.append(ce)
34333438
else:

tests/Makefile

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ all: \
3131
all-make_differential_dfxml \
3232
all-walk_to_dfxml \
3333
check-mypy \
34-
check-mypy-strict
34+
check-mypy-stricter
3535

3636
all-make_differential_dfxml: \
3737
.venv.done.log
@@ -75,7 +75,7 @@ check: \
7575

7676
#TODO - Type-checking would best be done against all of ../dfxml, when someone finds some time to do so.
7777
check-mypy: \
78-
check-mypy-strict
78+
check-mypy-stricter
7979
source venv/bin/activate \
8080
&& mypy \
8181
../dfxml/bin/idifference.py \
@@ -88,11 +88,10 @@ check-mypy: \
8888
@echo "INFO:tests/Makefile:mypy is currently run against a subset of the dfxml directory." >&2
8989

9090
#TODO - Strict type-checking is another long-term goal, likewise eventually done against all of ../dfxml.
91-
check-mypy-strict: \
91+
check-mypy-stricter: \
9292
.venv.done.log
9393
source venv/bin/activate \
9494
&& mypy \
95-
--strict \
9695
../demos/demo_fiwalk_diskimage.py \
9796
../dfxml/bin/idifference2.py \
9897
../dfxml/bin/make_differential_dfxml.py \

tests/misc_object_tests/VolumeObject_externals_test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ def test_externals():
100100
assert len(vor.externals) == 3
101101

102102
def test_prefixed_externals_round_trip():
103+
_logger = logging.getLogger(os.path.basename(__file__))
103104
dobj = Objects.DFXMLObject(version="1.2.0")
104105
vobj = Objects.VolumeObject()
105106
dobj.append(vobj)

0 commit comments

Comments
 (0)