diff --git a/music21/common/misc.py b/music21/common/misc.py index f0f6609eb..11ee48307 100644 --- a/music21/common/misc.py +++ b/music21/common/misc.py @@ -26,19 +26,17 @@ import typing as t import weakref -from music21.common.decorators import deprecated - __all__ = [ + 'cleanedFlatNotation', + 'defaultDeepcopy', 'flattenList', 'getMissingImportStr', 'getPlatform', 'macOSVersion', - 'sortModules', 'pitchList', - 'unique', 'runningInNotebook', - 'defaultDeepcopy', - 'cleanedFlatNotation', + 'sortModules', + 'unique', ] if t.TYPE_CHECKING: @@ -229,14 +227,6 @@ def runningInNotebook() -> bool: return False -@deprecated('v9', 'v10', 'use runningInNotebook() instead') -def runningUnderIPython() -> bool: # pragma: no cover - ''' - DEPRECATED in v9: use runningInNotebook() instead - ''' - return runningInNotebook() - - # ---------------------------- # match collections, defaultdict() diff --git a/music21/common/numberTools.py b/music21/common/numberTools.py index 323095541..62be3cfe1 100644 --- a/music21/common/numberTools.py +++ b/music21/common/numberTools.py @@ -21,34 +21,34 @@ import unittest from music21 import defaults -from music21.common import deprecated from music21.common.types import OffsetQLIn, OffsetQL if TYPE_CHECKING: - from decimal import Decimal - from collections.abc import Iterable, Sequence, Collection + from collections.abc import Sequence, Collection __all__ = [ - 'ordinals', 'musicOrdinals', 'ordinalsToNumbers', - 'numToIntOrFloat', - - 'opFrac', 'mixedNumeral', - 'roundToHalfInteger', - 'addFloatPrecision', 'strTrimFloat', - 'nearestMultiple', - - 'dotMultiplier', 'decimalToTuplet', - 'unitNormalizeProportion', 'unitBoundaryProportion', - 'weightedSelection', + 'addFloatPrecision', 'approximateGCD', - 'contiguousList', - + 'decimalToTuplet', + 'dotMultiplier', + 'fromRoman', 'groupContiguousIntegers', - - 'fromRoman', 'toRoman', + 'mixedNumeral', + 'musicOrdinals', + 'nearestMultiple', + 'numToIntOrFloat', + 'opFrac', 'ordinalAbbreviation', + 'ordinals', + 'ordinalsToNumbers', + 'roundToHalfInteger', + 'strTrimFloat', + 'toRoman', + 'unitBoundaryProportion', + 'unitNormalizeProportion', + 'weightedSelection', ] ordinals = [ @@ -855,42 +855,6 @@ def approximateGCD(values: Collection[int|float|Fraction], grain: float = 1e-4) return max(commonUniqueDivisions) -@deprecated('v9', 'v10', 'Use math.lcm instead') -def lcm(filterList: Iterable[int]) -> int: - ''' - Find the least common multiple of a list of values - - common.lcm([3, 4, 5]) - 60 - common.lcm([3, 4]) - 12 - common.lcm([1, 2]) - 2 - common.lcm([3, 6]) - 6 - - Works with any iterable, like this set - - common.lcm({3, 5, 6}) - 30 - - Deprecated in v9 since Python 3.10 is the minimum version - and math.lcm works in C and is faster - ''' - def _lcm(a, b): - ''' - find the least common multiple of a, b - ''' - # // forces integer style division (no remainder) - return abs(a * b) // gcd(a, b) - - # derived from - # http://www.oreillynet.com/cs/user/view/cs_msg/41022 - lcmVal = 1 - for flValue in filterList: - lcmVal = _lcm(lcmVal, flValue) - return lcmVal - def contiguousList(inputListOrTuple) -> bool: ''' @@ -1125,6 +1089,10 @@ def ordinalAbbreviation(value: int, plural=False) -> str: ordinalsToNumbers[musicOrdinalNameLower] = ordinal_index del ordinal_index +del ordinalName +del ordinalNameLower +del musicOrdinalName +del musicOrdinalNameLower class Test(unittest.TestCase): diff --git a/music21/converter/__init__.py b/music21/converter/__init__.py index 821da9f32..56c7fc79f 100644 --- a/music21/converter/__init__.py +++ b/music21/converter/__init__.py @@ -36,7 +36,6 @@ from __future__ import annotations from collections import deque -import copy from http.client import responses import io from math import isclose @@ -69,14 +68,26 @@ __all__ = [ - 'subConverters', 'museScore', - 'ArchiveManagerException', 'PickleFilterException', - 'ConverterException', 'ConverterFileException', - 'ArchiveManager', 'PickleFilter', 'resetSubConverters', - 'registerSubConverter', 'unregisterSubConverter', - 'Converter', 'parseFile', 'parseData', 'parseURL', - 'parse', 'freeze', 'thaw', 'freezeStr', 'thawStr', - + 'ArchiveManager', + 'ArchiveManagerException', + 'Converter', + 'ConverterException', + 'ConverterFileException', + 'PickleFilter', + 'PickleFilterException', + 'freeze', + 'freezeStr', + 'museScore', + 'parse', + 'parseData', + 'parseFile', + 'parseURL', + 'registerSubConverter', + 'resetSubConverters', + 'subConverters', + 'thaw', + 'thawStr', + 'unregisterSubConverter', ] environLocal = environment.Environment('converter') @@ -424,15 +435,6 @@ def registerSubConverter(newSubConverter: type[subConverters.SubConverter]) -> N ''' _registeredSubConverters.appendleft(newSubConverter) -@common.deprecated('v9', 'v10', 'use unregisterSubconverter with capital C') -def registerSubconverter( - newSubConverter: type[subConverters.SubConverter] -) -> None: # pragma: no cover - ''' - Deprecated: use registerSubConverter w/ capital "C" instead. - ''' - registerSubConverter(newSubConverter) - def unregisterSubConverter( removeSubConverter: t.Literal['all']|type[subConverters.SubConverter] ) -> None: @@ -487,16 +489,6 @@ def unregisterSubConverter( f'Could not remove {removeSubConverter!r} from registered subConverters') -@common.deprecated('v9', 'v10', 'use unregisterSubConverter with capital C') -def unregisterSubconverter( - newSubConverter: type[subConverters.SubConverter] -) -> None: # pragma: no cover - ''' - Deprecated: use unregisterSubConverter w/ capital "C" instead. - ''' - unregisterSubConverter(newSubConverter) - - # ------------------------------------------------------------------------------ class Converter: ''' @@ -806,13 +798,6 @@ def parseURL( # -----------------------------------------------------------------------# # SubConverters - @common.deprecated('v9', 'v10', 'use subConvertersList with capital C') - def subconvertersList( - self, - converterType: t.Literal['any', 'input', 'output'] = 'any' - ) -> list[type[subConverters.SubConverter]]: # pragma: no cover - return self.subConvertersList(converterType) - @staticmethod def subConvertersList( converterType: t.Literal['any', 'input', 'output'] = 'any' @@ -944,10 +929,6 @@ def subConvertersList( return filteredSubConvertersList - @common.deprecated('v9', 'v10', 'use defaultSubConverters with capital C') - def defaultSubconverters(self) -> list[type[subConverters.SubConverter]]: # pragma: no cover - return self.defaultSubConverters() - @staticmethod def defaultSubConverters() -> list[type[subConverters.SubConverter]]: ''' @@ -992,12 +973,6 @@ def defaultSubConverters() -> list[type[subConverters.SubConverter]]: defaultSubConverters.append(possibleSubConverter) return defaultSubConverters - @common.deprecated('v9', 'v10', 'use getSubConverterFormats with capital C') - def getSubconverterFormats( - self - ) -> dict[str, type[subConverters.SubConverter]]: # pragma: no cover - return self.getSubConverterFormats() - @staticmethod def getSubConverterFormats() -> dict[str, type[subConverters.SubConverter]]: ''' @@ -1071,10 +1046,6 @@ def getSubConverterFromFormat( subConverterClass = scf[converterFormat] return subConverterClass() - @common.deprecated('v9', 'v10', 'use setSubConverterFromFormat with capital C') - def setSubconverterFromFormat(self, converterFormat: str): # pragma: no cover - self.setSubConverterFromFormat(converterFormat) - def setSubConverterFromFormat(self, converterFormat: str): ''' sets the .subConverter according to the format of `converterFormat`: @@ -1749,19 +1720,20 @@ def testConversionMXChords(self): # print(chords[i].pitches, len(chords[i].pitches)) self.assertEqual(knownSize[i], len(chords[i].pitches)) - def testConversionMXBeams(self): + def testConversionMXBeams(self) -> None: + from music21 import beam from music21 import note from music21.musicxml import testPrimitive mxString = testPrimitive.beams01 - a = parse(mxString) + a = t.cast(stream.Score, parse(mxString)) part = a.parts[0] notes = part.recurse().notesAndRests - beams = [] + theseBeams: list[beam.Beam] = [] for n in notes: if isinstance(n, note.Note): - beams += n.beams.beamsList - self.assertEqual(len(beams), 152) + theseBeams += n.beams.beamsList + self.assertEqual(len(theseBeams), 152) def testConversionMXTime(self): diff --git a/music21/duration.py b/music21/duration.py index 8ebd9baec..11be4bc94 100644 --- a/music21/duration.py +++ b/music21/duration.py @@ -167,58 +167,6 @@ class QuarterLengthConversion(t.NamedTuple): components: tuple[DurationTuple] tuplet: Tuplet|None - -def unitSpec(durationObjectOrObjects): - ''' - DEPRECATED and to be removed in v10. - - A simple data representation of most Duration objects. Processes a single - Duration or a List of Durations, returning a single or list of unitSpecs. - - A unitSpec is a tuple of qLen, durType, dots, tupleNumerator, - tupletDenominator, and tupletType (assuming top and bottom tuplets are the - same). - - This function does not deal with nested tuplets, etc. - - >>> aDur = duration.Duration() - >>> aDur.quarterLength = 3 - >>> duration.unitSpec(aDur) - (3.0, 'half', 1, None, None, None) - - >>> bDur = duration.Duration() - >>> bDur.quarterLength = 1.125 - >>> duration.unitSpec(bDur) - (1.125, 'complex', 0, None, None, None) - - >>> cDur = duration.Duration() - >>> cDur.quarterLength = 0.3333333 - >>> duration.unitSpec(cDur) - (Fraction(1, 3), 'eighth', 0, 3, 2, 'eighth') - - >>> duration.unitSpec([aDur, bDur, cDur]) - [(3.0, 'half', 1, None, None, None), - (1.125, 'complex', 0, None, None, None), - (Fraction(1, 3), 'eighth', 0, 3, 2, 'eighth')] - ''' - if isinstance(durationObjectOrObjects, list): - ret = [] - for dO in durationObjectOrObjects: - ret.append(unitSpec(dO)) - return ret - else: - dO = durationObjectOrObjects - if (not hasattr(dO, 'tuplets')) or dO.tuplets is None or not dO.tuplets: - return (dO.quarterLength, dO.type, dO.dots, None, None, None) - else: - return (dO.quarterLength, - dO.type, - dO.dots, - dO.tuplets[0].numberNotesActual, - dO.tuplets[0].numberNotesNormal, - dO.tuplets[0].durationNormal.type) - - def nextLargerType(durType: str) -> str: ''' Given a type (such as 16th or quarter), return the next larger type. @@ -2956,34 +2904,38 @@ def _setQuarterLength(self, value: OffsetQLIn): 3.5 >>> for thisUnit in a.components: - ... print(duration.unitSpec(thisUnit)) - (3.5, 'half', 2, None, None, None) + ... print(thisUnit.quarterLength, thisUnit.type, thisUnit.dots) + 3.5 half 2 - >>> a.quarterLength = 2.5 - >>> a.quarterLength + A duration of 2.5 quarter notes has to be represented as more than one + component. + + >>> b = duration.Duration() + >>> b.quarterLength = 2.5 + >>> b.quarterLength 2.5 - >>> for thisUnit in a.components: - ... print(duration.unitSpec(thisUnit)) - (2.0, 'half', 0, None, None, None) - (0.5, 'eighth', 0, None, None, None) + >>> for thisUnit in b.components: + ... print(thisUnit.quarterLength, thisUnit.type, thisUnit.dots) + 2.0 half 0 + 0.5 eighth 0 Note that integer values of quarter lengths get silently converted to floats (internally opFracs): - >>> b = duration.Duration() - >>> b.quarterLength = 5 - >>> b.quarterLength + >>> c = duration.Duration() + >>> c.quarterLength = 5 + >>> c.quarterLength 5.0 - >>> b.type # complex because 5qL cannot be expressed as a single note. + >>> c.type # complex because 5 quarters cannot be expressed as a single note. 'complex' Float values will be converted to fractions if they are inexpressible exactly as floats: - >>> b = duration.Duration() - >>> b.quarterLength = 1/3 - >>> b.quarterLength + >>> d = duration.Duration() + >>> d.quarterLength = 1/3 + >>> d.quarterLength Fraction(1, 3) ''') @@ -3908,7 +3860,6 @@ def testSimpleSetQuarterLength(self): self.assertFalse(d._componentsNeedUpdating) self.assertFalse(d._quarterLengthNeedsUpdating) self.assertEqual(repr(d.quarterLength), 'Fraction(1, 3)') - self.assertEqual(str(unitSpec(d)), "(Fraction(1, 3), 'eighth', 0, 3, 2, 'eighth')") def testTupletDurations(self): ''' diff --git a/music21/midi/__init__.py b/music21/midi/__init__.py index d8581067f..dc60c1458 100644 --- a/music21/midi/__init__.py +++ b/music21/midi/__init__.py @@ -43,11 +43,8 @@ MidiFile, MidiTrack, SysExEvents, - charToBinary, getNumber, - getNumbersAsList, getVariableLengthNumber, - intsToHexBytes, putNumber, putNumbersAsList, putVariableLengthNumber, @@ -72,11 +69,8 @@ 'MidiTrack', 'SysExEvents', - 'charToBinary', 'getNumber', - 'getNumbersAsList', 'getVariableLengthNumber', - 'intsToHexBytes', 'putNumber', 'putNumbersAsList', 'putVariableLengthNumber', diff --git a/music21/midi/base.py b/music21/midi/base.py index 4d2babc24..1bc6eb1aa 100644 --- a/music21/midi/base.py +++ b/music21/midi/base.py @@ -23,17 +23,21 @@ from __future__ import annotations __all__ = [ - 'MidiEvent', 'MidiFile', 'MidiTrack', 'MidiException', + 'ChannelModeMessages', + 'ChannelVoiceMessages', 'DeltaTime', - 'MetaEvents', 'ChannelVoiceMessages', 'ChannelModeMessages', - 'SysExEvents', - 'charToBinary', - 'getNumber', 'getVariableLengthNumber', 'putNumber', 'putVariableLengthNumber', - 'getNumbersAsList', 'putNumbersAsList', - 'intsToHexBytes', - # add enums: - 'ChannelVoiceMessages', 'ChannelModeMessages', 'SysExEvents', 'METAEVENT_MARKER', + 'MetaEvents', + 'MidiEvent', + 'MidiException', + 'MidiFile', + 'MidiTrack', + 'SysExEvents', + 'getNumber', + 'getVariableLengthNumber', + 'putNumber', + 'putNumbersAsList', + 'putVariableLengthNumber', ] from collections.abc import Iterable @@ -41,7 +45,6 @@ from typing import overload import typing as t -from music21 import common from music21.common.enums import ContainsEnum from music21 import defaults from music21 import environment @@ -57,47 +60,6 @@ class MidiException(exceptions21.Music21Exception): pass # ------------------------------------------------------------------------------ -@common.deprecated('v9.7', 'v10', 'use bin(ord(char)) instead.') -def charToBinary(char: str): - ''' - DEPRECATED: just use bin(ord(char)) instead. - - Or for the exact prior output (with left-padding) - use `f'{int(bin(ord(char))[2:]):08d}'` - - - Convert a char into its binary representation. Useful for debugging. - - >>> #_DOCS_SHOW midi.charToBinary('a') - >>> f'{int(bin(ord("a"))[2:]):08d}' #_DOCS_HIDE - '01100001' - - Note: This function is deprecated and will be removed in v10. Music21 actually - predates the bin() function in Python (added in Python 2.6). - ''' - binary = bin(ord(char))[2:] - zeroFix = (8 - len(binary)) * '0' - return zeroFix + binary - -@common.deprecated('v9.7', 'v10', 'Just use bytes(...) instead') -def intsToHexBytes(intList: Iterable[int]) -> bytes: - r''' - (Deprecated: just use bytes(...) instead) - - Convert a list of integers into hex bytes, suitable for testing MIDI encoding. - - Here we take NOTE_ON message, Middle C, 120 velocity and translate it to bytes - - >>> #_DOCS_SHOW midi.intsToHexBytes([0x90, 60, 120]) - >>> bytes([0x90, 60, 120]) #_DOCS_HIDE - b'\x90 tuple[int, int]: ... @@ -238,34 +200,6 @@ def getVariableLengthNumber(midiBytes: bytes) -> tuple[int, bytes]: raise MidiException('did not find the end of the number!') -@common.deprecated('v9.7', 'v10', 'use list(midiBytes) instead') -def getNumbersAsList(midiBytes: bytes|Iterable[int]) -> list[int]: - r''' - **Deprecated**: this method existed in Python 2.6 and for Python 2 (no bytes) - compatibility. Now use `list(midiBytes)` instead. - - Translate each char into a number, return in a list. - Used for reading data messages where each byte encodes - a different discrete value. - - >>> #_DOCS_SHOW midi.getNumbersAsList(b'\x00\x00\x00\x03') - >>> list(b'\x00\x00\x00\x03') #_DOCS_HIDE - [0, 0, 0, 3] - - Now just do: - - >>> list(b'\x00\x00\x00\x03') - [0, 0, 0, 3] - ''' - post = [] - for midiByte in midiBytes: - if isinstance(midiByte, str): - post.append(ord(midiByte)) - else: - post.append(midiByte) - return post - - def putNumber(num: int, length: int) -> bytes: r''' Put a single number as a hex number at the end of a bytes object `length` bytes long. diff --git a/music21/prebase.py b/music21/prebase.py index b49e085ee..e08445702 100644 --- a/music21/prebase.py +++ b/music21/prebase.py @@ -17,12 +17,9 @@ ''' from __future__ import annotations -from collections.abc import Sequence import typing as t import unittest -from music21.common import deprecated - class ProtoM21Object: ''' A class for pseudo-m21 objects to inherit from. Any object can inherit from @@ -82,36 +79,6 @@ class ProtoM21Object: __slots__: tuple[str, ...] = () - @deprecated('v7', 'v10', 'use `someClass in .classSet`' - 'or for intersection: `not classSet.isdisjoint(classList)`') - def isClassOrSubclass(self, classFilterList: Sequence) -> bool: - ''' - Given a class filter list (a list or tuple must be submitted), - which may have strings or class objects, determine - if this class is of the provided classes or a subclasses. - - NOTE: this is a performance critical operation - for performance, only accept lists or tuples - - DEPRECATED in v7 -- prefer `someClass in el.classSet` or - `not el.classSet.isdisjoint(classList)` instead. - - >>> n = note.Note() - >>> #_DOCS_SHOW n.isClassOrSubclass(('Note',)) - True - >>> #_DOCS_SHOW n.isClassOrSubclass(('GeneralNote',)) - True - >>> #_DOCS_SHOW n.isClassOrSubclass((note.Note,)) - True - >>> #_DOCS_SHOW n.isClassOrSubclass((note.Rest,)) - False - >>> #_DOCS_SHOW n.isClassOrSubclass((note.Note, note.Rest)) - True - >>> #_DOCS_SHOW n.isClassOrSubclass(('Rest', 'Note')) - True - ''' - return not self.classSet.isdisjoint(classFilterList) - @property def classes(self) -> tuple[str, ...]: ''' @@ -171,9 +138,9 @@ def classSet(self) -> frozenset[str|type]: to a particular class when you don't know if the user has given a string, a fully qualified string name, or an object. - Did I mention it's fast? It's a drop in substitute for the deprecated - `.isClassOrSubclass`. It's not as fast as x in n.classes or isinstance(n, x) - if you know whether it's a string or class, but this is good and safe. + Did I mention it's fast? It's not as fast as x in n.classes or isinstance(n, x) + if you know whether it's a string or class, but this is good and safe to take + in either a string or a class. >>> n = note.Note() >>> 'Note' in n.classSet @@ -188,6 +155,13 @@ def classSet(self) -> frozenset[str|type]: >>> note.Rest in n.classSet False + For checking if an object is part of any number of objects use `not` + with `isdisjoint`. A little unwiedly but works super fast: + + >>> checkClasses = (spanner.Slur, note.NotRest) + >>> not n.classSet.isdisjoint(checkClasses) + True + >>> object in n.classSet True diff --git a/music21/scale/__init__.py b/music21/scale/__init__.py index 9aaa99580..a425f49c3 100644 --- a/music21/scale/__init__.py +++ b/music21/scale/__init__.py @@ -90,7 +90,6 @@ ] import copy -import typing as t from music21.scale import intervalNetwork from music21.scale.intervalNetwork import Direction, Terminus @@ -98,7 +97,6 @@ # ------------------------- from music21 import base from music21 import common -from music21.common.decorators import deprecated from music21 import defaults from music21 import environment from music21 import exceptions21 @@ -2076,33 +2074,6 @@ def solfeg(self, else: return syllableDict[scaleDeg][0] - # no type checking as a deprecated call that shadows superclass. - @t.no_type_check - @deprecated('v9', 'v10', 'use nextPitch instead') - def next( - self, - pitchOrigin=None, - direction: 'music21.scale.intervalNetwork.Direction'|int = Direction.ASCENDING, - stepSize=1, - getNeighbor: 'music21.scale.intervalNetwork.Direction'|bool = True, - ): # pragma: no cover - ''' - See :meth:`~music21.scale.ConcreteScale.nextPitch`. This function - is a deprecated alias for that method. - - This routine was named and created before music21 aspired to have - full subclass substitution. Thus, is shadows the `.next()` function of - Music21Object without performing similar functionality. - - The routine is formally deprecated in v9 and will be removed in v10. - ''' - return self.nextPitch( - pitchOrigin=pitchOrigin, - direction=direction, - stepSize=stepSize, - getNeighbor=getNeighbor - ) - def nextPitch( self, pitchOrigin=None,