Skip to content

Commit

Permalink
Merge pull request #1286 from cuthbertLab/iterator_fixes
Browse files Browse the repository at this point in the history
Work around not-an-iterable bug; Expr. docs; rem .iter.
  • Loading branch information
mscuthbert committed Apr 30, 2022
2 parents b889fa7 + cb18ab2 commit 5381ab6
Show file tree
Hide file tree
Showing 11 changed files with 289 additions and 132 deletions.
1 change: 0 additions & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ confidence=
# anything changed here, also change in test/testLint.py for now

disable=
not-an-iterable, # TOO BAD -- this is important, but so many false positives
cyclic-import, # we use these inside functions when there's a deep problem.
unnecessary-pass, # not really a problem..
locally-disabled, # test for this later, but hopefully will know what we're doing
Expand Down
16 changes: 14 additions & 2 deletions music21/dynamics.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# Authors: Michael Scott Asato Cuthbert
# Christopher Ariza
#
# Copyright: Copyright © 2009-2015 Michael Scott Asato Cuthbert and the music21 Project
# Copyright: Copyright © 2009-2022 Michael Scott Asato Cuthbert and the music21 Project
# License: BSD, see license.txt
# ------------------------------------------------------------------------------

Expand Down Expand Up @@ -212,7 +212,19 @@ class Dynamic(base.Music21Object):
>>> d.englishName
'very soft'
''',
'placement': "Staff placement: 'above', 'below', or None.",
'placement': '''
Staff placement: 'above', 'below', or None.
A setting of None implies that the placement will be determined
by notation software and no particular placement is demanded.
This is not placed in the `.style` property, since for some dynamics,
the placement above or below an object has semantic
meaning and is not purely presentational. For instance, a dynamic
placed between two staves in a piano part implies that it applies
to both hands, while one placed below the lower staff would apply
only to the left hand.
''',
}

def __init__(self, value=None):
Expand Down
2 changes: 1 addition & 1 deletion music21/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,7 @@ class Environment:
PosixPath('/Applications/Finale Reader.app')
'''

# define order to present names in documentation; use strings
# Defines the order of presenting names in the documentation; use strings
_DOC_ORDER = ['read', 'write', 'getSettingsPath']

# documentation for all attributes (not properties or methods)
Expand Down
43 changes: 29 additions & 14 deletions music21/expressions.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
# Name: expressions.py
# Purpose: notation mods
# Purpose: Expressions such as Fermatas, etc.
#
# Authors: Michael Scott Asato Cuthbert
# Christopher Ariza
# Neena Parikh
#
# Copyright: Copyright © 2009-2012 Michael Scott Asato Cuthbert and the music21 Project
# Copyright: Copyright © 2009-2022 Michael Scott Asato Cuthbert and the music21 Project
# License: BSD, see license.txt
# ------------------------------------------------------------------------------
'''
This module provides object representations of expressions, that is
notational symbols such as Fermatas, Mordents, Trills, Turns, etc.
which are stored under a Music21Object's .expressions attribute
which are stored under a Music21Object's .expressions attribute.
It also includes representations of things such as TextExpressions which
are better attached to the Stream itself.
A sub-category of Expressions are Ornaments.
TODO: replace .size with a string representing interval and then
create interval.Interval objects only when necessary.
Unlike articulations, expressions can be attached to the Stream itself.
For instance, TextExpressions.
'''
# TODO: replace .size with a string representing interval and then
# create interval.Interval objects only when necessary.

import copy
import string
import unittest
Expand All @@ -42,7 +44,6 @@ def realizeOrnaments(srcObject):
convert them into a list of objects that represents
the performed version of the object:
>>> n1 = note.Note('D5')
>>> n1.quarterLength = 1
>>> n1.expressions.append(expressions.WholeStepMordent())
Expand Down Expand Up @@ -328,7 +329,16 @@ class TextExpression(Expression):
_styleClass = style.TextStyle

_DOC_ATTR = {
'placement': "Staff placement: 'above', 'below', or None.",
'placement': '''
Staff placement: 'above', 'below', or None.
A setting of None implies that the placement will be determined
by notation software and no particular placement is demanded.
This is not placed in the `.style` property, since for some
expressions, the placement above or below an object has semantic
meaning and is not purely presentational.
''',
}

def __init__(self, content=None):
Expand Down Expand Up @@ -422,7 +432,7 @@ def getRepeatExpression(self):
# this will transfer all positional/formatting settings
re.setTextExpression(copy.deepcopy(self))
return re
# if cannot be expressed as a repeat expression
# Return None if it cannot be expressed as a repeat expression
return None

