Skip to content

Commit

Permalink
Merge pull request #1339 from jacobtylerwalls/no-member
Browse files Browse the repository at this point in the history
Enable pylint `no-member` check
  • Loading branch information
mscuthbert authored Aug 6, 2022
2 parents 04428a5 + e020f7a commit 83b7020
Show file tree
Hide file tree
Showing 23 changed files with 119 additions and 97 deletions.
7 changes: 1 addition & 6 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ disable=
fixme, # obviously known
superfluous-parens, # nope -- if they make things clearer...
too-many-statements, # someday
no-member, # important, but too many false positives
too-many-arguments, # definitely! but takes too long to get a fix now...
too-many-public-methods, # maybe...
too-many-branches, # yes, someday
Expand Down Expand Up @@ -273,11 +272,7 @@ ignored-modules=

# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set).
ignored-classes=SQLObject

# When zope mode is activated, add a predefined set of Zope acquired attributes
# to generated-members.
# zope=no
ignored-classes=StreamCore

# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular
Expand Down
2 changes: 1 addition & 1 deletion music21/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1910,7 +1910,7 @@ def contextSites(
callerFirst = self
if self.isStream and self not in memo:
streamSelf = t.cast('music21.stream.Stream', self)
recursionType = streamSelf.recursionType
recursionType = streamSelf.recursionType # pylint: disable=no-member
environLocal.printDebug(
f'Caller first is {callerFirst} with offsetAppend {offsetAppend}')
if returnSortTuples:
Expand Down
13 changes: 8 additions & 5 deletions music21/chord/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def __deepcopy__(self: _ChordBaseType, memo=None) -> _ChordBaseType:
# after copying, if a Volume exists, it is linked to the old object
# look at _volume so as not to create object if not already there
# noinspection PyProtectedMember
for d in new._notes:
for d in new._notes: # pylint: disable=no-member
# if .volume is called, a new Volume obj will be created
if d.hasVolumeInformation():
d.volume.client = new # update with new instance
Expand Down Expand Up @@ -379,6 +379,9 @@ def remove(self, removeItem):
except ValueError:
raise ValueError('Chord.remove(x), x not in chord')

@property
def notes(self) -> t.Tuple[note.NotRest, ...]:
return ()

@property
def tie(self):
Expand Down Expand Up @@ -5182,7 +5185,7 @@ def multisetCardinality(self):
return len(self.pitchClasses)

@property
def notes(self):
def notes(self) -> t.Tuple[note.Note, ...]:
'''
Return a tuple (immutable) of the notes contained in the chord.
Expand Down Expand Up @@ -5244,7 +5247,7 @@ def notes(self):
return tuple(self._notes)

@notes.setter
def notes(self, newNotes):
def notes(self, newNotes: t.Iterable[note.Note]) -> None:
'''
sets notes to an iterable of Note objects
'''
Expand Down Expand Up @@ -5805,9 +5808,9 @@ def scaleDegrees(self):
'''
from music21 import scale
# roman numerals have this built in as the key attribute
if hasattr(self, 'key') and self.key is not None:
if hasattr(self, 'key') and self.key is not None: # pylint: disable=no-member
# Key is a subclass of scale.DiatonicScale
sc = self.key
sc = self.key # pylint: disable=no-member
else:
sc = self.getContextByClass(scale.Scale, sortByCreationTime=True)
if sc is None:
Expand Down
3 changes: 2 additions & 1 deletion music21/clef.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,9 @@ def getStemDirectionForPitches(
relevantPitches = pitchList

differenceSum = 0
# pylint: disable-next=no-member
if isinstance(self, (PercussionClef, PitchClef)) and self.lowestLine is not None:
midLine = self.lowestLine + 4
midLine = self.lowestLine + 4 # pylint: disable=no-member
else:
midLine = 35 # assume TrebleClef-like.

Expand Down
5 changes: 3 additions & 2 deletions music21/converter/subConverters.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,8 @@ def show(self, obj, fmt, app=None, subformats=None, **keywords): # pragma: no c
subformats = ['vexflow']

if subformats and subformats[0] == 'vexflow':
return self.vfshow(obj)
raise NotImplementedError
# return self.vfshow(obj)
# subformats = ['lilypond', 'png']
if subformats:
helperFormat = subformats[0]
Expand Down Expand Up @@ -1340,7 +1341,7 @@ def parseData(self, strData, number=None):
from music21.capella import fromCapellaXML
ci = fromCapellaXML.CapellaImporter()
ci.parseXMLText(strData)
scoreObj = ci.systemScoreFromScore(self.mainDom.documentElement)
scoreObj = ci.systemScoreFromScore(ci.mainDom.documentElement)
partScore = ci.partScoreFromSystemScore(scoreObj)
self.stream = partScore

Expand Down
3 changes: 3 additions & 0 deletions music21/features/outputFormats.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ def getHeaderLines(self):
'''
pass # define in subclass

def getString(self, includeClassLabel=True, includeId=True, lineBreak=None):
pass # define in subclass

def write(self, fp=None, includeClassLabel=True, includeId=True):
'''
Write the file. If not file path is given, a temporary file will be written.
Expand Down
2 changes: 1 addition & 1 deletion music21/freezeThaw.py
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,7 @@ def open(self, fp, zipType=None):
try:
storage = pickle.loads(uncompressed)
except AttributeError as e:
common.restoreWindowsAfterUnpickling()
common.restorePathClassesAfterUnpickling()
raise FreezeThawException(
f'Problem in decoding: {e}'
) from e
Expand Down
4 changes: 4 additions & 0 deletions music21/graph/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
from music21 import environment
environLocal = environment.Environment('graph.plot')

# Graph uses setattr, which PyLint can't infer from currently
# https://github.com/PyCQA/pylint/issues/2878
# pylint: disable=no-member


# ------------------------------------------------------------------------------
# graphing utilities that operate on streams
Expand Down
2 changes: 1 addition & 1 deletion music21/humdrum/questions.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ def xtest015(self):
if thisInt.name != "P1":
intervals2[thisInt.name] += 1

for key in intervals2.sort(key='simpleName'):
for key in intervals2.keys().sort(key='simpleName'):
print(key, intervals2[key])

def test016(self):
Expand Down
1 change: 1 addition & 0 deletions music21/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,7 @@ def __init__(self):
super().__init__()
self._modifier = None
self._modifierToPercMapPitch = {}
self._percMapPitchToModifier = {}
self.midiChannel = 9 # 0-indexed, i.e. MIDI channel 10

def _getModifier(self):
Expand Down
3 changes: 2 additions & 1 deletion music21/midi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,8 @@ def __repr__(self):

@classmethod
def hasValue(cls, val):
return val in cls._value2member_map_
# https://github.com/PyCQA/pylint/issues/3941
return val in cls._value2member_map_ # pylint: disable=no-member


class ChannelVoiceMessages(_ContainsEnum):
Expand Down
3 changes: 2 additions & 1 deletion music21/musicxml/xmlToM21.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ def xmlStaffLayoutToStaffLayout(self, mxStaffLayout, inputM21=None):
staffLayout.staffNumber = staffNumber

if hasattr(self, 'staffLayoutObjects') and hasattr(self, 'offsetMeasureNote'):
# pylint: disable=no-member
staffLayoutKey = ((staffNumber or 1), self.offsetMeasureNote)
self.staffLayoutObjects[staffLayoutKey] = staffLayout

Expand Down Expand Up @@ -1277,7 +1278,7 @@ def xmlMetadata(self, el=None, inputM21=None):
movement-title, identification
'''
if el is None:
el = self.root
el = self.xmlRoot

if inputM21 is None:
md = metadata.Metadata()
Expand Down
1 change: 1 addition & 0 deletions music21/note.py
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,7 @@ def __deepcopy__(self, memo=None):
new = super().__deepcopy__(memo=memo)
# after copying, if a Volume exists, it is linked to the old object
# look at _volume so as not to create object if not already there
# pylint: disable=no-member
if self._volume is not None:
new.volume.client = new # update with new instance
return new
Expand Down
16 changes: 9 additions & 7 deletions music21/percussion.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# License: BSD, see license.txt
# ------------------------------------------------------------------------------

import typing as t
import unittest

from music21 import common
Expand Down Expand Up @@ -58,11 +59,11 @@ class PercussionChord(chord.ChordBase):


@property
def notes(self) -> tuple:
def notes(self) -> t.Tuple[note.NotRest, ...]:
return tuple(self._notes)

@notes.setter
def notes(self, newNotes):
def notes(self, newNotes: t.Iterable[t.Union[note.Unpitched, note.Note]]) -> None:
'''
Sets notes to an iterable of Note or Unpitched objects
'''
Expand All @@ -79,12 +80,13 @@ def _reprInternal(self) -> str:

allNotes = []
for thisNote in self.notes:
if hasattr(thisNote, 'nameWithOctave'):
if isinstance(thisNote, note.Note):
allNotes.append(thisNote.nameWithOctave)
elif thisNote.storedInstrument:
allNotes.append(str(thisNote.storedInstrument.instrumentName))
else:
allNotes.append(f'unpitched[{thisNote.displayName}]')
elif isinstance(thisNote, note.Unpitched):
if thisNote.storedInstrument:
allNotes.append(str(thisNote.storedInstrument.instrumentName))
else:
allNotes.append(f'unpitched[{thisNote.displayName}]')

return '[' + ' '.join(allNotes) + ']'

Expand Down
2 changes: 1 addition & 1 deletion music21/pitch.py
Original file line number Diff line number Diff line change
Expand Up @@ -4172,7 +4172,7 @@ def informClient(self):
if this pitch is attached to a note, then let it know that it has changed.
'''
if self._client is not None:
self._client.pitchChanged()
self._client.pitchChanged() # pylint: disable=no-member


def getAllCommonEnharmonics(self: PitchType, alterLimit: int = 2) -> t.List[PitchType]:
Expand Down
7 changes: 5 additions & 2 deletions music21/romanText/rtObjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,10 @@ class RTKeyTypeAtom(RTAtom):
>>> gMinor = romanText.rtObjects.RTKeyTypeAtom('g;:')
>>> gMinor
<music21.romanText.rtObjects.RTKeyTypeAtom 'g;:'>
>>> gMinor.getKey()
<music21.key.Key of g minor>
'''
footerStrip = ';:'

def getKey(self):
'''
Expand Down Expand Up @@ -868,7 +871,7 @@ class RTKey(RTKeyTypeAtom):

class RTAnalyticKey(RTKeyTypeAtom):
'''An RTAnalyticKey(RTKeyTypeAtom) only defines a change in the key
being analyzed. It does not in itself create a :class:~'music21.key.Key'
being analyzed. It does not in itself create a :class:`~music21.key.Key`
object.
>>> gMinor = romanText.rtObjects.RTAnalyticKey('g:')
Expand All @@ -890,7 +893,7 @@ class RTAnalyticKey(RTKeyTypeAtom):
class RTKeySignature(RTAtom):
'''
An RTKeySignature(RTAtom) only defines a change in the KeySignature.
It does not in itself create a :class:~'music21.key.Key' object, nor
It does not in itself create a :class:`~music21.key.Key` object, nor
does it change the analysis taking place.
The number after KS defines the number of sharps (negative for flats).
Expand Down
4 changes: 2 additions & 2 deletions music21/scale/intervalNetwork.py
Original file line number Diff line number Diff line change
Expand Up @@ -2301,7 +2301,7 @@ def sortTerminusLowThenIntThenTerminusHigh(a):
n = self.nodes[nId]
if n.degree not in degreeCount:
degreeCount[n.degree] = 0
g.node[nId]['pos'] = (degreeCount[n.degree], n.degree)
g.node[nId]['pos'] = (degreeCount[n.degree], n.degree) # pylint: disable=no-member
degreeCount[n.degree] += 1
environLocal.printDebug(['got degree count', degreeCount])
return g
Expand All @@ -2327,7 +2327,7 @@ def plot(self,
# import is here to avoid import of matplotlib problems
from music21 import graph
# first ordered arg can be method type
g = graph.primitives.GraphNetworxGraph(
g = graph.primitives.GraphNetworkxGraph(
networkxGraph=self.getNetworkxGraph())
g.process()

Expand Down
3 changes: 2 additions & 1 deletion music21/search/serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class ContiguousSegmentOfNotes(base.Music21Object):
A list of pitch classes representing the way the contiguous
segment of notes is being read as a sequence of single pitches. Set to None
unless the container stream is being searched for segments or multisets
(for example, using :func:`~music21.search.serial.findSegments`), in which case
(for example, using :meth:`~music21.search.serial.SegmentMatcher.find`), in which case
the representation depends on the segments or multisets being searched for.
If there are no chords in the segment, this attribute will simply give the
pitch classes of the notes in the segment.''',
Expand All @@ -80,6 +80,7 @@ def __init__(self, segment=None, containerStream=None, partNumber=0):
self.segment = segment
self.containerStream = containerStream
self.partNumber = partNumber
self.activeSegment = []
self.matchedSegment = None

def _reprInternal(self):
Expand Down
3 changes: 3 additions & 0 deletions music21/spanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ def _deepcopySubclassable(self, memo=None, ignoreAttributes=None, removeFromIgno
# there used to be a bug here where spannerStorage would
# try to append twice. I've removed the guardrail here in v7.
# because I'm pretty sure we have solved it.
# disable pylint check until this inheritance bug is solved:
# https://github.com/PyCQA/astroid/issues/457
# pylint: disable=no-member
for c in self.spannerStorage._elements:
new.spannerStorage.coreAppend(c)
new.spannerStorage.coreElementsChanged(updateIsFlat=False)
Expand Down
5 changes: 3 additions & 2 deletions music21/stream/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1793,6 +1793,7 @@ class or subclass in the Stream in place.
elFilter = self.iter().getElementsNotOfClass(classFilterList)
return self._removeIteration(elFilter)

# pylint: disable=no-member
def _deepcopySubclassable(self, memo=None, ignoreAttributes=None, removeFromIgnore=None):
# NOTE: this is a performance critical operation
defaultIgnoreSet = {'_offsetDict', 'streamStatus', '_elements', '_endElements', '_cache',
Expand Down Expand Up @@ -1868,7 +1869,7 @@ def __deepcopy__(self, memo=None):
'''
# does not purgeOrphans -- q: is that a bug or by design?
new = self._deepcopySubclassable(memo)
if new._elements:
if new._elements: # pylint: disable:no-member
self._replaceSpannerBundleForDeepcopy(new)

# purging these orphans works in nearly all cases, but there are a few
Expand Down Expand Up @@ -12424,7 +12425,7 @@ def showVariantAsOssialikePart(self, containedPart, variantGroups, *, inPlace=Fa
else:
returnObj = self.coreCopyAsDerivation('showVariantAsOssialikePart')
containedPartIndex = self.parts.stream().index(containedPart)
returnPart = returnObj.parts[containedPartIndex]
returnPart = returnObj.iter().parts[containedPartIndex]

# First build a new part object that is the same length as returnPart
# but entirely hidden rests.
Expand Down
1 change: 0 additions & 1 deletion music21/test/testLint.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ def main(fnAccept=None, strict=False):
'too-many-ancestors', # -- 8 is okay.
'fixme', # known...
'superfluous-parens', # nope -- if they make things clearer...
'no-member', # important, but too many false positives
'too-many-locals', # no
'bad-whitespace', # maybe later, but "bad" isn't something I necessarily agree with
'bad-continuation', # never remove -- this is a good thing many times.
Expand Down
19 changes: 8 additions & 11 deletions music21/test/timeGraphs.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,20 @@ class Test:
# ------------------------------------------------------------------------------
class TestTimeHumdrum(Test):
def testFocus(self):
# pylint: disable=expression-not-assigned
# noinspection PyStatementEffect
music21.humdrum.parseData(music21.humdrum.humdrumTestFiles.mazurka6
).stream
music21.converter.parse(music21.humdrum.testFiles.mazurka6)

class TestTimeMozart(Test):
def testFocus(self):
music21.converter.parse(music21.corpus.getWork('k155')[0])

class TestTimeCapua1(Test):
def testFocus(self):
c1 = music21.trecento.capua.Test()
c1.testRunPiece()
# class TestTimeCapua1(Test):
# def testFocus(self):
# c1 = music21.trecento.capua.Test()
# c1.testRunPiece()

class TestTimeCapua2(Test):
def testFocus(self):
music21.trecento.capua.ruleFrequency()
# class TestTimeCapua2(Test):
# def testFocus(self):
# music21.trecento.capua.ruleFrequency()

class TestTimeIsmir(Test):
def testFocus(self):
Expand Down
Loading

0 comments on commit 83b7020

Please sign in to comment.