Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ init-import=no

# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=_$|dummy|unused|i$|j$|junk|counter
dummy-variables-rgx=_|dummy|unused|i$|j$|junk|counter

# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
Expand Down
34 changes: 17 additions & 17 deletions documentation/docbuild/documenters.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,8 +538,11 @@ def _formatInheritedMembersMapping(self, mapping, banner):
for classDocumenter in self.baseClassDocumenters:
if classDocumenter not in mapping:
continue
result.append(banner.format(
classDocumenter.rstCrossReferenceString))
result.append(
banner.format(
classDocumenter.rstCrossReferenceString
)
)
result.append('')
memberDocumenters = mapping[classDocumenter]
result.append('.. hlist::')
Expand Down Expand Up @@ -757,10 +760,9 @@ def inheritedReadwritePropertiesMapping(self):
>>> mapping = documenter.inheritedReadwritePropertiesMapping
>>> sortBy = lambda x: x.referentPackageSystemPath
>>> for classDocumenter in sorted(mapping, key=sortBy):
... print('{0}:'.format(classDocumenter.referentPackageSystemPath))
... print(f'{classDocumenter.referentPackageSystemPath}:')
... for attributeDocumenter in mapping[classDocumenter][:10]:
... print('- {0}'.format(attributeDocumenter.referentPackageSystemPath))
...
... print(f'- {attributeDocumenter.referentPackageSystemPath}')
music21.base.Music21Object:
- music21.base.Music21Object.activeSite
- music21.base.Music21Object.derivation
Expand Down Expand Up @@ -940,13 +942,10 @@ def rstInheritedDocAttrFormat(self):
result.append('.. hlist::')
result.append(' :columns: 3')
result.append('')
formatString = ' - :attr:`~{0}.{1}`'
basePath = baseDocumenter.referentPackageSystemPath
for attrName in attrNames:
result.append(
formatString.format(
baseDocumenter.referentPackageSystemPath,
attrName,
)
f' - :attr:`~{basePath}.{attrName}`'
)
result.append('')
return result
Expand Down Expand Up @@ -1594,14 +1593,15 @@ def getRstComposerWorksFormat(self, corpusWork):

# def getRstVirtualWorkFileDictFormat(self, corpusFile):
# result = []
# result.append('- {0} *({1})*: `{2}`'.format(
# str(corpusFile.title),
# str(corpusFile.format),
# str(corpusFile.path),
# ))
# result.append(
# f'- {corpusFile.title} '
# f'*({corpusFile.format})*: '
# f'`{corpusFile.path}`'
# )
# result.append('')
# result.append(' Source: {0}'.format(
# str(corpusFile.url)))
# result.append(
# f' Source: {corpusFile.url}'
# )
# result.append('')
# return result

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,17 @@
"Conventions:\n",
"\n",
" - **Strings MUST be 'single-quoted', but \"double quotes\" are allowed internally**\n",
" - This rule applies to triple quotes and doc strings also, contrary to PEP 257.\n",
" - Docstrings must begin and end on their own lines. No one-line doc-strings or text\n",
" - This rule applies to triple quotes and docstrings also, contrary to PEP 257.\n",
" - Docstrings must begin and end on their own lines. No one-line docstrings or text\n",
" immediately following the triple quotes.\n",
" - When there is a hyphen or single quote in the string, double quotes should be used,\n",
" not escaping/backslashing.\n",
" - For long streams of TinyNotation or Lilypond code, which both use single quotes to indicate octave,\n",
" triple single quotes around the string are better than double quotes. Internal whitespace\n",
" rarely matters in those formats.\n",
" - Before v10 concatenating strings without a plus sign was discouraged. I've changed my mind,\n",
" and am \"letting Python be Python\" now especially when three or more lines are involved.\n",
" However, use a + sign if concatenation is mixed with different comma-separated arguments.\n",
" - Documentation should follow quoting in American English grammar when not\n",
" discussing code. So for instance, a quotation in documentation is in double quotes.\n",
" - Variable names:\n",
Expand All @@ -163,7 +166,8 @@
" - Line lengths are capped at 100, but if approaching this limit, look for ways to avoid one-lining.\n",
" - if it's easy to split your line into two which are both under 80 characters, do so.\n",
" - Line continuation characters (`\\`) are not allowed; use open parentheses.\n",
" - Prefer f-strings to `.format()`. The `%` interpolation is no longer allowed.\n",
" - Greatly prefer f-strings to `.format()`. The `%` interpolation is no longer allowed.\n",
" - `.format()` is only to be used when a repeated format string is involved.\n",
" - Annotating types is **required** in new code, and encouraged to be added to older code.\n",
" - e.g. `self.counter: int = 0` or `def makeNoises() -> list['noise.Noise']:`\n",
" - The typing library should always be imported as `t`.\n",
Expand Down Expand Up @@ -193,7 +197,8 @@
" manipulation of the original object. When `inPlace` is True, nothing should be returned\n",
" (not true for `music21j` since passing through objects is so expected in JavaScript thanks\n",
" to JQuery and other libraries). Use the `@overload` decorator to show how this parameter\n",
" affects the return value -- Python makes this a bit hard, but see for instance, :meth:`~music21.stream.base.Stream.getElementsByClass` for an example of how to use this.\n",
" affects the return value -- Python makes this a bit hard, but see for\n",
" instance, :meth:`~music21.stream.base.Stream.getElementsByClass` for an example of how to use this.\n",
" - Use descriptive pull request titles (rather than GitHub's default \"Update pitch.py\")\n",
" - Do not have a PR title so long that it cannot be seen in one line. Simplify and\n",
" rewrite and go into more detail in the description. I depend on skimming PR titles\n",
Expand Down
10 changes: 10 additions & 0 deletions music21/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,16 @@
'voiceLeading',
'volpiano',
'volume',

