
    rh                        % S r SSKJr  SSKrSSKJrJr  SSKr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  \R                   (       a  SS	KJr  S
r\R&                  " 5       rS\S'    " S S\R,                  5      r " S S\R0                  \R2                  5      r\" 5       rS\l        S\l        \R<                  " 5       r " S S\R0                  5      r  " S S\
RB                  5      r"\\ /r#\$S:X  a  SSKr\RJ                  " \"5        gg)zM
sites.py -- Objects for keeping track of relationships among Music21Objects
    )annotationsN)	GeneratorMutableMapping)overload)common)exceptions21)prebasestreamTz!MutableMapping[str, t.Any | None]GLOBAL_SITE_STATE_DICTc                      \ rS rSrSrg)SitesException1    N)__name__
__module____qualname____firstlineno____static_attributes__r       G/home/james-whalen/.local/lib/python3.13/site-packages/music21/sites.pyr   r   1   s    r   r   c                  R    \ rS rSrSrSrS rS rS rS r	\
" \\	5      rS rS	 rS
rg)SiteRef7   am  
a single Site (stream, container, parent, reference, etc.) stored inside the Sites object.

A very simple object.

This site would be stored in the .sites.siteDict for, say a note.Note, if it were in
st at offset 20.0

>>> st = stream.Stream()
>>> st.id = 'hi'

>>> s = sites.SiteRef()
>>> s.classString = st.classes[0]
>>> s.site = st
>>> s.isDead
False

If you call s.site, you always get an object out, but internally, there's a .siteWeakref that
stores a weakref to the site.

>>> s.site
<music21.stream.Stream hi>
>>> s.siteWeakref
<weakref at 0x123456; to ...Stream' at 0x111111>

If you turn sites.WEAKREF_ACTIVE to False then .siteWeakref just stores another reference to
the site.  Bad for memory. Good for debugging pickling.

OMIT_FROM_DOCS

Note that the ...Stream was needed after Python 3.13.
When 3.13 is the lowest version, replace ... with the
actual output.
)classStringglobalSiteIndex	siteIndexisDeadsiteWeakrefc                J    SU l         S U l        S U l        S U l        S U l        g NF)r   r   r   r   r   selfs    r   __init__SiteRef.__init__e   s(    #r   c                    U [         L a  g[        U R                  5      nU R                  (       a  SnU R                   SU R
                   SU 3$ )NzGlobal None Indexz	dead site/z to )_NoneSiteRefreprsiter   r   r   )r#   siteReprs     r   _reprInternalSiteRef._reprInternall   sI    <&		?;;"H..!4#7#7"8XJGGr   c                    [         (       a!  [        R                  " U R                  5      nOU R                  nUc  U [        La  SU l        U$ NT)WEAKREF_ACTIVEr   unwrapWeakrefr   r(   r   )r#   rets     r   _getAndUnwrapSiteSiteRef._getAndUnwrapSitev   s@    >&&t'7'78C""C;4|3DK
