signature:
def scrollright ( self , window_name , object_name ) :
    """Scroll right
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
if not self . verifyscrollbarhorizontal ( window_name , object_name ) :
    raise LdtpServerException ( 'Object not horizontal scrollbar' )
return self . setmax ( window_name , object_name )


signature:
def onedown ( self , window_name , object_name , iterations ) :
    """Press scrollbar down with number of iterations
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ param interations : iterations to perform on slider increase
 @ type iterations : integer
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
if not self . verifyscrollbarvertical ( window_name , object_name ) :
    raise LdtpServerException ( 'Object not vertical scrollbar' )
object_handle = self . _get_object_handle ( window_name , object_name )
i = 0
maxValue = 1.0 / 8
flag = False
while i < iterations :
    if object_handle . AXValue >= 1 :
        raise LdtpServerException ( 'Maximum limit reached' )
    object_handle . AXValue += maxValue
    time . sleep ( 1.0 / 100 )
    flag = True
    i += 1
if flag :
    return 1
else :
    raise LdtpServerException ( 'Unable to increase scrollbar' )


signature:
def oneup ( self , window_name , object_name , iterations ) :
    """Press scrollbar up with number of iterations
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ param interations : iterations to perform on slider increase
 @ type iterations : integer
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
if not self . verifyscrollbarvertical ( window_name , object_name ) :
    raise LdtpServerException ( 'Object not vertical scrollbar' )
object_handle = self . _get_object_handle ( window_name , object_name )
i = 0
minValue = 1.0 / 8
flag = False
while i < iterations :
    if object_handle . AXValue <= 0 :
        raise LdtpServerException ( 'Minimum limit reached' )
    object_handle . AXValue -= minValue
    time . sleep ( 1.0 / 100 )
    flag = True
    i += 1
if flag :
    return 1
else :
    raise LdtpServerException ( 'Unable to decrease scrollbar' )


signature:
def oneright ( self , window_name , object_name , iterations ) :
    """Press scrollbar right with number of iterations
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ param interations : iterations to perform on slider increase
 @ type iterations : integer
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
if not self . verifyscrollbarhorizontal ( window_name , object_name ) :
    raise LdtpServerException ( 'Object not horizontal scrollbar' )
object_handle = self . _get_object_handle ( window_name , object_name )
i = 0
maxValue = 1.0 / 8
flag = False
while i < iterations :
    if object_handle . AXValue >= 1 :
        raise LdtpServerException ( 'Maximum limit reached' )
    object_handle . AXValue += maxValue
    time . sleep ( 1.0 / 100 )
    flag = True
    i += 1
if flag :
    return 1
else :
    raise LdtpServerException ( 'Unable to increase scrollbar' )


signature:
def oneleft ( self , window_name , object_name , iterations ) :
    """Press scrollbar left with number of iterations
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ param interations : iterations to perform on slider increase
 @ type iterations : integer
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
if not self . verifyscrollbarhorizontal ( window_name , object_name ) :
    raise LdtpServerException ( 'Object not horizontal scrollbar' )
object_handle = self . _get_object_handle ( window_name , object_name )
i = 0
minValue = 1.0 / 8
flag = False
while i < iterations :
    if object_handle . AXValue <= 0 :
        raise LdtpServerException ( 'Minimum limit reached' )
    object_handle . AXValue -= minValue
    time . sleep ( 1.0 / 100 )
    flag = True
    i += 1
if flag :
    return 1
else :
    raise LdtpServerException ( 'Unable to decrease scrollbar' )


signature:
def selecttab ( self , window_name , object_name , tab_name ) :
    """Select tab based on name .
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ param tab _ name : tab to select
 @ type data : string
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
tab_handle = self . _get_tab_handle ( window_name , object_name , tab_name )
tab_handle . Press ( )
return 1


signature:
def selecttabindex ( self , window_name , object_name , tab_index ) :
    """Select tab based on index .
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ param tab _ index : tab to select
 @ type data : integer
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
children = self . _get_tab_children ( window_name , object_name )
length = len ( children )
if tab_index < 0 or tab_index > length :
    raise LdtpServerException ( u"Invalid tab index %s" % tab_index )
tab_handle = children [ tab_index ]
if not tab_handle . AXEnabled :
    raise LdtpServerException ( u"Object %s state disabled" % object_name )
tab_handle . Press ( )
return 1


signature:
def verifytabname ( self , window_name , object_name , tab_name ) :
    """Verify tab name .
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ param tab _ name : tab to select
 @ type data : string
 @ return : 1 on success 0 on failure
 @ rtype : integer"""

implementation:
try :
    tab_handle = self . _get_tab_handle ( window_name , object_name , tab_name )
    if tab_handle . AXValue :
        return 1
except LdtpServerException :
    pass
return 0


signature:
def gettabcount ( self , window_name , object_name ) :
    """Get tab count .
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ return : tab count on success .
 @ rtype : integer"""

implementation:
children = self . _get_tab_children ( window_name , object_name )
return len ( children )


signature:
def gettabname ( self , window_name , object_name , tab_index ) :
    """Get tab name
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ param tab _ index : Index of tab ( zero based index )
 @ type object _ name : int
 @ return : text on success .
 @ rtype : string"""

implementation:
children = self . _get_tab_children ( window_name , object_name )
length = len ( children )
if tab_index < 0 or tab_index > length :
    raise LdtpServerException ( u"Invalid tab index %s" % tab_index )
tab_handle = children [ tab_index ]
if not tab_handle . AXEnabled :
    raise LdtpServerException ( u"Object %s state disabled" % object_name )
return tab_handle . AXTitle


signature:
def mouseleftclick ( self , window_name , object_name ) :
    """Mouse left click on an object .
 @ param window _ name : Window name to look for , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to look for , either full name ,
 LDTP ' s name convention , or a Unix glob . Or menu heirarchy
 @ type object _ name : string
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
object_handle = self . _get_object_handle ( window_name , object_name )
if not object_handle . AXEnabled :
    raise LdtpServerException ( u"Object %s state disabled" % object_name )
self . _grabfocus ( object_handle )
x , y , width , height = self . _getobjectsize ( object_handle )
# Mouse left click on the object
object_handle . clickMouseButtonLeft ( ( x + width / 2 , y + height / 2 ) )
return 1


signature:
def mouserightclick ( self , window_name , object_name ) :
    """Mouse right click on an object .
 @ param window _ name : Window name to look for , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to look for , either full name ,
 LDTP ' s name convention , or a Unix glob . Or menu heirarchy
 @ type object _ name : string
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
object_handle = self . _get_object_handle ( window_name , object_name )
if not object_handle . AXEnabled :
    raise LdtpServerException ( u"Object %s state disabled" % object_name )
self . _grabfocus ( object_handle )
x , y , width , height = self . _getobjectsize ( object_handle )
# Mouse right click on the object
object_handle . clickMouseButtonRight ( ( x + width / 2 , y + height / 2 ) )
return 1


signature:
def generatemouseevent ( self , x , y , eventType = "b1c" , drag_button_override = 'drag_default_button' ) :
    """Generate mouse event on x , y co - ordinates .
 @ param x : X co - ordinate
 @ type x : int
 @ param y : Y co - ordinate
 @ type y : int
 @ param eventType : Mouse click type
 @ type eventType : str
 @ param drag _ button _ override : Any drag _ xxx value
 Only relevant for movements , i . e . | type | = " abs " or " rel "
 Quartz is not fully compatible with windows , so for drags
 the drag button must be explicitly defined . generatemouseevent
 will remember the last button pressed by default , and drag
 that button , use this argument to override that .
 @ type drag _ button _ override : str
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
if drag_button_override not in mouse_click_override :
    raise ValueError ( 'Unsupported drag_button_override type: %s' % drag_button_override )
global drag_button_remembered
point = ( x , y )
button = centre
# Only matters for " other " buttons
click_type = None
if eventType == "abs" or eventType == "rel" :
    if drag_button_override is not 'drag_default_button' :
        events = [ mouse_click_override [ drag_button_override ] ]
    elif drag_button_remembered :
        events = [ drag_button_remembered ]
    else :
        events = [ move ]
    if eventType == "rel" :
        point = CGEventGetLocation ( CGEventCreate ( None ) )
        point . x += x
        point . y += y
elif eventType == "b1p" :
    events = [ press_left ]
    drag_button_remembered = drag_left
elif eventType == "b1r" :
    events = [ release_left ]
    drag_button_remembered = None
elif eventType == "b1c" :
    events = [ press_left , release_left ]
elif eventType == "b1d" :
    events = [ press_left , release_left ]
    click_type = double_click
elif eventType == "b2p" :
    events = [ press_other ]
    drag_button_remembered = drag_other
elif eventType == "b2r" :
    events = [ release_other ]
    drag_button_remembered = None
elif eventType == "b2c" :
    events = [ press_other , release_other ]
elif eventType == "b2d" :
    events = [ press_other , release_other ]
    click_type = double_click
elif eventType == "b3p" :
    events = [ press_right ]
    drag_button_remembered = drag_right
elif eventType == "b3r" :
    events = [ release_right ]
    drag_button_remembered = None
elif eventType == "b3c" :
    events = [ press_right , release_right ]
elif eventType == "b3d" :
    events = [ press_right , release_right ]
    click_type = double_click
else :
    raise LdtpServerException ( u"Mouse event '%s' not implemented" % eventType )
for event in events :
    CG_event = CGEventCreateMouseEvent ( None , event , point , button )
    if click_type :
        CGEventSetIntegerValueField ( CG_event , kCGMouseEventClickState , click_type )
    CGEventPost ( kCGHIDEventTap , CG_event )
    # Give the event time to happen
    time . sleep ( 0.01 )
return 1


signature:
def doubleclick ( self , window_name , object_name ) :
    """Double click on the object
 @ param window _ name : Window name to look for , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to look for , either full name ,
 LDTP ' s name convention , or a Unix glob . Or menu heirarchy
 @ type object _ name : string
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
object_handle = self . _get_object_handle ( window_name , object_name )
if not object_handle . AXEnabled :
    raise LdtpServerException ( u"Object %s state disabled" % object_name )
self . _grabfocus ( object_handle )
x , y , width , height = self . _getobjectsize ( object_handle )
window = self . _get_front_most_window ( )
# Mouse double click on the object
# object _ handle . doubleClick ( )
window . doubleClickMouse ( ( x + width / 2 , y + height / 2 ) )
return 1


signature:
def selectitem ( self , window_name , object_name , item_name ) :
    """Select combo box / layered pane item
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ param item _ name : Item name to select
 @ type object _ name : string
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
object_handle = self . _get_object_handle ( window_name , object_name )
if not object_handle . AXEnabled :
    raise LdtpServerException ( u"Object %s state disabled" % object_name )
self . _grabfocus ( object_handle . AXWindow )
try :
    object_handle . Press ( )
