# Path: soco/exceptions.py
# class DIDLMetadataError(CannotCreateDIDLMetadata):
# 
#     """Raised if a data container class cannot create the DIDL metadata due to
#     missing information.
# 
#     For backward compatibility, this is currently a subclass of
#     `CannotCreateDIDLMetadata`. In a future version, it will likely become
#     a direct subclass of `SoCoException`.
#     """
# 
# Path: soco/utils.py
# def really_unicode(in_string):
#     """Make a string unicode. Really.
# 
#     Ensure ``in_string`` is returned as unicode through a series of
#     progressively relaxed decodings.
# 
#     Args:
#         in_string (str): The string to convert.
# 
#     Returns:
#         str: Unicode.
# 
#     Raises:
#         ValueError
#     """
#     if isinstance(in_string, bytes):
#         for args in (("utf-8",), ("latin-1",), ("ascii", "replace")):
#             try:
#                 # pylint: disable=star-args
#                 in_string = in_string.decode(*args)
#                 break
#             except UnicodeDecodeError:
#                 continue
#     if not isinstance(in_string, str):
#         raise ValueError("%s is not a string at all." % in_string)
#     return in_string
# 
# def first_cap(string):
#     """Return upper cased first character"""
#     return string[0].upper() + string[1:]


import textwrap
import warnings
from .exceptions import DIDLMetadataError
from .utils import really_unicode, first_cap
from .xml import XML, ns_tag
from .data_structure_quirks import apply_resource_quirks
            from . import data_structures_entry
        if item_class != cls.item_class:
            raise DIDLMetadataError(
                "UPnP class is incorrect. Expected '{}',"
                " got '{}'".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:

# Path: soco/exceptions.py
# class DIDLMetadataError(CannotCreateDIDLMetadata):
# 
#     """Raised if a data container class cannot create the DIDL metadata due to
#     missing information.
# 
#     For backward compatibility, this is currently a subclass of
#     `CannotCreateDIDLMetadata`. In a future version, it will likely become
#     a direct subclass of `SoCoException`.
#     """
# 
# Path: soco/utils.py
# def really_unicode(in_string):
#     """Make a string unicode. Really.
# 
#     Ensure ``in_string`` is returned as unicode through a series of
#     progressively relaxed decodings.
# 
#     Args:
#         in_string (str): The string to convert.
# 
#     Returns:
#         str: Unicode.
# 
#     Raises:
#         ValueError
#     """
#     if isinstance(in_string, bytes):
#         for args in (("utf-8",), ("latin-1",), ("ascii", "replace")):
#             try:
#                 # pylint: disable=star-args
#                 in_string = in_string.decode(*args)
#                 break
#             except UnicodeDecodeError:
#                 continue
#     if not isinstance(in_string, str):
#         raise ValueError("%s is not a string at all." % in_string)
#     return in_string
# 
# def first_cap(string):
#     """Return upper cased first character"""
#     return string[0].upper() + string[1:]


# Path: soco/data_structures.py
import textwrap
import warnings
from .exceptions import DIDLMetadataError
from .utils import really_unicode, first_cap
from .xml import XML, ns_tag
from .data_structure_quirks import apply_resource_quirks
            from . import data_structures_entry

        if item_class != cls.item_class:
            raise DIDLMetadataError(
                "UPnP class is incorrect. Expected '{}',"
                " got '{}'".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)