r   c                l    [         (       a  [        R                  " U5      U l        OXl        SU l        g r!   )r0   r   wrapWeakrefr   r   )r#   r*   s     r   _setAndWrapSiteSiteRef._setAndWrapSite   s'    >%11$7D#r   c                l   S n[         (       aR  U R                  nUc  S U l        O;[        [	        U5      5      S-   [        [        5       5      -   n U[        U'   X l        [        R                  R                  U 5      n[         (       a	  Ub  Xl        U$ ! [         a  n[        SU 35      UeS nAff = f)N_z This str screwed up everything: )r0   r*   r   strid_singletonCounterr   	TypeErrorr   SlottedObjectMixin__getstate__)r#   currentSitesiteIdValuetereturnStates        r   r@   SiteRef.__getstate__   s    >))K"#' !"[/2S83?P?R;SS:E*;7
 $/ //<<TB>k5#I ! #:;-Hs   	B 
B3B..B3c                    [         R                  R                  X5        [        (       a2  U R                  b$  U R                  n [
        U   n[
        U	 X0l        g g g ! [         a    S nSU l         Nf = fr/   )	r   r?   __setstate__r0   r   r   KeyErrorr   r*   )r#   staterB   rA   s       r   rG   SiteRef.__setstate__   ss    !!..t;>d..:**K#4[A*;7 $I ;>
  #""#s   A A43A4)r   r   r   r*   r   r   N)r   r   r   r   __doc__	__slots__r$   r,   r3   r7   propertyr*   r@   rG   r   r   r   r   r   r   7   s=    !HI H	 %7D*
$r   r   c                  p   \ rS rSrSrSrS rS#S jrS rS r	S	 r
S$S
 jrS r\SSS.     S%S jj5       r\SSSS.     S&S jj5       rSSSS.     S&S jjrSSSS.S jrS rSSS\R$                  R&                  R(                  SS.S jrS rS rS rS rS rS rS rS'S jrS rS  rS! r S"r!g)(Sites   a`  
An object, stored within a Music21Object, that stores (weak) references to
a collection of objects that may be contextually relevant to this object.

Most of these objects are locations (also called sites), or Streams that
contain this object.

All defined contexts are stored as dictionaries in a dictionary. The
outermost dictionary stores objects.
)siteDict_lastID
_siteIndexc                d    [         R                  " S [        4/5      U l        SU l        SU l        g )Nr   )collectionsOrderedDictr(   rR   rT   rS   r"   s    r   r$   Sites.__init__   s.    #//$1E0HI  r   Nc                   U R                  5       nU R                   H  nUc  M  U R                  U   nUR                  (       a  M*  [        5       nUR                  Ul        UR                  c  SnO[        UR                  5      nUR                  Ul        [        5       Ul        UR                  Ul	        SUl        XRR                  U'   M     U R                  Ul
        U$ )a  
Helper function for copy.deepcopy that in addition to copying produces
a new, independent Sites object.  This does not, however, deepcopy site
references stored therein.

All sites, however, are passed on to the new deepcopy, which means that
in a deepcopy of a Stream that contains Notes, the copied Note will
have the former site as a location, even though the new Note instance
is not actually found in the old Stream.

>>> import copy
>>> class Mock(base.Music21Object):
...     pass
>>> aObj = Mock()
>>> aContexts = sites.Sites()
>>> aContexts.add(aObj)
>>> bContexts = copy.deepcopy(aContexts)
>>> len(aContexts.get()) == 2
True

>>> len(bContexts.get()) == 2
True

>>> aContexts.get() == bContexts.get()
True
NF)	__class__rR   r   r   r*   r<   r   r=   r   r   rT   )r#   memonewidKeyoldSitenewSitenewIdKeys          r   __deepcopy__Sites.__deepcopy__   s    < nn ]]E}mmE*G~~iG"<<GL||#gll+ !( 1 1G&7&9G#")"5"5G"GN
 &-LL"- #0 
r   c                ,    [        U R                  5      $ )z
Return the total number of references.

>>> class Mock(base.Music21Object):
...     pass
>>> aObj = Mock()
>>> aContexts = sites.Sites()
>>> len(aContexts)
1
>>> aContexts.add(aObj)
>>> len(aContexts)
2

)lenrR   r"   s    r   __len__Sites.__len__  s     4==!!r   c                l    U R                   R                  5        H  u  p#UR                  UL d  M    g   g)z
returns True if checkSite in Sites.

>>> m1 = stream.Measure(number=1)
>>> m2 = stream.Measure(number=2)
>>> n = note.Note()
>>> m1.append(n)
>>> m1 in n.sites
True
>>> m2 in n.sites
False

None is always in sites

>>> None in n.sites
True
TF)rR   itemsr*   )r#   	checkSiteunused_siteRefIdsiteRefs       r   __contains__Sites.__contains__#  s3    $ *.)<)<)>%||y( *? r   c                     U R                  SS9$ )aS  
Returns all non-None sites.  Order is oldest first.

>>> n = note.Note()
>>> m = stream.Measure(number=1)
>>> s = stream.Stream(id='thisStream')
>>> m.insert(10, n)
>>> s.insert(20, n)
>>> for site in n.sites:
...     print(site, n.getOffsetBySite(site))
<music21.stream.Measure 1 offset=0.0> 10.0
<music21.stream.Stream thisStream> 20.0
T)excludeNone)
yieldSitesr"   s    r   __iter__Sites.__iter__:  s     400r   c                   Ub  [        S5      eUc  Ub  [        U5      nSnX0R                  ;   a-  U R                  U   nUR                  SL a  UR                  b  SnUb  Uc  UR
                  S   nUSL a  U R                  U   nSUl        O