def getTempoText(self):
Expand Down Expand Up @@ -1344,8 +1354,9 @@ class TrillExtension(spanner.Spanner):
>>> print(te)
<music21.expressions.TrillExtension <music21.note.Note C><music21.note.Note C>>
'''
# musicxml defines a start, stop, and a continue; will try to avoid continue
# note that this always includes a trill symbol
# musicxml defines a "start", "stop", and a "continue" type;
# We will try to avoid "continue".
# N.B. this extension always includes a trill symbol

def __init__(self, *arguments, **keywords):
super().__init__(*arguments, **keywords)
Expand All @@ -1369,6 +1380,9 @@ def _setPlacement(self, value):
>>> te.placement = 'above'
>>> te.placement
'above'
A setting of None implies that the placement will be determined
by notation software and no particular placement is demanded.
''')


Expand All @@ -1388,7 +1402,8 @@ class TremoloSpanner(spanner.Spanner):
Traceback (most recent call last):
music21.expressions.TremoloException: Number of marks must be a number from 0 to 8
'''
# musicxml defines a start, stop, and a continue; will try to avoid continue
# musicxml defines a "start", "stop", and a "continue" type.
# We will try to avoid using the "continue" type.

def __init__(self, *arguments, **keywords):
super().__init__(*arguments, **keywords)
Expand Down Expand Up @@ -1568,7 +1583,7 @@ def testUnpitchedUnsupported(self):
unp = note.Unpitched()
mord = Mordent()
with self.assertRaises(TypeError):
mord.realize(unp)
mord.realize(unp) # type: ignore


# class TestExternal(unittest.TestCase):
Expand Down
20 changes: 10 additions & 10 deletions music21/note.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ class GeneralNote(base.Music21Object):
isChord = False
_styleClass: Type[style.Style] = style.NoteStyle

# define order to present names in documentation; use strings
# define order for presenting names in documentation; use strings
_DOC_ORDER = ['duration', 'quarterLength']
# documentation for all attributes (not properties or methods)
_DOC_ATTR = {
Expand Down Expand Up @@ -553,8 +553,8 @@ def __init__(self, *arguments, **keywords):

def __eq__(self, other):
'''
General Note objects are equal if their durations are equal and
they have the same articulation and expression classes (in any order)
General Note objects are equal if their durations are equal, and
they have the same articulation and expression classes (in any order),
and their ties are equal.
'''

Expand All @@ -563,10 +563,10 @@ def __eq__(self, other):
# checks type, dots, tuplets, quarterLength, uses Pitch.__eq__
if self.duration != other.duration:
return False
# articulations are a list of Articulation objects
# converting to sets produces ordered cols that remove duplicate
# however, must then convert to list to match based on class ==
# not on class id()
# Articulations are a list of Articulation objects.
# Converting them to Set objects produces ordered cols that remove duplicates.
# However, we must then convert to list to match based on class ==
# not on class id().
if (sorted({x.classes[0] for x in self.articulations})
!= sorted({x.classes[0] for x in other.articulations})):
return False
Expand Down Expand Up @@ -936,7 +936,7 @@ def __eq__(self, other):
def __deepcopy__(self, memo=None):
'''
As NotRest objects have a Volume, objects, and Volume objects
store weak refs to the to client object, need to specialize deep copy handling
store weak refs to the client object, need to specialize deep copy handling
>>> import copy
>>> n = note.NotRest()
Expand Down Expand Up @@ -1342,7 +1342,7 @@ class Note(NotRest):
'''
isNote = True

# define order to present names in documentation; use strings
# Defines the order of presenting names in the documentation; use strings
_DOC_ORDER = ['duration', 'quarterLength', 'nameWithOctave']
# documentation for all attributes (not properties or methods)
_DOC_ATTR = {
Expand Down Expand Up @@ -2259,7 +2259,7 @@ def testTieContinue(self):
s = stream.Stream()
s.append([n1, n2, n3])

# need to test that this gets us a continue tie, but hard to test
# need to test that this gets us a "continue" tie, but hard to test
# post musicxml processing
# s.show()

Expand Down
2 changes: 1 addition & 1 deletion music21/prebase.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class ProtoM21Object:
objects that only inherit from ProtoM21Object unless you like wasting 200ns.
'''

# define order to present names in documentation; use strings
# Defines the order of presenting names in the documentation; use strings
_DOC_ORDER = [
'classes',
'classSet',
Expand Down
Loading

0 comments on commit 5381ab6

Please sign in to comment.