
    3j^                       U d Z ddlmZ ddlZddlmZmZ ddlZ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 ej                   rdd	lmZ d
Z ej&                         Zded<    G d dej,                        Z G d dej0                  ej2                        Z e       Zde_        de_         ej<                         Z G d dej0                        Z  G d de
jB                        Z"ee gZ#e$dk(  rddlZ ejJ                  e"       yy)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                      e Zd Zy)SitesExceptionN)__name__
__module____qualname__     :/DATA/.local/lib/python3.12/site-packages/music21/sites.pyr   r   0   s    r   r   c                  J    e Zd ZdZdZd Zd Zd Zd Z e	ee      Z
d Zd Zy	)
SiteRefa  
    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    d| _         d | _        d | _        d | _        d | _        y NF)r   r   r   r   r   selfs    r   __init__zSiteRef.__init__d   s(    #r   c                    | t         u ryt        | j                        }| j                  rd}| j                   d| j
                   d| S )NzGlobal None Indexz	dead site/z to )_NoneSiteRefreprsiter   r   r   )r   siteReprs     r   _reprInternalzSiteRef._reprInternalk   sI    <&		?;;"H..!4#7#7"8XJGGr   c                    t         r t        j                  | j                        }n| j                  }|| t        urd| _        |S NT)WEAKREF_ACTIVEr   unwrapWeakrefr   r#   r   )r   rets     r   _getAndUnwrapSitezSiteRef._getAndUnwrapSiteu   s>    &&t'7'78C""C;4|3DK
r   c                p    t         r"t        j                  |      | _        d| _        y || _        d| _        y r   )r*   r   wrapWeakrefr   r   )r   r%   s     r   _setAndWrapSitezSiteRef._setAndWrapSite   s2    %11$7D   $Dr   c                V   d }t         rR| j                  }|d | _        n<t        t	        |            dz   t        t                     z   }	 |t        |<   || _        t        j                  j                  |       }t         r	||| _        |S # t        $ r}t        d|       |d }~ww xY w)N_z This str screwed up everything: )r*   r%   r   strid_singletonCounterr   	TypeErrorr   SlottedObjectMixin__getstate__)r   currentSitesiteIdValuetereturnStates        r   r8   zSiteRef.__getstate__   s    ))K"#' !"[/2S83?P?R;SS:E*;7
 $/ //<<TBk5#DI ! #:;-Hs   	B 	B(B##B(c                    t         j                  j                  | |       t        r2| j                  %| j                  }	 t
        |   }t
        |= || _        y y y # t        $ r d }d| _        Y w xY wr)   )	r   r7   __setstate__r*   r   r   KeyErrorr   r%   )r   stater:   r9   s       r   r>   zSiteRef.__setstate__   su    !!..tU;d..:**K#4[A*;7 $DI ;>
  #""#s    A A/.A/N)r   r   r   __doc__	__slots__r    r'   r-   r0   propertyr%   r8   r>   r   r   r   r   r   6   s=    !HI H	 %7D*
$r   r   c                  R   e Zd ZdZdZd Zd!dZd Zd Zd Z	d"d	Z
d
 Zeddd	 	 	 	 	 d#d       Zedddd	 	 	 	 	 d$d       Zdddd	 	 	 	 	 d$dZdddddZd Zdddej"                  j$                  j&                  dddZd Zd Zd Zd Zd Zd Zd Zd%dZd Zd Zd  Zy)&Sitesa|  
    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                b    t        j                  d t        fg      | _        d| _        d| _        y )Nr   )collectionsOrderedDictr#   rG   rI   rH   r   s    r   r    zSites.__init__   s.    #//$1E0HI  r   Nc                   | j                         }| j                  D ]  }|| j                  |   }|j                  r"t               }|j                  |_        |j                  d}nt        |j                        }|j                  |_        t               |_        |j                  |_	        d|_        ||j                  |<    | j                  |_
        |S )av  
        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__rG   r   r   r%   r4   r   r5   r   r   rI   )r   memonewidKeyoldSitenewSitenewIdKeys          r   __deepcopy__zSites.__deepcopy__   s    < nn ]]E}mmE*G~~iG"<<GL||#gll+ ' 1 1G&7&9G#")"5"5G"GN
 &-CLL") #, 