[        5       nXl        XGl        U R                  Ul	        U =R                  S-  sl        [        5       Ul        U(       d  XpR                  U'   gg)a'  
Add a reference to the `Sites` collection for this object.  Automatically
called on stream.insert(n), etc.

`idKey` stores the id() of the obj.  If `None`, then id(obj) is used.

`classString` stores the class of obj.  If `None` then `obj.classes[0]`
is used.

TODO: Tests.  Including updates.
NzNo timeValue in sites anymore!FTr      )r   r<   rR   r   r*   classesr   r   rT   r   r=   r   )r#   obj	timeValuer^   r   updateNotAddtempSiteRefrl   s           r   add	Sites.addL  s       !ABB
 =S_sGEMM!--.K""e+#((4# ?{2++a.K4mmE*G"GNiG) !OO1"3"5#*MM%  r   c                V    [         R                  " S[        4/5      U l        SU l        g)z
Clear all stored data.
NrV   )rW   rX   r(   rR   rS   r"   s    r   clearSites.clear  s%     $//$1E0HIr   F)sortByCreationTimepriorityTargetc                   g Nr   r#   rp   r   r   s       r   rq   Sites.yieldSites       	r   )rp   r   r   c                   g r   r   r   s       r   rq   r     r   r   c             #    #    [        U R                  R                  5       5      nUSL a  UR                  5         Ub@  [	        U5      nXT;   a0  UR                  SUR                  UR                  U5      5      5        U HT  nU R                  U   nUR                  c  U(       d  UR                  v   M6  M8  UR                  nUc	  SUl	        MP  Uv   MV     g7f)a  
Yield references; order, based on dictionary keys, is from least
recently added to most recently added.

The `sortByCreationTime` option if set to True will sort objects by creation time,
where most-recently assigned objects are returned first.

Note that priorityTarget is searched only on id -- this could be dangerous if the
target has been garbage collected and the id is reused. Unlikely since you have to
pass in the priorityTarget itself, so therefore it still exists.

This can be much faster than .get in the case where the sought-for site
is earlier in the list.

>>> class Mock(base.Music21Object):
...     def __init__(self, idEl):
...         self.id = idEl
>>> aObj = Mock('a')
>>> bObj = Mock('b')
>>> cObj = Mock('c')
>>> aSites = sites.Sites()
>>> aSites.add(cObj)
>>> aSites.add(aObj)
>>> aSites.add(bObj)

Returns a generator:

>>> ys = aSites.yieldSites()
>>> ys
<generator object Sites.yieldSites at 0x1058085e8>

That's no help, so iterate over it instead:

>>> for s in aSites.yieldSites(sortByCreationTime=True, excludeNone=True):
...     print(s.id)
b
a
c

With priorityTarget

>>> for s in aSites.yieldSites(sortByCreationTime=True, priorityTarget=cObj,
...                            excludeNone=True):
...     print(s.id)
c
b
a

* Changed in v3: changed dramatically from previously unused version
  `sortByCreationTime='reverse'` is removed, since the ordered dict takes
  care of it and was not working.
* Changed in v8: arguments are keyword only
TNr   )
listrR   keysreverser<   insertpopindexr*   r   )	r#   rp   r   r   keyRepository
priorityIdkeyrl   rw   s	            r   rq   r     s     x T]]//12%!!#%N+J* $$Q%2%6%6}7J7J:7V%WY !CmmC(G||#"!,,& # ll;%)GNI !s   CCr   r   rp   c                   [        U R                  UUUS95      nUb5  X$;   a0  UR                  SUR                  UR	                  U5      5      5        U$ )a  
Get references; order, based on dictionary keys, is from most
recently added to least recently added.

The `sortByCreationTime` option will sort objects by creation time,
where most-recently assigned objects are returned first.
Can be [False, other], [True, 1] or ['reverse', -1]

If `priorityTarget` is defined, this object will be placed first in the list of objects.

>>> class Mock(base.Music21Object):
...     pass
>>> aObj = Mock()
>>> bObj = Mock()
>>> cObj = Mock()
>>> aSites = sites.Sites()
>>> aSites.add(cObj)
>>> aSites.add(aObj)
>>> aSites.add(bObj)

Arbitrary order, so we compare with sets:

>>> set(aSites.get()) == {None, cObj, aObj, bObj}
True

Particular order, with None at the end.

>>> aSites.get(sortByCreationTime=True) == [bObj, aObj, cObj, None]
True

Priority target

>>> begotten = aSites.get(sortByCreationTime=True, priorityTarget=cObj, excludeNone=True)
>>> begotten == [cObj, bObj, aObj]
True

* Changed in v5.5: keyword only.
r   r   )r   rq   r   r   r   )r#   r   r   rp   posts        r   get	Sites.get  s]    V DOO7I3A0; $ = > %% Atxx

