
    rh1.                   $   S r SSKJr  SSKJrJrJr  SSK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Jr  SSKJr  SS	KJrJrJ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!  \	RD                  " S5      r#\	RD                  " S5      r$\	RD                  " SSS9r%\	RL                  \\	RN                  \	RP                  \	RN                     /\	RN                  4   \RR                  4   r* " S S\+5      r, " S S\	RZ                  SS9r. " S S\R^                  \\   5      r0 " S S\0\\1\      5      r2 " S S\0\   \\   5      r3 " S  S!\Rh                  5      r5\0\3\2/r6\7S":X  a  SSKr\Rp                  " \55        gg)#z
this class contains iterators and filters for walking through streams

StreamIterators are explicitly allowed to access private methods on streams.
    )annotations)CallableIterableSequenceN)overload)common)tempAttributesaveAttributes)OffsetSpecial)
M21ObjType
StreamTypeChangedM21ObjType)note)filters)prebase)base)SitesExceptionstreamTSStreamIteratorTypeStreamIterator)boundc                      \ rS rSrSrg) StreamIteratorInefficientWarning2    N)__name__
__module____qualname____firstlineno____static_attributes__r       Q/home/james-whalen/.local/lib/python3.13/site-packages/music21/stream/iterator.pyr   r   2   s    r$   r   c                  H    \ rS rSr% S\S'   S\S'   S\S'   S\S'   S	\S
'   Srg)ActiveInformation6   zstreamModule.Stream | Noner   intelementIndex&t.Literal['_elements', '_endElements']iterSectionsectionIndexzbase.Music21Object | NonelastYieldedr   N)r   r    r!   r"   __annotations__r#   r   r$   r%   r'   r'   6   s     $$77((r$   r'   F)totalc                  $   \ rS rSrSrSSSSS.         S7S jjrS rS8S	 jrS9S
 jrS r	\
S:S j5       r\
S;S j5       r\
S<S j5       rS=S jrS>S jrS?S jrS rS rS8S jrS@S jrS@S jrSAS jrSAS jrSAS jrSAS jrSS.   SBS jjrSCS jrSDS jr\
SES j5       r\
SFSGS  jj5       r SF   SHS! jjr\SIS" j5       rSS#.   S8S$ jjrSS#.   S8S% jjrSJS& jr\
SS#.     SKS' jj5       r \
SS#.     SLS( jj5       r \
SS#.     SMS) jj5       r \
SS#.     SNS* jj5       r SS#.     SOS+ jjr SS#.SPS, jjr!SS#.S- jr"SS#.S. jr# SQSSSSSSS/.   S8S0 jjjr$\S1 5       r%\S2 5       r&\S3 5       r'\S4 5       r(\S5 5       r)S6r*g)Rr   ?   a
  
An Iterator object used to handle getting items from Streams.
The :meth:`~music21.stream.Stream.__iter__` method
returns this object, passing a reference to self.

Note that this iterator automatically sets the active site of
returned elements to the source Stream.

There is one property to know about: .overrideDerivation which overrides the set
derivation of the class when .stream() is called

Sets:

* StreamIterator.srcStream -- the Stream iterated over
* StreamIterator.elementIndex -- current index item
* StreamIterator.streamLength -- length of elements.

* StreamIterator.srcStreamElements -- srcStream._elements
* StreamIterator.cleanupOnStop -- should the StreamIterator delete the
  reference to srcStream and srcStreamElements when stopping? default
  False -- DEPRECATED: to be removed in v10.
* StreamIterator.activeInformation -- a dict that contains information
  about where we are in the parse.  Especially useful for recursive
  streams:

      * `stream` = the stream that is currently active,
      * `elementIndex` = where in `.elements` we are,
      * `iterSection` is `_elements` or `_endElements`,
      * `sectionIndex` is where we are in the iterSection, or -1 if
        we have not started.
      * `lastYielded` the element that was last returned by the iterator.
        (for OffsetIterators, contains the first element last returned)
      * (This dict is shared among all sub iterators.)

Constructor keyword-only arguments:

* `filterList` is a list of stream.filters.Filter objects to apply

* if `restoreActiveSites` is True (default), then on iterating, the activeSite is set
  to the Stream being iterated over.

* if `ignoreSorting` is True (default is False) then the Stream is not sorted before
  iterating.  If the Stream is already sorted, then this value does not matter, and
  no time will be saved by setting to False.

* For `activeInformation` see above.

* Changed in v5.2: all arguments except srcStream are keyword only.
* Changed in v8:
  - filterList must be a list or None, not a single filter.
  - StreamIterator inherits from typing.Sequence, hence index
  was moved to elementIndex.
* Changed in v9: cleanupOnStop is deprecated.  Was not working properly before: noone noticed.

OMIT_FROM_DOCS

Informative exception for user error:

>>> s = stream.Stream()
>>> sIter = stream.iterator.StreamIterator(s, filterList=[note.Note])
Traceback (most recent call last):
TypeError: filterList expects Filters or callables,
not types themselves; got <class 'music21.note.Note'>

