Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
dict_encoded[key] = escape(value).\
encode('ascii', 'xmlcharrefreplace').decode('ascii')
else:
dict_encoded[key] = value
didl = DIDL_TEMPLATE.format(item_class=class_.item_class,
**dict_encoded)
assert helpers.compare_xml(
item_from_xml.didl_metadata, XML.fromstring(didl)
)
assert helpers.compare_xml(
item_from_dict.didl_metadata, XML.fromstring(didl)
)
else:
with pytest.raises(DIDLMetadataError):
# pylint: disable=pointless-statement
item_from_xml.didl_metadata
# Text attributes with mandatory content
for name in ['item_id', 'extended_id', 'title', 'service_id']:
getter_attributes_test(name, item_from_xml, item_from_dict,
dict_[name])
# Text attributes with voluntary content
for name in ['parent_id', 'album_art_uri']:
getter_attributes_test(name, item_from_xml, item_from_dict,
dict_.get(name))
# Boolean attribute
getter_attributes_test('can_play', item_from_xml, item_from_dict,
bool(dict_.get('can_play')))
return item_from_xml, item_from_dict
def test_didl_object_from_wrong_element(self):
# Using the wrong element
elt = XML.fromstring("""URI""")
with pytest.raises(DIDLMetadataError) as excinfo:
didl_object = data_structures.DidlObject.from_element(elt)
assert "Wrong element. Expected '', got ''" in str(
excinfo.value)
"""
items = []
root = XML.fromstring(string.encode('utf-8'))
for elt in root:
if elt.tag.endswith('item') or elt.tag.endswith('container'):
item_class = elt.findtext(ns_tag('upnp', 'class'))
# In case this class has an # specified unofficial
# subclass, ignore it by stripping it from item_class
if '.#' in item_class:
item_class = item_class[:item_class.find('.#')]
try:
cls = _DIDL_CLASS_TO_CLASS[item_class]
except KeyError:
raise DIDLMetadataError("Unknown UPnP class: %s" % item_class)
item = cls.from_element(elt)
item = attempt_datastructure_upgrade(item)
items.append(item)
else:
#
def to_element(self):
"""Return an ElementTree Element based on this resource.
Returns:
~xml.etree.ElementTree.Element: an Element.
"""
if not self.protocol_info:
raise DIDLMetadataError('Could not create Element for this'
'resource:'
'protocolInfo not set (required).')
root = XML.Element('res')
# Required
root.attrib['protocolInfo'] = self.protocol_info
# Optional
if self.import_uri is not None:
root.attrib['importUri'] = self.import_uri
if self.size is not None:
root.attrib['size'] = str(self.size)
if self.duration is not None:
root.attrib['duration'] = self.duration
if self.bitrate is not None:
root.attrib['bitrate'] = str(self.bitrate)
if self.sample_frequency is not None:
item_class = item_class[:item_class.find('.#')]
if item_class != cls.item_class:
raise DIDLMetadataError(
"UPnP class is incorrect. Expected '{0}',"
" got '{1}'".format(cls.item_class, item_class))
# parent_id, item_id and restricted are stored as attributes on the
# element
item_id = element.get('id', None)
if item_id is None:
raise DIDLMetadataError("Missing id attribute")
item_id = really_unicode(item_id)
parent_id = element.get('parentID', None)
if parent_id is None:
raise DIDLMetadataError("Missing parentID attribute")
parent_id = really_unicode(parent_id)
# CAUTION: This implementation deviates from the spec.
# Elements are normally required to have a `restricted` tag, but
# Spotify Direct violates this. To make it work, a missing restricted
# tag is interpreted as `restricted = True`.
restricted = element.get('restricted', None)
restricted = (restricted not in [0, 'false', 'False'])
# Similarily, all elements should have a title tag, but Spotify Direct
# does not comply
title_elt = element.find(ns_tag('dc', 'title'))
if title_elt is None or not title_elt.text:
title = ''
else:
title = really_unicode(title_elt.text)
if not self.can_play:
message = 'This item is not meant to be played and therefore '\
'also not to create its own didl_metadata'
raise DIDLMetadataError(message)
# Check if we have the attributes to create the didl metadata:
for key in ['extended_id', 'title', 'item_class']:
if not hasattr(self, key):
message = 'The property \'{}\' is not present on this item. '\
'This indicates that this item was not meant to create '\
'didl_metadata'.format(key)
raise DIDLMetadataError(message)
if 'description' not in self.content:
message = 'The item for \'description\' is not present in '\
'self.content. This indicates that this item was not meant '\
'to create didl_metadata'
raise DIDLMetadataError(message)
# Main element, ugly? yes! but I have given up on using namespaces
# with xml.etree.ElementTree
xml = XML.Element(
'{urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/}DIDL-Lite'
)
# Item sub element
item_attrib = {
'parentID': '',
'restricted': 'true',
'id': self.extended_id
}
# Only add the parent_id if we have it
if self.parent_id:
item_attrib['parentID'] = self.parent_id
item = XML.SubElement(
try:
return int(result)
except ValueError:
raise DIDLMetadataError(
'Could not convert {0} to an integer'.format(name))
else:
return None
# Check for and fix non-spec compliant behavior in the incoming data
element = apply_resource_quirks(element)
content = {}
# required
content['protocol_info'] = element.get('protocolInfo')
if content['protocol_info'] is None:
raise DIDLMetadataError('Could not create Resource from Element: '
'protocolInfo not found (required).')
# Optional
content['import_uri'] = element.get('importUri')
content['size'] = _int_helper('size')
content['duration'] = element.get('duration')
content['bitrate'] = _int_helper('bitrate')
content['sample_frequency'] = _int_helper('sampleFrequency')
content['bits_per_sample'] = _int_helper('bitsPerSample')
content['nr_audio_channels'] = _int_helper('nrAudioChannels')
content['resolution'] = element.get('resolution')
content['color_depth'] = _int_helper('colorDepth')
content['protection'] = element.get('protection')
content['uri'] = element.text
return cls(**content)
def _int_helper(name):
"""Try to convert the name attribute to an int, or None."""
result = element.get(name)
if result is not None:
try:
return int(result)
except ValueError:
raise DIDLMetadataError(
'Could not convert {0} to an integer'.format(name))
else:
return None
tag = element.tag
if not (tag.endswith('item') or tag.endswith('container')):
raise DIDLMetadataError(
"Wrong element. Expected or ,"
" got <{0}> for class {1}'".format(
tag, cls.item_class))
# and that the upnp matches what we are expecting
item_class = element.find(ns_tag('upnp', 'class')).text
# In case this class has an # specified unofficial
# subclass, ignore it by stripping it from item_class
if '.#' in item_class:
item_class = item_class[:item_class.find('.#')]
if item_class != cls.item_class:
raise DIDLMetadataError(
"UPnP class is incorrect. Expected '{0}',"
" got '{1}'".format(cls.item_class, item_class))
# parent_id, item_id and restricted are stored as attributes on the
# element
item_id = element.get('id', None)
if item_id is None:
raise DIDLMetadataError("Missing id attribute")
item_id = really_unicode(item_id)
parent_id = element.get('parentID', None)
if parent_id is None:
raise DIDLMetadataError("Missing parentID attribute")
parent_id = really_unicode(parent_id)
# CAUTION: This implementation deviates from the spec.
# Elements are normally required to have a `restricted` tag, but
# In case this class has an # specified unofficial
# subclass, ignore it by stripping it from item_class
if '.#' in item_class:
item_class = item_class[:item_class.find('.#')]
if item_class != cls.item_class:
raise DIDLMetadataError(
"UPnP class is incorrect. Expected '{0}',"
" got '{1}'".format(cls.item_class, item_class))
# parent_id, item_id and restricted are stored as attributes on the
# element
item_id = element.get('id', None)
if item_id is None:
raise DIDLMetadataError("Missing id attribute")
item_id = really_unicode(item_id)
parent_id = element.get('parentID', None)
if parent_id is None:
raise DIDLMetadataError("Missing parentID attribute")
parent_id = really_unicode(parent_id)
# CAUTION: This implementation deviates from the spec.
# Elements are normally required to have a `restricted` tag, but
# Spotify Direct violates this. To make it work, a missing restricted
# tag is interpreted as `restricted = True`.
restricted = element.get('restricted', None)
restricted = (restricted not in [0, 'false', 'False'])
# Similarily, all elements should have a title tag, but Spotify Direct
# does not comply
title_elt = element.find(ns_tag('dc', 'title'))