
    3j+                    h   d dl mZ d dlZd dlZd dlmZ d dlm	Z	 d dlm
Z
 d dlmZ d dlmZ ej                  rd dlmZ d dlmc mZ d d	lmZ d
dddZd ZddZddZddZddZddZ	 	 	 	 	 	 ddZ	 	 d	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 d	 	 	 	 	 	 	 	 	 d dZe dk(  rd dlZ ejB                          yy)!    )annotationsN)tostring)common)meter)
xmlObjects)prebase)Callable)Music21ObjectF)noCopyc               b   |du rt        j                  |       }n| }t        |       |j                         D ]W  }|j                  }t        |      dkD  st        |j                               }|j                          |j                  |       Y t        |d      }|j                         }|S )u  
    wrapper around xml.etree.ElementTree that returns a string
    in every case and indents tags and sorts attributes.

    >>> from music21.musicxml.m21ToXml import Element
    >>> from music21.musicxml.helpers import dumpString
    >>> e = Element('accidental')

    >>> dumpString(e)
    '<accidental />'

    >>> e.text = '∆'
    >>> e.text == '∆'
    True
    >>> dumpString(e)
    '<accidental>∆</accidental>'
    F   unicode)encoding)copydeepcopyindentiterattriblensorteditemsclearupdateet_tostringrstrip)objr   xmlElelr   attribsxStrs          E/DATA/.local/lib/python3.12/site-packages/music21/musicxml/helpers.py
dumpStringr"      s    $ c"
5Mjjlv;?V\\^,GLLNMM'"  uy1D;;=DK    c                ,    t        t        |              y)u  
    wrapper around xml.etree.ElementTree that prints a string
    in every case and indents tags and sorts attributes.  (Prints, does not return)

    >>> from music21.musicxml.helpers import dump
    >>> from xml.etree.ElementTree import Element
    >>> e = Element('accidental')

    >>> dump(e)
    <accidental />

    >>> e.text = '∆'
    >>> e.text == '∆'
    True
    >>> dump(e)
    <accidental>∆</accidental>
    N)printr"   )r   s    r!   dumpr&   A   s    $ 
*S/r#   c                   d|dz  z   }t        |       }|r| j                  r| j                  j                         s
|dz   | _        | j                  r| j                  j                         s|| _        d}| D ]  }t	        ||dz           |||_        | j                  r| j                  j                         sd|dz  z   | _        yy|r/| j                  r| j                  j                         s|| _        yyy)z4
    helper method, indent an element in place:
    