THIS IS IN OMIT -- Add info above.
NTF
filterListrestoreActiveSitesactiveInformationignoreSortingc               ~   U(       d0  UR                   SL a!  UR                  (       a  UR                  5         Xl        SU l        [
        R                  " [        [        S4   UR                  5      U l
        [        U R                  5      U l        [        U R                  R                  5      U l        SU l        SU l        SU l        X0l        S U l        Uc  / nU H&  n[)        U[*        5      (       d  M  [-        SU 35      e   X l        S U l        0 U l        Ub  X@l        g 0 U l        U R7                  5         g )NFr   .	_elementszCfilterList expects Filters or callables, not types themselves; got )isSortedautoSortsort	srcStreamr*   tcasttupler   elementssrcStreamElementslenstreamLengthr:   elementsLengthr-   r,   cleanupOnStopr5   overrideDerivation
isinstancetype	TypeErrorr   _len_matchingElementsr6   updateActiveInformation)selfr>   r4   r5   r6   r7   xs          r%   __init__StreamIterator.__init__   s     !3!3u!<ASASNN%.!" "#j#o(>	@R@R!S!$T%;%;!< $'t~~'?'?#@ "$CN#((:,0JA!T""YZ[Y\]_ _  *4"	DF (8I"%'D"((*r$   c                \   U R                   R                  R                  nU R                   R                  n[	        U[
        5      (       a  [        U5      nUS:X  a<  U R                   R                  S:w  a"  S[        U R                   R                  5      -   nSU SU SU R                   3$ )NMeasurer   zm.zfor :z @:)
r>   	__class__r   idrI   r)   hexnumberstrr*   )rO   streamClasssrcStreamIds      r%   _reprInternalStreamIterator._reprInternal   s    nn..77nn''k3''k*K)#(=(=(BT^^%:%:!;;Kk]!K=D4E4E3FGGr$   c                &    U R                  5         U $ N)resetrO   s    r%   __iter__StreamIterator.__iter__   s    

r$   c                p   U R                   U R                  :  a  U R                   U R                  :  a&  SU l        U R                   U R                  -
  U l        OU R                   U l         U R
                  U R                      nU =R                   S-  sl         U R                  U5      SL a  M  U R                  SL a  U R                  R                  U5        U R                  5         XR                  S'   U$ U R                  5         [        e! [         a    U =R                   S-  sl          GM3  f = f)N_endElements   FTr.   )r*   rE   rF   r,   r-   rC   
IndexErrormatchesFiltersr5   r>   coreSelfActiveSiterN   r6   cleanupStopIteration)rO   es     r%   __next__StreamIterator.__next__   s   $"3"33  D$7$77#1 $($5$58K8K$K!$($5$5!**4+<+<= """1%.&&$.11!4((*45""=1H#  !!Q&!s   -D D54D5c                   US:X  a  g[        U R                  U5      (       d&  [        U R                  R                  < SU< 35      e[
        R                  " US-   [        SS9  U R                  5       n[        X!5      $ )a
  
DEPRECATED in v8 -- will be removed in v9.

In case an attribute is defined on Stream but not on a StreamIterator,
create a Stream and then return that attribute.  This is NOT performance
optimized -- calling this repeatedly will mean creating a lot of different
streams.  However, it will prevent most code that worked on v2. from breaking
on v3 and onwards.

Deprecated in v8. The upgrade path is to just call `.stream()` on the iterator
before accessing the attribute.

>>> s = stream.Measure()
>>> s.insert(0, note.Rest())
>>> s.repeatAppend(note.Note('C'), 2)

>>> s.definesExplicitSystemBreaks
False

>>> s.notes
<music21.stream.iterator.StreamIterator for Measure:0x101c1a208 @:0>

>>> import warnings  #_DOCS_HIDE
>>> with warnings.catch_warnings(): #_DOCS_HIDE
...      warnings.simplefilter('ignore') #_DOCS_HIDE
...      explicit = s.notes.definesExplicitSystemBreaks #_DOCS_HIDE
>>> #_DOCS_SHOW explicit = s.notes.definesExplicitSystemBreaks
>>> explicit
False

Works with methods as well:

>>> with warnings.catch_warnings(): #_DOCS_HIDE
...      warnings.simplefilter('ignore') #_DOCS_HIDE
...      popC = s.notes.pop(0) #_DOCS_HIDE
>>> #_DOCS_SHOW popC = s.notes.pop(0)
>>> popC
<music21.note.Note C>

But remember that a new Stream is being created each time that an attribute
only defined on a Stream is called, so for instance, so you can pop() forever,
always getting the same element.

>>> with warnings.catch_warnings(): #_DOCS_HIDE
...      warnings.simplefilter('ignore') #_DOCS_HIDE
...      popC = s.notes.pop(0) #_DOCS_HIDE
>>> #_DOCS_SHOW popC = s.notes.pop(0)
>>> popC
<music21.note.Note C>
>>> with warnings.catch_warnings(): #_DOCS_HIDE
...      warnings.simplefilter('ignore') #_DOCS_HIDE
...      popC = s.notes.pop(0) #_DOCS_HIDE
>>> #_DOCS_SHOW popC = s.notes.pop(0)
>>> popC
<music21.note.Note C>
>>> with warnings.catch_warnings(): #_DOCS_HIDE
...      warnings.simplefilter('ignore') #_DOCS_HIDE
...      popC = s.notes.pop(0) #_DOCS_HIDE
>>> #_DOCS_SHOW popC = s.notes.pop(0)
>>> popC
<music21.note.Note C>

If run with -w, this call will send a StreamIteratorInefficientWarning to stderr
reminding developers that this is not an efficient call, and .stream() should be
called (and probably cached) explicitly.

Failures are explicitly given as coming from the StreamIterator object.

>>> s.asdf
Traceback (most recent call last):
AttributeError: 'Measure' object has no attribute 'asdf'
>>> s.notes.asdf
Traceback (most recent call last):
AttributeError: 'StreamIterator' object has no attribute 'asdf'

OMIT_FROM_DOCS

srcStream is accessible, but not with "__getattr__", which joblib uses

>>> s.notes.srcStream is s
True
>>> s.notes.__getattr__('srcStream') is None
True
r>   Nz object has no attribute zG is not defined on StreamIterators. Call .stream() first for efficiency   )
stacklevel)
hasattrr>   AttributeErrorrV   r   warningswarnr   r   getattr)rO   attrsOuts      r%   __getattr__StreamIterator.__getattr__   sx    n ;t~~t,, DNN$;$;#>>WX\W_!`aa\\,	
 {{}t""r$   c                    g r`   r   rO   ks     r%   __getitem__StreamIterator.__getitem__F      r$   c                    g r`   r   r}   s     r%   r   r   J  r   r$   c                    g r`   r   r}   s     r%   r   r   N  r   r$   c                X   U R                  5       n[        U[        5      (       a  UR                  S5      (       a  USS nU HT  n[        UR                  [        5      (       d  M$  UR                  R                  5       UR                  5       :X  d  MR  Us  $    [        U5      eX!   nU$ )aa  
Iterators can request other items by index or slice.

>>> s = stream.Stream()
>>> s.insert(0, note.Note('F#'))
>>> s.repeatAppend(note.Note('C'), 2)
>>> sI = s.iter()
>>> sI
<music21.stream.iterator.StreamIterator for Stream:0x104743be0 @:0>

>>> sI.srcStream is s
True

>>> for n in sI:
...    printer = (repr(n), repr(sI[0]))
...    print(printer)
('<music21.note.Note F#>', '<music21.note.Note F#>')
('<music21.note.Note C>', '<music21.note.Note F#>')
('<music21.note.Note C>', '<music21.note.Note F#>')
>>> sI.srcStream is s
True


To request an element by id, put a '#' sign in front of the id,
like in HTML DOM queries:

>>> bach = corpus.parse('bwv66.6')
>>> soprano = bach.recurse()['#Soprano']
>>> soprano
<music21.stream.Part Soprano>

This behavior is often used to get an element from the Parts iterator:

>>> bach.parts['#soprano']  # notice: case-insensitive retrieval
<music21.stream.Part Soprano>

Slices work:

>>> nSlice = sI[1:]
>>> for n in nSlice:
...     print(n)
<music21.note.Note C>
<music21.note.Note C>

Filters, such as "notes" apply.

>>> s.insert(0, clef.TrebleClef())
>>> s[0]
<music21.clef.TrebleClef>
>>> s.iter().notes[0]
<music21.note.Note F#>

Demo of cleanupOnStop = True; the sI[0] call counts as another iteration, so
after it is called, there is nothing more to iterate over!  Note that cleanupOnStop
will be removed in music21 v10.

>>> sI.cleanupOnStop = True
>>> for n in sI:
...    printer = (repr(n), repr(sI[0]))
...    print(printer)
('<music21.note.Note F#>', '<music21.note.Note F#>')
>>> sI.srcStream is s  # set to an empty stream
False
>>> for n in sI:
...    printer = (repr(n), repr(sI[0]))
...    print(printer)

(nothing is printed)

* Changed in v8: for strings: prepend a '#' sign to get elements by id.
  The old behavior still works until v9.
  This is an attempt to unify __getitem__ behavior in
  StreamIterators and Streams.
#rg   N)matchingElementsrI   rZ   
startswithrW   lowerKeyError)rO   r~   feelrm   s        r%   r   r   R  s    V ""$a||C  abEbeeS))beekkmqwwy.HI  1+Er$   c                    U R                   b  U R                   $ [        U R                  SS95      nXl         U R                  5         U$ )a  
returns the length of the elements that
match the filter set.

>>> s = converter.parse('tinynotation: 3/4 c4 d e f g a', makeNotation=False)
>>> len(s)
7
>>> len(s.iter())
7
>>> len(s.iter().notes)
6
>>> [n.name for n in s.iter().notes]
['C', 'D', 'E', 'F', 'G', 'A']
Fr5   )rL   rD   r   ra   )rO   lenMatchings     r%   __len__StreamIterator.__len__  sD     99 99$//5/IJ	

r$   c                    U R                   b  [        U R                   5      $ [        U SS5         U  H  n  SSS5        g   SSS5        g! , (       d  f       g= f)a  
return True if anything matches the filter
otherwise, return False

>>> s = converter.parse('tinyNotation: 2/4 c4 r4')
>>> bool(s)
True
>>> iterator = s.recurse()
>>> bool(iterator)
True
>>> bool(iterator.notesAndRests)
True
>>> bool(iterator.notes)
True

test cache

>>> len(iterator.notes)
1
>>> bool(iterator.notes)
True
>>> bool(iterator.notes)
True

>>> iterator = s.recurse()
>>> bool(iterator)
True
>>> bool(iterator)
True
>>> bool(iterator)
True

>>> bool(iterator.getElementsByClass(chord.Chord))
False

test false cache:

>>> len(iterator.getElementsByClass(chord.Chord))
0
>>> bool(iterator.getElementsByClass(chord.Chord))
False

Nr5   FT)rL   boolr	   )rO   _s     r%   __bool__StreamIterator.__bool__  sW    X 99 		?" 4!5u= >= > 	 >= s   A A
Ac                $    XR                  SS9;   $ )zA
Does the iterator contain `item`?  Needed for AbstractBaseClass
Fr   r   )rO   items     r%   __contains__StreamIterator.__contains__  s     ,,,FFFr$   c              #  d   #    U R                  5       nUR                  5         U S h  vN   g  N7fr`   )r   reverse)rO   mes     r%   __reversed__StreamIterator.__reversed__  s#     ""$


s   &0.0c                    [        U 5      " U R                  [        R                  " U R                  5      U R                  [        R                  " U R
                  5      S9nU$ )zc
Returns a new copy of the same iterator.
(a shallow copy of some things except activeInformation)
)r4   r5   r6   )rJ   r>   copyr   r5   r6   )rO   outs     r%   cloneStreamIterator.clone  sK    
 #'t*NNyy.#66"ii(>(>?	#
 
