.. _migratingToV11: Migrating to music21 v11 ======================== *(This is an in-progress guide that was automatically generated by Myke's AI Agent.)* What changed between the v10 line and v11, and what to use instead. The big, code-breaking items come first, then smaller improvements by area, then one table of everything removed or deprecated. Python 3.12 or newer -------------------- Python 3.11 support is gone; 3.12, 3.13, and 3.14 are tested. The payoff is real generics: ``Stream`` and its iterators use the PEP 695 bracket form, so a type checker can follow ``stream.Stream[note.Note]()`` all the way to ``for n in s: n.pitch``. Octaves are always integers --------------------------- **In one line:** ``octave`` is always an ``int``, and ``octaveIsImplicit`` says whether you gave one. Before v11, ``pitch.Pitch('F#').octave`` was ``None``: a lovely idea (an F-sharp in *any* octave) that crashed the moment someone wrote ``p.octave + 1``. The pitch knew all along which octave it would use for MIDI or a staff. It kept that in ``implicitOctave``, a property that nobody remembered. Now ``octave`` does that job itself: >>> from music21 import * >>> anyFSharp = pitch.Pitch('F#') >>> anyFSharp.octave 4 >>> anyFSharp.octaveIsImplicit True Nothing else about an octave-less pitch changes. It still prints without a number, transposes without one, and is not equal to an explicit F#4: >>> anyFSharp >>> anyFSharp.transpose('P8') >>> anyFSharp == pitch.Pitch('F#4') False Give it an octave and the flag flips: >>> anyFSharp.octave = 5 >>> anyFSharp.octaveIsImplicit False >>> anyFSharp Notes follow along: ``note.Note('B-').octave`` is ``4``, and the flag lives on the note's pitch, ``n.pitch.octaveIsImplicit``. .. list-table:: :header-rows: 1 :widths: 50 50 * - Before v11 - v11 * - ``if p.octave is None:`` - ``if p.octaveIsImplicit:`` * - ``p.octave = None`` - ``p.octaveIsImplicit = True`` (the old spelling is deprecated; removed in v13) * - ``p.implicitOctave`` - ``p.octave`` * - ``if p.octave is None: p.octave = p.implicitOctave`` - ``p.octaveIsImplicit = False`` * - ``octave: int | None`` - ``octave: int`` ``p.octave + 1`` and ``f'{p.name}{p.octave}'`` no longer crash. The few methods that need a pitch's *own* octave, such as :meth:`~music21.pitch.Pitch.transposeAboveTarget`, still raise for an implicit one; set ``.octave`` first. ``implicitOctave`` stays as a synonym so nothing breaks today, but it is deprecated and starts warning in v12. KeySignature.sharps is always an int ------------------------------------ Similar idea to Octave. ``KeySignature.sharps`` (and ``Key.sharps``) is an ``int`` you can add to and subtract from. A non-traditional signature is a flag plus a list of pitches. ``sharps=None`` still works but warns: >>> unusual = key.KeySignature() >>> unusual.isNonTraditional = True >>> unusual.alteredPitches = ['E-', 'G#4'] >>> unusual Chord indexing gets simpler --------------------------- ``c[1]``, ``c['G4']`` and ``c[somePitch]`` still return the chord's :class:`~music21.note.Note`; everything fancier is gone. Attribute paths such as ``c['2.tie']`` and ``c['D-4.style.color']`` no longer work, a Note is no longer accepted as a key (use its pitch), and the per-note getters and setters (``getTie``, ``setColor``, ``getNotehead``, and their siblings) are deprecated. Index, then use the Note: >>> c = chord.Chord('C4 E4 G4') >>> c['E4'].tie = tie.Tie('start') >>> c[1].tie VoiceLeadingQuartet needs its four notes ---------------------------------------- ``voiceLeading.VoiceLeadingQuartet(v1n1, v1n2, v2n1, v2n2)`` requires all four notes up front, the first Music21Object ever to insist on arguments. In return they are always Notes, never ``None``. ``analyticKey`` is now ``key``, ``vIntervals`` and ``hIntervals`` are tuples, and two dogmatic names got truer ones: ``opensIncorrectly()`` is ``not modalOpening()`` and ``closesIncorrectly()`` is ``not clausulaVera()``. Roman numerals -------------- * ``romanNumeralFromChord`` keeps the sharp on major-quality chords built on the raised sixth and seventh degrees in minor: ``#VI``, not ``VI#63``. ``correctRNAlterationForMinor`` gained a ``chordHasMajorThird`` keyword for the same reason. * Figures containing ``x``, ``y`` or ``z`` raise. ``RomanNumeral('IIIx')`` used to be a III13 chord by accident. * ``FigureTuple`` and ``PitchFigureTuple`` are typed NamedTuples, and ``FigureTuple.fromPitchAndReference()`` replaces ``figureTupleSolo``. Durations and sorting --------------------- * Two Durations with ``expressionIsInferred`` True are equal when their quarterLengths match; type, dots and tuplets are free to be re-expressed. * ``sorting.SortTuple`` is a modern NamedTuple. ``priority`` and ``classSortOrder`` may be floats, and ``modify()`` with a bad field name raises ``ValueError``. * tinyNotation's undocumented ``0`` duration (a whole bar plus a fermata) is deprecated. Streams ------- * New ``Stream.isAtEnd(el)`` says whether ``storeAtEnd`` put ``el`` there. * ``Stream.hasElement(el)`` is removed: write ``el in s``. ``hasElementOfClass`` is deprecated: write ``if s.getElementsByClass(X):``. Pitches ------- ``pitch.simplifyMultipleEnharmonics`` takes ``criterion`` and ``keyContext`` as keyword-only arguments. File formats ------------ * **ABC**: ``w:`` lyric lines are imported, with hyphenation and ``*`` skips. ``abcToStreamOpus`` always returns an Opus. * **Humdrum**: grace notes keep their written duration instead of becoming eighths; duration parsing lives in a new ``hdStringToDuration``; a token with no duration warns when a quarter is assumed; ``GlobalReference`` is no longer a Music21Object. * **LilyPond**: output targets current LilyPond (``\tuplet``, modern barline names, ``\markuplist``), and every ``stringOutput()`` returns a ``str``. * **MIDI**: ``midiEventsToInstrument`` is removed; use ``midiEventToInstrument``. * **Vexflow**: the ``music21.vexflow`` module is gone. It had not worked in a decade; music21j is the way to draw in a browser. * **configure**: choosing MuseScore as the MusicXML reader also sets ``musescoreDirectPNGPath``. figuredBass, features, tree --------------------------- * figuredBass: ``hiddenFifth`` and ``hiddenOctave`` are now ``hiddenFifths`` and ``hiddenOctaves``, matching ``parallelFifths``. ``FiguredBassScale``'s first argument is ``scaleTonic``, not ``scaleValue``. Rests inside a possibility are typed sentinels rather than the string ``'RT'``. * features: ``Feature.vector`` starts as ``[]`` rather than ``None``, and ``FeatureExtractor.dimensions`` defaults to 1. * tree: ``ElementTimespan`` and ``PitchedTimespan`` take their arguments in the same order as ``Timespan``; ``offset``, ``endTime`` and ``element`` are required. For developers -------------- * Type annotations across nearly the whole library, with ``t.cast()`` for narrowing and ``@property`` decorators throughout. * ``common.enums.ContainsEnum`` is not needed: Python 3.12's ``StrEnum`` suffices, or ``HexEnum`` for hex values such as MIDI. The alias leaves in v12. ``common.defaultlist`` is deprecated. * The test runners import modules the normal way, so a module's tests no longer need ``from music21.key import KeySignature`` to compare types. * AI agents get their own instructions, skills and shared memory in ``AGENTS.md`` and ``.agents/``. Removed and deprecated ---------------------- .. list-table:: Removed in v11 :header-rows: 1 :widths: 50 50 * - Gone - Use instead * - Python 3.11 - Python 3.12 or newer * - ``music21.vexflow`` - music21j * - ``midi.translate.midiEventsToInstrument`` - ``midiEventToInstrument`` * - ``Stream.hasElement(el)`` - ``el in s`` * - ``musicxml.xmlToM21.MusicXMLImporter.identificationToMetadata`` - ``addIdentificationToMetadata`` * - a string for ``musicxml.xmlToM21.MeasureParser.getStaffNumber`` - an ``int`` * - ``VoiceLeadingQuartet.unison`` / ``.fifth`` / ``.octave`` - ``interval.Interval('P1')`` and friends * - ``c['2.tie']`` attribute paths into a Chord - ``c[2].tie`` * - a Note as a Chord index, ``c[someNote]`` - ``c[someNote.pitch]`` .. list-table:: Deprecated in v11 (removed in v12 unless noted) :header-rows: 1 :widths: 50 50 * - Deprecated - Use instead * - ``Stream.hasElementOfClass(X)`` - ``if s.getElementsByClass(X):`` * - ``Chord.getTie``, ``setTie``, ``getColor``, ``setColor``, ``getNotehead``, ``setNotehead``, ``getNoteheadFill``, ``setNoteheadFill``, ``getStemDirection``, ``setStemDirection`` - ``c[i].tie``, ``c[i].style.color``, ``c[i].notehead``, ``c[i].noteheadFill``, ``c[i].stemDirection`` * - ``roman.figureTupleSolo`` - ``FigureTuple.fromPitchAndReference()`` * - ``VoiceLeadingQuartet.opensIncorrectly()`` / ``closesIncorrectly()`` - ``not modalOpening()`` / ``not clausulaVera()`` * - ``KeySignature(sharps=None)`` - ``ks.isNonTraditional = True`` * - ``variant.addVariant(replacementDuration=...)`` - ``replacementQuarterLength=...`` * - ``common.defaultlist`` - a ``list`` or a ``dict`` * - ``common.enums.ContainsEnum`` - not needed: ``enum.StrEnum`` suffices, or ``HexEnum`` for hex values such as MIDI * - tinyNotation ``0`` duration - the duration plus an ``expressions.Fermata`` * - ``Pitch.implicitOctave`` - ``Pitch.octave`` (warns from v12, removed later)