except AttributeError : # AXPress doesn ' t work with Instruments
# So did the following work around
    x , y , width , height = self . _getobjectsize ( object_handle )
    # Mouse left click on the object
    # Note : x + width / 2 , y + height / 2 doesn ' t work
    self . generatemouseevent ( x + 5 , y + 5 , "b1c" )
    self . wait ( 5 )
    handle = self . _get_sub_menu_handle ( object_handle , item_name )
    x , y , width , height = self . _getobjectsize ( handle )
    # on OSX 10.7 default " b1c " doesn ' t work
    # so using " b1d " , verified with Fusion test , this works
    self . generatemouseevent ( x + 5 , y + 5 , "b1d" )
    return 1
# Required for menuitem to appear in accessibility list
self . wait ( 1 )
menu_list = re . split ( ";" , item_name )
try :
    menu_handle = self . _internal_menu_handler ( object_handle , menu_list , True )
    # Required for menuitem to appear in accessibility list
    self . wait ( 1 )
    if not menu_handle . AXEnabled :
        raise LdtpServerException ( u"Object %s state disabled" % menu_list [ - 1 ] )
    menu_handle . Press ( )
except LdtpServerException :
    object_handle . activate ( )
    object_handle . sendKey ( AXKeyCodeConstants . ESCAPE )
    raise
return 1


signature:
def getallitem ( self , window_name , object_name ) :
    """Get all combo box item
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ return : list of string on success .
 @ rtype : list"""

implementation:
object_handle = self . _get_object_handle ( window_name , object_name )
if not object_handle . AXEnabled :
    raise LdtpServerException ( u"Object %s state disabled" % object_name )
object_handle . Press ( )
# Required for menuitem to appear in accessibility list
self . wait ( 1 )
child = None
try :
    if not object_handle . AXChildren :
        raise LdtpServerException ( u"Unable to find menu" )
    # Get AXMenu
    children = object_handle . AXChildren [ 0 ]
    if not children :
        raise LdtpServerException ( u"Unable to find menu" )
    children = children . AXChildren
    items = [ ]
    for child in children :
        label = self . _get_title ( child )
        # Don ' t add empty label
        # Menu separator have empty label ' s
        if label :
            items . append ( label )
finally :
    if child : # Set it back , by clicking combo box
        child . Cancel ( )
return items


signature:
def showlist ( self , window_name , object_name ) :
    """Show combo box list / menu
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
object_handle = self . _get_object_handle ( window_name , object_name )
if not object_handle . AXEnabled :
    raise LdtpServerException ( u"Object %s state disabled" % object_name )
object_handle . Press ( )
return 1


signature:
def hidelist ( self , window_name , object_name ) :
    """Hide combo box list / menu
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
object_handle = self . _get_object_handle ( window_name , object_name )
object_handle . activate ( )
object_handle . sendKey ( AXKeyCodeConstants . ESCAPE )
return 1


signature:
def verifydropdown ( self , window_name , object_name ) :
    """Verify drop down list / menu poped up
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ return : 1 on success 0 on failure .
 @ rtype : integer"""

implementation:
try :
    object_handle = self . _get_object_handle ( window_name , object_name )
    if not object_handle . AXEnabled or not object_handle . AXChildren :
        return 0
    # Get AXMenu
    children = object_handle . AXChildren [ 0 ]
    if children :
        return 1
except LdtpServerException :
    pass
return 0


signature:
def verifyselect ( self , window_name , object_name , item_name ) :
    """Verify the item selected in combo box
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ param item _ name : Item name to select
 @ type object _ name : string
 @ return : 1 on success .
 @ rtype : integer"""

implementation:
try :
    object_handle = self . _get_object_handle ( window_name , object_name )
    if not object_handle . AXEnabled :
        return 0
    role , label = self . _ldtpize_accessible ( object_handle )
    title = self . _get_title ( object_handle )
    if re . match ( item_name , title , re . M | re . U | re . L ) or re . match ( item_name , label , re . M | re . U | re . L ) or re . match ( item_name , u"%u%u" % ( role , label ) , re . M | re . U | re . L ) :
        return 1
except LdtpServerException :
    pass
return 0


signature:
def getcombovalue ( self , window_name , object_name ) :
    """Get current selected combobox value
 @ param window _ name : Window name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type window _ name : string
 @ param object _ name : Object name to type in , either full name ,
 LDTP ' s name convention , or a Unix glob .
 @ type object _ name : string
 @ return : selected item on success , else LdtpExecutionError on failure .
 @ rtype : string"""

implementation:
object_handle = self . _get_object_handle ( window_name , object_name )
if not object_handle . AXEnabled :
    raise LdtpServerException ( u"Object %s state disabled" % object_name )
return self . _get_title ( object_handle )


signature:
def login ( self , username = None , password = None , android_id = None ) :
    """Authenticate the gmusicapi Mobileclient instance .
 Parameters :
 username ( Optional [ str ] ) : Your Google Music username . Will be prompted if not given .
 password ( Optional [ str ] ) : Your Google Music password . Will be prompted if not given .
 android _ id ( Optional [ str ] ) : The 16 hex digits from an Android device ID .
 Default : Use gmusicapi . Mobileclient . FROM _ MAC _ ADDRESS to create ID from computer ' s MAC address .
 Returns :
 ` ` True ` ` on successful login or ` ` False ` ` on unsuccessful login ."""

implementation:
cls_name = type ( self ) . __name__
if username is None :
    username = input ( "Enter your Google username or email address: " )
if password is None :
    password = getpass . getpass ( "Enter your Google Music password: " )
if android_id is None :
    android_id = Mobileclient . FROM_MAC_ADDRESS
try :
    self . api . login ( username , password , android_id )
except OSError :
    logger . exception ( "{} authentication failed." . format ( cls_name ) )
if not self . is_authenticated :
    logger . warning ( "{} authentication failed." . format ( cls_name ) )
    return False
logger . info ( "{} authentication succeeded.\n" . format ( cls_name ) )
return True


signature:
def get_google_songs ( self , include_filters = None , exclude_filters = None , all_includes = False , all_excludes = False ) :
    """Create song list from user ' s Google Music library .
 Parameters :
 include _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid Google Music metadata field available to the Mobileclient client .
 Patterns are Python regex patterns .
 Google Music songs are filtered out if the given metadata field values don ' t match any of the given patterns .
 exclude _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid Google Music metadata field available to the Mobileclient client .
 Patterns are Python regex patterns .
 Google Music songs are filtered out if the given metadata field values match any of the given patterns .
 all _ includes ( bool ) : If ` ` True ` ` , all include _ filters criteria must match to include a song .
 all _ excludes ( bool ) : If ` ` True ` ` , all exclude _ filters criteria must match to exclude a song .
 Returns :
 A list of Google Music song dicts matching criteria and
 a list of Google Music song dicts filtered out using filter criteria ."""

implementation:
logger . info ( "Loading Google Music songs..." )
google_songs = self . api . get_all_songs ( )
matched_songs , filtered_songs = filter_google_songs ( google_songs , include_filters = include_filters , exclude_filters = exclude_filters , all_includes = all_includes , all_excludes = all_excludes )
logger . info ( "Filtered {0} Google Music songs" . format ( len ( filtered_songs ) ) )
logger . info ( "Loaded {0} Google Music songs" . format ( len ( matched_songs ) ) )
return matched_songs , filtered_songs


signature:
def get_google_playlist ( self , playlist ) :
    """Get playlist information of a user - generated Google Music playlist .
 Parameters :
 playlist ( str ) : Name or ID of Google Music playlist . Names are case - sensitive .
 Google allows multiple playlists with the same name .
 If multiple playlists have the same name , the first one encountered is used .
 Returns :
 dict : The playlist dict as returned by Mobileclient . get _ all _ user _ playlist _ contents ."""

implementation:
logger . info ( "Loading playlist {0}" . format ( playlist ) )
for google_playlist in self . api . get_all_user_playlist_contents ( ) :
    if google_playlist [ 'name' ] == playlist or google_playlist [ 'id' ] == playlist :
        return google_playlist
else :
    logger . warning ( "Playlist {0} does not exist." . format ( playlist ) )
    return { }


signature:
def get_google_playlist_songs ( self , playlist , include_filters = None , exclude_filters = None , all_includes = False , all_excludes = False ) :
    """Create song list from a user - generated Google Music playlist .
 Parameters :
 playlist ( str ) : Name or ID of Google Music playlist . Names are case - sensitive .
 Google allows multiple playlists with the same name .
 If multiple playlists have the same name , the first one encountered is used .
 include _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid Google Music metadata field available to the Musicmanager client .
 Patterns are Python regex patterns .
 Google Music songs are filtered out if the given metadata field values don ' t match any of the given patterns .
 exclude _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid Google Music metadata field available to the Musicmanager client .
 Patterns are Python regex patterns .
 Google Music songs are filtered out if the given metadata field values match any of the given patterns .
 all _ includes ( bool ) : If ` ` True ` ` , all include _ filters criteria must match to include a song .
 all _ excludes ( bool ) : If ` ` True ` ` , all exclude _ filters criteria must match to exclude a song .
 Returns :
 A list of Google Music song dicts in the playlist matching criteria and
 a list of Google Music song dicts in the playlist filtered out using filter criteria ."""

implementation:
logger . info ( "Loading Google Music playlist songs..." )
google_playlist = self . get_google_playlist ( playlist )
if not google_playlist :
    return [ ] , [ ]
playlist_song_ids = [ track [ 'trackId' ] for track in google_playlist [ 'tracks' ] ]
playlist_songs = [ song for song in self . api . get_all_songs ( ) if song [ 'id' ] in playlist_song_ids ]
matched_songs , filtered_songs = filter_google_songs ( playlist_songs , include_filters = include_filters , exclude_filters = exclude_filters , all_includes = all_includes , all_excludes = all_excludes )
logger . info ( "Filtered {0} Google playlist songs" . format ( len ( filtered_songs ) ) )
logger . info ( "Loaded {0} Google playlist songs" . format ( len ( matched_songs ) ) )
return matched_songs , filtered_songs


signature:
def cast_to_list ( position ) :
    """Cast the positional argument at given position into a list if not already a list ."""

implementation:
@ wrapt . decorator
def wrapper ( function , instance , args , kwargs ) :
    if not isinstance ( args [ position ] , list ) :
        args = list ( args )
        args [ position ] = [ args [ position ] ]
        args = tuple ( args )
    return function ( * args , ** kwargs )
return wrapper


signature:
def _pybossa_req ( method , domain , id = None , payload = None , params = { } , headers = { 'content-type' : 'application/json' } , files = None ) :
    """Send a JSON request .
 Returns True if everything went well , otherwise it returns the status
 code of the response ."""

implementation:
url = _opts [ 'endpoint' ] + '/api/' + domain
if id is not None :
    url += '/' + str ( id )
if 'api_key' in _opts :
    params [ 'api_key' ] = _opts [ 'api_key' ]
if method == 'get' :
    r = requests . get ( url , params = params )