r$   c                P    [        U 5         [        U 5      $ ! [         a     gf = f)a  
Efficiently return the first matching element, or None if no
elements match.

Does not require creating the whole list of matching elements.

>>> s = converter.parse('tinyNotation: 3/4 D4 E2 F4 r2 G2 r4')
>>> s.recurse().notes.first()
<music21.note.Note D>
>>> s[note.Rest].first()
<music21.note.Rest half>

If no elements match, returns None:

>>> print(s[chord.Chord].first())
None

* New in v7.

OMIT_FROM_DOCS

Ensure that next continues after the first note running:

>>> notes = s.recurse().notes
>>> notes.first()
<music21.note.Note D>
>>> next(notes)
<music21.note.Note E>

Now reset on new iteration:

>>> for n in notes:
...     print(n)
<music21.note.Note D>
<music21.note.Note E>
...

An Empty stream:

>>> s = stream.Stream()
>>> s.iter().notes.first() is None
True
N)iternextrl   rb   s    r%   firstStreamIterator.first  s-    X 	T
	: 		s   
 
%%c                <    U R                  5       nU(       d  gUS   $ )a  
Returns the last matching element, or None if no elements match.

Currently is not efficient (does not iterate backwards, for instance),
but easier than checking for an IndexError.  Might be refactored later
to iterate the stream backwards instead if it gets a lot of use.

>>> s = converter.parse('tinyNotation: 3/4 D4 E2 F4 r2 G2 r4')
>>> s.recurse().notes.last()
<music21.note.Note G>
>>> s[note.Rest].last()
<music21.note.Rest quarter>

* New in v7.

OMIT_FROM_DOCS

Check on empty Stream:

>>> s2 = stream.Stream()
>>> s2.iter().notes.last() is None
True

Next has a different feature from first(), will start again from beginning.
This behavior may change.

>>> notes = s.recurse().notes
>>> notes.last()
<music21.note.Note G>
>>> next(notes)
<music21.note.Note D>
Nr9   r   )rO   r   s     r%   lastStreamIterator.lastA  s"    B ""$"vr$   c                    U R                   nU R                  US'   U R                  S-
  US'   U R                  US'   U R                  US'   SUS'   g)zy
Updates the (shared) activeInformation dictionary
with information about where we are.

Call before any element return.
r   rg   r*   r,   r-   Nr.   )r6   r>   r*   r,   r-   )rO   ais     r%   rN   &StreamIterator.updateActiveInformationi  s[     ##~~8!..2> ,,=!..> =r$   c                    SU l         SU l        U R                  5         SU R                  S'   U R                   H4  n[        U[        R                  5      (       d  M$  UR                  5         M6     g)
reset prior to iteration
r   r:   Nr.   )r*   r,   rN   r6   r   rI   StreamFilterra   )rO   fs     r%   ra   StreamIterator.resetw  sZ     &$$&04}-A!W1122	 r$   c                     SU l         0 U l        g)z
reset any cached data. -- do not use this at
the start of iteration since we might as well
save this information. But do call it if
the filter changes.
N)rL   rM   rb   s    r%   resetCachesStreamIterator.resetCaches  s     	!#r$   c                    U R                   (       a>  U R                  5         U R                  R                  nU ?U ?U" 5       U l        SU l        gg)z)
stop iteration; and cleanup if need be.
r   N)rG   ra   r>   rV   rC   )rO   SrcStreamClasss     r%   rk   StreamIterator.cleanup  sI     JJL "^^55N&+-DN%'D" r$   r   c               $   XR                   ;   a  U R                   U   $ Uc  U R                  n[        U SS5         Xl        U  Vs/ s H  o"PM     nnU R                  5         SSS5        WU R                   U'   U$ s  snf ! , (       d  f       N$= f)a  
Returns a list of elements that match the filter.

This sort of defeats the point of using a generator, so only used if
it's requested by __len__ or __getitem__ etc.

Subclasses should override to cache anything they need saved (index,
recursion objects, etc.)

activeSite will not be set.

Cached for speed.

>>> s = converter.parse('tinynotation: 3/4 c4 d e f g a', makeNotation=False)
>>> s.id = 'tn3/4'
>>> sI = s.iter()
>>> sI
<music21.stream.iterator.StreamIterator for Part:tn3/4 @:0>

>>> sI.matchingElements()
[<music21.meter.TimeSignature 3/4>, <music21.note.Note C>, <music21.note.Note D>,
 <music21.note.Note E>, <music21.note.Note F>, <music21.note.Note G>,
 <music21.note.Note A>]

>>> sI_notes = sI.notes
>>> sI_notes
<music21.stream.iterator.StreamIterator for Part:tn3/4 @:0>

Adding a filter to the Stream iterator returns a new Stream iterator; it
does not change the original.

>>> sI_notes is sI
False

>>> sI.filters
[]

>>> sI_notes.filters
[<music21.stream.filters.ClassFilter <class 'music21.note.NotRest'>>]

>>> sI_notes.matchingElements()
[<music21.note.Note C>, <music21.note.Note D>,
 <music21.note.Note E>, <music21.note.Note F>, <music21.note.Note G>,
 <music21.note.Note A>]

If restoreActiveSites is False then the elements will not have
their activeSites changed (callers should use it when they do not plan to actually
expose the elements to users, such as in `__len__`).  By default, it is `None`
which means to take from the iterator's `restoreActiveSites` attribute.

A demonstration of restoreActiveSites = False.  First we create a second stream
from the first, so that all elements are in two streams, then we'll check the
id of iterating through the second stream normally, and then the first stream
with restoreActiveSites=False, and then the first stream without the restoreActiveSites:

>>> s2 = stream.Part()
>>> s2.id = 'second'
>>> s2.elements = s
>>> {e.activeSite.id for e in s2.iter().notes.matchingElements()}
{'second'}
>>> {e.activeSite.id for e in sI_notes.matchingElements(restoreActiveSites=False)}
{'second'}
>>> {e.activeSite.id for e in sI_notes.matchingElements()}
{'tn3/4'}

* New in v7: restoreActiveSites
* Changed in v9.3: restoreActiveSites allows `None` which takes from the iterator's
  `restoreActiveSites` attribute.
Nr5   r*   )rM   r5   r
   ra   )rO   r5   rP   r   s       r%   r   StreamIterator.matchingElements  s    T !7!77))*<==%!%!8!8D"6G&8#!"T!TB"JJL	 H 6812	 # HGs   BA<B<B
Bc                   U R                    H  n  U" X5      SL a    gM     g! [         aH    [        R                  (       a!  [	        U[         R
                  5      (       d   eU" U5      SL a     g Mh  f = f! [         a    e f = f)z<
returns False if any filter returns False, True otherwise.
FT)r   rK   r?   TYPE_CHECKINGrI   r   rl   )rO   rm   r   s      r%   ri   StreamIterator.matchesFilters  s    
 A
%zU*$ +   ! %)!W-A-ABBBBtu}$ %%
 ! s(   $AA6/A92A95A66A99Bc                .    SSK Jn  UR                  5       $ )a9  
Returns a new stream.Stream.  The same thing as calling:

>>> s = stream.Stream()

This is used in places where returnStreamSubclass is False, so we
cannot just call `type(StreamIterator.srcStream)()`