r   c                ,    t        | j                        S )a%  
        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

        )lenrG   r   s    r   __len__zSites.__len__  s     4==!!r   c                h    | j                   j                         D ]  \  }}|j                  |u s y y)aY  
        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)rG   itemsr%   )r   	checkSiteunused_siteRefIdsiteRefs       r   __contains__zSites.__contains__   s5    $ *.)<)<)>%g||y( *? r   c                &    | j                  d      S )a  
        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__zSites.__iter__7  s     400r   c                   |t        d      ||t        |      }d}|| j                  v r+| j                  |   }|j                  du r|j                  d}|||j
                  d   }|du r| j                  |   }d|_        n
t               }||_        ||_        | j                  |_	        | xj                  dz  c_        t               |_        |s|| j                  |<   yy)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   r4   rG   r   r%   classesr   r   rI   r   r5   r   )r   obj	timeValuerR   r   updateNotAddtempSiteRefr^   s           r   addz	Sites.addI  s       !ABB
 =S_sGEDMM!--.K""e+#((4# ?{2++a.K4mmE*G"GNiG) !OO1"3"5#*DMM%  r   c                T    t        j                  dt        fg      | _        d| _        y)z(
        Clear all stored data.
        NrK   )rL   rM   r#   rG   rH   r   s    r   clearzSites.clear  s%     $//$1E0HIr   F)sortByCreationTimepriorityTargetc                    y Nr   r   ra   rn   ro   s       r   rb   zSites.yieldSites       	r   )ra   rn   ro   c                    y rq   r   rr   s       r   rb   zSites.yieldSites  rs   r   c             #    K   t        | j                  j                               }|du r|j                          |?t	        |      }||v r0|j                  d|j                  |j                  |                   |D ]I  }| j                  |   }|j                  |r!|j                   0|j                  }|d|_	        F| K yw)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   )
listrG   keysreverser4   insertpopindexr%   r   )	r   ra   rn   ro   keyRepository
priorityIdkeyr^   rg   s	            r   rb   zSites.yieldSites  s     x T]]//12%!!#%N+J]* $$Q%2%6%6}7J7J:7V%WY !CmmC(G||#"!,,&ll;%)GNI !s   BC
,C
rn   ro   ra   c                   t        | j                  |||            }|4||v r0|j                  d|j                  |j	                  |                   |S )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   )rv   rb   ry   rz   r{   )r   rn   ro   ra   posts        r   getz	Sites.get  s_    V DOO7I3A0; $ = > %% Atxx

>(BCDr   c                z    d}| j                  d      D ]  }|	 t        ||      }|c S  y# t        $ r Y $w xY w)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

        Nrx   )rn   )rb   getattrAttributeError)r   attrNamer   rg   s       r   getAttrByNamezSites.getAttrByName,  sR    D ??i?@C{sH- A " s   .	::)callerFirstrn   ro   getElementMethodrP   c                  || }|i }d}| j                  ||d      }t        |t              }	|D ]'  }
|	r||
j                  v s|
} nt        |
|      s%|
} n ||S |D ]v  }
|	r=|
j                  r1|
j
                  j                         dk(  r|
j                  |d      sBt        |
      |vsP|
|t        |
      <   |
j                  |||      }|u |S  |S )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)rn   r   )
rb   
isinstancer3   rf   isFlatsitesgetSiteCounthasElementOfClassr4   getContextByClass)r   	classNamer   rn   ro   r   rP   r   objsclassNameIsStrrg   s              r   getObjByClassz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    | j                   |   }|j                  S )a  
        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
        )rG   r%   )r   siteIdr^   s      r   getByIdzSites.getById  s     --'||r   c                    d}| j                   j                         D ]#  }|j                  du r|j                  |dz  }% |S )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   Tre   )rG   valuesr   r   )r   countr^   s      r   r   zSites.getSiteCount  sN      }}++-G~~%""*QJE . r   c                H    t        | j                  j                               S )a  
        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
        )setrG   rw   r   s    r   