elif method == 'post' :
    if files is None and headers [ 'content-type' ] == 'application/json' :
        r = requests . post ( url , params = params , headers = headers , data = json . dumps ( payload ) )
    else :
        r = requests . post ( url , params = params , files = files , data = payload )
elif method == 'put' :
    r = requests . put ( url , params = params , headers = headers , data = json . dumps ( payload ) )
elif method == 'delete' :
    r = requests . delete ( url , params = params , headers = headers , data = json . dumps ( payload ) )
if r . status_code // 100 == 2 :
    if r . text and r . text != '""' :
        return json . loads ( r . text )
    else :
        return True
else :
    return json . loads ( r . text )


signature:
def get_projects ( limit = 100 , offset = 0 , last_id = None ) :
    """Return a list of registered projects .
 : param limit : Number of returned items , default 100
 : type limit : integer
 : param offset : Offset for the query , default 0
 : type offset : integer
 : param last _ id : id of the last project , used for pagination . If provided , offset is ignored
 : type last _ id : integer
 : rtype : list
 : returns : A list of PYBOSSA Projects"""

implementation:
if last_id is not None :
    params = dict ( limit = limit , last_id = last_id )
else :
    print ( OFFSET_WARNING )
    params = dict ( limit = limit , offset = offset )
try :
    res = _pybossa_req ( 'get' , 'project' , params = params )
    if type ( res ) . __name__ == 'list' :
        return [ Project ( project ) for project in res ]
    else :
        raise TypeError
except : # pragma : no cover
    raise


signature:
def get_project ( project_id ) :
    """Return a PYBOSSA Project for the project _ id .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : rtype : PYBOSSA Project
 : returns : A PYBOSSA Project object"""

implementation:
try :
    res = _pybossa_req ( 'get' , 'project' , project_id )
    if res . get ( 'id' ) :
        return Project ( res )
    else :
        return res
except : # pragma : no cover
    raise


signature:
def find_project ( ** kwargs ) :
    """Return a list with matching project arguments .
 : param kwargs : PYBOSSA Project members
 : rtype : list
 : returns : A list of projects that match the kwargs"""

implementation:
try :
    res = _pybossa_req ( 'get' , 'project' , params = kwargs )
    if type ( res ) . __name__ == 'list' :
        return [ Project ( project ) for project in res ]
    else :
        return res
except : # pragma : no cover
    raise


signature:
def create_project ( name , short_name , description ) :
    """Create a project .
 : param name : PYBOSSA Project Name
 : type name : string
 : param short _ name : PYBOSSA Project short name or slug
 : type short _ name : string
 : param description : PYBOSSA Project description
 : type decription : string
 : returns : True - - the response status code"""

implementation:
try :
    project = dict ( name = name , short_name = short_name , description = description )
    res = _pybossa_req ( 'post' , 'project' , payload = project )
    if res . get ( 'id' ) :
        return Project ( res )
    else :
        return res
except : # pragma : no cover
    raise


signature:
def update_project ( project ) :
    """Update a project instance .
 : param project : PYBOSSA project
 : type project : PYBOSSA Project
 : returns : True - - the response status code"""

implementation:
try :
    project_id = project . id
    project = _forbidden_attributes ( project )
    res = _pybossa_req ( 'put' , 'project' , project_id , payload = project . data )
    if res . get ( 'id' ) :
        return Project ( res )
    else :
        return res
except : # pragma : no cover
    raise


signature:
def delete_project ( project_id ) :
    """Delete a Project with id = project _ id .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : returns : True - - the response status code"""

implementation:
try :
    res = _pybossa_req ( 'delete' , 'project' , project_id )
    if type ( res ) . __name__ == 'bool' :
        return True
    else :
        return res
except : # pragma : no cover
    raise


signature:
def get_categories ( limit = 20 , offset = 0 , last_id = None ) :
    """Return a list of registered categories .
 : param limit : Number of returned items , default 20
 : type limit : integer
 : param offset : Offset for the query , default 0
 : type offset : integer
 : param last _ id : id of the last category , used for pagination . If provided , offset is ignored
 : type last _ id : integer
 : rtype : list
 : returns : A list of PYBOSSA Categories"""

implementation:
if last_id is not None :
    params = dict ( limit = limit , last_id = last_id )
else :
    params = dict ( limit = limit , offset = offset )
    print ( OFFSET_WARNING )
try :
    res = _pybossa_req ( 'get' , 'category' , params = params )
    if type ( res ) . __name__ == 'list' :
        return [ Category ( category ) for category in res ]
    else :
        raise TypeError
except :
    raise


signature:
def get_category ( category_id ) :
    """Return a PYBOSSA Category for the category _ id .
 : param category _ id : PYBOSSA Category ID
 : type category _ id : integer
 : rtype : PYBOSSA Category
 : returns : A PYBOSSA Category object"""

implementation:
try :
    res = _pybossa_req ( 'get' , 'category' , category_id )
    if res . get ( 'id' ) :
        return Category ( res )
    else :
        return res
except : # pragma : no cover
    raise


signature:
def find_category ( ** kwargs ) :
    """Return a list with matching Category arguments .
 : param kwargs : PYBOSSA Category members
 : rtype : list
 : returns : A list of project that match the kwargs"""

implementation:
try :
    res = _pybossa_req ( 'get' , 'category' , params = kwargs )
    if type ( res ) . __name__ == 'list' :
        return [ Category ( category ) for category in res ]
    else :
        return res
except : # pragma : no cover
    raise


signature:
def create_category ( name , description ) :
    """Create a Category .
 : param name : PYBOSSA Category Name
 : type name : string
 : param description : PYBOSSA Category description
 : type decription : string
 : returns : True - - the response status code"""

implementation:
try :
    category = dict ( name = name , short_name = name . lower ( ) . replace ( " " , "" ) , description = description )
    res = _pybossa_req ( 'post' , 'category' , payload = category )
    if res . get ( 'id' ) :
        return Category ( res )
    else :
        return res
except : # pragma : no cover
    raise


signature:
def update_category ( category ) :
    """Update a Category instance .
 : param category : PYBOSSA Category
 : type category : PYBOSSA Category
 : returns : True - - the response status code"""

implementation:
try :
    res = _pybossa_req ( 'put' , 'category' , category . id , payload = category . data )
    if res . get ( 'id' ) :
        return Category ( res )
    else :
        return res
except : # pragma : no cover
    raise


signature:
def delete_category ( category_id ) :
    """Delete a Category with id = category _ id .
 : param category _ id : PYBOSSA Category ID
 : type category _ id : integer
 : returns : True - - the response status code"""

implementation:
try :
    res = _pybossa_req ( 'delete' , 'category' , category_id )
    if type ( res ) . __name__ == 'bool' :
        return True
    else :
        return res
except : # pragma : no cover
    raise


signature:
def get_tasks ( project_id , limit = 100 , offset = 0 , last_id = None ) :
    """Return a list of tasks for a given project ID .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : param limit : Number of returned items , default 100
 : type limit : integer
 : param offset : Offset for the query , default 0
 : param last _ id : id of the last task , used for pagination . If provided , offset is ignored
 : type last _ id : integer
 : type offset : integer
 : returns : True - - the response status code"""

implementation:
if last_id is not None :
    params = dict ( limit = limit , last_id = last_id )
else :
    params = dict ( limit = limit , offset = offset )
    print ( OFFSET_WARNING )
params [ 'project_id' ] = project_id
try :
    res = _pybossa_req ( 'get' , 'task' , params = params )
    if type ( res ) . __name__ == 'list' :
        return [ Task ( task ) for task in res ]
    else :
        return res
except : # pragma : no cover
    raise


signature:
def find_tasks ( project_id , ** kwargs ) :
    """Return a list of matched tasks for a given project ID .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : param kwargs : PYBOSSA Task members
 : type info : dict
 : rtype : list
 : returns : A list of tasks that match the kwargs"""

implementation:
try :
    kwargs [ 'project_id' ] = project_id
    res = _pybossa_req ( 'get' , 'task' , params = kwargs )
    if type ( res ) . __name__ == 'list' :
        return [ Task ( task ) for task in res ]
    else :
        return res
except : # pragma : no cover
    raise


signature:
def create_task ( project_id , info , n_answers = 30 , priority_0 = 0 , quorum = 0 ) :
    """Create a task for a given project ID .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : param info : PYBOSSA Project info JSON field
 : type info : dict
 : param n _ answers : Number of answers or TaskRuns per task , default 30
 : type n _ answers : integer
 : param priority _ 0 : Value between 0 and 1 indicating priority of task within
 Project ( higher = more important ) , default 0.0
 : type priority _ 0 : float
 : param quorum : Number of times this task should be done by different users ,
 default 0
 : type quorum : integer
 : returns : True - - the response status code"""

implementation:
try :
    task = dict ( project_id = project_id , info = info , calibration = 0 , priority_0 = priority_0 , n_answers = n_answers , quorum = quorum )
    res = _pybossa_req ( 'post' , 'task' , payload = task )
    if res . get ( 'id' ) :
        return Task ( res )
    else :
        return res
except : # pragma : no cover
    raise


signature:
def update_task ( task ) :
    """Update a task for a given task ID .
 : param task : PYBOSSA task"""

implementation:
try :
    task_id = task . id
    task = _forbidden_attributes ( task )
    res = _pybossa_req ( 'put' , 'task' , task_id , payload = task . data )
    if res . get ( 'id' ) :
        return Task ( res )
    else :
        return res
except : # pragma : no cover
    raise


signature:
def delete_task ( task_id ) :
    """Delete a task for a given task ID .
 : param task : PYBOSSA task"""

implementation:
# : : arg task : A task
try :
    res = _pybossa_req ( 'delete' , 'task' , task_id )
    if type ( res ) . __name__ == 'bool' :
        return True
    else :
        return res
except : # pragma : no cover
    raise


signature:
def get_taskruns ( project_id , limit = 100 , offset = 0 , last_id = None ) :
    """Return a list of task runs for a given project ID .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : param limit : Number of returned items , default 100
 : type limit : integer
 : param offset : Offset for the query , default 0
 : type offset : integer
 : param last _ id : id of the last taskrun , used for pagination . If provided , offset is ignored
 : type last _ id : integer
 : rtype : list
 : returns : A list of task runs for the given project ID"""

implementation:
if last_id is not None :
    params = dict ( limit = limit , last_id = last_id )
else :
    params = dict ( limit = limit , offset = offset )
    print ( OFFSET_WARNING )
params [ 'project_id' ] = project_id
try :
    res = _pybossa_req ( 'get' , 'taskrun' , params = params )
    if type ( res ) . __name__ == 'list' :
        return [ TaskRun ( taskrun ) for taskrun in res ]
    else :
        raise TypeError
except :
    raise


signature:
def find_taskruns ( project_id , ** kwargs ) :
    """Return a list of matched task runs for a given project ID .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : param kwargs : PYBOSSA Task Run members
 : rtype : list
 : returns : A List of task runs that match the query members"""