>>> p = stream.Part()
>>> pi = p.iter()
>>> s = pi._newBaseStream()
>>> s
<music21.stream.Stream 0x1047eb2e8>
r   r   )music21r   StreamrO   r   s     r%   _newBaseStreamStreamIterator._newBaseStream  s     	#}}r$   c                    g r`   r   )rO   returnStreamSubClasss     r%   r   StreamIterator.stream$  r   r$   c                    U R                   nU$ r`   )	streamObj)rO   r   rP   s      r%   r   r   (  s     r$   c                   U R                   nSnU(       a   UR                  5       nOU R                  5       nUR	                  U5        X$R
                  l        U R                  b  U R                  UR
                  l        O~/ nU R                   HL  n[        U[        R                  5      (       a  UR                  nOUR                  nUR                  U5        MN     SR                  U5      UR
                  l        U R!                  5       nU Hs  n	 UR#                  U	SS9n
[        U
[(        5      (       d  UR+                  XSS9  M;  U
[,        R.                  :X  a  UR1                  U	5        Mb  UR1                  U	5        Mu     U(       a  UR3                  US9  U$ ! [         a    U R                  5       n GNf = f! [$         a    U	R'                  U5      n
Sn Nf = f)au  
return a new stream from this iterator.

Does nothing except copy if there are no filters, but a drop in
replacement for the old .getElementsByClass() etc. if it does.

In other words:

`s.getElementsByClass()` == `s.iter().getElementsByClass().stream()`

>>> s = stream.Part()
>>> s.insert(0, note.Note('C'))
>>> s.append(note.Rest())
>>> s.append(note.Note('D'))
>>> b = bar.Barline()
>>> s.storeAtEnd(b)

>>> s2 = s.iter().getElementsByClass(note.Note).stream()
>>> s2.show('t')
{0.0} <music21.note.Note C>
{2.0} <music21.note.Note D>
>>> s2.derivation.method
'getElementsByClass'
>>> s2
<music21.stream.Part ...>

>>> s3 = s.iter().stream()
>>> s3.show('t')
{0.0} <music21.note.Note C>
{1.0} <music21.note.Rest quarter>
{2.0} <music21.note.Note D>
{3.0} <music21.bar.Barline type=regular>

>>> s3.elementOffset(b, returnSpecial=True)
<OffsetSpecial.AT_END>

>>> s4 = s.iter().getElementsByClass(bar.Barline).stream()
>>> s4.show('t')
{0.0} <music21.bar.Barline type=regular>


Note that this routine can create Streams that have elements that the original
stream did not, in the case of recursion:

>>> bach = corpus.parse('bwv66.6')
>>> bn = bach.flatten()[34]
>>> bn
<music21.note.Note E>

>>> bn in bach
False
>>> bfn = bach.recurse().notes.stream()
>>> bn in bfn
True
>>> bn.getOffsetBySite(bfn)
2.0
>>> bn.getOffsetInHierarchy(bach)
2.0

OMIT_FROM_DOCS

>>> s4._endElements[0] is b
True
F.T)returnSpecial)
ignoreSort)clearIsSorted)r>   rV   rK   r   mergeAttributes
derivationoriginrH   methodr   rI   r   derivationStrr   appendjoinr   elementOffsetr   getOffsetInHierarchyrZ   
coreInsertr   AT_ENDcoreStoreAtEndcoreElementsChanged)rO   r   ssr   foundderivationMethodsr   dStrr   rm   os              r%   r   r   3  s   H ^^ .  '')Eb!"$"".&*&=&=E# "\\a!5!566??D::D!((. " '*hh/@&AE#""$A%$$Qd$; a%%  $ 7,,,((+ ((+! $ %%M%BS  .++-.. " % **2. $	%s#   F! G!F?>F?G"!G"c                N    [        U R                  S   U R                  S   5      $ )z]
Returns the element list (`_elements` or `_endElements`)
for the current activeInformation.
r   r,   )rw   r6   rb   s    r%   activeElementList StreamIterator.activeElementList  s(     t--h79O9OP]9^__r$   returnClonec                   U(       a  U R                  5       nOU nUR                  5         UR                   H  nX:X  d  M
  Us  $    UR                  R                  U5        U$ )a'  
Return a new StreamIterator with an additional filter.
Also resets caches -- so do not add filters any other way.

If returnClone is False then adds without creating a new StreamIterator

* Changed in v6: Encourage creating new StreamIterators: change
  default to return a new StreamIterator.
)r   r   r   r   )rO   	newFilterr   r   r   s        r%   	addFilterStreamIterator.addFilter  sR     **,CCA~
  	9%
r$   c                   U(       a  U R                  5       nOU nUR                  5         XR                  ;   a4  UR                  R                  UR                  R	                  U5      5        U$ )z9
Return a new StreamIterator where oldFilter is removed.
)r   r   r   popindex)rO   	oldFilterr   r   s       r%   removeFilterStreamIterator.removeFilter  sO     **,CC#KKOOCKK--i89
r$   c                d    U R                  [        R                  " U5      5      nU H  nUs  $    g)aO  
Returns a single element (or None) that matches elementId.

If chaining filters, this should be the last one, as it returns an element

>>> s = stream.Stream(id='s1')
>>> s.append(note.Note('C'))
>>> r = note.Rest()
>>> r.id = 'restId'
>>> s.append(r)
>>> r2 = s.recurse().getElementById('restId')
>>> r2 is r
True
>>> r2.id
'restId'
N)r   r   IdFilter)rO   	elementIdr   rm   s       r%   getElementByIdStreamIterator.getElementById  s/    " nnW--i89AH r$   c                   g r`   r   rO   classFilterListr   s      r%   getElementsByClass!StreamIterator.getElementsByClass      
 	r$   c                   g r`   r   r   s      r%   r   r     r   r$   c                   g r`   r   r   s      r%   r   r     r   r$   c                   g r`   r   r   s      r%   r   r     r   r$   c               J    U R                  [        R                  " U5      US9$ )aM  
Add a filter to the Iterator to remove all elements
except those that match one
or more classes in the `classFilterList`. A single class
can also be used for the `classFilterList` parameter instead of a List.

>>> s = stream.Stream(id='s1')
>>> s.append(note.Note('C'))
>>> r = note.Rest()
>>> s.append(r)
>>> s.append(note.Note('D'))
>>> for el in s.iter().getElementsByClass(note.Rest):
...     print(el)
<music21.note.Rest quarter>


ActiveSite is restored.

>>> s2 = stream.Stream(id='s2')
>>> s2.insert(0, r)
>>> r.activeSite.id
's2'

>>> for el in s.iter().getElementsByClass(note.Rest):
...     print(el.activeSite.id)
s1


Strings work in addition to classes, but your IDE will not know that
`el` is a :class:`~music21.note.Rest` object.

>>> for el in s.iter().getElementsByClass('Rest'):
...     print(el)
<music21.note.Rest quarter>
r   r   r   ClassFilterr   s      r%   r   r     s$    \ ~~g11/BP[~\\r$   c               >   UR                  S5      (       a'  U R                  [        R                  " USS 5      US9$ UR                  S5      (       a'  U R                  [        R                  " USS 5      US9$ U R                  [        R
                  " U5      US9$ )ab  
First implementation of a query selector, similar to CSS QuerySelectors used in
HTML DOM:

* A leading `#` indicates the id of an element, so '#hello' will find elements
  with `el.id=='hello'` (should only be one)
* A leading `.` indicates the group of an element, so '.high' will find elements
  with `'high'` in el.groups.
* Any other string is considered to be the type/class of the element.  So `Note`
  will find all Note elements.  Can be fully qualified like `music21.note.Note`
  or partially qualified like `note.Note`.

Eventually, more complex query selectors will be implemented.  This is just a start.

Setting up an example:

>>> s = converter.parse('tinyNotation: 4/4 GG4 AA4 BB4 r4 C4 D4 E4 F4 r1')
>>> s[note.Note].last().id = 'last'
>>> for n in s[note.Note]:
...     if n.octave == 3:
...         n.groups.append('tenor')

>>> list(s.recurse().getElementsByQuerySelector('.tenor'))
[<music21.note.Note C>,
 <music21.note.Note D>,
 <music21.note.Note E>,
 <music21.note.Note F>]

>>> list(s.recurse().getElementsByQuerySelector('Rest'))
[<music21.note.Rest quarter>,
 <music21.note.Rest whole>]

Note that unlike with stream slices, the querySelector does not do anything special
for id searches.  `.first()` will need to be called to find the element (if any)

>>> s.recurse().getElementsByQuerySelector('#last').first()
<music21.note.Note F>

* New in v7.
r   rg   Nr   r   )r   r   r   r   GroupFilterr  )rO   querySelectorr   s      r%   getElementsByQuerySelector)StreamIterator.getElementsByQuerySelectorO  s    R ##C((>>'"2"2=3D"ES^>__##C((>>'"5"5mAB6G"HVa>bb~~g11-@k~ZZr$   c               J    U R                  [        R                  " U5      US9$ )a=  
Adds a filter, removing all Elements that do not
match the one or more classes in the `classFilterList`.

In lieu of a list, a single class can be used as the `classFilterList` parameter.

>>> a = stream.Stream()
>>> a.repeatInsert(note.Rest(), range(10))
>>> for x in range(4):
...     n = note.Note('G#')
...     n.offset = x * 3
...     a.insert(n)
>>> found = a.iter().getElementsNotOfClass(note.Note)
>>> len(found)
10
>>> found = a.iter().getElementsNotOfClass('Rest')
>>> len(found)
4
>>> found = a.iter().getElementsNotOfClass(['Note', 'Rest'])
>>> len(found)
0

>>> b = stream.Stream()
>>> b.repeatInsert(note.Rest(), range(15))
>>> a.insert(b)

>>> found = a.recurse().getElementsNotOfClass([note.Rest, 'Stream'])
>>> len(found)
4
>>> found = a.recurse().getElementsNotOfClass([note.Note, 'Stream'])
>>> len(found)
25
r   )r   r   ClassNotFilterr   s      r%   getElementsNotOfClass$StreamIterator.getElementsNotOfClass  s$    D ~~g44_ES^~__r$   c               J    U R                  [        R                  " U5      US9$ )a  
>>> n1 = note.Note('C')
>>> n1.groups.append('trombone')
>>> n2 = note.Note('D')
>>> n2.groups.append('trombone')
>>> n2.groups.append('tuba')
>>> n3 = note.Note('E')
>>> n3.groups.append('tuba')
>>> s1 = stream.Stream()
>>> s1.append(n1)
>>> s1.append(n2)
>>> s1.append(n3)

>>> tboneSubStream = s1.iter().getElementsByGroup('trombone')
>>> for thisNote in tboneSubStream:
...     print(thisNote.name)
C
D
>>> tubaSubStream = s1.iter().getElementsByGroup('tuba')
>>> for thisNote in tubaSubStream:
...     print(thisNote.name)
D
E
r   )r   r   r  )rO   groupFilterListr   s      r%   getElementsByGroup!StreamIterator.getElementsByGroup  s#    2 ~~g11/BP[~\\r$   )includeEndBoundarymustFinishInSpanmustBeginInSpanincludeElementsThatEndAtStartstopAfterEndr   c               R    U R                  [        R                  " UUUUUUUS9US9$ )aq  
Adds a filter keeping only Music21Objects that
are found at a certain offset or within a certain
offset time range (given the start and optional stop values).