>(BCDr   c                |    SnU R                  SS9 H  nUc  M   [        X15      nUs  $    g! [         a     M(  f = f)a  
Given an attribute name, search all objects and find the first that
matches this attribute name; then return a reference to this attribute.

Works in reverse order, so most recent site is returned first.

>>> class Mock(base.Music21Object):
...     attr1 = 234
>>> aObj = Mock()
>>> aObj.attr1 = 234
>>> bObj = Mock()
>>> bObj.attr1 = 98
>>> aSites = sites.Sites()
>>> len(aSites)
1
>>> aSites.add(aObj)
>>> len(aSites)
2

>>> aSites.getAttrByName('attr1') == 234
True

>>> aSites.remove(aObj)
>>> aSites.add(bObj)
>>> aSites.getAttrByName('attr1') == 98
True

An incorrect attribute name will just give none:

>>> aSites.getAttrByName('blah') is None
True

Nr   )r   )rq   getattrAttributeError)r#   attrNamer   rw   s       r   getAttrByNameSites.getAttrByName,  sP    D ??i?@C{s- A " s   -
;;)callerFirstr   r   getElementMethodr\   c                  Uc  U nUc  0 nSnU R                  UUSS9n[        U[        5      n	U H3  n
U	(       a  XR                  ;   a  U
n  OM  [        X5      (       d  M1  U
n  O   Ub  U$ U H  n
U	(       aF  U
R                  (       a5  U
R
                  R                  5       S:X  a  U
R                  USS9(       d  MP  [        U
5      U;  d  Ma  X[        U
5      '   U
R                  UUUS9nUc  M    U$    U$ )ak  
Return the most recently added reference based on className.  Class
name can be a string or the class name.

This will recursively search the sitesDicts of objects in Site objects in
the siteDict.

The `callerFirst` parameters is simply used to pass a reference of the
first caller; this is necessary if we are looking within a Stream for a
flat offset position.

If `priorityTarget` is specified, this location will be searched first. use
priorityTarget=activeSite to prioritize that.

The `getElementMethod` is a string that selects which Stream method is
used to get elements for searching with getElementsByClass() calls.

>>> import time
>>> class Mock(base.Music21Object):
...     pass
>>> aObj = Mock()
>>> bObj = Mock()
>>> aSites = sites.Sites()
>>> aSites.add(aObj)
>>> aSites.add(bObj)

We get the most recently added object first

>>> aSites.getObjByClass('Mock', sortByCreationTime=True) == bObj
True

>>> aSites.getObjByClass(Mock, sortByCreationTime=True) == bObj
True

* Changed in v5.5: all arguments except className are keyword only.

OMIT_FROM_DOCS
TODO: not sure if memo is properly working: need a test case
NTr   r   )	forceFlat)r   r   )
rq   
isinstancer;   rv   isFlatsitesgetSiteCounthasElementOfClassr<   getContextByClass)r#   	classNamer   r   r   r   r\   r   objsclassNameIsStrrw   s              r   getObjByClassSites.getObjByClassX  s#   j K<D
 1)  
 $Is3C+D , C++  K
 C#** 99))+q000d0K  #wd" !$RW,,'9%5 - 7 #7 6 r   c                8    U R                   U   nUR                  $ )z
Return the object specified by an id.
Used for testing and debugging.  Should NOT be used in production code.

>>> a = note.Note()
>>> s = stream.Stream()
>>> s.append(a)
>>> a.sites.getById(id(s)) is s
True
)rR   r*   )r#   siteIdrl   s      r   getByIdSites.getById  s     --'||r   c                    SnU R                   R                  5        H(  nUR                  SL a  M  UR                  c  M#  US-  nM*     U$ )a  
Return the number of non-dead sites, excluding the None site.  This does not
unwrap weakrefs for performance.

>>> a = note.Note()
>>> a.sites.getSiteCount()
0
>>> s = stream.Stream()
>>> s.append(a)
>>> a.sites.getSiteCount()
1
>>> sf = s.flatten()
>>> a.sites.getSiteCount()
2
r   Tru   )rR   valuesr   r   )r#   countrl   s      r   r   Sites.getSiteCount  sN      }}++-G~~%""*QJE . r   c                H    [        U R                  R                  5       5      $ )z
Return a set of all site Ids.