implementation:
try :
    kwargs [ 'project_id' ] = project_id
    res = _pybossa_req ( 'get' , 'taskrun' , params = kwargs )
    if type ( res ) . __name__ == 'list' :
        return [ TaskRun ( taskrun ) for taskrun in res ]
    else :
        return res
except : # pragma : no cover
    raise


signature:
def delete_taskrun ( taskrun_id ) :
    """Delete the given taskrun .
 : param task : PYBOSSA task"""

implementation:
try :
    res = _pybossa_req ( 'delete' , 'taskrun' , taskrun_id )
    if type ( res ) . __name__ == 'bool' :
        return True
    else :
        return res
except : # pragma : no cover
    raise


signature:
def get_results ( project_id , limit = 100 , offset = 0 , last_id = None ) :
    """Return a list of results for a given project ID .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : param limit : Number of returned items , default 100
 : type limit : integer
 : param offset : Offset for the query , default 0
 : param last _ id : id of the last result , used for pagination . If provided , offset is ignored
 : type last _ id : integer
 : type offset : integer
 : returns : True - - the response status code"""

implementation:
if last_id is not None :
    params = dict ( limit = limit , last_id = last_id )
else :
    params = dict ( limit = limit , offset = offset )
    print ( OFFSET_WARNING )
params [ 'project_id' ] = project_id
try :
    res = _pybossa_req ( 'get' , 'result' , params = params )
    if type ( res ) . __name__ == 'list' :
        return [ Result ( result ) for result in res ]
    else :
        return res
except : # pragma : no cover
    raise


signature:
def find_results ( project_id , ** kwargs ) :
    """Return a list of matched results for a given project ID .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : param kwargs : PYBOSSA Results members
 : type info : dict
 : rtype : list
 : returns : A list of results that match the kwargs"""

implementation:
try :
    kwargs [ 'project_id' ] = project_id
    res = _pybossa_req ( 'get' , 'result' , params = kwargs )
    if type ( res ) . __name__ == 'list' :
        return [ Result ( result ) for result in res ]
    else :
        return res
except : # pragma : no cover
    raise


signature:
def update_result ( result ) :
    """Update a result for a given result ID .
 : param result : PYBOSSA result"""

implementation:
try :
    result_id = result . id
    result = _forbidden_attributes ( result )
    res = _pybossa_req ( 'put' , 'result' , result_id , payload = result . data )
    if res . get ( 'id' ) :
        return Result ( res )
    else :
        return res
except : # pragma : no cover
    raise


signature:
def _forbidden_attributes ( obj ) :
    """Return the object without the forbidden attributes ."""

implementation:
for key in list ( obj . data . keys ( ) ) :
    if key in list ( obj . reserved_keys . keys ( ) ) :
        obj . data . pop ( key )
return obj


signature:
def create_helpingmaterial ( project_id , info , media_url = None , file_path = None ) :
    """Create a helping material for a given project ID .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : param info : PYBOSSA Helping Material info JSON field
 : type info : dict
 : param media _ url : URL for a media file ( image , video or audio )
 : type media _ url : string
 : param file _ path : File path to the local image , video or sound to upload .
 : type file _ path : string
 : returns : True - - the response status code"""

implementation:
try :
    helping = dict ( project_id = project_id , info = info , media_url = None , )
    if file_path :
        files = { 'file' : open ( file_path , 'rb' ) }
        payload = { 'project_id' : project_id }
        res = _pybossa_req ( 'post' , 'helpingmaterial' , payload = payload , files = files )
    else :
        res = _pybossa_req ( 'post' , 'helpingmaterial' , payload = helping )
    if res . get ( 'id' ) :
        return HelpingMaterial ( res )
    else :
        return res
except : # pragma : no cover
    raise


signature:
def get_helping_materials ( project_id , limit = 100 , offset = 0 , last_id = None ) :
    """Return a list of helping materials for a given project ID .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : param limit : Number of returned items , default 100
 : type limit : integer
 : param offset : Offset for the query , default 0
 : param last _ id : id of the last helping material , used for pagination . If provided , offset is ignored
 : type last _ id : integer
 : type offset : integer
 : returns : True - - the response status code"""

implementation:
if last_id is not None :
    params = dict ( limit = limit , last_id = last_id )
else :
    params = dict ( limit = limit , offset = offset )
    print ( OFFSET_WARNING )
params [ 'project_id' ] = project_id
try :
    res = _pybossa_req ( 'get' , 'helpingmaterial' , params = params )
    if type ( res ) . __name__ == 'list' :
        return [ HelpingMaterial ( helping ) for helping in res ]
    else :
        return res
except : # pragma : no cover
    raise


signature:
def find_helping_materials ( project_id , ** kwargs ) :
    """Return a list of matched helping materials for a given project ID .
 : param project _ id : PYBOSSA Project ID
 : type project _ id : integer
 : param kwargs : PYBOSSA HelpingMaterial members
 : type info : dict
 : rtype : list
 : returns : A list of helping materials that match the kwargs"""

implementation:
try :
    kwargs [ 'project_id' ] = project_id
    res = _pybossa_req ( 'get' , 'helpingmaterial' , params = kwargs )
    if type ( res ) . __name__ == 'list' :
        return [ HelpingMaterial ( helping ) for helping in res ]
    else :
        return res
except : # pragma : no cover
    raise


signature:
def update_helping_material ( helpingmaterial ) :
    """Update a helping material for a given helping material ID .
 : param helpingmaterial : PYBOSSA helping material"""

implementation:
try :
    helpingmaterial_id = helpingmaterial . id
    helpingmaterial = _forbidden_attributes ( helpingmaterial )
    res = _pybossa_req ( 'put' , 'helpingmaterial' , helpingmaterial_id , payload = helpingmaterial . data )
    if res . get ( 'id' ) :
        return HelpingMaterial ( res )
    else :
        return res
except : # pragma : no cover
    raise


signature:
def login ( self , oauth_filename = "oauth" , uploader_id = None ) :
    """Authenticate the gmusicapi Musicmanager instance .
 Parameters :
 oauth _ filename ( str ) : The filename of the oauth credentials file to use / create for login .
 Default : ` ` oauth ` `
 uploader _ id ( str ) : A unique id as a MAC address ( e . g . ` ` ' 00:11:22:33 : AA : BB ' ` ` ) .
 This should only be provided in cases where the default ( host MAC address incremented by 1 ) won ' t work .
 Returns :
 ` ` True ` ` on successful login , ` ` False ` ` on unsuccessful login ."""

implementation:
cls_name = type ( self ) . __name__
oauth_cred = os . path . join ( os . path . dirname ( OAUTH_FILEPATH ) , oauth_filename + '.cred' )
try :
    if not self . api . login ( oauth_credentials = oauth_cred , uploader_id = uploader_id ) :
        try :
            self . api . perform_oauth ( storage_filepath = oauth_cred )
        except OSError :
            logger . exception ( "\nUnable to login with specified oauth code." )
        self . api . login ( oauth_credentials = oauth_cred , uploader_id = uploader_id )
except ( OSError , ValueError ) :
    logger . exception ( "{} authentication failed." . format ( cls_name ) )
    return False
if not self . is_authenticated :
    logger . warning ( "{} authentication failed." . format ( cls_name ) )
    return False
logger . info ( "{} authentication succeeded.\n" . format ( cls_name ) )
return True


signature:
def get_google_songs ( self , include_filters = None , exclude_filters = None , all_includes = False , all_excludes = False , uploaded = True , purchased = True ) :
    """Create song list from user ' s Google Music library .
 Parameters :
 include _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid Google Music metadata field available to the Musicmanager client .
 Patterns are Python regex patterns .
 Google Music songs are filtered out if the given metadata field values don ' t match any of the given patterns .
 exclude _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid Google Music metadata field available to the Musicmanager client .
 Patterns are Python regex patterns .
 Google Music songs are filtered out if the given metadata field values match any of the given patterns .
 all _ includes ( bool ) : If ` ` True ` ` , all include _ filters criteria must match to include a song .
 all _ excludes ( bool ) : If ` ` True ` ` , all exclude _ filters criteria must match to exclude a song .
 uploaded ( bool ) : Include uploaded songs . Default : ` ` True ` ` .
 purchased ( bool ) : Include purchased songs . Default : ` ` True ` ` .
 Returns :
 A list of Google Music song dicts matching criteria and
 a list of Google Music song dicts filtered out using filter criteria ."""

implementation:
if not uploaded and not purchased :
    raise ValueError ( "One or both of uploaded/purchased parameters must be True." )
logger . info ( "Loading Google Music songs..." )
google_songs = [ ]
if uploaded :
    google_songs += self . api . get_uploaded_songs ( )
if purchased :
    for song in self . api . get_purchased_songs ( ) :
        if song not in google_songs :
            google_songs . append ( song )
matched_songs , filtered_songs = filter_google_songs ( google_songs , include_filters = include_filters , exclude_filters = exclude_filters , all_includes = all_includes , all_excludes = all_excludes )
logger . info ( "Filtered {0} Google Music songs" . format ( len ( filtered_songs ) ) )
logger . info ( "Loaded {0} Google Music songs" . format ( len ( matched_songs ) ) )
return matched_songs , filtered_songs


signature:
def download ( self , songs , template = None ) :
    """Download Google Music songs .
 Parameters :
 songs ( list or dict ) : Google Music song dict ( s ) .
 template ( str ) : A filepath which can include template patterns .
 Returns :
 A list of result dictionaries .
 { ' result ' : ' downloaded ' , ' id ' : song _ id , ' filepath ' : downloaded [ song _ id ] } , # downloaded
 { ' result ' : ' error ' , ' id ' : song _ id , ' message ' : error [ song _ id ] } # error"""

implementation:
if not template :
    template = os . getcwd ( )
songnum = 0
total = len ( songs )
results = [ ]
errors = { }
pad = len ( str ( total ) )
for result in self . _download ( songs , template ) :
    song_id = songs [ songnum ] [ 'id' ]
    songnum += 1
    downloaded , error = result
    if downloaded :
        logger . info ( "({num:>{pad}}/{total}) Successfully downloaded -- {file} ({song_id})" . format ( num = songnum , pad = pad , total = total , file = downloaded [ song_id ] , song_id = song_id ) )
        results . append ( { 'result' : 'downloaded' , 'id' : song_id , 'filepath' : downloaded [ song_id ] } )
    elif error :
        title = songs [ songnum ] . get ( 'title' , "<empty>" )
        artist = songs [ songnum ] . get ( 'artist' , "<empty>" )
        album = songs [ songnum ] . get ( 'album' , "<empty>" )
        logger . info ( "({num:>{pad}}/{total}) Error on download -- {title} -- {artist} -- {album} ({song_id})" . format ( num = songnum , pad = pad , total = total , title = title , artist = artist , album = album , song_id = song_id ) )
        results . append ( { 'result' : 'error' , 'id' : song_id , 'message' : error [ song_id ] } )