There are several attributes that govern how this range is
determined:


If `mustFinishInSpan` is True then an event that begins
between offsetStart and offsetEnd but which ends after offsetEnd
will not be included.  The default is False.


For instance, a half note at offset 2.0 will be found in
getElementsByOffset(1.5, 2.5) or getElementsByOffset(1.5, 2.5,
mustFinishInSpan = False) but not by getElementsByOffset(1.5, 2.5,
mustFinishInSpan = True).

The `includeEndBoundary` option determines if an element
begun just at the offsetEnd should be included.  For instance,
the half note at offset 2.0 above would be found by
getElementsByOffset(0, 2.0) or by getElementsByOffset(0, 2.0,
includeEndBoundary = True) but not by getElementsByOffset(0, 2.0,
includeEndBoundary = False).

Setting includeEndBoundary to False at the same time as
mustFinishInSpan is set to True is probably NOT what you want to do
unless you want to find things like clefs at the end of the region
to display as courtesy clefs.

The `mustBeginInSpan` option determines whether notes or other
objects that do not begin in the region but are still sounding
at the beginning of the region are excluded.  The default is
True -- that is, these notes will not be included.
For instance the half note at offset 2.0 from above would not be found by
getElementsByOffset(3.0, 3.5) or getElementsByOffset(3.0, 3.5,
mustBeginInSpan = True) but it would be found by
getElementsByOffset(3.0, 3.5, mustBeginInSpan = False)

Setting includeElementsThatEndAtStart to False is useful for zeroLength
searches that set mustBeginInSpan == False to not catch notes that were
playing before the search but that end just before the end of the search type.
See the code for allPlayingWhileSounding for a demonstration.

This chart, like the examples below, demonstrates the various
features of getElementsByOffset.  It is one of the most complex
methods of music21 but also one of the most powerful, so it
is worth learning at least the basics.

    .. image:: images/getElementsByOffset.*
        :width: 600

>>> st1 = stream.Stream()
>>> n0 = note.Note('C')
>>> n0.duration.type = 'half'
>>> n0.offset = 0
>>> st1.insert(n0)
>>> n2 = note.Note('D')
>>> n2.duration.type = 'half'
>>> n2.offset = 2
>>> st1.insert(n2)
>>> out1 = list(st1.iter().getElementsByOffset(2))
>>> len(out1)
1
>>> out1[0].step
'D'
>>> out2 = list(st1.iter().getElementsByOffset(1, 3))
>>> len(out2)
1
>>> out2[0].step
'D'
>>> out3 = list(st1.iter().getElementsByOffset(1, 3, mustFinishInSpan=True))
>>> len(out3)
0
>>> out4 = list(st1.iter().getElementsByOffset(1, 2))
>>> len(out4)
1
>>> out4[0].step
'D'
>>> out5 = list(st1.iter().getElementsByOffset(1, 2, includeEndBoundary=False))
>>> len(out5)
0
>>> out6 = list(st1.iter().getElementsByOffset(1, 2, includeEndBoundary=False,
...                                          mustBeginInSpan=False))
>>> len(out6)
1
>>> out6[0].step
'C'
>>> out7 = list(st1.iter().getElementsByOffset(1, 3, mustBeginInSpan=False))
>>> len(out7)
2
>>> [el.step for el in out7]
['C', 'D']

Note, that elements that end at the start offset are included if mustBeginInSpan is False

>>> out8 = list(st1.iter().getElementsByOffset(2, 4, mustBeginInSpan=False))
>>> len(out8)
2
>>> [el.step for el in out8]
['C', 'D']

To change this behavior set includeElementsThatEndAtStart=False

>>> out9 = list(st1.iter().getElementsByOffset(2, 4, mustBeginInSpan=False,
...                                          includeElementsThatEndAtStart=False))
>>> len(out9)
1
>>> [el.step for el in out9]
['D']

>>> a = stream.Stream(id='a')
>>> n = note.Note('G')
>>> n.quarterLength = 0.5
>>> a.repeatInsert(n, list(range(8)))
>>> b = stream.Stream(id='b')
>>> b.repeatInsert(a, [0, 3, 6])
>>> c = list(b.iter().getElementsByOffset(2, 6.9))
>>> len(c)
2
>>> c = list(b.flatten().iter().getElementsByOffset(2, 6.9))
>>> len(c)
10

Testing multiple zero-length elements with mustBeginInSpan:

>>> c = clef.TrebleClef()
>>> ts = meter.TimeSignature('4/4')
>>> ks = key.KeySignature(2)
>>> s = stream.Stream()
>>> s.insert(0.0, c)
>>> s.insert(0.0, ts)
>>> s.insert(0.0, ks)
>>> len(list(s.iter().getElementsByOffset(0.0, mustBeginInSpan=True)))
3
>>> len(list(s.iter().getElementsByOffset(0.0, mustBeginInSpan=False)))
3

On a :class:`~music21.stream.iterator.RecursiveIterator`,
`.getElementsByOffset(0.0)`, will get everything
at the start of the piece, which is useful:

>>> bwv66 = corpus.parse('bwv66.6')
>>> list(bwv66.recurse().getElementsByOffset(0.0))
[<music21.metadata.Metadata object at 0x10a32f490>,
 <music21.stream.Part Soprano>,
 <music21.instrument.Instrument 'P1: Soprano: Instrument 1'>,
 <music21.stream.Measure 0 offset=0.0>,
 <music21.clef.TrebleClef>,
 <music21.tempo.MetronomeMark Quarter=96 (playback only)>,
 <music21.key.Key of f# minor>,
 <music21.meter.TimeSignature 4/4>,
 <music21.note.Note C#>,
 <music21.stream.Part Alto>,
 ...
 <music21.note.Note E>,
 <music21.stream.Part Tenor>,
 ...]

However, any other offset passed to `getElementsByOffset` on a
`RecursiveIterator` without additional arguments, is unlikely to be useful,
because the iterator ends as soon as it encounters an element
with an offset beyond the `offsetEnd` point.  For instance,
calling `.getElementsByOffset(1.0).notes` on a :class:`~music21.stream.Part`,
in bwv66.6 only gets the note that appears at offset 1.0 of a measure that begins
or includes offset 1.0.
(Fortunately, this piece begins with a one-beat pickup, so there is such a note):

>>> soprano = bwv66.parts['#Soprano']  # = getElementById('Soprano')
>>> for el in soprano.recurse().getElementsByOffset(1.0):
...     print(el, el.offset, el.getOffsetInHierarchy(bwv66), el.activeSite)
<music21.stream.Measure 1 offset=1.0> 1.0 1.0 <music21.stream.Part Soprano>
<music21.note.Note B> 1.0 2.0 <music21.stream.Measure 1 offset=1.0>


RecursiveIterators will probably want to use
:meth:`~music21.stream.iterator.RecursiveIterator.getElementsByOffsetInHierarchy`
instead.  Or to get all elements with a particular local offset, such as everything
on the third quarter note of a measure, use the `stopAfterEnd=False` keyword,
which lets the iteration continue to search for elements even after encountering
some within Streams whose offsets are greater than the end element.

>>> len(soprano.recurse().getElementsByOffset(2.0, stopAfterEnd=False))
9

* Changed in v5.5: all arguments changing behavior are keyword only.
* New in v6.5: `stopAfterEnd` keyword.

OMIT_FROM_DOCS

Same test as above, but with floats

>>> out1 = list(st1.iter().getElementsByOffset(2.0))
>>> len(out1)
1
>>> out1[0].step
'D'
>>> out2 = list(st1.iter().getElementsByOffset(1.0, 3.0))
>>> len(out2)
1
>>> out2[0].step
'D'
>>> out3 = list(st1.iter().getElementsByOffset(1.0, 3.0, mustFinishInSpan=True))
>>> len(out3)
0
>>> out3b = list(st1.iter().getElementsByOffset(0.0, 3.001, mustFinishInSpan=True))
>>> len(out3b)
1
>>> out3b[0].step
'C'
>>> out3b = list(st1.iter().getElementsByOffset(1.0, 3.001, mustFinishInSpan=True,
...                                           mustBeginInSpan=False))
>>> len(out3b)
1
>>> out3b[0].step
'C'