'Music21Exception',
'SitesException',
'Music21ObjectException',
'ElementException',

'Groups',
'Music21Object',
'ElementWrapper',
'VERSION',
]

# ------------------------------------------------------------------------------
Expand Down
57 changes: 30 additions & 27 deletions music21/abcFormat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2621,7 +2621,7 @@ def tokenProcess(self) -> None:
else:
environLocal.printDebug(
['broken rhythm marker '
+ f'({token.src}) not positioned between two notes or chords'])
f'({token.src}) not positioned between two notes or chords'])

# need to update tuplets with currently active meter
if isinstance(token, ABCTuplet):
Expand Down Expand Up @@ -2698,7 +2698,7 @@ def tokenProcess(self) -> None:
if lastDefaultQL is None:
raise ABCHandlerException(
'no active default note length provided for note processing. '
+ f'tPrev: {tPrev}, token: {token}, tNext: {tNext}'
f'tPrev: {tPrev}, token: {token}, tNext: {tNext}'
)
token.activeDefaultQuarterLength = lastDefaultQL
token.activeKeySignature = lastKeySignature
Expand Down Expand Up @@ -3671,21 +3671,22 @@ def testSplitByMeasure(self):
ah.process(testFiles.hectorTheHero)
ahm = ah.splitByMeasure()

for i, l, r in [(0, None, None), # metadata
(2, '|:', '|'),
(3, '|', '|'),
(-2, '[1', ':|'),
(-1, '[2', '|'),
]:
if l is None:
for i, left, right in [
(0, None, None), # metadata
(2, '|:', '|'),
(3, '|', '|'),
(-2, '[1', ':|'),
(-1, '[2', '|'),
]:
if left is None:
self.assertEqual(ahm[i].leftBarToken, None)
else:
self.assertEqual(ahm[i].leftBarToken.src, l)
self.assertEqual(ahm[i].leftBarToken.src, left)

if r is None:
if right is None:
self.assertEqual(ahm[i].rightBarToken, None)
else:
self.assertEqual(ahm[i].rightBarToken.src, r)
self.assertEqual(ahm[i].rightBarToken.src, right)

# for ahSub in ah.splitByMeasure():
# environLocal.printDebug(['split by measure:', ahSub.tokens])
Expand All @@ -3696,37 +3697,39 @@ def testSplitByMeasure(self):
ah.process(testFiles.theBeggerBoy)
ahm = ah.splitByMeasure()

for i, l, r in [(0, None, None), # metadata
(1, None, '|'),
(-1, '||', None), # trailing lyric metadata
]:
if l is None:
for i, left, right in [
(0, None, None), # metadata
(1, None, '|'),
(-1, '||', None), # trailing lyric metadata
]:
if left is None:
self.assertEqual(ahm[i].leftBarToken, None)
else:
self.assertEqual(ahm[i].leftBarToken.src, l)
self.assertEqual(ahm[i].leftBarToken.src, left)

if r is None:
if right is None:
self.assertEqual(ahm[i].rightBarToken, None)
else:
self.assertEqual(ahm[i].rightBarToken.src, r)
self.assertEqual(ahm[i].rightBarToken.src, right)

