Skip to content

Commit

Permalink
Fix TypeError when parsing certain files, closes #100
Browse files Browse the repository at this point in the history
This was a regression introduced by 099192c
when I moved away from generic exceptions. It happened with media files
containing tracks of Type "Other", resulting in attributes such as
"Other_Format_List" in the general track.

We fix this by listing all repeated attributes instead of relying on
them starting with "other_".
  • Loading branch information
sbraz committed Nov 23, 2020
1 parent 88775db commit 646ed4c
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 14 deletions.
22 changes: 13 additions & 9 deletions pymediainfo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,34 +65,38 @@ def __setstate__(self, state): # type: ignore

def __init__(self, xml_dom_fragment: ET.Element):
self.track_type = xml_dom_fragment.attrib["type"]
repeated_attributes = []
for elem in xml_dom_fragment:
node_name = elem.tag.lower().strip().strip("_")
if node_name == "id":
node_name = "track_id"
node_value = elem.text
other_node_name = "other_%s" % node_name
if getattr(self, node_name) is None:
setattr(self, node_name, node_value)
else:
other_node_name = f"other_{node_name}"
repeated_attributes.append((node_name, other_node_name))
if getattr(self, other_node_name) is None:
setattr(self, other_node_name, [node_value])
else:
getattr(self, other_node_name).append(node_value)

for other in [d for d in self.__dict__.keys() if d.startswith("other_")]:
for primary_key, other_key in repeated_attributes:
try:
primary = other.replace("other_", "")
# Attempt to convert the main value to int
setattr(self, primary, int(getattr(self, primary)))
# Usually, if an attribute is repeated, one of its value
# is an int and others are human-readable formats
setattr(self, primary_key, int(getattr(self, primary_key)))
except ValueError:
# If it fails, try to set the main value to an int taken from other values
for value in getattr(self, other):
# If it fails, try to find a secondary value
# that is an int and swap it with the main value
for other_value in getattr(self, other_key):
try:
current = getattr(self, primary)
current = getattr(self, primary_key)
# Set the main value to an int
setattr(self, primary, int(value))
setattr(self, primary_key, int(other_value))
# Append its previous value to other values
getattr(self, other).append(current)
getattr(self, other_key).append(current)
break
except ValueError:
pass
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def get_tag(self):
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Operating System :: POSIX :: Linux",
Expand Down
25 changes: 25 additions & 0 deletions tests/data/issue100.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<Mediainfo version="20.09">
<File>
<track type="General">
<Count>331</Count>
<Count_of_stream_of_this_kind>1</Count_of_stream_of_this_kind>
<Kind_of_stream>General</Kind_of_stream>
<Kind_of_stream>General</Kind_of_stream>
<Stream_identifier>0</Stream_identifier>
<Count_of_video_streams>1</Count_of_video_streams>
<Count_of_audio_streams>1</Count_of_audio_streams>
<OtherCount>2</OtherCount>
<Video_Format_List>AVC</Video_Format_List>
<Video_Format_WithHint_List>AVC</Video_Format_WithHint_List>
<Codecs_Video>AVC</Codecs_Video>
<Audio_Format_List>AAC LC</Audio_Format_List>
<Audio_Format_WithHint_List>AAC LC</Audio_Format_WithHint_List>
<Audio_codecs>AAC LC</Audio_codecs>
<Other_Format_List>RTP / RTP</Other_Format_List>
<Other_Format_WithHint_List>RTP / RTP</Other_Format_WithHint_List>
<Other_Codec_List>RTP / RTP</Other_Codec_List>
<Other_Language_List>English / English</Other_Language_List>
</track>
</File>
</Mediainfo>
20 changes: 15 additions & 5 deletions tests/test_pymediainfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,21 @@ def test_track_integer_attributes(self):
break

def test_track_other_attributes(self):
for track in self.media_info.tracks:
if track.track_type == "General":
self.assertEqual(5, len(track.other_file_size))
self.assertEqual(4, len(track.other_duration))
break
general_tracks = [
track for track in self.media_info.tracks if track.track_type == "General"
]
general_track = general_tracks[0]
self.assertEqual(5, len(general_track.other_file_size))
self.assertEqual(
["1mn 1s", "1mn 1s 394ms", "1mn 1s", "00:01:01.394"], general_track.other_duration
)

def test_track_existing_other_attributes(self):
with open(os.path.join(data_dir, "issue100.xml")) as f:
media_info = MediaInfo(f.read())
general_tracks = [track for track in media_info.tracks if track.track_type == "General"]
general_track = general_tracks[0]
self.assertEqual(general_track.other_format_list, "RTP / RTP")

def test_load_mediainfo_from_string(self):
self.assertEqual(4, len(self.media_info.tracks))
Expand Down

0 comments on commit 646ed4c

Please sign in to comment.