>>> out4 = list(st1.iter().getElementsByOffset(1.0, 2.0))
>>> len(out4)
1
>>> out4[0].step
'D'
>>> out5 = list(st1.iter().getElementsByOffset(1.0, 2.0, includeEndBoundary=False))
>>> len(out5)
0
>>> out6 = list(st1.iter().getElementsByOffset(1.0, 2.0, includeEndBoundary=False,
...                                          mustBeginInSpan=False))
>>> len(out6)
1
>>> out6[0].step
'C'
>>> out7 = list(st1.iter().getElementsByOffset(1.0, 3.0, mustBeginInSpan=False))
>>> len(out7)
2
>>> [el.step for el in out7]
['C', 'D']
)r  r  r  r  r  r   )r   r   OffsetFilter)	rO   offsetStart	offsetEndr  r  r  r  r  r   s	            r%   getElementsByOffset"StreamIterator.getElementsByOffset  sC    t ~~  #5!1 /.K) $  
 	
r$   c                @    U R                  [        R                  5      $ )a4  
Returns all :class:`~music21.note.NotRest` objects

(will sometime become simply Note and Chord objects.)

>>> s = stream.Stream()
>>> s.append(note.Note('C'))
>>> s.append(note.Rest())
>>> s.append(note.Note('D'))
>>> for el in s.iter().notes:
...     print(el)
<music21.note.Note C>
<music21.note.Note D>
)r   r   NotRestrb   s    r%   notesStreamIterator.notes  s      &&t||44r$   c                @    U R                  [        R                  5      $ )a3  
Returns all :class:`~music21.note.GeneralNote` objects, including
Rests and Unpitched elements.

>>> s = stream.Stream()
>>> s.append(meter.TimeSignature('4/4'))
>>> s.append(note.Note('C'))
>>> s.append(note.Rest())
>>> s.append(note.Note('D'))
>>> for el in s.iter().notesAndRests:
...     print(el)
<music21.note.Note C>
<music21.note.Rest quarter>
<music21.note.Note D>

Chained filters (this makes no sense since notes is a subset of notesAndRests):

>>> for el in s.iter().notesAndRests.notes:
...     print(el)
<music21.note.Note C>
<music21.note.Note D>
)r   r   GeneralNoterb   s    r%   notesAndRestsStreamIterator.notesAndRests  s    0 &&t'7'788r$   c                D    SSK Jn  U R                  UR                  5      $ )z%
Adds a ClassFilter for Part objects
r   r   )r   r   r   Partr   s     r%   partsStreamIterator.parts  s    
 	#&&v{{33r$   c                D    SSK Jn  U R                  UR                  5      $ )z(
Adds a ClassFilter for Spanner objects
r   )spanner)r   r'  r   Spanner)rO   r'  s     r%   spannersStreamIterator.spanners  s    
 	$&&w77r$   c                D    SSK Jn  U R                  UR                  5      $ )z&
Adds a ClassFilter for Voice objects
r   r   )r   r   r   Voicer   s     r%   voicesStreamIterator.voices  s    
 	#&&v||44r$   )rL   rM   r6   rG   r*   rF   r   r,   rH   r5   r-   r>   rC   rE   )
r>   r   r4   zlist[FilterType] | Noner5   r   r6   zActiveInformation | Noner7   r   rO   r   returnr   r0  r   )r~   r)   r0  r   )r~   slicer0  list[M21ObjType])r~   rZ   r0  M21ObjType | None)r~   zint | slice | strr0  z$M21ObjType | list[M21ObjType] | None)r0  r)   )r0  r   )r0  r4  r0  None)r5   zbool | Noner0  r3  )rm   zbase.Music21Objectr0  r   )r0  streamModule.Stream)r   zt.Literal[False]r0  r7  )T)r   zt.Literal[True]r0  r   )r   r   r0  z streamModule.Stream | StreamType)r0  r+   )r   rZ   r0  r4  )r   rZ   r   r   r0  StreamIterator[M21ObjType])r   Iterable[str]r   r   r0  r8  )r   type[ChangedM21ObjType]r   r   r0  z!StreamIterator[ChangedM21ObjType])r   Iterable[type]r   r   r0  r8  )r   Dt.Union[str, type[ChangedM21ObjType], Iterable[str], Iterable[type]]r   r   r0  zFt.Union[StreamIterator[M21ObjType], StreamIterator[ChangedM21ObjType]])r  rZ   r`   )+r   r    r!   r"   __doc__rQ   r]   rc   rn   rz   r   r   r   r   r   r   r   r   r   rN   ra   r   rk   r   ri   r   r   propertyr   r   r   r   r   r  r	  r  r  r  r   r$  r)  r-  r#   r   r$   r%   r   r   ?   sw   AL 6:,0=A',0+&0+ 3	0+
 &*0+ %;0+ !%0+d	H:d#L      Wr,4lG
0d$P!
$(4 )-Y &Y 
	Yv&$     &*w"w 
(wr ` ` 	 
 
@ 	 
 
(,  04,/ )- 9S   04,9 )- 9S   04,C )- 9Z   04,: )- 9S  !.]
.] .] 
P.]` MQ -[` EI "`H BF ]< E

  &*E
 E
 
E
T 5 5" 9 92 4 4 8 8 5 5r$   c                    ^  \ rS rSrSrSSSSS. SU 4S jjjrSU 4S jjrU 4S	 jr\SS
.     SS jj5       r	\SS
.     SS jj5       r	\SS
.     SS jj5       r	\SS
.     SS jj5       r	SS
.     SS jjr	Sr
U =r$ )OffsetIteratori  a  
An iterator that with each iteration returns a list of elements
that are at the same offset (or all at end)

>>> s = stream.Stream()
>>> s.insert(0, note.Note('C'))
>>> s.insert(0, note.Note('D'))
>>> s.insert(1, note.Note('E'))
>>> s.insert(2, note.Note('F'))
>>> s.insert(2, note.Note('G'))
>>> s.storeAtEnd(bar.Repeat('end'))
>>> s.storeAtEnd(clef.TrebleClef())

>>> oIter = stream.iterator.OffsetIterator(s)
>>> for groupedElements in oIter:
...     print(groupedElements)
[<music21.note.Note C>, <music21.note.Note D>]
[<music21.note.Note E>]
[<music21.note.Note F>, <music21.note.Note G>]
[<music21.bar.Repeat direction=end>, <music21.clef.TrebleClef>]

Does it work again?

>>> for groupedElements2 in oIter:
...     print(groupedElements2)
[<music21.note.Note C>, <music21.note.Note D>]
[<music21.note.Note E>]
[<music21.note.Note F>, <music21.note.Note G>]
[<music21.bar.Repeat direction=end>, <music21.clef.TrebleClef>]


>>> for groupedElements in oIter.notes:
...     print(groupedElements)
[<music21.note.Note C>, <music21.note.Note D>]
[<music21.note.Note E>]
[<music21.note.Note F>, <music21.note.Note G>]

>>> for groupedElements in stream.iterator.OffsetIterator(s).getElementsByClass(clef.Clef):
...     print(groupedElements)
[<music21.clef.TrebleClef>]
NTFr3   c               R   > [         TU ]  UUUUUS9  SU l        / U l        S U l        g )Nr3   F)superrQ   raiseStopIterationNextnextToYieldnextOffsetToYield)rO   r>   r4   r5   r6   r7   rV   s         r%   rQ   OffsetIterator.__init__8  s?     	$.,>+<'4 	 	 ',#-/!%r$   c                  > U R                   (       a  [        e/ n U R                  (       a  U R                  nU R                  nO,[        TU ]  5       nU R                  R                  U5      nU/nU R                  U R                  ::  a  [        TU ]  5       nU R                  R                  U5      nXR:X  a  UR                  U5        O"U/U l        XPl        US   U R                  S'   U$ U R                  U R                  ::  a  M~  g g ! [         a+    U(       a  SU l         US   U R                  S'   Us $ [        ef = f)Nr   r.   T)rC  rl   rD  rE  rB  rn   r>   r   r*   rE   r   r6   )rO   retElementListretElOffsetretElnextElnextElOffsetrV   s         r%   rn   OffsetIterator.__next__L  s,   &&+-	$!%!1!1"44(*"nn::5A"'
 ##t'8'88)+#~~;;FC."))&1(.xD$-9*<J1<MD**=9)) ##t'8'88  	$.2+8Fq8I&&}5%%##	$s   CD .D ,E:Ec                L   > [         TU ]  5         / U l        SU l        SU l        g)z