if errors :
    logger . info ( "\n\nThe following errors occurred:\n" )
    for filepath , e in errors . items ( ) :
        logger . info ( "{file} | {error}" . format ( file = filepath , error = e ) )
    logger . info ( "\nThese files may need to be synced again.\n" )
return results


signature:
def upload ( self , filepaths , enable_matching = False , transcode_quality = '320k' , delete_on_success = False ) :
    """Upload local songs to Google Music .
 Parameters :
 filepaths ( list or str ) : Filepath ( s ) to upload .
 enable _ matching ( bool ) : If ` ` True ` ` attempt to use ` scan and match
 < http : / / support . google . com / googleplay / bin / answer . py ? hl = en & answer = 2920799 & topic = 2450455 > ` _ _ .
 This requieres ffmpeg or avconv .
 transcode _ quality ( str or int ) : If int , pass to ffmpeg / avconv ` ` - q : a ` ` for libmp3lame ` VBR quality
 < http : / / trac . ffmpeg . org / wiki / Encode / MP3 # VBREncoding > ' _ _ .
 If string , pass to ffmpeg / avconv ` ` - b : a ` ` for libmp3lame ` CBR quality
 < http : / / trac . ffmpeg . org / wiki / Encode / MP3 # CBREncoding > ' _ _ .
 Default : ` ` 320k ` `
 delete _ on _ success ( bool ) : Delete successfully uploaded local files . Default : ` ` False ` `
 Returns :
 A list of result dictionaries .
 { ' result ' : ' uploaded ' , ' filepath ' : < filepath > , ' id ' : < song _ id > } , # uploaded
 { ' result ' : ' matched ' , ' filepath ' : < filepath > , ' id ' : < song _ id > } , # matched
 { ' result ' : ' error ' , ' filepath ' : < filepath > , ' message ' : < error _ message > } , # error
 { ' result ' : ' not _ uploaded ' , ' filepath ' : < filepath > , ' id ' : < song _ id > , ' message ' : < reason _ message > } , # not _ uploaded ALREADY _ EXISTS
 { ' result ' : ' not _ uploaded ' , ' filepath ' : < filepath > , ' message ' : < reason _ message > } # not _ uploaded"""

implementation:
filenum = 0
total = len ( filepaths )
results = [ ]
errors = { }
pad = len ( str ( total ) )
exist_strings = [ "ALREADY_EXISTS" , "this song is already uploaded" ]
for result in self . _upload ( filepaths , enable_matching = enable_matching , transcode_quality = transcode_quality ) :
    filepath = filepaths [ filenum ]
    filenum += 1
    uploaded , matched , not_uploaded , error = result
    if uploaded :
        logger . info ( "({num:>{pad}}/{total}) Successfully uploaded -- {file} ({song_id})" . format ( num = filenum , pad = pad , total = total , file = filepath , song_id = uploaded [ filepath ] ) )
        results . append ( { 'result' : 'uploaded' , 'filepath' : filepath , 'id' : uploaded [ filepath ] } )
    elif matched :
        logger . info ( "({num:>{pad}}/{total}) Successfully scanned and matched -- {file} ({song_id})" . format ( num = filenum , pad = pad , total = total , file = filepath , song_id = matched [ filepath ] ) )
        results . append ( { 'result' : 'matched' , 'filepath' : filepath , 'id' : matched [ filepath ] } )
    elif error :
        logger . warning ( "({num:>{pad}}/{total}) Error on upload -- {file}" . format ( num = filenum , pad = pad , total = total , file = filepath ) )
        results . append ( { 'result' : 'error' , 'filepath' : filepath , 'message' : error [ filepath ] } )
        errors . update ( error )
    else :
        if any ( exist_string in not_uploaded [ filepath ] for exist_string in exist_strings ) :
            response = "ALREADY EXISTS"
            song_id = GM_ID_RE . search ( not_uploaded [ filepath ] ) . group ( 0 )
            logger . info ( "({num:>{pad}}/{total}) Failed to upload -- {file} ({song_id}) | {response}" . format ( num = filenum , pad = pad , total = total , file = filepath , response = response , song_id = song_id ) )
            results . append ( { 'result' : 'not_uploaded' , 'filepath' : filepath , 'id' : song_id , 'message' : not_uploaded [ filepath ] } )
        else :
            response = not_uploaded [ filepath ]
            logger . info ( "({num:>{pad}}/{total}) Failed to upload -- {file} | {response}" . format ( num = filenum , pad = pad , total = total , file = filepath , response = response ) )
            results . append ( { 'result' : 'not_uploaded' , 'filepath' : filepath , 'message' : not_uploaded [ filepath ] } )
    success = ( uploaded or matched ) or ( not_uploaded and 'ALREADY_EXISTS' in not_uploaded [ filepath ] )
    if success and delete_on_success :
        try :
            os . remove ( filepath )
        except ( OSError , PermissionError ) :
            logger . warning ( "Failed to remove {} after successful upload" . format ( filepath ) )
if errors :
    logger . info ( "\n\nThe following errors occurred:\n" )
    for filepath , e in errors . items ( ) :
        logger . info ( "{file} | {error}" . format ( file = filepath , error = e ) )
    logger . info ( "\nThese filepaths may need to be synced again.\n" )
return results


signature:
def convert_cygwin_path ( path ) :
    """Convert Unix path from Cygwin to Windows path ."""

implementation:
try :
    win_path = subprocess . check_output ( [ "cygpath" , "-aw" , path ] , universal_newlines = True ) . strip ( )
except ( FileNotFoundError , subprocess . CalledProcessError ) :
    logger . exception ( "Call to cygpath failed." )
    raise
return win_path


signature:
def _get_mutagen_metadata ( filepath ) :
    """Get mutagen metadata dict from a file ."""

implementation:
try :
    metadata = mutagen . File ( filepath , easy = True )
except mutagen . MutagenError :
    logger . warning ( "Can't load {} as music file." . format ( filepath ) )
    raise
return metadata


signature:
def _mutagen_fields_to_single_value ( metadata ) :
    """Replace mutagen metadata field list values in mutagen tags with the first list value ."""

implementation: return dict ( ( k , v [ 0 ] ) for k , v in metadata . items ( ) if v )


signature:
def _split_field_to_single_value ( field ) :
    """Convert number field values split by a ' / ' to a single number value ."""

implementation:
split_field = re . match ( r'(\d+)/\d+' , field )
return split_field . group ( 1 ) or field


signature:
def _normalize_metadata ( metadata ) :
    """Normalize metadata to improve match accuracy ."""

implementation:
metadata = str ( metadata )
metadata = metadata . lower ( )
metadata = re . sub ( r'\/\s*\d+' , '' , metadata )
# Remove " / < totaltracks > " from track number .
metadata = re . sub ( r'^0+([0-9]+)' , r'\1' , metadata )
# Remove leading zero ( s ) from track number .
metadata = re . sub ( r'^\d+\.+' , '' , metadata )
# Remove dots from track number .
metadata = re . sub ( r'[^\w\s]' , '' , metadata )
# Remove any non - words .
metadata = re . sub ( r'\s+' , ' ' , metadata )
# Reduce multiple spaces to a single space .
metadata = re . sub ( r'^\s+' , '' , metadata )
# Remove leading space .
metadata = re . sub ( r'\s+$' , '' , metadata )
# Remove trailing space .
metadata = re . sub ( r'^the\s+' , '' , metadata , re . I )
# Remove leading " the " .
return metadata


signature:
def compare_song_collections ( src_songs , dst_songs ) :
    """Compare two song collections to find missing songs .
 Parameters :
 src _ songs ( list ) : Google Music song dicts or filepaths of local songs .
 dest _ songs ( list ) : Google Music song dicts or filepaths of local songs .
 Returns :
 A list of Google Music song dicts or local song filepaths from source missing in destination ."""

implementation:
def gather_field_values ( song ) :
    return tuple ( ( _normalize_metadata ( song [ field ] ) for field in _filter_comparison_fields ( song ) ) )
dst_songs_criteria = { gather_field_values ( _normalize_song ( dst_song ) ) for dst_song in dst_songs }
return [ src_song for src_song in src_songs if gather_field_values ( _normalize_song ( src_song ) ) not in dst_songs_criteria ]


signature:
def get_supported_filepaths ( filepaths , supported_extensions , max_depth = float ( 'inf' ) ) :
    """Get filepaths with supported extensions from given filepaths .
 Parameters :
 filepaths ( list or str ) : Filepath ( s ) to check .
 supported _ extensions ( tuple or str ) : Supported file extensions or a single file extension .
 max _ depth ( int ) : The depth in the directory tree to walk .
 A depth of ' 0 ' limits the walk to the top directory .
 Default : No limit .
 Returns :
 A list of supported filepaths ."""

implementation:
supported_filepaths = [ ]
for path in filepaths :
    if os . name == 'nt' and CYGPATH_RE . match ( path ) :
        path = convert_cygwin_path ( path )
    if os . path . isdir ( path ) :
        for root , __ , files in walk_depth ( path , max_depth ) :
            for f in files :
                if f . lower ( ) . endswith ( supported_extensions ) :
                    supported_filepaths . append ( os . path . join ( root , f ) )
    elif os . path . isfile ( path ) and path . lower ( ) . endswith ( supported_extensions ) :
        supported_filepaths . append ( path )
return supported_filepaths


signature:
def exclude_filepaths ( filepaths , exclude_patterns = None ) :
    """Exclude file paths based on regex patterns .
 Parameters :
 filepaths ( list or str ) : Filepath ( s ) to check .
 exclude _ patterns ( list ) : Python regex patterns to check filepaths against .
 Returns :
 A list of filepaths to include and a list of filepaths to exclude ."""

implementation:
if not exclude_patterns :
    return filepaths , [ ]
exclude_re = re . compile ( "|" . join ( pattern for pattern in exclude_patterns ) )
included_songs = [ ]
excluded_songs = [ ]
for filepath in filepaths :
    if exclude_patterns and exclude_re . search ( filepath ) :
        excluded_songs . append ( filepath )
    else :
        included_songs . append ( filepath )
return included_songs , excluded_songs


signature:
def _check_field_value ( field_value , pattern ) :
    """Check a song metadata field value for a pattern ."""

implementation:
if isinstance ( field_value , list ) :
    return any ( re . search ( pattern , str ( value ) , re . I ) for value in field_value )
else :
    return re . search ( pattern , str ( field_value ) , re . I )


signature:
def _check_filters ( song , include_filters = None , exclude_filters = None , all_includes = False , all_excludes = False ) :
    """Check a song metadata dict against a set of metadata filters ."""

implementation:
include = True
if include_filters :
    if all_includes :
        if not all ( field in song and _check_field_value ( song [ field ] , pattern ) for field , pattern in include_filters ) :
            include = False
    else :
        if not any ( field in song and _check_field_value ( song [ field ] , pattern ) for field , pattern in include_filters ) :
            include = False
if exclude_filters :
    if all_excludes :
        if all ( field in song and _check_field_value ( song [ field ] , pattern ) for field , pattern in exclude_filters ) :
            include = False
    else :
        if any ( field in song and _check_field_value ( song [ field ] , pattern ) for field , pattern in exclude_filters ) :
            include = False
