
    rh,                       S SK Jr  S SKrS SKrS SKJr  S SKJ	r	  S SKJ
r
  S SKJr  S SKJr  \R                  (       a  S SKJr  S SKJs  Jr  S S	KJr  S
S.SS jjrS rSS jrSS jrSS jrSS jrSS jr      SS jr  S           SS jjr  S         S S jjr\ S:X  a  S SKr\RB                  " 5         gg)!    )annotationsN)tostring)common)meter)
xmlObjects)prebase)Callable)Music21ObjectF)noCopyc               h   USL a  [         R                  " U 5      nOU n[        U5        UR                  5        HZ  nUR                  n[        U5      S:  d  M   [        UR                  5       5      nUR                  5         UR                  U5        M\     [        USS9nUR                  5       nU$ )ux  
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          R/home/james-whalen/.local/lib/python3.13/site-packages/music21/musicxml/helpers.py
dumpStringr"      s    $ c"
5Mjjlv;?V\\^,GLLNMM'"  uy1D;;=DK    c                ,    [        [        U 5      5        g)ux  
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&   B   s    $ 
*S/r#   c                X   SUS-  -   n[        U 5      nU(       a  U R                  (       a  U R                  R                  5       (       d
  US-   U l        U R                  (       a  U R                  R                  5       (       d  X l        SnU  H  n[	        XAS-   5        M     Ub  X$l        U R                  (       a  U R                  R                  5       (       d  SUS-  -   U l        ggU(       a8  U R                  (       a  U R                  R                  5       (       d  X l        ggg)z,
helper method, indent an element in place:

z  Nr   )r   textstriptailr   )elemlevelilenLsubElems        r!   r   r   W   s     	ut|At9Dyy		 1 1DDIyy		 1 1IG7AI& Lyy		 1 1ut|+DI !2 $))499??+<+<I ,=5r#   c                   U(       d  U R                  U5        g[        U 5      1n[        U R                  S5      5       H(  u  pEUR                  U;   d  M  UR                  U5        M*     U R                  [        U5      U5        g)a  
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>   p   sk    @ FYKMdll3/099a  1 	KKM"F+r#   c                    S nX:X  a  gU" U 5      u  p4U" U5      u  pV[        U5      [        U5      :w  a  [        U5      [        U5      :  $ [        XF/5      nXGS   L $ )a  
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                p    SnU  H  nUR                  5       (       a  X-  nM    O   U [        U5      S  nX4$ )N )	isnumericr   )measureNumbernumbercharsuffixs       r!   splitSuffix-measureNumberComesBefore.<locals>.splitSuffix   sB    !D~~	 "
 s6{|,~r#   Fr   )intr   )mNum1mNum2rG   	m1Numericm1Suffix	m2Numericm2SuffixsortedSuffixess           r!   measureNumberComesBeforerQ      si    , ~%e,I%e,I
9~Y'9~I.. 45!,,,r#   c                    SnU R                   S;   a  SnU$ U R                   S:X  aV  U R                  [        R                  5      nU(       a0  UR                  R
                  U R                  R
                  :X  a  SnU$ )NF)TalwaysTauto)fullMeasuregetContextByClassr   TimeSignaturebarDurationquarterLengthduration)risFullMeasure	tsContexts      r!   isFullMeasureRestr^      sp    M}}((
 	 
&	 ''(;(;<	..<<

@X@XX Mr#   c                D    U R                  SS5      nU(       d  gX!l        g)aF  
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!   synchronizeIdsToM21re      s    2 KKd#ELr#   c                    [        U[        R                  5      (       d  g[        US5      (       d  gUR                  nUc  g[
        R                  " U5      (       d  gU R                  SU5        g)aH  
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)rb   rc   m21Ids      r!   synchronizeIdsToXMLrm      s^    N i!7!7889d##LLE}""5))KKer#   c                    UR                  U5      nUc  gUb  U" U5      nUc  [        R                  " U5      n[        XU5        g)aX  
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)ra   r   hyphenToCamelCasesetattrm21Elr   xmlAttributeNameattributeName	transformvalues         r!   setM21AttributeFromAttributerw   &  sM    R II&'E}% 001ABE%(r#   c                    Uc  [         R                  " U5      n[        XS5      nUc  gUb  U" U5      nUR                  U[	        U5      5        g)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   ro   getattrrk   strrq   s         r!   setXMLAttributeFromAttributer{   [  sS    T 001ABE$/E}% 	IIE
+r#   __main__)returnrz   )r   )N)rJ   rz   rK   rz   r}   bool)r[   z'music21.note.Rest'r}   r~   )rb   
ET.Elementrc   r
   )rb   r   rc   zprebase.ProtoM21Object | Noner}   None)NN)rr   t.Anyr   r   rs   rz   rt   
str | Noneru   zCallable[[str], t.Any] | Noner}   r   )
rr   r   r   r   rs   rz   rt   r   ru   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>   rQ   r^   re   rm   rw   r{   __name__mainTest r#   r!   <module>r      s   #   9   ' ??(&&* $ !H*2(,V(-V<33*3 
3v #-12)2)2) 2) 	2)
 +2) 
2)r #/34,4,4, 4, 	4,
 -4,p z r#   