getSiteIdszSites.getSiteIds  s     4==%%'((r   c                
   g }t        |t              st        j                  |      }| j                  j                         D ]>  }|j                  r|j                  }||k(  s"|j                  }|j                  |       @ |S )aq  
        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   r3   r   classToClassStrrG   r   r   r   r%   append)r   r   foundr^   classStrobjRefs         r   getSitesByClasszSites.getSitesByClass  ss    2 )S)..y9I}}++-G~~**H9$ V$ . r   c                    || j                   v S )a  
        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
        )rG   )r   r   s     r   	hasSiteIdzSites.hasSiteId)  s    , &&r   c                ~    | j                   j                         D ]   }|j                  r|j                  dk(  s  y y)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rG   r   r   r   r   r^   s     r   hasSpannerSitezSites.hasSpannerSiteA  <    
 }}++-G~~""&66	 .
 r   c                ~    | j                   j                         D ]   }|j                  r|j                  dk(  s  y y)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   hasVariantSitezSites.hasVariantSiteM  r   r   c                >   |r@| j                   D ]1  }|| j                   |   }|j                  }|d|_        +d|_        3 g }| j                   D ]2  }|| j                   |   }|j                  s"|j                  |       4 |D ]  }| j	                  |        y)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)rG   r%   r   r   
removeById)r   rescanIsDeadrR   r^   rg   removes         r   purgeLocationszSites.purgeLocationsY  s    B =--.ll;%)GN%*GN ' ]]E}mmE*G~~e$ # E OOE" r   c                    d| _         d}|t        |      }	 | j                  |= y# t        $ r}t	        d| d      |d}~ww xY w)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

        rK   Nzan entry for this object (z$) is not stored in this Sites object)rH   r4   rG   	Exceptionr   )r   r%   r   es       r   r   zSites.remove  sg    T XF	f%  	 6=? 	s   & 	A?Ac                    || j                   k(  rd| _         |t        d      	 | j                  |= y# t        $ r Y yw xY w)zU
        Remove a site entry by id key,
        which is id() of the object.
        rK   Nz*trying to remove None idKey is not allowed)rH   r   rG   r?   )r   rR   s     r   r   zSites.removeById  sK     DLL DL= !MNN	e$ 		s   3 	??c                    | j                         D ]  }|	 t        ||      }t        |||       ! y# t        $ r Y .w xY w)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   valuerg   junks        r   setAttrByNamezSites.setAttrByName  sM    $ 88:C{sH-Xu-  " s   4	A A rq   )NNN)ra   zt.Literal[True]rn   bool | t.Literal['reverse']returnz$Generator[stream.Stream, None, None])ra   boolrn   r   r   z+Generator[stream.Stream | None, None, None])F) r   r   r   rA   rB   r    rV   rY   r_   rc   rk   rm   r   rb   r   r   r   enumsElementSearchAT_OR_BEFOREr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rF   rF      sW   	I	8t"".1$:+x  DI"&	 / (A
 =   (-CH"&	 $ (A
 B  (-CH"&	T $T (AT
 BTp  %	6p*`  33@@sj2)$L'0

8#t7r$r   rF   c                      e Zd Zd Zy)Testc                   ddl m} ddl m} ddl m} ddl m}  |j
                         }d|_        |j                         }|j                  |       |j                         }|j                  j                  |       |j                         }|j                  j                  |       | j                  |j                  j                  d      d       |j                  j                  dt        |j                  j                  d                   | j                  |j                   d	       |j                  j                  d|j                  j                  d             | j                  |j                   d	       |j#                  d
dd      j%                  d      }	|	j'                         j(                  d   }
|
j+                  |j                        }| j-                  ||j.                         y )Nr   )noter
   )corpus)clef"   numberlyric34zbeethoven/opus18no1   )xml)fileExtensionszViolin IrK   )music21r   r   r   r   Measurer   Noter   r   rk   ClefassertEqualr   r   r3   r   parsegetElementByIdflattennotesr   assertIsInstance
TrebleClef)r   r   r   r   r   mnn2cviolin1lastNotelastNoteClefs               r   	testSiteszTest.testSites  sk    "" FNNIIK	YY[
QIIK	A//92>	gs288+A+A(+K'LM$'	grxx'='=h'GH$',,!#  
 .
$	 	
 ??$**2.11$))<lDOO<r   N)r   r   r   r   r   r   r   r   r     s    =r   r   __main__)&rA   
__future__r   rL   collections.abcr   r   typingtr   unittestweakrefr   r   r   r	   TYPE_CHECKINGr   r*   WeakValueDictionaryr   __annotations__Music21Exceptionr   r7   ProtoM21Objectr   r#   r   r   SingletonCounterr5   rF   TestCaser   
_DOC_ORDERr   mainTestr   r   r   <module>r      s   #  5         ??  ;V':U:U:W 7 W	\22 	s$f'')?)? s$l y!  +F++- DF%% DN =8  =H u
 zGT r   