return include


signature:
def filter_google_songs ( songs , include_filters = None , exclude_filters = None , all_includes = False , all_excludes = False ) :
    """Match a Google Music song dict against a set of metadata filters .
 Parameters :
 songs ( list ) : Google Music song dicts to filter .
 include _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid Google Music metadata field available to the Musicmanager client .
 Patterns are Python regex patterns .
 Google Music songs are filtered out if the given metadata field values don ' t match any of the given patterns .
 exclude _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid Google Music metadata field available to the Musicmanager client .
 Patterns are Python regex patterns .
 Google Music songs are filtered out if the given metadata field values match any of the given patterns .
 all _ includes ( bool ) : If ` ` True ` ` , all include _ filters criteria must match to include a song .
 all _ excludes ( bool ) : If ` ` True ` ` , all exclude _ filters criteria must match to exclude a song .
 Returns :
 A list of Google Music song dicts matching criteria and
 a list of Google Music song dicts filtered out using filter criteria .
 ( matched , filtered )"""

implementation:
matched_songs = [ ]
filtered_songs = [ ]
if include_filters or exclude_filters :
    for song in songs :
        if _check_filters ( song , include_filters = include_filters , exclude_filters = exclude_filters , all_includes = all_includes , all_excludes = all_excludes ) :
            matched_songs . append ( song )
        else :
            filtered_songs . append ( song )
else :
    matched_songs += songs
return matched_songs , filtered_songs


signature:
def filter_local_songs ( filepaths , include_filters = None , exclude_filters = None , all_includes = False , all_excludes = False ) :
    """Match a local file against a set of metadata filters .
 Parameters :
 filepaths ( list ) : Filepaths to filter .
 include _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid mutagen metadata fields .
 Patterns are Python regex patterns .
 Local songs are filtered out if the given metadata field values don ' t match any of the given patterns .
 exclude _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid mutagen metadata fields .
 Patterns are Python regex patterns .
 Local songs are filtered out if the given metadata field values match any of the given patterns .
 all _ includes ( bool ) : If ` ` True ` ` , all include _ filters criteria must match to include a song .
 all _ excludes ( bool ) : If ` ` True ` ` , all exclude _ filters criteria must match to exclude a song .
 Returns :
 A list of local song filepaths matching criteria and
 a list of local song filepaths filtered out using filter criteria .
 Invalid music files are also filtered out .
 ( matched , filtered )"""

implementation:
matched_songs = [ ]
filtered_songs = [ ]
for filepath in filepaths :
    try :
        song = _get_mutagen_metadata ( filepath )
    except mutagen . MutagenError :
        filtered_songs . append ( filepath )
    else :
        if include_filters or exclude_filters :
            if _check_filters ( song , include_filters = include_filters , exclude_filters = exclude_filters , all_includes = all_includes , all_excludes = all_excludes ) :
                matched_songs . append ( filepath )
            else :
                filtered_songs . append ( filepath )
        else :
            matched_songs . append ( filepath )
return matched_songs , filtered_songs


signature:
def get_suggested_filename ( metadata ) :
    """Generate a filename for a song based on metadata .
 Parameters :
 metadata ( dict ) : A metadata dict .
 Returns :
 A filename ."""

implementation:
if metadata . get ( 'title' ) and metadata . get ( 'track_number' ) :
    suggested_filename = '{track_number:0>2} {title}' . format ( ** metadata )
elif metadata . get ( 'title' ) and metadata . get ( 'trackNumber' ) :
    suggested_filename = '{trackNumber:0>2} {title}' . format ( ** metadata )
elif metadata . get ( 'title' ) and metadata . get ( 'tracknumber' ) :
    suggested_filename = '{tracknumber:0>2} {title}' . format ( ** metadata )
else :
    suggested_filename = '00 {}' . format ( metadata . get ( 'title' , '' ) )
return suggested_filename


signature:
def template_to_filepath ( template , metadata , template_patterns = None ) :
    """Create directory structure and file name based on metadata template .
 Parameters :
 template ( str ) : A filepath which can include template patterns as defined by : param template _ patterns : .
 metadata ( dict ) : A metadata dict .
 template _ patterns ( dict ) : A dict of ` ` pattern : field ` ` pairs used to replace patterns with metadata field values .
 Default : : const TEMPLATE _ PATTERNS :
 Returns :
 A filepath ."""

implementation:
if template_patterns is None :
    template_patterns = TEMPLATE_PATTERNS
metadata = metadata if isinstance ( metadata , dict ) else _mutagen_fields_to_single_value ( metadata )
assert isinstance ( metadata , dict )
suggested_filename = get_suggested_filename ( metadata ) . replace ( '.mp3' , '' )
if template == os . getcwd ( ) or template == '%suggested%' :
    filepath = suggested_filename
else :
    t = template . replace ( '%suggested%' , suggested_filename )
    filepath = _replace_template_patterns ( t , metadata , template_patterns )
return filepath


signature:
def walk_depth ( path , max_depth = float ( 'inf' ) ) :
    """Walk a directory tree with configurable depth .
 Parameters :
 path ( str ) : A directory path to walk .
 max _ depth ( int ) : The depth in the directory tree to walk .
 A depth of ' 0 ' limits the walk to the top directory .
 Default : No limit ."""

implementation:
start_level = os . path . abspath ( path ) . count ( os . path . sep )
for dir_entry in os . walk ( path ) :
    root , dirs , _ = dir_entry
    level = root . count ( os . path . sep ) - start_level
    yield dir_entry
    if level >= max_depth :
        dirs [ : ] = [ ]


signature:
def get_local_songs ( filepaths , include_filters = None , exclude_filters = None , all_includes = False , all_excludes = False , exclude_patterns = None , max_depth = float ( 'inf' ) ) :
    """Load songs from local filepaths .
 Parameters :
 filepaths ( list or str ) : Filepath ( s ) to search for music files .
 include _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid mutagen metadata fields . Patterns are Python regex patterns .
 Local songs are filtered out if the given metadata field values don ' t match any of the given patterns .
 exclude _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid mutagen metadata fields . Patterns are Python regex patterns .
 Local songs are filtered out if the given metadata field values match any of the given patterns .
 all _ includes ( bool ) : If ` ` True ` ` , all include _ filters criteria must match to include a song .
 all _ excludes ( bool ) : If ` ` True ` ` , all exclude _ filters criteria must match to exclude a song .
 exclude _ patterns ( list or str ) : Pattern ( s ) to exclude .
 Patterns are Python regex patterns .
 Filepaths are excluded if they match any of the exclude patterns .
 max _ depth ( int ) : The depth in the directory tree to walk .
 A depth of ' 0 ' limits the walk to the top directory .
 Default : No limit .
 Returns :
 A list of local song filepaths matching criteria ,
 a list of local song filepaths filtered out using filter criteria ,
 and a list of local song filepaths excluded using exclusion criteria ."""

implementation:
logger . info ( "Loading local songs..." )
supported_filepaths = get_supported_filepaths ( filepaths , SUPPORTED_SONG_FORMATS , max_depth = max_depth )
included_songs , excluded_songs = exclude_filepaths ( supported_filepaths , exclude_patterns = exclude_patterns )
matched_songs , filtered_songs = filter_local_songs ( included_songs , include_filters = include_filters , exclude_filters = exclude_filters , all_includes = all_includes , all_excludes = all_excludes )
logger . info ( "Excluded {0} local songs" . format ( len ( excluded_songs ) ) )
logger . info ( "Filtered {0} local songs" . format ( len ( filtered_songs ) ) )
logger . info ( "Loaded {0} local songs" . format ( len ( matched_songs ) ) )
return matched_songs , filtered_songs , excluded_songs


signature:
def get_local_playlists ( filepaths , exclude_patterns = None , max_depth = float ( 'inf' ) ) :
    """Load playlists from local filepaths .
 Parameters :
 filepaths ( list or str ) : Filepath ( s ) to search for music files .
 exclude _ patterns ( list or str ) : Pattern ( s ) to exclude .
 Patterns are Python regex patterns .
 Filepaths are excluded if they match any of the exclude patterns .
 max _ depth ( int ) : The depth in the directory tree to walk .
 A depth of ' 0 ' limits the walk to the top directory .
 Default : No limit .
 Returns :
 A list of local playlist filepaths matching criteria
 and a list of local playlist filepaths excluded using exclusion criteria ."""

implementation:
logger . info ( "Loading local playlists..." )
included_playlists = [ ]
excluded_playlists = [ ]
supported_filepaths = get_supported_filepaths ( filepaths , SUPPORTED_PLAYLIST_FORMATS , max_depth = max_depth )
included_playlists , excluded_playlists = exclude_filepaths ( supported_filepaths , exclude_patterns = exclude_patterns )
logger . info ( "Excluded {0} local playlists" . format ( len ( excluded_playlists ) ) )
logger . info ( "Loaded {0} local playlists" . format ( len ( included_playlists ) ) )
return included_playlists , excluded_playlists


signature:
def get_local_playlist_songs ( playlist , include_filters = None , exclude_filters = None , all_includes = False , all_excludes = False , exclude_patterns = None ) :
    """Load songs from local playlist .
 Parameters :
 playlist ( str ) : An M3U ( 8 ) playlist filepath .
 include _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid mutagen metadata fields . Patterns are Python regex patterns .
 Local songs are filtered out if the given metadata field values don ' t match any of the given patterns .
 exclude _ filters ( list ) : A list of ` ` ( field , pattern ) ` ` tuples .
 Fields are any valid mutagen metadata fields . Patterns are Python regex patterns .
 Local songs are filtered out if the given metadata field values match any of the given patterns .
 all _ includes ( bool ) : If ` ` True ` ` , all include _ filters criteria must match to include a song .
 all _ excludes ( bool ) : If ` ` True ` ` , all exclude _ filters criteria must match to exclude a song .
 exclude _ patterns ( list or str ) : Pattern ( s ) to exclude .
 Patterns are Python regex patterns .
 Filepaths are excluded if they match any of the exclude patterns .
 Returns :
 A list of local playlist song filepaths matching criteria ,
 a list of local playlist song filepaths filtered out using filter criteria ,
 and a list of local playlist song filepaths excluded using exclusion criteria ."""

implementation:
logger . info ( "Loading local playlist songs..." )
if os . name == 'nt' and CYGPATH_RE . match ( playlist ) :
    playlist = convert_cygwin_path ( playlist )
filepaths = [ ]
base_filepath = os . path . dirname ( os . path . abspath ( playlist ) )
with open ( playlist ) as local_playlist :
    for line in local_playlist . readlines ( ) :
        line = line . strip ( )
        if line . lower ( ) . endswith ( SUPPORTED_SONG_FORMATS ) :
            path = line
            if not os . path . isabs ( path ) :
                path = os . path . join ( base_filepath , path )
            if os . path . isfile ( path ) :
                filepaths . append ( path )
