From cd1ae0e21b8be0eedc301c6610869ba308f6f946 Mon Sep 17 00:00:00 2001 From: hill Date: Wed, 23 Sep 2026 13:38:08 +0200 Subject: [PATCH 1/2] Find an instrument's names by its class in getAllNamesForInstrument getAllNamesForInstrument looked the instrument's display name up among the class names the language tables map to, so it only found names where the two are spelled alike -- Flute -- and none for an acoustic bass, whose class is AcousticBass, or for a violin renamed for its part: >>> instrument.getAllNamesForInstrument(instrument.AcousticBass(), 'english') {'english': []} It now uses the nearest class in the instrument's hierarchy that the tables name, which also covers a subclass of one of music21's classes. A generic Instrument, whose class the tables do not name, is still looked up by its name. --- music21/instrument.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/music21/instrument.py b/music21/instrument.py index 16becc2d6..50eaa8a3b 100644 --- a/music21/instrument.py +++ b/music21/instrument.py @@ -9,7 +9,7 @@ # Ben Houge # Mark Gotham # -# Copyright: Copyright © 2009-2024 Michael Scott Asato Cuthbert +# Copyright: Copyright © 2009-2026 Michael Scott Asato Cuthbert # License: BSD, see license.txt # ------------------------------------------------------------------------------ ''' @@ -2544,10 +2544,18 @@ def getAllNamesForInstrument(instrumentClass: Instrument, Note that the language string is not case-sensitive, so 'German' is also fine. ''' + from music21.languageExcerpts import instrumentLookup + language = language.lower() instrumentNameDict = {} - instrumentClassName = instrumentClass.instrumentName or '' + # the lookup tables name classes: the nearest one they know stands for + # this instrument, whatever it is called or subclassed as. A generic + # Instrument is found by its name. + namedClasses = set(instrumentLookup.allToClassName.values()) + instrumentClassName = next((cls.__name__ for cls in type(instrumentClass).__mro__ + if cls.__name__ in namedClasses), + instrumentClass.instrumentName or '') if language == SearchLanguage.ALL: for lang in SearchLanguage: @@ -2569,6 +2577,18 @@ class TestExternal(unittest.TestCase): class Test(unittest.TestCase): + def testGetAllNamesForInstrumentByClass(self): + acousticBass = getAllNamesForInstrument(AcousticBass(), SearchLanguage.ENGLISH) + self.assertEqual(acousticBass, {'english': ['acoustic bass']}) + + firstViolins = Violin() + firstViolins.instrumentName = 'Violin I' + self.assertEqual(getAllNamesForInstrument(firstViolins, SearchLanguage.ENGLISH), + {'english': ['violin', 'violins']}) + + self.assertEqual(getAllNamesForInstrument(Instrument('Violin'), SearchLanguage.ENGLISH), + {'english': ['violin', 'violins']}) + def testCopyAndDeepcopy(self): from music21.test.commonTest import testCopyAll testCopyAll(self, globals()) From d10b5befe507ab3574f7602164d85ca31eeeaeea Mon Sep 17 00:00:00 2001 From: hill Date: Fri, 2 Oct 2026 18:04:05 +0200 Subject: [PATCH 2/2] Drop the comment in getAllNamesForInstrument --- music21/instrument.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/music21/instrument.py b/music21/instrument.py index 50eaa8a3b..11f0cb59b 100644 --- a/music21/instrument.py +++ b/music21/instrument.py @@ -2549,9 +2549,6 @@ def getAllNamesForInstrument(instrumentClass: Instrument, language = language.lower() instrumentNameDict = {} - # the lookup tables name classes: the nearest one they know stands for - # this instrument, whatever it is called or subclassed as. A generic - # Instrument is found by its name. namedClasses = set(instrumentLookup.allToClassName.values()) instrumentClassName = next((cls.__name__ for cls in type(instrumentClass).__mro__ if cls.__name__ in namedClasses),