runs before iteration
NF)rB  ra   rD  rE  rC  rO   rV   s    r%   ra   OffsetIterator.resetq  s&     	!%&+#r$   r   c                   g r`   r   r   s      r%   r   !OffsetIterator.getElementsByClass}  r   r$   c                   g r`   r   r   s      r%   r   rR    r   r$   c                   g r`   r   r   s      r%   r   rR    r   r$   c                   g r`   r   r   s      r%   r   rR    r   r$   c               J    U R                  [        R                  " U5      US9$ )zU
Identical to the same method in StreamIterator, but needs to be duplicated
for now.
r   r   r   s      r%   r   rR    s#     ~~g11/BP[~\\r$   )rE  rD  rC  r5  )r0  r3  )r   rZ   r   r   r0  OffsetIterator[M21ObjType])r   r9  r   r   r0  rW  )r   r:  r   r   r0  z!OffsetIterator[ChangedM21ObjType])r   r;  r   r   r0  rW  )r   r<  r   r   r0  zFt.Union[OffsetIterator[M21ObjType], OffsetIterator[ChangedM21ObjType]])r   r    r!   r"   r=  rQ   rn   ra   r   r   r#   __classcell__rV   s   @r%   r@  r@    sA   (Z !$(#'$& & &(#$J,  04,/ )- 9S   04,9 )- 9S   04,C )- 9Z   04,: )- 9S  04]-] )-]!K] ]r$   r@  c                  b  ^  \ rS rSrSrSSSSSSS. SU 4S jjjrSS jrU 4S	 jrSS
.U 4S jjrSS jr	S r
S r SSSSSS.   SS jjjr\SS.     SS jj5       r\SS.     SS jj5       r\SS.     SS jj5       r\SS.     S S jj5       rSS.     S!U 4S jjjrSrU =r$ )"RecursiveIteratori  a  
One of the most powerful iterators in music21.  Generally not called
directly, but created by being invoked on a stream with `Stream.recurse()`

>>> b = corpus.parse('bwv66.6')
>>> ri = stream.iterator.RecursiveIterator(b, streamsOnly=True)
>>> for x in ri:
...     print(x)
<music21.stream.Part Soprano>
<music21.stream.Measure 0 offset=0.0>
<music21.stream.Measure 1 offset=1.0>
<music21.stream.Measure 2 offset=5.0>
...
<music21.stream.Part Alto>
<music21.stream.Measure 0 offset=0.0>
...
<music21.stream.Part Tenor>
...
<music21.stream.Part Bass>
...

But this is how you'll actually use it:

>>> for x in b.recurse(streamsOnly=True, includeSelf=True):
...     print(x)
<music21.stream.Score bach/bwv66.6.mxl>
<music21.stream.Part Soprano>
<music21.stream.Measure 0 offset=0.0>
<music21.stream.Measure 1 offset=1.0>
<music21.stream.Measure 2 offset=5.0>
...
<music21.stream.Part Alto>
<music21.stream.Measure 0 offset=0.0>
...
<music21.stream.Part Tenor>
...
<music21.stream.Part Bass>
...

>>> hasExpressions = lambda el, i: True if (hasattr(el, 'expressions')
...       and el.expressions) else False
>>> expressive = b.recurse().addFilter(hasExpressions)
>>> expressive
<music21.stream.iterator.RecursiveIterator for Score:bach/bwv66.6.mxl @:0>

>>> for el in expressive:
...     print(el, el.expressions)
<music21.note.Note C#> [<music21.expressions.Fermata>]
<music21.note.Note A> [<music21.expressions.Fermata>]
<music21.note.Note F#> [<music21.expressions.Fermata>]
<music21.note.Note C#> [<music21.expressions.Fermata>]
<music21.note.Note G#> [<music21.expressions.Fermata>]
<music21.note.Note F#> [<music21.expressions.Fermata>]

>>> len(expressive)
6
>>> expressive[-1].measureNumber
9
>>> bool(expressive)
True
NTF)r4   r5   r6   streamsOnlyincludeSelfr7   c                  > [         TU ]  UUUUUS9  X`l        X`l        Xpl        SU l        USL a/  U R                  R                  [        R                  " S5      5        S U l	        g )Nr3           Tr   )
rB  rQ   
returnSelfr]  r7   iteratorStartOffsetInHierarchyr   r   r  childRecursiveIterator)	rO   r>   r4   r5   r6   r\  r]  r7   rV   s	           r%   rQ   RecursiveIterator.__init__  so     	$.,>+<'4 	 	 &&* /2+$LL 3 3H =>EI#r$   c           	     .   U R                   U R                  :  Ga]  U R                  b   [        U R                  5      $ U R
                  SL a  U R                  U R                  5      (       ac  SU R                  S'   SU R                  S'   U R                  U R                  S'   SU l        [        R                  " [        U R                  5      $ U R
                  SL a  SU l        U R                   U R                  :  a&  SU l        U R                   U R                  -
  U l        OU R                   U l         U R                  U R                      nU =R                   S	-  sl         UR"                  (       a  [        R$                  (       a!  ['        U[(        R*                  5      (       d   e[-        UU R.                  U R0                  U R                  SU R2                  S
9nU R4                  U R                  R7                  U5      -   nX2l        X l        U R                  U5      SL a  GM.  U R.                  SL a  U R                  R9                  U5        U R;                  5         XR                  S'   U$ U R                  b   [        U R                  5      $ SU R                  S'   U R=                  5         [        e! [         a    SU l         GNf = f! [          a    U =R                   S	-  sl          GM  f = f! [         a
    SU l         Nwf = f)zc
Get the next element of the stream under iteration.

The same __iter__ as the superclass is used.
NTr   r9   r*   r.   Frf   rg   )r>   r5   r4   r6   r]  r7   )r*   rE   rb  r   rl   r`  ri   r>   r6   r?   r@   r   rF   r,   r-   rC   rh   isStreamr   rI   streamModuler   r[  r5   r   r7   ra  r   rj   rN   rk   )rO   rm   rb  newStartOffsets       r%   rn   RecursiveIterator.__next__  s    $"3"33 **67 ; ;<<
 $&4+>+>t~~+N+N37&&x09;&&~68<&&}5"'vvj$..99D("'  D$7$77#1 $($5$58K8K$K!$($5$5!**4+<+<= " zz??%a)<)<====HY'+'>'>#||&*&<&< %"&"4"4I& #'"E"E$(NN$@$@$C#D IWE.D+""1%.&&$.11!4((*45""=1H &&23D7788
 15}-K % 726D/7,  !!Q&!R ! 3.2+3s5   K 9K L  KKK=<K= LLc                R   > U R                   U l        SU l        [        TU ]  5         g)r   N)r]  r`  rb  rB  ra   rO  s    r%   ra   RecursiveIterator.reseth  s#     **&*#r$   r   c               p   > [        U S5         [        TU ]	  US9nS S S 5        U$ ! , (       d  f       W$ = f)Nrb  r   )r	   rB  r   )rO   r5   r   rV   s      r%   r   "RecursiveIterator.matchingElementsp  s;     4!9:)=O)PB ;	 ;:	s   &
5c                    U /nU nUR                   b,  UR                   nUR                  U5        UR                   b  M,  U$ )a  
Returns a stack of RecursiveIterators at this point in the iteration.  Last is most recent.