supported_filepaths = get_supported_filepaths ( filepaths , SUPPORTED_SONG_FORMATS )
included_songs , excluded_songs = exclude_filepaths ( supported_filepaths , exclude_patterns = exclude_patterns )
matched_songs , filtered_songs = filter_local_songs ( included_songs , include_filters = include_filters , exclude_filters = exclude_filters , all_includes = all_includes , all_excludes = all_excludes )
logger . info ( "Excluded {0} local playlist songs" . format ( len ( excluded_songs ) ) )
logger . info ( "Filtered {0} local playlist songs" . format ( len ( filtered_songs ) ) )
logger . info ( "Loaded {0} local playlist songs" . format ( len ( matched_songs ) ) )
return matched_songs , filtered_songs , excluded_songs


signature:
def _prepare_lines_ ( self , lines ) :
    """Prepare the lines read from the text file before starting to process
 it ."""

implementation:
result = [ ]
for line in lines : # Remove all whitespace from the start and end of the line .
    line = line . strip ( )
    # Replace all tabs with spaces .
    line = line . replace ( '\t' , ' ' )
    # Replace all repeating spaces with a single space .
    while line . find ( '  ' ) > - 1 :
        line = line . replace ( '  ' , ' ' )
    result . append ( line )
return result


signature:
def _create_element_list_ ( self ) :
    """Extract an alphabetically sorted list of elements from the compounds of
 the material .
 : returns : An alphabetically sorted list of elements ."""

implementation:
element_set = stoich . elements ( self . compounds )
return sorted ( list ( element_set ) )


signature:
def add_assay ( self , name , assay ) :
    """Add an assay to the material .
 : param name : The name of the new assay .
 : param assay : A list containing the compound mass fractions for
 the assay . The sequence of the assay ' s elements must correspond to
 the sequence of the material ' s compounds ."""

implementation:
if not type ( assay ) is list :
    raise Exception ( 'Invalid assay. It must be a list.' )
elif not len ( assay ) == self . compound_count :
    raise Exception ( 'Invalid assay: It must have the same number of ' 'elements as the material has compounds.' )
elif name in self . assays :
    raise Exception ( 'Invalid assay: An assay with that name already ' 'exists.' )
self . assays [ name ] = assay


signature:
def _is_compound_mass_tuple ( self , value ) :
    """Determines whether value is a tuple of the format ( compound ( str ) ,
 mass ( float ) ) ."""

implementation:
if not type ( value ) is tuple :
    return False
elif not len ( value ) == 2 :
    return False
elif not type ( value [ 0 ] ) is str :
    return False
elif not type ( value [ 1 ] ) is float :
    return False
else :
    return True


signature:
def clone ( self ) :
    """Create a complete copy of self .
 : returns : A MaterialPackage that is identical to self ."""

implementation:
result = copy . copy ( self )
result . compound_masses = copy . deepcopy ( self . compound_masses )
return result


signature:
def get_assay ( self ) :
    """Determine the assay of self .
 : returns : [ mass fractions ] An array containing the assay of self ."""

implementation:
masses_sum = sum ( self . compound_masses )
return [ m / masses_sum for m in self . compound_masses ]


signature:
def get_element_masses ( self ) :
    """Get the masses of elements in the package .
 : returns : [ kg ] An array of element masses . The sequence of the elements
 in the result corresponds with the sequence of elements in the
 element list of the material ."""

implementation:
result = [ 0 ] * len ( self . material . elements )
for compound in self . material . compounds :
    c = self . get_compound_mass ( compound )
    f = [ c * x for x in emf ( compound , self . material . elements ) ]
    result = [ v + f [ ix ] for ix , v in enumerate ( result ) ]
return result


signature:
def get_element_mass ( self , element ) :
    """Determine the masses of elements in the package .
 : returns : [ kg ] An array of element masses . The sequence of the elements
 in the result corresponds with the sequence of elements in the
 element list of the material ."""

implementation:
result = [ 0 ]
for compound in self . material . compounds :
    c = self . get_compound_mass ( compound )
    f = [ c * x for x in emf ( compound , [ element ] ) ]
    result = [ v + f [ ix ] for ix , v in enumerate ( result ) ]
return result [ 0 ]


signature:
def extract ( self , other ) :
    """Extract ' other ' from self , modifying self and returning the extracted
 material as a new package .
 : param other : Can be one of the following :
 * float : A mass equal to other is extracted from self . Self is
 reduced by other and the extracted package is returned as a
 new package .
 * tuple ( compound , mass ) : The other tuple specifies the mass of
 a compound to be extracted . It is extracted from self and the
 extracted mass is returned as a new package .
 * string : The ' other ' string specifies the compound to be extracted .
 All of the mass of that compound will be removed from self and a
 new package created with it .
 : returns : A new material package containing the material that was
 extracted from self ."""

implementation:
# Extract the specified mass .
if type ( other ) is float :
    if other > self . get_mass ( ) :
        raise Exception ( 'Invalid extraction operation. Cannot extract' 'a mass larger than the package\'s mass.' )
    fraction_to_subtract = other / self . get_mass ( )
    result = MaterialPackage ( self . material , [ m * fraction_to_subtract for m in self . compound_masses ] )
    self . compound_masses = [ m * ( 1.0 - fraction_to_subtract ) for m in self . compound_masses ]
    return result
# Extract the specified mass of the specified compound .
elif self . _is_compound_mass_tuple ( other ) :
    index = self . material . get_compound_index ( other [ 0 ] )
    if other [ 1 ] > self . compound_masses [ index ] :
        raise Exception ( 'Invalid extraction operation. Cannot extract' 'a compound mass larger than what the package' 'contains.' )
    self . compound_masses [ index ] -= other [ 1 ]
    resultarray = [ 0.0 ] * len ( self . compound_masses )
    resultarray [ index ] = other [ 1 ]
    result = MaterialPackage ( self . material , resultarray )
    return result
# Extract all of the specified compound .
elif type ( other ) is str :
    index = self . material . get_compound_index ( other )
    result = self * 0.0
    result . compound_masses [ index ] = self . compound_masses [ index ]
    self . compound_masses [ index ] = 0.0
    return result
# If not one of the above , it must be an invalid argument .
else :
    raise TypeError ( 'Invalid extraction argument.' )


signature:
def add_to ( self , other ) :
    """Add another chem material package to this material package .
 : param other : The other material package ."""

implementation:
# Add another package .
if type ( other ) is MaterialPackage : # Packages of the same material .
    if self . material == other . material :
        self . compound_masses += other . compound_masses
    # Packages of different materials .
    else :
        for compound in other . material . compounds :
            if compound not in self . material . compounds :
                raise Exception ( "Packages of '" + other . material . name + "' cannot be added to packages of '" + self . material . name + "'. The compound '" + compound + "' was not found in '" + self . material . name + "'." )
            self . add_to ( ( compound , other . get_compound_mass ( compound ) ) )
# Add the specified mass of the specified compound .
elif self . _is_compound_mass_tuple ( other ) : # Added material variables .
    compound = other [ 0 ]
    compound_index = self . material . get_compound_index ( compound )
    mass = other [ 1 ]
    # Create the result package .
    self . compound_masses [ compound_index ] += mass
# If not one of the above , it must be an invalid argument .
else :
    raise TypeError ( 'Invalid addition argument.' )


signature:
def calculate ( self , ** state ) :
    """Calculate the density at the specified temperature .
 : param T : [ K ] temperature
 : returns : [ kg / m3 ] density
 The * * state parameter contains the keyword argument ( s ) specified above that are used to describe the state of the material ."""

implementation:
super ( ) . calculate ( ** state )
return self . mm * self . P / R / state [ "T" ]


signature:
def calculate ( self , ** state ) :
    """Calculate the density at the specified temperature , pressure , and
 composition .
 : param T : [ K ] temperature
 : param P : [ Pa ] pressure
 : param x : [ mole fraction ] dictionary of compounds and mole fractions
 : returns : [ kg / m3 ] density
 The * * state parameter contains the keyword argument ( s ) specified above that are used to describe the state of the material ."""

implementation:
super ( ) . calculate ( ** state )
mm_average = 0.0
for compound , molefraction in state [ "x" ] . items ( ) :
    mm_average += molefraction * mm ( compound )
mm_average /= 1000.0
return mm_average * state [ "P" ] / R / state [ "T" ]


signature:
def set_parent_path ( self , value ) :
    """Set the parent path and the path from the new parent path .
 : param value : The path to the object ' s parent"""

implementation:
self . _parent_path = value
self . path = value + r'/' + self . name
self . _update_childrens_parent_path ( )


signature:
def create_account ( self , name , number = None , description = None ) :
    """Create a sub account in the account .
 : param name : The account name .
 : param description : The account description .
 : param number : The account number .
 : returns : The created account ."""

implementation:
new_account = GeneralLedgerAccount ( name , description , number , self . account_type )
new_account . set_parent_path ( self . path )
self . accounts . append ( new_account )
return new_account


signature:
def remove_account ( self , name ) :
    """Remove an account from the account ' s sub accounts .
 : param name : The name of the account to remove ."""

implementation:
acc_to_remove = None
for a in self . accounts :
    if a . name == name :
        acc_to_remove = a
if acc_to_remove is not None :
    self . accounts . remove ( acc_to_remove )


signature:
def get_child_account ( self , account_name ) :
    """Retrieves a child account .
 This could be a descendant nested at any level .
 : param account _ name : The name of the account to retrieve .
 : returns : The child account , if found , else None ."""

implementation:
if r'/' in account_name :
    accs_in_path = account_name . split ( r'/' , 1 )
    curr_acc = self [ accs_in_path [ 0 ] ]
    if curr_acc is None :
        return None
    return curr_acc . get_child_account ( accs_in_path [ 1 ] )
    pass
else :
    return self [ account_name ]


signature:
def _create_account_ ( self , name , number , account_type ) :
    """Create an account in the general ledger structure .
 : param name : The account name .
 : param number : The account number .
 : param account _ type : The account type .
 : returns : The created account ."""

implementation:
new_acc = GeneralLedgerAccount ( name , None , number , account_type )
self . accounts . append ( new_acc )
return new_acc


signature:
def get_account_descendants ( self , account ) :
    """Retrieves an account ' s descendants from the general ledger structure
 given the account name .
 : param account _ name : The account name .
 : returns : The decendants of the account ."""

implementation:
result = [ ]
for child in account . accounts :
    self . _get_account_and_descendants_ ( child , result )
return result


signature:
def _get_account_and_descendants_ ( self , account , result ) :
    """Returns the account and all of it ' s sub accounts .
 : param account : The account .
 : param result : The list to add all the accounts to ."""

implementation:
result . append ( account )
for child in account . accounts :
    self . _get_account_and_descendants_ ( child , result )


signature:
def validate_account_names ( self , names ) :
    """Validates whether the accounts in a list of account names exists .
 : param names : The names of the accounts .
 : returns : The descendants of the account ."""