>>> class Mock(base.Music21Object):
...     pass
>>> aSite = Mock()
>>> dc = sites.Sites()
>>> dc.add(aSite)
>>> dc.getSiteIds() == {None, id(aSite)}
True
)setrR   r   r"   s    r   
getSiteIdsSites.getSiteIds  s     4==%%'((r   c                (   / n[        U[        5      (       d  [        R                  " U5      nU R                  R                  5        HF  nUR                  (       a  M  UR                  nXA:X  d  M)  UR                  nUR                  U5        MH     U$ )a  
Return a list of unwrapped site from siteDict.site [SiteRef.site]
(generally a Stream)
that matches the provided class.

Input can be either a Class object or a string

>>> class Mock(base.Music21Object):
...     pass
>>> aObj = Mock()
>>> bObj = Mock()
>>> cObj = stream.Stream()
>>> aSites = sites.Sites()

>>> aSites.add(aObj)
>>> aSites.add(bObj)
>>> aSites.add(cObj)

>>> aSites.getSitesByClass(Mock) == [aObj, bObj]
True

>>> aSites.getSitesByClass('Stream') == [cObj]
True
)
r   r;   r   classToClassStrrR   r   r   r   r*   append)r#   r   foundrl   classStrobjRefs         r   getSitesByClassSites.getSitesByClass  st    2 )S))..y9I}}++-G~~**H$ V$ . r   c                    XR                   ;   $ )aw  
Return True or False if this Sites object already has this site id.

>>> class Mock(base.Music21Object):
...     pass
>>> aSite = Mock()
>>> bSite = Mock()
>>> dc = sites.Sites()
>>> dc.add(aSite)
>>> dc.hasSiteId(id(aSite))
True
>>> dc.hasSiteId(id(bSite))
False

Note that we use 'None' not id(None) as a key:

>>> dc.hasSiteId(id(None))
False
>>> dc.hasSiteId(None)
True
)rR   )r#   r   s     r   	hasSiteIdSites.hasSiteId%  s    , &&r   c                    U R                   R                  5        H(  nUR                  (       a  M  UR                  S:X  d  M(    g   g)z
Return True if this object is found in any Spanner. This is determined
by looking for a SpannerStorage Stream class as a Site.
SpannerStorageTFrR   r   r   r   r#   rl   s     r   hasSpannerSiteSites.hasSpannerSite=  <    
 }}++-G~~""&66	 .
 r   c                    U R                   R                  5        H(  nUR                  (       a  M  UR                  S:X  d  M(    g   g)z
Return True if this object is found in any Variant. This is determined
by looking for a VariantStorage Stream class as a Site.
VariantStorageTFr   r   s     r   hasVariantSiteSites.hasVariantSiteI  r   r   c                l   U(       aF  U R                    H6  nUc  M  U R                   U   nUR                  nUc	  SUl        M/  SUl        M8     / nU R                    H;  nUc  M  U R                   U   nUR                  (       d  M*  UR                  U5        M=     U H  nU R	                  U5        M     g)a  
Clean all locations that refer to objects that no longer exist.

The `removeOrphanedSites` option removes sites that may have been the
result of deepcopy: the element has the site, but the site does not
have the element. This results b/c Sites are shallow-copied, and then
elements are re-added.

>>> import gc
>>> class Mock(base.Music21Object):
...     pass
>>> aStream = stream.Stream()
>>> bStream = stream.Stream()
>>> mySites = sites.Sites()
>>> len(mySites)
1
>>> mySites.add(aStream)
>>> mySites.add(bStream)
>>> del aStream
>>> numObjectsCollected = gc.collect()  # make sure to garbage collect

We still have 3 locations -- just because aStream is gone, doesn't
make it disappear from sites

>>> len(mySites)
3

>>> mySites.purgeLocations(rescanIsDead=True)
>>> len(mySites)
2
NTF)rR   r*   r   r   
removeById)r#   rescanIsDeadr^   rl   rw   removes         r   purgeLocationsSites.purgeLocationsU  s    B =--.ll;%)GN%*GN ' ]]E}mmE*G~~~e$ # E OOE" r   c                    SU l         SnUb  [        U5      n U R                  U	 g! [         a  n[	        SSU S3-   5      UeSnAff = f)a  
Remove the object (a context or location site) specified from Sites.
Object provided can be a location site (i.e., a Stream) or a pure
context (like a Temperament).

N.B. -- like all .sites operations, this is an advanced tool not for
standard music21 usage.  Instead of:

    elObj.remove(streamObj)

use this command, which will take care of `.sites.remove` as well as
removing `elObj` from `streamObj.elements`:

    streamObj.remove(elObj)

>>> class Mock(base.Music21Object):
...     pass
>>> aSite = Mock()
>>> bSite = Mock()
>>> cSite = Mock()
>>> aSites = sites.Sites()
>>> len(aSites)
1
>>> aSites.add(aSite)
>>> len(aSites)
2

>>> aSites.add(bSite)
>>> len(aSites)
3

>>> aSites.add(cSite)
>>> len(aSites)
4

>>> aSites.remove(aSite)
>>> len(aSites)
3

rV   Nzan entry for this object (z$) is not stored in this Sites object)rS   r<   rR   	Exceptionr   )r#   r*   r   es       r   r   Sites.remove  sk    T XF	f%  	 +dV?@A 	s   ' 
A	AA	c                    XR                   :X  a  SU l         Uc  [        S5      e U R                  U	 g! [         a     gf = f)z=
Remove a site entry by id key,
which is id() of the object.
rV   Nz*trying to remove None idKey is not allowed)rS   r   rR   rH   )r#   r^   s     r   r   Sites.removeById  sI     LL DL= !MNN	e$ 		s   4 
A Ac                    U R                  5        H   nUc  M   [        X15      n[        X1U5        M"     g! [         a     M2  f = f)a  
Given an attribute name, search all objects and find the first that
matches this attribute name; then return a reference to this attribute.

>>> class Mock(base.Music21Object):
...     attr1 = 234
>>> aObj = Mock()
>>> bObj = Mock()
>>> bObj.attr1 = 98
>>> aSites = sites.Sites()
>>> aSites.add(aObj)
>>> aSites.add(bObj)
>>> aSites.setAttrByName('attr1', 'test')
>>> aSites.getAttrByName('attr1') == 'test'
True
N)r   r   setattrr   )r#   r   valuerw   junks        r   setAttrByNameSites.setAttrByName  sI    $ 88:C{s-u-  " s   6
AA)rS   rT   rR   r   )NNN)rp   zt.Literal[True]r   #t.Union[bool, t.Literal['reverse']]returnz$Generator[stream.Stream, None, None])rp   boolr   r   r   z+Generator[stream.Stream | None, None, None])F)"r   r   r   r   rK   rL   r$   rb   rf   rm   rr   r{   r~   r   rq   r   r   r   enumsElementSearchAT_OR_BEFOREr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rP   rP      sW   	I	:x"".1$7+r  NS"&	 / (K
 =   (-MR"&	 $ (K
 B  (-MR"&	T $T (KT
 BTp  %	6p*`  33@@ob2)$L'0

8#t7r$r   rP   c                      \ rS rSrS rSrg)Testi  c                   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR
                  " 5       nSUl        UR                  5       nUR                  U5        UR                  5       nUR                  R                  U5        UR                  5       nUR                  R                  U5        U R                  UR                  R                  S5      S5        UR                  R                  S[        UR                  R                  S5      5      5        U R                  UR                   S	5        UR                  R                  SUR                  R                  S5      5        U R                  UR                   S	5        UR#                  S
SSS9R%                  S5      n	U	R'                  5       R(                  S   n
U
R+                  UR                  5      nU R-                  XR.                  5        g )Nr   )noter
   )corpus)clef"   numberlyric34zbeethoven/opus18no1   )xml)fileExtensionszViolin IrV   )music21r   r   r   r   Measurer   Noter   r   r{   ClefassertEqualr   r   r;   r   parsegetElementByIdflattennotesr   assertIsInstance
TrebleClef)r#   r   r   r   r   mnn2cviolin1lastNotelastNoteClefs               r   	testSitesTest.testSites  sg    "" NNIIK	YY[
QIIK	A//92>	gs288+A+A(+K'LM$'	grxx'='=h'GH$',,!#  
 .
$	 	
 ??$**2.11$))<lOO<r   r   N)r   r   r   r   r  r   r   r   r   r   r     s    =r   r   __main__)&rK   
__future__r   rW   collections.abcr   r   typingtr   unittestweakrefr   r   r   r	   TYPE_CHECKINGr   r0   WeakValueDictionaryr   __annotations__Music21Exceptionr   r?   ProtoM21Objectr   r(   r   r   SingletonCounterr=   rP   TestCaser   
_DOC_ORDERr   mainTestr   r   r   <module>r     s    #  5         ??  ;B:U:U:W 7 W	\22 	s$f'')?)? s$l y!  ++- F%% D =8  =H u
 zT r   