>>> b = corpus.parse('bwv66.6')
>>> bRecurse = b.recurse()
>>> i = 0
>>> for _ in bRecurse:
...     i += 1
...     if i > 13:
...         break
>>> bRecurse.iteratorStack()
[<music21.stream.iterator.RecursiveIterator for Score:bach/bwv66.6.mxl @:2>,
 <music21.stream.iterator.RecursiveIterator for Part:Soprano @:3>,
 <music21.stream.iterator.RecursiveIterator for Measure:m.1 @:3>]
)rb  r   )rO   	iterStackrP   s      r%   iteratorStackRecursiveIterator.iteratorStackw  sK      F	&&2((AQ &&2 r$   c                `    U R                  5        Vs/ s H  oR                  PM     sn$ s  snf )a  
Returns a stack of Streams at this point.  Last is most recent.

However, the current element may be the same as the last element in the stack

>>> b = corpus.parse('bwv66.6')
>>> bRecurse = b.recurse()
>>> i = 0
>>> for x in bRecurse:
...     i += 1
...     if i > 12:
...         break
>>> bRecurse.streamStack()
[<music21.stream.Score bach/bwv66.6.mxl>,
 <music21.stream.Part Soprano>,
 <music21.stream.Measure 1 offset=1.0>]
)ro  r>   )rO   is     r%   streamStackRecursiveIterator.streamStack  s)    $ &*%7%7%9:%9%9:::s   +c                   U R                   S   nUc  gU R                  5       nUS   nUR                  nUR                  nXL a  [        R
                  " U5      $ [        R
                  " XTR                  U5      -   5      $ )a3  
Called on the current iterator, returns the current offset in the hierarchy.
Or None if we are not currently iterating.

>>> b = corpus.parse('bwv66.6')
>>> bRecurse = b.recurse().notes
>>> print(bRecurse.currentHierarchyOffset())
None
>>> for n in bRecurse:
...     print(n.measureNumber, bRecurse.currentHierarchyOffset(), n)
0 0.0 <music21.note.Note C#>
0 0.5 <music21.note.Note B>
1 1.0 <music21.note.Note A>
1 2.0 <music21.note.Note B>
1 3.0 <music21.note.Note C#>
1 4.0 <music21.note.Note E>
2 5.0 <music21.note.Note C#>
...
9 34.5 <music21.note.Note E#>
9 35.0 <music21.note.Note F#>
0 0.0 <music21.note.Note E>
1 1.0 <music21.note.Note F#>
...

After iteration completes, the figure is reset to None:

>>> print(bRecurse.currentHierarchyOffset())
None

The offsets are with respect to the position inside the stream
being iterated, so, for instance, this will not change the output from above:

>>> o = stream.Opus()
>>> o.insert(20.0, b)
>>> bRecurse = b.recurse().notes
>>> for n in bRecurse:
...     print(n.measureNumber, bRecurse.currentHierarchyOffset(), n)
0 0.0 <music21.note.Note C#>
...

But of course, this will add 20.0 to all numbers:

>>> oRecurse = o.recurse().notes
>>> for n in oRecurse:
...     print(n.measureNumber, oRecurse.currentHierarchyOffset(), n)
0 20.0 <music21.note.Note C#>
...

* New in v4.
r.   Nr9   )r6   ro  r>   ra  r   opFracr   )rO   	lastYieldro  newestIterator
lastStreamlastStartOffsets         r%   currentHierarchyOffset(RecursiveIterator.currentHierarchyOffset  s~    f **=9	**,&r*#--
(GG"==11==3K3KI3V!VWWr$   r  r  r  r  c          	     V    [         R                  " UUUUUUS9nU R                  U5      $ )a  
Adds a filter keeping only Music21Objects that
are found at a certain offset or within a certain
offset time range (given the `offsetStart` and optional `offsetEnd` values) from
the beginning of the hierarchy.

>>> b = corpus.parse('bwv66.6')
>>> for n in b.recurse().getElementsByOffsetInHierarchy(8, 9.5).notes:
...     print(n,
...           n.getOffsetInHierarchy(b),
...           n.measureNumber,
...           n.getContextByClass(stream.Part).id)
<music21.note.Note C#> 8.0 2 Soprano
<music21.note.Note A> 9.0 3 Soprano
<music21.note.Note B> 9.5 3 Soprano
<music21.note.Note G#> 8.0 2 Alto
<music21.note.Note F#> 9.0 3 Alto
<music21.note.Note G#> 9.5 3 Alto
<music21.note.Note C#> 8.0 2 Tenor
<music21.note.Note C#> 9.0 3 Tenor
<music21.note.Note D> 9.5 3 Tenor
<music21.note.Note E#> 8.0 2 Bass
<music21.note.Note F#> 9.0 3 Bass
<music21.note.Note B> 9.5 3 Bass

* Changed in v5.5: all behavior-changing options are keyword only.
r}  )r   OffsetHierarchyFilterr   )rO   r  r  r  r  r  r  r   s           r%   getElementsByOffsetInHierarchy0RecursiveIterator.getElementsByOffsetInHierarchy  s9    H ))1-+*GI ~~a  r$   r   c                   g r`   r   r   s      r%   r   $RecursiveIterator.getElementsByClass  r   r$   c                   g r`   r   r   s      r%   r   r    r   r$   c                   g r`   r   r   s      r%   r   r    r   r$   c                   g r`   r   r   s      r%   r   r  -  r   r$   c                 > [         TU ]  XS9n[        U[        5      (       aA  [	        U[
        R                  5      (       a"  [        R                  " [        [           U5      $ [        R                  " [        [           U5      $ )Nr   )rB  r   rI   rJ   
issubclassr   Music21Objectr?   r@   r[  r   r   )rO   r   r   r   rV   s       r%   r   r  5  se     g((Rot,,OTM_M_1`1`66+,=>DD66+J7==r$   )rb  r7   r]  r,   ra  r`  r-   r5  r1  )r0  zlist[RecursiveIterator]r`   r/  )r   rZ   r   r   r0  RecursiveIterator[M21ObjType])r   r9  r   r   r0  r  )r   r:  r   r   r0  z$RecursiveIterator[ChangedM21ObjType])r   r;  r   r   r0  r  )r   zWt.Union[str, type[ChangedM21ObjType], Iterable[str], Iterable[type[ChangedM21ObjType]]]r   r   r0  zLt.Union[RecursiveIterator[M21ObjType], RecursiveIterator[ChangedM21ObjType]])r   r    r!   r"   r=  rQ   rn   ra   r   ro  rs  r{  r  r   r   r#   rX  rY  s   @r%   r[  r[    s   <D J 
J J@Tl 6:  .;(?XJ +!
  $" *.+!$+! 4F+!Z  04,/ )- 9V   04,9 )- 9V   04,C )- 9]   04,: )- 9V  04>-> )->!N> >r$   r[  c                  2    \ rS rSrS rS rS rS rS rSr	g)	TestiG  c                
   SSK Jn  UR                  5       n[        R                  " 5       n[        R
                  " 5       nUR                  X4/5        [        UR                  5       5      nU R                  [        U5      S5        U R                  US   U5        U R                  US   U5        [        UR                  5       R                  5      nU R                  [        U5      S5        U R                  US   U5        g )Nr   r   rq   rg   )r   r   r   r   RestNoter   listr   assertEqualrD   assertIsr  )rO   r   srnall_ss_notess          r%   testSimpleCloneTest.testSimpleCloneH  s    "MMOIIKIIK	!QVVXUQ'eAh"eAh"qvvx~~&Wq)gaj!$r$   c                   SSK Jn  UR                  5       n[        R                  " 5       n[        R
                  " 5       nUR                  X4/5        UR                  5       n[        U5      nU R                  Xc5        UR                  n[        U5      nU R                  X5        [        U5      n	U R                  X5        g )Nr   r   )r   r   r   r   r  r  r   r   r   r  r   )
rO   r   r  r  r  sIterr0sIter2obj0n0s
             r%   testAddingFiltersMidIteration"Test.testAddingFiltersMidIterationV  s    "MMOIIKIIK	!%[b $$F|d %[br$   c                    SSK Jn  UR                  S5      nUR                  5       nUR	                  S5      nU R                  UR                  R                  S5        g )Nr   )	converterz!tinyNotation: 4/4 c1 c4 d=id2 e fid2rq   )r   r  parserecurser   r  
activeSiterY   )rO   r  r  recr  s        r%   testRecursiveActiveSitesTest.testRecursiveActiveSitesj  sI    %OO?@iiku%,,a0r$   c                .   SSK Jn  UR                  5       nUR                  5       nUR	                  [
        R                  " S5      5        UR	                  [
        R                  " S5      5        UR                  S[
        R                  " S5      5        UR	                  U5        UR                  SS9n/ nU H"  nUR	                  UR                  5       5        M$     U R                  U/ SQ5        UR                  5       nU R                  U5        g )	Nr   r   DECT)r]  )r_  r_        ?r  g       @)r   r   r#  rT   r   r   r  insertr  r{  assertListEqualassertIsNone)rO   r   pmpRecurse
allOffsetsr   currentOffsets           r%   testCurrentHierarchyOffsetReset$Test.testCurrentHierarchyOffsetResetq  s    "KKMNN	3 	3 	DIIcN#	999.
Ah==?@ Z)BC 779-(r$   c                   SSK Jn  SSKJn  UR	                  5       n[
        R                  " 5       n[
        R                  " 5       nUR                  XE/5        UR                  5       nUR                  U5        UR                  5       nUR                  U5        UR                  5       n[        U5      n	U R                  X5        UR                  n
U R                  X5        g )Nr   r   )r[  )r   r   music21.stream.iteratorr[  rT   r   r  r  r   r#  Scorer  r   r  rb  assertIsInstance)rO   r   ImportedRecursiveIteratorr  r  r  r  scr  p0childs              r%   &testAddingFiltersMidRecursiveIteration+Test.testAddingFiltersMidRecursiveIteration  s    "ZNNIIKIIK	!KKM	\\^
		!

%[b,,e?r$   r   N)
r   r    r!   r"   r  r  r  r  r  r#   r   r$   r%   r  r  G  s    %(1) @r$   r  __main__)9r=  
__future__r   collections.abcr   r   r   r   typingr?   r   unittestru   r   r   music21.common.classToolsr	   r
   music21.common.enumsr   music21.common.typesr   r   r   r   music21.streamr   r   r   music21.sitesr   r   r   rf  TypeVarr   r   r   UnionAnyOptionalr   
FilterTypeUserWarningr   	TypedDictr'   ProtoM21Objectr   r  r@  r[  TestCaser  
_DOC_ORDERr   mainTestr   r$   r%   <module>r     sn  
 # 8 8       C . J J  "   (??.IIcNIIcNYY3;KL  WWXquuajj&78!%%?@'BVBVVW
	{ 	)5 )K5W++Xj-A K5^.a]^Xd:.>%? a]LP>z2HZ4H P>fM@8 M@d /@
zT r$   