z  Nr   )r   textstriptailr   )elemlevelilenLsubElems        r!   r   r   V   s     	ut|At9Dyy		 1DDIyy		 1DIG7EAI& GLyy		 1ut|+DI !2 $))499??+<DI ,=5r#   c                    |s| j                  |       yt        |       h}t        | j                  d            D ]%  \  }}|j                  |v s|j                  |       ' | j                  t        |      |       y)aH  
    Insert element `insert` into element `root` at the earliest position
    of any instance of a child tag given in `tagList`. Append the element
    if `tagList` is `None`.

    >>> from xml.etree.ElementTree import fromstring as EL
    >>> from music21.musicxml.helpers import insertBeforeElements, dump
    >>> root = EL('<clef><sign>G</sign><line>4</line></clef>')
    >>> insert = EL('<foo/>')

    >>> insertBeforeElements(root, insert, tagList=['line'])
    >>> dump(root)
    <clef>
        <sign>G</sign>
        <foo />
        <line>4</line>
    </clef>

    Now insert another element at the end by not specifying a tag list:

    >>> insert2 = EL('<bar/>')
    >>> insertBeforeElements(root, insert2)
    >>> dump(root)
    <clef>
        <sign>G</sign>
        <foo />
        <line>4</line>
        <bar />
    </clef>
    N*)appendr   	enumeratefindalltagaddinsertmin)rootr8   tagListinsertIndicesr.   childs         r!   insertBeforeElementsr>   o   sm    @ FYKMdll3/0599a  1 	KKM"F+r#   c                    d }| |k(  ry ||       \  }} ||      \  }}t        |      t        |      k7  rt        |      t        |      k  S t        ||g      }||d   u S )ag  
    Determine whether `measureNumber1` strictly precedes
    `measureNumber2` given that they could involve suffixes.
    Equal values return False.

    >>> from music21.musicxml.helpers import measureNumberComesBefore
    >>> measureNumberComesBefore('23', '24')
    True
    >>> measureNumberComesBefore('23', '23')
    False
    >>> measureNumberComesBefore('23', '23a')
    True
    >>> measureNumberComesBefore('23a', '23b')
    True
    >>> measureNumberComesBefore('23b', '23a')
    False
    >>> measureNumberComesBefore('23b', '24a')
    True
    >>> measureNumberComesBefore('23b', '23b')
    False
    c                f    d}| D ]  }|j                         r||z  } n | t        |      d  }||fS )N )	isnumericr   )measureNumbernumbercharsuffixs       r!   splitSuffixz-measureNumberComesBefore.<locals>.splitSuffix   sC    !D~~$	 "
 s6{|,v~r#   Fr   )intr   )mNum1mNum2rG   	m1Numericm1Suffix	m2Numericm2SuffixsortedSuffixess           r!   measureNumberComesBeforerP      ss    , ~%e,Ix%e,Ix
9~Y'9~I..8 45>!,,,r#   c                    d}| j                   dv rd}|S | j                   dk(  rP| j                  t        j                        }|r/|j                  j
                  | j                  j
                  k(  rd}|S )NF)TalwaysTauto)fullMeasuregetContextByClassr   TimeSignaturebarDurationquarterLengthduration)risFullMeasure	tsContexts      r!   isFullMeasureRestr]      sp    M}}((
 	 
&	 ''(;(;<	..<<

@X@XX Mr#   c                <    | j                  dd      }|sy||_        y)a  
    MusicXML 3.1 defines the id attribute
    (%optional-unique-id)
    on many elements which is perfect for setting as .id on
    a music21 element.

    <fermata id="hello"><id>bye</id></fermata>

    >>> from xml.etree.ElementTree import fromstring as EL
    >>> e = EL('<fermata id="fermata1"/>')
    >>> f = expressions.Fermata()
    >>> musicxml.helpers.synchronizeIdsToM21(e, f)
    >>> f.id
    'fermata1'

    Does not change the id if the id is not specified:

    >>> e = EL('<fermata />')
    >>> f = expressions.Fermata()
    >>> f.id = 'doNotOverwrite'
    >>> musicxml.helpers.synchronizeIdsToM21(e, f)
    >>> f.id
    'doNotOverwrite'
    idN)getr_   )element	m21ObjectnewIds      r!   synchronizeIdsToM21rd      s!    2 KKd#EILr#   c                    t        |t        j                        syt        |d      sy|j                  }|yt        j                  |      sy| j                  d|       y)a  
    MusicXML 3.1 defines the id attribute (entity: %optional-unique-id)
    on many elements which is perfect for getting from .id on
    a music21 element.

    >>> from xml.etree.ElementTree import fromstring as EL
    >>> e = EL('<fermata />')
    >>> f = expressions.Fermata()
    >>> f.id = 'fermata1'
    >>> musicxml.helpers.synchronizeIdsToXML(e, f)
    >>> e.get('id')
    'fermata1'

    Does not set attr: id if el.id is not valid or default:

    >>> e = EL('<fermata />')
    >>> f = expressions.Fermata()
    >>> musicxml.helpers.synchronizeIdsToXML(e, f)
    >>> e.get('id', None) is None
    True
    >>> f.id = '123456'  # invalid for MusicXML id
    >>> musicxml.helpers.synchronizeIdsToXML(e, f)
    >>> e.get('id', None) is None
    True

    None can be passed in instead of a m21object.

    >>> e = EL('<fermata />')
    >>> musicxml.helpers.synchronizeIdsToXML(e, None)
    >>> e.get('id', 'no idea')
    'no idea'
    Nr_   )
isinstancer   ProtoM21Objecthasattrr_   r   isValidXSDIDset)ra   rb   m21Ids      r!   synchronizeIdsToXMLrl      sU    N i!7!789d#LLE}""5)KKer#   c                    |j                  |      }|y| ||      }|t        j                  |      }t        | ||       y)a  
    If xmlEl has at least one element of tag==tag with some text. If
    it does, set the attribute either with the same name (with "foo-bar" changed to
    "fooBar") or with attributeName to the text contents.

    Pass a function or lambda function as transform to transform the value before setting it

    >>> from xml.etree.ElementTree import fromstring as EL
    >>> e = EL('<page-layout new-page="yes" page-number="4" />')

    >>> setb = musicxml.helpers.setM21AttributeFromAttribute
    >>> pl = layout.PageLayout()
    >>> setb(pl, e, 'page-number')
    >>> pl.pageNumber
    '4'

    >>> setb(pl, e, 'new-page', 'isNew')
    >>> pl.isNew
    'yes'

    Transform the pageNumber value to an int.

    >>> setb(pl, e, 'page-number', transform=int)
    >>> pl.pageNumber
    4

    More complex:

    >>> convBool = musicxml.xmlObjects.yesNoToBoolean
    >>> setb(pl, e, 'new-page', 'isNew', transform=convBool)
    >>> pl.isNew
    True
    N)r`   r   hyphenToCamelCasesetattrm21Elr   xmlAttributeNameattributeName	transformvalues         r!   setM21AttributeFromAttributerv   %  sO    P II&'E}% 001ABE=%(r#   c                    |t        j                  |      }t        | |d      }|y| ||      }|j                  |t	        |             y)a  
    If m21El has at least one element of tag==tag with some text. If
    it does, set the attribute either with the same name (with "foo-bar" changed to
    "fooBar") or with attributeName to the text contents.

    Pass a function or lambda function as transform to transform the value before setting it

    >>> from xml.etree.ElementTree import fromstring as EL
    >>> e = EL('<page-layout/>')

    >>> setb = musicxml.helpers.setXMLAttributeFromAttribute
    >>> pl = layout.PageLayout()
    >>> pl.pageNumber = 4
    >>> pl.isNew = True

    >>> setb(pl, e, 'page-number')
    >>> e.get('page-number')
    '4'

    >>> XB = musicxml.m21ToXml.XMLExporterBase()
    >>> XB.dump(e)
    <page-layout page-number="4" />

    >>> setb(pl, e, 'new-page', 'isNew')
    >>> e.get('new-page')
    'True'

    Transform the isNew value to 'yes'.

    >>> convBool = musicxml.xmlObjects.booleanToYesNo
    >>> setb(pl, e, 'new-page', 'isNew', transform=convBool)
    >>> e.get('new-page')
    'yes'
    N)r   rn   getattrrj   strrp   s         r!   setXMLAttributeFromAttributerz   Y  sU    R 001ABE=$/E}% 	IIE
+r#   __main__)returnry   )r   )N)rI   ry   rJ   ry   r|   bool)rZ   z'music21.note.Rest'r|   r}   )ra   
ET.Elementrb   r
   )ra   r~   rb   zprebase.ProtoM21Object | Noner|   None)NN)rq   t.Anyr   r~   rr   ry   rs   
str | Nonert   zCallable[[str], t.Any] | Noner|   r   )
rq   r   r   r~   rr   ry   rs   r   rt   zCallable[[t.Any], t.Any] | None)"
__future__r   r   typingtxml.etree.ElementTreer   r   music21r   r   music21.musicxmlr   r   TYPE_CHECKINGcollections.abcr	   etreeElementTreeETmusic21.baser
   r"   r&   r   r>   rP   r]   rd   rl   rv   rz   __name__mainTest r#   r!   <module>r      s   #   9   ' ??(&&* $ !H*2(,V(-V<33*3 
3v #-11)1)1) 1) 	1)
 +1) 
1)p #/33,3,3, 3, 	3,
 -3,n zG r#   