# test a simple string with no bars
ah = ABCHandler()
ah.process('M:6/8\nL:1/8\nK:G\nc1D2')
ahm = ah.splitByMeasure()

for i, l, r in [(0, None, None), # metadata
(-1, None, None), # note data, but no bars
]:
if l is None:
for i, left, right in [
(0, None, None), # metadata
(-1, None, None), # note data, but no bars
]:
if left is None:
self.assertEqual(ahm[i].leftBarToken, None)
else:
self.assertEqual(ahm[i].leftBarToken.src, l)
self.assertEqual(ahm[i].leftBarToken.src, left)

if r is None:
if right is None:
self.assertEqual(ahm[i].rightBarToken, None)
else:
self.assertEqual(ahm[i].rightBarToken.src, r)
self.assertEqual(ahm[i].rightBarToken.src, right)

def testMergeLeadingMetaData(self):
from music21.abcFormat import testFiles
Expand Down
2 changes: 1 addition & 1 deletion music21/analysis/correlate.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def pitchToDynamic(self, dataPoints=True):
dstCheck = self.streamObj.recurse().getElementsByClass(objName)
if not dstCheck:
raise CorrelateException('cannot create correlation: an object '
+ f'that is not found in the Stream: {objName}')
f'that is not found in the Stream: {objName}')

self._findActive(objNameSrc, objNameDst)

Expand Down
2 changes: 1 addition & 1 deletion music21/analysis/metrical.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def labelBeatDepth(streamIn):
>>> sOut = []
>>> for n in s.flatten().notes:
... stars = "".join([l.text for l in n.lyrics])
... sOut.append("{0:8s} {1}".format(n.beatStr, stars))
... sOut.append(f'{n.beatStr:8s} {stars}')
>>> print("\n".join(sOut))
1 ****
1 1/2 *
Expand Down
6 changes: 3 additions & 3 deletions music21/analysis/pitchAnalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def pitchAttributeCount(s, pitchAttr='name'):
>>> bach = corpus.parse('bach/bwv324.xml')
>>> pcCount = analysis.pitchAnalysis.pitchAttributeCount(bach, 'pitchClass')
>>> for n in sorted(pcCount):
... print("%2d: %2d" % (n, pcCount[n]))
... print(f'{n:2d}: {pcCount[n]:2d}')
0: 3
2: 26
3: 3
Expand All @@ -36,15 +36,15 @@ def pitchAttributeCount(s, pitchAttr='name'):

>>> nameCount = analysis.pitchAnalysis.pitchAttributeCount(bach, 'name')
>>> for n, count in nameCount.most_common(3):
... print("%2s: %2d" % (n, nameCount[n]))
... print(f'{n:>2s}: {nameCount[n]:2d}')
D: 26
A: 17
F#: 15


