Skip to content

Commit 8f7cd8f

Browse files
authored
Merge pull request #1793 from cuthbertLab/stream-iterator-improvements
Misc StreamIterator improvements
2 parents e93f84a + d5dff4e commit 8f7cd8f

File tree

1 file changed

+29
-20
lines changed

1 file changed

+29
-20
lines changed

music21/stream/iterator.py

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# Authors: Michael Scott Asato Cuthbert
77
# Christopher Ariza
88
#
9-
# Copyright: Copyright © 2008-2024 Michael Scott Asato Cuthbert
9+
# Copyright: Copyright © 2008-2025 Michael Scott Asato Cuthbert
1010
# License: BSD, see license.txt
1111
# -----------------------------------------------------------------------------
1212
'''
@@ -59,7 +59,6 @@ class ActiveInformation(t.TypedDict, total=False):
5959
lastYielded: base.Music21Object|None
6060

6161

62-
6362
# -----------------------------------------------------------------------------
6463
class StreamIterator(prebase.ProtoM21Object, Sequence[M21ObjType]):
6564
'''
@@ -96,11 +95,11 @@ class StreamIterator(prebase.ProtoM21Object, Sequence[M21ObjType]):
9695
(for OffsetIterators, contains the first element last returned)
9796
* (This dict is shared among all sub iterators.)
9897
99-
Constructor keyword only arguments:
98+
Constructor keyword-only arguments:
10099
101100
* `filterList` is a list of stream.filters.Filter objects to apply
102101
103-
* if `restoreActiveSites` is True (default) then on iterating, the activeSite is set
102+
* if `restoreActiveSites` is True (default), then on iterating, the activeSite is set
104103
to the Stream being iterated over.
105104
106105
* if `ignoreSorting` is True (default is False) then the Stream is not sorted before
@@ -146,6 +145,7 @@ def __init__(self,
146145
self.streamLength: int = len(self.srcStreamElements)
147146

148147
# this information can help in speed later
148+
# noinspection PyProtectedMember
149149
self.elementsLength: int = len(self.srcStream._elements)
150150

151151
# where we are within a given section (_elements or _endElements)
@@ -312,7 +312,7 @@ def __getattr__(self, attr):
312312
return None
313313

314314
if not hasattr(self.srcStream, attr):
315-
# original stream did not have the attribute, so new won't; but raise on iterator.
315+
# the original stream did not have the attribute, so new won't; but raise on iterator.
316316
raise AttributeError(f'{self.__class__.__name__!r} object has no attribute {attr!r}')
317317

318318
warnings.warn(
@@ -325,15 +325,15 @@ def __getattr__(self, attr):
325325

326326
@overload
327327
def __getitem__(self, k: int) -> M21ObjType:
328-
return self.matchingElements()[k]
328+
...
329329

330330
@overload
331331
def __getitem__(self, k: slice) -> list[M21ObjType]:
332-
return self.matchingElements()
332+
...
333333

334334
@overload
335335
def __getitem__(self, k: str) -> M21ObjType|None:
336-
return None
336+
...
337337

338338
def __getitem__(self, k: int|slice|str) -> M21ObjType|list[M21ObjType]|None:
339339
'''
@@ -389,7 +389,7 @@ def __getitem__(self, k: int|slice|str) -> M21ObjType|list[M21ObjType]|None:
389389
<music21.note.Note F#>
390390
391391
Demo of cleanupOnStop = True; the sI[0] call counts as another iteration, so
392-
after it is called there is nothing more to iterate over! Note that cleanupOnStop
392+
after it is called, there is nothing more to iterate over! Note that cleanupOnStop
393393
will be removed in music21 v10.
394394
395395
>>> sI.cleanupOnStop = True
@@ -495,7 +495,7 @@ def __bool__(self) -> bool:
495495

496496
# do not change active site of first element in bool
497497
with tempAttribute(self, 'restoreActiveSites', False):
498-
for unused in self:
498+
for _ in self:
499499
return True
500500

501501
return False
@@ -658,8 +658,11 @@ def cleanup(self) -> None:
658658
self.reset()
659659

660660
# cleanupOnStop is rarely used, so we put in
661-
# a dummy stream so that srcStream does not need
662-
# to be x|None
661+
# a dummy stream so that self.srcStream does not need
662+
# to be typed as Stream|None
663+
664+
# eventually want this to work
665+
# SrcStreamClass = t.cast(type[StreamType], self.srcStream.__class__)
663666
SrcStreamClass = self.srcStream.__class__
664667

665668
del self.srcStream
@@ -886,8 +889,10 @@ def stream(
886889
# if this stream was sorted, the resultant stream is sorted
887890
clearIsSorted = False
888891
found: streamModule.Stream|StreamType
889-
if returnStreamSubClass is True:
892+
if returnStreamSubClass:
890893
try:
894+
# PyCharm??? totally used!
895+
# noinspection PyUnusedLocal
891896
found = ss.__class__()
892897
except TypeError:
893898
found = self._newBaseStream()
@@ -1619,6 +1624,9 @@ def __next__(self) -> list[M21ObjType]: # type: ignore
16191624
retElOffset = self.srcStream.elementOffset(retEl)
16201625
retElementList = [retEl]
16211626

1627+
# this inspection does not catch that we do return consistently
1628+
# because we catch the end of the while with the StopIteration
1629+
# noinspection PyInconsistentReturns
16221630
while self.elementIndex <= self.streamLength:
16231631
nextEl = super().__next__()
16241632
nextElOffset = self.srcStream.elementOffset(nextEl)
@@ -1630,7 +1638,7 @@ def __next__(self) -> list[M21ObjType]: # type: ignore
16301638
self.activeInformation['lastYielded'] = retElementList[0]
16311639
return retElementList
16321640

1633-
except StopIteration:
1641+
except StopIteration: # from the while statement.
16341642
if retElementList:
16351643
self.raiseStopIterationNext = True
16361644
self.activeInformation['lastYielded'] = retElementList[0]
@@ -1705,7 +1713,7 @@ def getElementsByClass(self,
17051713

17061714

17071715
# -----------------------------------------------------------------------------
1708-
class RecursiveIterator(StreamIterator, Sequence[M21ObjType]):
1716+
class RecursiveIterator(StreamIterator[M21ObjType], Sequence[M21ObjType]):
17091717
'''
17101718
One of the most powerful iterators in music21. Generally not called
17111719
directly, but created by being invoked on a stream with `Stream.recurse()`
@@ -1974,7 +1982,7 @@ def currentHierarchyOffset(self):
19741982
None
19751983
19761984
The offsets are with respect to the position inside the stream
1977-
being iterated, so for instance, this will not change the output from above:
1985+
being iterated, so, for instance, this will not change the output from above:
19781986
19791987
>>> o = stream.Opus()
19801988
>>> o.insert(20.0, b)
@@ -2043,7 +2051,7 @@ def getElementsByOffsetInHierarchy(
20432051
<music21.note.Note F#> 9.0 3 Bass
20442052
<music21.note.Note B> 9.5 3 Bass
20452053
2046-
* Changed in v5.5: all behavior changing options are keyword only.
2054+
* Changed in v5.5: all behavior-changing options are keyword only.
20472055
'''
20482056
f = filters.OffsetHierarchyFilter(
20492057
offsetStart,
@@ -2138,8 +2146,8 @@ def testAddingFiltersMidIteration(self):
21382146
obj0 = next(sIter2)
21392147
self.assertIs(obj0, r)
21402148

2141-
# original StreamIterator should be at its original spot, so this should
2142-
# move to next element
2149+
# the original StreamIterator should be at its original spot, so this should
2150+
# move to the next element
21432151
n0 = next(sIter)
21442152
self.assertIs(n0, n)
21452153

@@ -2160,14 +2168,15 @@ def testCurrentHierarchyOffsetReset(self):
21602168
p.append(m)
21612169
pRecurse = p.recurse(includeSelf=True)
21622170
allOffsets = []
2163-
for unused in pRecurse:
2171+
for _ in pRecurse:
21642172
allOffsets.append(pRecurse.currentHierarchyOffset())
21652173
self.assertListEqual(allOffsets, [0.0, 0.0, 1.0, 1.0, 2.0])
21662174
currentOffset = pRecurse.currentHierarchyOffset()
21672175
self.assertIsNone(currentOffset)
21682176

21692177
def testAddingFiltersMidRecursiveIteration(self):
21702178
from music21 import stream
2179+
# noinspection PyUnresolvedReferences
21712180
from music21.stream.iterator import RecursiveIterator as ImportedRecursiveIterator
21722181
m = stream.Measure()
21732182
r = note.Rest()

0 commit comments

Comments
 (0)