implementation:
for name in names :
    if self . get_account ( name ) is None :
        raise ValueError ( "The account '{}' does not exist in the" "  general ledger structure." . format ( name ) )


signature:
def report ( self , format = ReportFormat . printout , output_path = None ) :
    """Returns a report of this class .
 : param format : The format of the report .
 : param output _ path : The path to the file the report is written to .
 If None , then the report is not written to a file .
 : returns : The descendants of the account ."""

implementation:
rpt = GlsRpt ( self , output_path )
return rpt . render ( format )


signature:
def create_transaction ( self , name , description = None , tx_date = datetime . min . date ( ) , dt_account = None , cr_account = None , source = None , amount = 0.00 ) :
    """Create a transaction in the general ledger .
 : param name : The transaction ' s name .
 : param description : The transaction ' s description .
 : param tx _ date : The date of the transaction .
 : param cr _ account : The transaction ' s credit account ' s name .
 : param dt _ account : The transaction ' s debit account ' s name .
 : param source : The name of source the transaction originated from .
 : param amount : The transaction amount .
 : returns : The created transaction ."""

implementation:
new_tx = Transaction ( name , description , tx_date , dt_account , cr_account , source , amount )
self . transactions . append ( new_tx )
return new_tx


signature:
def transaction_list ( self , start = datetime . min , end = datetime . max , format = ReportFormat . printout , component_path = "" , output_path = None ) :
    """Generate a transaction list report .
 : param start : The start date to generate the report for .
 : param end : The end date to generate the report for .
 : param format : The format of the report .
 : param component _ path : The path of the component to filter the report ' s
 transactions by .
 : param output _ path : The path to the file the report is written to .
 If None , then the report is not written to a file .
 : returns : The generated report ."""

implementation:
rpt = TransactionList ( self , start , end , component_path , output_path )
return rpt . render ( format )


signature:
def balance_sheet ( self , end = datetime . max , format = ReportFormat . printout , output_path = None ) :
    """Generate a transaction list report .
 : param end : The end date to generate the report for .
 : param format : The format of the report .
 : param output _ path : The path to the file the report is written to .
 If None , then the report is not written to a file .
 : returns : The generated report ."""

implementation:
rpt = BalanceSheet ( self , end , output_path )
return rpt . render ( format )


signature:
def income_statement ( self , start = datetime . min , end = datetime . max , format = ReportFormat . printout , component_path = "" , output_path = None ) :
    """Generate a transaction list report .
 : param start : The start date to generate the report for .
 : param end : The end date to generate the report for .
 : param format : The format of the report .
 : param component _ path : The path of the component to filter the report ' s
 transactions by .
 : param output _ path : The path to the file the report is written to .
 If None , then the report is not written to a file .
 : returns : The generated report ."""

implementation:
rpt = IncomeStatement ( self , start , end , component_path , output_path )
return rpt . render ( format )


signature:
def get_path_relative_to_module ( module_file_path , relative_target_path ) :
    """Calculate a path relative to the specified module file .
 : param module _ file _ path : The file path to the module ."""

implementation:
module_path = os . path . dirname ( module_file_path )
path = os . path . join ( module_path , relative_target_path )
path = os . path . abspath ( path )
return path


signature:
def get_date ( date ) :
    """Get the date from a value that could be a date object or a string .
 : param date : The date object or string .
 : returns : The date object ."""

implementation:
if type ( date ) is str :
    return datetime . strptime ( date , '%Y-%m-%d' ) . date ( )
else :
    return date


signature:
def f_tr_Haaland ( Re_D , ɛ , D , warn = True ) :
    """Calculate the friction factor of turbulent flow ( t ) in a rough duct ( r ) for
 the provided conditions with Haaland ' s equation .
 : param Re _ D : Reynolds number for the specified hydraulic diameter .
 : param ɛ : [ m ] Surface roughness .
 : param D : [ m ] Duct hydraulic diameter .
 : return : Friction factor .
 Source : lienhard2018 , Eq . 7.50."""

implementation:
if warn :
    try :
        if ( ɛ / D ) < 0.0 or ( ɛ / D ) > 0.05 :
            raise Warning ( f"ɛ/D '{ɛ / D:.3e}' out of range 0.0 <= ɛ/D <= 0.05." )
    except Warning as w :
        ex_type , ex_value , ex_traceback = sys . exc_info ( )
        print ( color_warn ( "WARNING: " ) , ex_value )
    try :
        if Re_D < 4000.0 or Re_D > 1.0E8 :
            raise Warning ( f"Reynolds number '{Re_D:.3e}' out of range " "4000 <= Re_D <= 1E8." )
    except Warning as w :
        ex_type , ex_value , ex_traceback = sys . exc_info ( )
        print ( color_warn ( "WARNING: " ) , ex_value )
return 1 / ( 1.8 * log10 ( ( 6.9 / Re_D ) + ( ɛ / D / 3.7 ) ** 1.11 ) ) ** 2


signature:
def Nu_x ( self , L , theta , Ts , ** statef ) :
    """Calculate the local Nusselt number .
 : param L : [ m ] characteristic length of the heat transfer surface
 : param theta : [ ° ] angle of the surface with the vertical
 : param Ts : [ K ] heat transfer surface temperature
 : param Tf : [ K ] bulk fluid temperature
 : returns : float"""

implementation:
Tf = statef [ 'T' ]
thetar = radians ( theta )
if self . _isgas :
    self . Tr = Ts - 0.38 * ( Ts - Tf )
    beta = self . _fluid . beta ( T = Tf )
else : # for liquids
    self . Tr = Ts - 0.5 * ( Ts - Tf )
    beta = self . _fluid . beta ( T = self . Tr )
if Ts > Tf : # hot surface
    if 0.0 < theta < 45.0 :
        g = const . g * cos ( thetar )
    else :
        g = const . g
else : # cold surface
    if - 45.0 < theta < 0.0 :
        g = const . g * cos ( thetar )
    else :
        g = const . g
nu = self . _fluid . nu ( T = self . Tr )
alpha = self . _fluid . alpha ( T = self . Tr )
Gr = dq . Gr ( L , Ts , Tf , beta , nu , g )
Pr = dq . Pr ( nu , alpha )
Ra = Gr * Pr
eq = [ self . equation_dict [ r ] for r in self . regions if r . contains_point ( theta , Ra ) ] [ 0 ]
return eq ( self , Ra , Pr )


signature:
def Nu_L ( self , L , theta , Ts , ** statef ) :
    """Calculate the average Nusselt number .
 : param L : [ m ] characteristic length of the heat transfer surface
 : param theta : [ ° ] angle of the surface with the vertical
 : param Ts : [ K ] heat transfer surface temperature
 : param * * statef : [ K ] bulk fluid temperature
 : returns : float"""

implementation: return self . Nu_x ( L , theta , Ts , ** statef ) / 0.75


signature:
def h_x ( self , L , theta , Ts , ** statef ) :
    """Calculate the local heat transfer coefficient .
 : param L : [ m ] characteristic length of the heat transfer surface
 : param theta : [ ° ] angle of the surface with the vertical
 : param Ts : [ K ] heat transfer surface temperature
 : param Tf : [ K ] bulk fluid temperature
 : returns : [ W / m2 / K ] float"""

implementation:
Nu_x = self . Nu_x ( L , theta , Ts , ** statef )
k = self . _fluid . k ( T = self . Tr )
return Nu_x * k / L


signature:
def h_L ( self , L , theta , Ts , ** statef ) :
    """Calculate the average heat transfer coefficient .
 : param L : [ m ] characteristic length of the heat transfer surface
 : param theta : [ ° ] angle of the surface with the vertical
 : param Ts : [ K ] heat transfer surface temperature
 : param Tf : [ K ] bulk fluid temperature
 : returns : [ W / m2 / K ] float"""

implementation:
Nu_L = self . Nu_L ( L , theta , Ts , ** statef )
k = self . _fluid . k ( T = self . Tr )
return Nu_L * k / L


signature:
def _prepare_lines ( self , lines ) :
    """Prepare the lines read from the text file before starting to process
 it ."""

implementation:
result = list ( )
for line in lines : # Remove all whitespace characters ( e . g . spaces , line breaks , etc . )
# from the start and end of the line .
    line = line . strip ( )
    # Replace all tabs with spaces .
    line = line . replace ( "\t" , " " )
    # Replace all repeating spaces with a single space .
    while line . find ( "  " ) > - 1 :
        line = line . replace ( "  " , " " )
    result . append ( line )
return result


signature:
def add_assay ( self , name , solid_density , H2O_fraction , assay ) :
    """Add an assay to the material .
 : param name : The name of the new assay .
 : param assay : A numpy array containing the size class mass fractions
 for the assay . The sequence of the assay ' s elements must correspond
 to the sequence of the material ' s size classes ."""

implementation:
if not type ( solid_density ) is float :
    raise Exception ( "Invalid solid density. It must be a float." )
self . solid_densities [ name ] = solid_density
if not type ( H2O_fraction ) is float :
    raise Exception ( "Invalid H2O fraction. It must be a float." )
self . H2O_fractions [ name ] = H2O_fraction
if not type ( assay ) is numpy . ndarray :
    raise Exception ( "Invalid assay. It must be a numpy array." )
elif not assay . shape == ( self . size_class_count , ) :
    raise Exception ( "Invalid assay: It must have the same number of elements as " "the material has size classes." )
elif name in self . assays . keys ( ) :
    raise Exception ( "Invalid assay: An assay with that name already exists." )
self . assays [ name ] = assay


signature:
def create_package ( self , assay = None , mass = 0.0 , normalise = True ) :
    """Create a MaterialPackage based on the specified parameters .
 : param assay : The name of the assay based on which the package
 must be created .
 : param mass : [ kg ] The mass of the package .
 : param normalise : Indicates whether the assay must be normalised
 before creating the package .
 : returns : The created MaterialPackage ."""

implementation:
if assay is None :
    return MaterialPackage ( self , 1.0 , 0.0 , self . create_empty_assay ( ) )
if normalise :
    assay_total = self . get_assay_total ( assay )
    if assay_total == 0.0 :
        assay_total = 1.0
else :
    assay_total = 1.0
H2O_mass = mass * self . H2O_fractions [ assay ]
solid_mass = mass - H2O_mass
return MaterialPackage ( self , self . solid_densities [ assay ] , H2O_mass , solid_mass * self . assays [ assay ] / assay_total )


signature:
def _is_size_class_mass_tuple ( self , value ) :
    """Determines whether value is a tuple of the format
 ( size class ( float ) , mass ( float ) ) .
 : param value : The value to check .
 : returns : Whether the value is a tuple in the required format ."""

implementation:
if not type ( value ) is tuple :
    return False
elif not len ( value ) == 2 :
    return False
elif not type ( value [ 0 ] ) is float :
    return False
elif not type ( value [ 1 ] ) is float and not type ( value [ 1 ] ) is numpy . float64 and not type ( value [ 1 ] ) is numpy . float32 :
    return False
else :
    return True