>>> nameOctaveCount = analysis.pitchAnalysis.pitchAttributeCount(bach, 'nameWithOctave')
>>> for n in sorted(nameOctaveCount):
... print("%3s: %2d" % (n, nameOctaveCount[n]))
... print(f'{n:>3s}: {nameOctaveCount[n]:2d}')
A2: 2
A3: 5
A4: 10
Expand Down
8 changes: 4 additions & 4 deletions music21/analysis/reduceChords.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ def computeMeasureChordWeights(
>>> cr = analysis.reduceChords.ChordReducer()
>>> cws = cr.computeMeasureChordWeights(s)
>>> for pcs in sorted(cws):
... print("%18r %2.1f" % (pcs, cws[pcs]))
... print(f'{pcs!r:18} {cws[pcs]:2.1f}')
(0, 4, 7) 3.0
(0, 11, 4, 5) 1.0

Expand All @@ -329,7 +329,7 @@ def computeMeasureChordWeights(
>>> cws = cr.computeMeasureChordWeights(s,
... weightAlgorithm=cr.quarterLengthBeatStrength)
>>> for pcs in sorted(cws):
... print("%18r %2.1f" % (pcs, cws[pcs]))
... print(f'{pcs!r:18} {cws[pcs]:2.1f}')
(0, 4, 7) 2.2
(0, 11, 4, 5) 0.5

Expand All @@ -338,7 +338,7 @@ def computeMeasureChordWeights(
>>> cws = cr.computeMeasureChordWeights(s,
... weightAlgorithm=cr.quarterLengthBeatStrengthMeasurePosition)
>>> for pcs in sorted(cws):
... print("%18r %2.1f" % (pcs, cws[pcs]))
... print(f'{pcs!r:18} {cws[pcs]:2.1f}')
(0, 4, 7) 3.0
(0, 11, 4, 5) 0.5

Expand All @@ -347,7 +347,7 @@ def computeMeasureChordWeights(
>>> cws = cr.computeMeasureChordWeights(s,
... weightAlgorithm=cr.qlbsmpConsonance)
>>> for pcs in sorted(cws):
... print("%18r %2.1f" % (pcs, cws[pcs]))
... print(f'{pcs!r:18} {cws[pcs]:2.1f}')
(0, 4, 7) 3.0
(0, 11, 4, 5) 0.1
'''
Expand Down
8 changes: 4 additions & 4 deletions music21/analysis/reduceChordsOld.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,15 @@ def computeMeasureChordWeights(self, measureObj, weightAlgorithm=None):
>>> cr = analysis.reduceChordsOld.ChordReducer()
>>> cws = cr.computeMeasureChordWeights(s)
>>> for pcs in sorted(cws):
... print("%18r %2.1f" % (pcs, cws[pcs]))
... print(f'{pcs!r:18} {cws[pcs]:2.1f}')
(0, 4, 7) 3.0
(0, 11, 4, 5) 1.0

Add beatStrength:

>>> cws = cr.computeMeasureChordWeights(s, weightAlgorithm=cr.quarterLengthBeatStrength)
>>> for pcs in sorted(cws):
... print("%18r %2.1f" % (pcs, cws[pcs]))
... print(f'{pcs!r:18} {cws[pcs]:2.1f}')
(0, 4, 7) 2.2
(0, 11, 4, 5) 0.5

Expand All @@ -176,15 +176,15 @@ def computeMeasureChordWeights(self, measureObj, weightAlgorithm=None):
>>> cws = cr.computeMeasureChordWeights(s,
... weightAlgorithm=cr.quarterLengthBeatStrengthMeasurePosition)
>>> for pcs in sorted(cws):
... print("%18r %2.1f" % (pcs, cws[pcs]))
... print(f'{pcs!r:18} {cws[pcs]:2.1f}')
(0, 4, 7) 3.0
(0, 11, 4, 5) 0.5

Make consonance count a lot:

>>> cws = cr.computeMeasureChordWeights(s, weightAlgorithm=cr.qlbsmpConsonance)
>>> for pcs in sorted(cws):
... print("%18r %2.1f" % (pcs, cws[pcs]))
... print(f'{pcs!r:18} {cws[pcs]:2.1f}')
(0, 4, 7) 3.0
(0, 11, 4, 5) 0.5
'''
Expand Down
8 changes: 4 additions & 4 deletions music21/analysis/reduction.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,13 @@ def _extractNoteReductiveEvent(self, n, infoDict=None, removeAfterParsing=True):


# a list of Lyric objects
for k, l in enumerate(n.lyrics):
for k, lyr in enumerate(n.lyrics):
# store measure index
rn = ReductiveNote(l.text, n, infoDict['measureIndex'], offset)
rn = ReductiveNote(lyr.text, n, infoDict['measureIndex'], offset)
if rn.isParsed():
# environLocal.printDebug(['parsing reductive note', rn])
# use id, lyric text as hash
key = str(id(n)) + l.text
key = str(id(n)) + lyr.text
self._reductiveNotes[key] = rn
removalIndices.append(k)
if removeAfterParsing:
Expand Down Expand Up @@ -1095,7 +1095,7 @@ def _matchWeightedData(self, match, target):
dataMatch[2],
dataTarget[2],
msg=(f'for partId {partId}, entry {i}: '
+ f'should be {dataMatch[2]} <-> was {dataTarget[2]}')
f'should be {dataMatch[2]} <-> was {dataTarget[2]}')
)

def testPartReductionB(self, show=False):
Expand Down
3 changes: 2 additions & 1 deletion music21/analysis/windowed.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ def analyze(self, windowSize, windowType='overlap'):
windowCount = int(windowCountFloat)
if windowCountFloat != windowCount:
warnings.warn(
'maxWindowCount is not divisible by windowSize, possibly undefined behavior'
'maxWindowCount is not divisible by windowSize, possibly undefined behavior',
stacklevel=2
)
elif windowType == 'adjacentAverage':
windowCount = maxWindowCount
Expand Down
Loading