Am Samstag, den 21.09.2019, 13:43 +0200 schrieb Werner LEMBERG:
> >> Well, I prefer a series of patches instead of a single patch.
> 
> > 
> 
> > Ok, I'll split the third one.  My concern was that a single part of
> 
> > the series won't bring any benefit on its own.  So for example only
> 
> > changing the division operator will not make musicxml2ly work with
> 
> > Python 3.
> 
> 
> In case there are patches within a series of patches that don't
> compile, please say that in the commit message for the benefit of `git
> bisect'.  I think it is better to have smaller, easily comprehensible
> but probably uncompilable changes than a single, working chunk that is
> hard to read.

All patches in the progress of porting to Python 3 won't fully work
until all remaining issues are fixed.
That said, I've split the third patch ("Fix musicxml2ly with Python 3")
into four smaller logical groups. I don't really mind which version is
applied, the outcome is the same.

Regards,
Jonas
From d14e98aacdac0a600108fce9bb1fd278ac9cd3df Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <hah...@hahnjo.de>
Date: Sat, 21 Sep 2019 13:47:08 +0200
Subject: [PATCH 1/4] musicxml: Replace new.classobj() by type() for Python 3

---
 python/musicxml.py | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/python/musicxml.py b/python/musicxml.py
index e1ddeb20e4..ecb0d0581f 100644
--- a/python/musicxml.py
+++ b/python/musicxml.py
@@ -1,5 +1,4 @@
 # -*- coding: utf-8 -*-
-#import new
 import string
 from rational import *
 import re
@@ -1794,7 +1793,7 @@ def get_class(name):
         return classname
     else:
         class_name = name2class_name(name)
-        klass = new.classobj(class_name,(Music_xml_node,) , {})
+        klass = type(class_name,(Music_xml_node,) , {})
         class_dict[name] = klass
         return klass
 
-- 
2.23.0

From 269eec622002f379b18e04eeba59aa430631cb0c Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <hah...@hahnjo.de>
Date: Sat, 21 Sep 2019 13:37:33 +0200
Subject: [PATCH 2/4] musicxml2ly: Fix calls to functions from string

---
 python/musicexp.py     | 21 ++++++++++-----------
 python/musicxml.py     |  9 ++++-----
 python/utilities.py    |  2 +-
 scripts/musicxml2ly.py | 25 ++++++++++++-------------
 4 files changed, 27 insertions(+), 30 deletions(-)

diff --git a/python/musicexp.py b/python/musicexp.py
index 29161432f1..d1eb0aaaa5 100644
--- a/python/musicexp.py
+++ b/python/musicexp.py
@@ -1,7 +1,6 @@
 # -*- coding: utf-8 -*-
 import inspect
 import sys
-import string
 import re
 import math
 import lilylib as ly
@@ -19,7 +18,7 @@ whatOrnament = ""
 ly_dur = None # stores lilypond durations
 
 def escape_instrument_string (input_string):
-    retstring = string.replace (input_string, "\"", "\\\"")
+    retstring = input_string.replace("\"", "\\\"")
     if re.match ('.*[\r\n]+.*', retstring):
         rx = re.compile (r'[\n\r]+')
         strings = rx.split (retstring)
@@ -529,7 +528,7 @@ class Music:
             printer.newline ()
             return
 
-        lines = string.split (text, '\n')
+        lines = text.split('\n')
         for l in lines:
             if l:
                 printer.unformatted_output ('% ' + l)
@@ -692,11 +691,11 @@ class NestedMusic(Music):
 
     def get_properties (self):
         return ("'elements (list %s)"
-            % string.join ([x.lisp_expression() for x in self.elements]))
+            % ' '.join ([x.lisp_expression() for x in self.elements]))
 
     def get_subset_properties (self, predicate):
         return ("'elements (list %s)"
-            % string.join ([x.lisp_expression() for x in list(filter (predicate, self.elements))]))
+            % ' '.join ([x.lisp_expression() for x in list(filter (predicate, self.elements))]))
     def get_neighbor (self, music, dir):
         assert music.parent == self
         idx = self.elements.index (music)
@@ -1036,7 +1035,7 @@ class ChordEvent (NestedMusic):
                     basepitch = previous_pitch
             if stem:
                 printer (stem.ly_expression ())
-            printer ('<%s>' % string.join (pitches))
+            printer ('<%s>' % ' '.join (pitches))
             previous_pitch = basepitch
             duration = self.get_duration ()
             if duration:
@@ -1475,7 +1474,7 @@ class FretBoardEvent (NestedMusic):
           notes = []
           for n in fretboard_notes:
               notes.append (n.ly_expression ())
-          contents = string.join (notes)
+          contents = ' '.join (notes)
           printer ('<%s>%s' % (contents,self.duration))
 
 class FunctionWrapperEvent (Event):
@@ -1665,7 +1664,7 @@ class RhythmicEvent(Event):
         return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
 
     def ly_expression_pre_note (self, is_chord_element):
-        res = string.join (self.pre_note_ly (is_chord_element), ' ')
+        res = ' '.join (self.pre_note_ly (is_chord_element))
         if res != '':
             res = res + ' '
         return res
@@ -1813,7 +1812,7 @@ class KeySignatureChange (Music):
         elif self.non_standard_alterations:
             alterations = [self.format_non_standard_alteration (a) for
                                         a in self.non_standard_alterations]
-            return "\\set Staff.keyAlterations = #`(%s)" % string.join (alterations, " ")
+            return "\\set Staff.keyAlterations = #`(%s)" % " ".join (alterations)
         else:
             return ''
 
@@ -1857,7 +1856,7 @@ class TimeSignatureChange (Music):
     def format_fraction (self, frac):
         if isinstance (frac, list):
             l = [self.format_fraction (f) for f in frac]
-            return "(" + string.join (l, " ") + ")"
+            return "(" + " ".join (l) + ")"
         else:
             return "%s" % frac
 
@@ -2074,7 +2073,7 @@ class FiguredBassEvent (NestedMusic):
           notes = []
           for x in figured_bass_events:
               notes.append (x.ly_expression ())
-          contents = string.join (notes)
+          contents = ' '.join (notes)
           if self.parentheses:
               contents = '[%s]' % contents
           printer ('<%s>' % contents)
diff --git a/python/musicxml.py b/python/musicxml.py
index ecb0d0581f..3f09dedc7e 100644
--- a/python/musicxml.py
+++ b/python/musicxml.py
@@ -1,5 +1,4 @@
 # -*- coding: utf-8 -*-
-import string
 from rational import *
 import re
 import sys
@@ -197,7 +196,7 @@ class Identification(Xml_node):
                 ret.append(result)
             else:
                 ret.append(text)
-        return string.join(ret, "\n")
+        return "\n".join(ret)
 
     # get contents of the source-element(usually used for publishing information).(These contents are saved in a custom variable named "source" in the header of the .ly file.)
     def get_source(self):
@@ -205,7 +204,7 @@ class Identification(Xml_node):
         ret = []
         for r in source:
           ret.append(r.get_text())
-        return string.join(ret, "\n")
+        return "\n".join(ret)
 
     def get_creator(self, type):
         creators = self.get_named_children('creator')
@@ -385,7 +384,7 @@ class Duration(Music_xml_node):
 class Hash_text(Music_xml_node):
 
     def dump(self, indent=''):
-        ly.debug_output('%s' % string.strip(self._data))
+        ly.debug_output('%s' % self._data.strip())
 
 
 class Pitch(Music_xml_node):
@@ -518,7 +517,7 @@ class Attributes(Measure_element):
                 current_sig = []
                 for i in mxl.get_all_children():
                     if isinstance(i, Beats):
-                        beats = string.split(i.get_text().strip(), "+")
+                        beats = i.get_text().strip().split("+")
                         current_sig = [int(j) for j in beats]
                     elif isinstance(i, BeatType):
                         current_sig.append(int(i.get_text()))
diff --git a/python/utilities.py b/python/utilities.py
index 3d339b0a9f..264e8e8b31 100644
--- a/python/utilities.py
+++ b/python/utilities.py
@@ -19,7 +19,7 @@ def escape_ly_output_string (input_string):
     return_string = input_string
     needs_quotes = not re.match ("^[a-zA-ZäöüÜÄÖßñ]*$", return_string);
     if needs_quotes:
-        return_string = "\"" + string.replace (return_string, "\"", "\\\"") + "\""
+        return_string = "\"" + return_string.replace("\"", "\\\"") + "\""
     return return_string
 
 def interpret_alter_element (alter_elm):
diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py
index 49bb8b4fff..67991c7312 100755
--- a/scripts/musicxml2ly.py
+++ b/scripts/musicxml2ly.py
@@ -4,7 +4,6 @@ import optparse
 import sys
 import re
 import os
-import string
 import codecs
 import zipfile
 import tempfile
@@ -311,14 +310,14 @@ def staff_attributes_to_string_tunings(mxl_attr):
     lines = 6
     staff_lines = details.get_maybe_exist_named_child('staff-lines')
     if staff_lines:
-        lines = string.atoi(staff_lines.get_text())
+        lines = int(staff_lines.get_text())
     tunings = [musicexp.Pitch()] * lines
     staff_tunings = details.get_named_children('staff-tuning')
     for i in staff_tunings:
         p = musicexp.Pitch()
         line = 0
         try:
-            line = string.atoi(i.line) - 1
+            line = int(i.line) - 1
         except ValueError:
             pass
         tunings[line] = p
@@ -358,7 +357,7 @@ def staff_attributes_to_lily_staff(mxl_attr):
     for d in details:
         staff_lines = d.get_maybe_exist_named_child('staff-lines')
         if staff_lines:
-            lines = string.atoi(staff_lines.get_text())
+            lines = int(staff_lines.get_text())
 
     # TODO: Handle other staff attributes like staff-space, etc.
 
@@ -849,8 +848,8 @@ def musicxml_transpose_to_lily(attributes):
     shift = musicexp.Pitch()
     octave_change = transpose.get_maybe_exist_named_child('octave-change')
     if octave_change:
-        shift.octave = string.atoi(octave_change.get_text())
-    chromatic_shift = string.atoi(transpose.get_named_child('chromatic').get_text())
+        shift.octave = int(octave_change.get_text())
+    chromatic_shift = int(transpose.get_named_child('chromatic').get_text())
     chromatic_shift_normalized = chromatic_shift % 12;
     (shift.step, shift.alteration) = [
         (0, 0), (0, 1), (1, 0), (2, -1), (2, 0),
@@ -861,7 +860,7 @@ def musicxml_transpose_to_lily(attributes):
 
     diatonic = transpose.get_maybe_exist_named_child('diatonic')
     if diatonic:
-        diatonic_step = string.atoi(diatonic.get_text()) % 7
+        diatonic_step = int(diatonic.get_text()) % 7
         if diatonic_step != shift.step:
             # We got the alter incorrect!
             old_semitones = shift.semitones()
@@ -883,7 +882,7 @@ def musicxml_staff_details_to_lily(attributes):
 
     stafflines = details.get_maybe_exist_named_child('staff-lines')
     if stafflines:
-        lines = string.atoi(stafflines.get_text());
+        lines = int(stafflines.get_text());
         lines_event = musicexp.StaffLinesEvent(lines);
         ret.append(lines_event);
 
@@ -1243,7 +1242,7 @@ def musicxml_dynamics_to_lily_event(dynentry):
     if not dynamicsname in dynamics_available:
         # Get rid of - in tag names (illegal in ly tags!)
         dynamicstext = dynamicsname
-        dynamicsname = string.replace(dynamicsname, "-", "")
+        dynamicsname = dynamicsname.replace("-", "")
         additional_definitions[dynamicsname] = dynamicsname + \
               " = #(make-dynamic-script \"" + dynamicstext + "\")"
         needed_additional_definitions.append(dynamicsname)
@@ -1313,7 +1312,7 @@ def musicxml_words_to_lily_event(words):
     if hasattr(words, 'default-y') and hasattr(options, 'convert_directions') and options.convert_directions:
         offset = getattr(words, 'default-y')
         try:
-            off = string.atoi(offset)
+            off = int(offset)
             if off > 0:
                 event.force_direction = 1
             else:
@@ -1373,7 +1372,7 @@ def musicxml_accordion_to_markup(mxl_event):
         # MusicXML spec is quiet about this case...
         txt = 1
         try:
-          txt = string.atoi(middle.get_text())
+          txt = int(middle.get_text())
         except ValueError:
             pass
         if txt == 3:
@@ -1783,7 +1782,7 @@ def musicxml_harmony_to_lily_chordname(n):
             # require you to know the chord and calculate either the fifth
             # pitch (for the first inversion) or the third pitch (for the
             # second inversion) so they may not be helpful for musicxml2ly.
-            inversion_count = string.atoi(inversion.get_text())
+            inversion_count = int(inversion.get_text())
             if inversion_count == 1:
               # TODO: Calculate the bass note for the inversion...
               pass
@@ -1875,7 +1874,7 @@ def musicxml_lyrics_to_text(lyrics, ignoremelismata):
         elif isinstance(e, musicxml.Text):
             # We need to convert soft hyphens to -, otherwise the ascii codec as well
             # as lilypond will barf on that character
-            text += string.replace(e.get_text(), '\xad', '-')
+            text += e.get_text().replace('\xad', '-')
         elif isinstance(e, musicxml.Elision):
             if text:
                 text += " "
-- 
2.23.0

From 0b781f83e53e894fdf3ce0fdf3c25d622ab9e1c0 Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <hah...@hahnjo.de>
Date: Sat, 21 Sep 2019 13:42:04 +0200
Subject: [PATCH 3/4] musicxml2ly: Fix handling of encoded data

---
 python/book_snippets.py | 24 +++++++++++++-----------
 python/musicexp.py      |  2 +-
 python/musicxml.py      |  2 +-
 scripts/musicxml2ly.py  | 15 +++++++--------
 4 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/python/book_snippets.py b/python/book_snippets.py
index 0a2f3fbb31..0f7888bcb9 100644
--- a/python/book_snippets.py
+++ b/python/book_snippets.py
@@ -605,7 +605,8 @@ class LilypondSnippet (Snippet):
             if self.relevant_contents (existing) != self.relevant_contents (self.full_ly ()):
                 warning ("%s: duplicate filename but different contents of original file,\n\
 printing diff against existing file." % filename)
-                ly.stderr_write (self.filter_pipe (self.full_ly (), 'diff -u %s -' % filename))
+                diff_against_existing = self.filter_pipe (self.full_ly ().encode ('utf-8'), 'diff -u %s -' % filename)
+                ly.stderr_write (diff_against_existing.decode ('utf-8'))
         else:
             out = open (filename, 'w')
             out.write (self.full_ly ())
@@ -757,7 +758,7 @@ printing diff against existing file." % filename)
             status = 0
             output = stdout.read ()
             status = stdout.close ()
-            err = stderr.read ()
+            err = stderr.read ().decode ('utf-8')
 
         if not status:
             status = 0
@@ -767,7 +768,7 @@ printing diff against existing file." % filename)
             ly.error (_ ("`%s' failed (%d)") % (cmd, exit_status))
             ly.error (_ ("The error log is as follows:"))
             ly.stderr_write (err)
-            ly.stderr_write (stderr.read ())
+            ly.stderr_write (stderr.read ().decode ('utf-8'))
             exit (status)
 
         debug ('\n')
@@ -820,13 +821,13 @@ class LilypondFileSnippet (LilypondSnippet):
         LilypondSnippet.__init__ (self, type, match, formatter, line_number, global_options)
         self.filename = self.substring ('filename')
         self.contents = open (BookBase.find_file (self.filename,
-            global_options.include_path, global_options.original_dir)).read ()
+            global_options.include_path, global_options.original_dir), 'rb').read ()
 
     def get_snippet_code (self):
-        return self.contents;
+        return self.contents.decode ('utf-8')
 
     def verb_ly (self):
-        s = self.contents
+        s = self.get_snippet_code ()
         s = re_begin_verbatim.split (s)[-1]
         s = re_end_verbatim.split (s)[0]
         if not NOGETTEXT in self.option_dict:
@@ -838,7 +839,7 @@ class LilypondFileSnippet (LilypondSnippet):
     def ly (self):
         name = self.filename
         return ('\\sourcefilename \"%s\"\n\\sourcefileline 0\n%s'
-                % (name, self.contents))
+                % (name, self.get_snippet_code ()))
 
     def final_basename (self):
         if self.global_options.use_source_file_names:
@@ -888,6 +889,7 @@ class MusicXMLFileSnippet (LilypondFileSnippet):
         progress (_ ("Converting MusicXML file `%s'...\n") % self.filename)
 
         ly_code = self.filter_pipe (self.contents, 'musicxml2ly %s --out=- - ' % opts)
+        ly_code = ly_code.decode ('utf-8')
         return ly_code
 
     def ly (self):
@@ -914,20 +916,20 @@ class MusicXMLFileSnippet (LilypondFileSnippet):
             if diff_against_existing:
                 warning (_ ("%s: duplicate filename but different contents of original file,\n\
 printing diff against existing file.") % xmlfilename)
-                ly.stderr_write (diff_against_existing)
+                ly.stderr_write (diff_against_existing.decode ('utf-8'))
         else:
-            out = open (xmlfilename, 'w')
+            out = open (xmlfilename, 'wb')
             out.write (self.contents)
             out.close ()
 
         # also write the converted lilypond
         filename = path + '.ly'
         if os.path.exists (filename):
-            diff_against_existing = self.filter_pipe (self.full_ly (), 'diff -u %s -' % filename)
+            diff_against_existing = self.filter_pipe (self.full_ly ().encode ('utf-8'), 'diff -u %s -' % filename)
             if diff_against_existing:
                 warning (_ ("%s: duplicate filename but different contents of converted lilypond file,\n\
 printing diff against existing file.") % filename)
-                ly.stderr_write (diff_against_existing)
+                ly.stderr_write (diff_against_existing.decode ('utf-8'))
         else:
             out = open (filename, 'w')
             out.write (self.full_ly ())
diff --git a/python/musicexp.py b/python/musicexp.py
index d1eb0aaaa5..01faa1b75d 100644
--- a/python/musicexp.py
+++ b/python/musicexp.py
@@ -813,7 +813,7 @@ class Lyrics:
         for l in self.lyrics_syllables:
             lstr += l
         #lstr += "\n}"
-        return lstr.encode('utf-8')
+        return lstr
 
 class Header:
 
diff --git a/python/musicxml.py b/python/musicxml.py
index 3f09dedc7e..0d58983715 100644
--- a/python/musicxml.py
+++ b/python/musicxml.py
@@ -41,7 +41,7 @@ class Xml_node:
         if not self._children:
             return ''
 
-        return ''.join([c.get_text() for c in self._children]).encode('utf-8')
+        return ''.join([c.get_text() for c in self._children])
 
     def message(self, msg):
         ly.warning(msg)
diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py
index 67991c7312..e5584f6851 100755
--- a/scripts/musicxml2ly.py
+++ b/scripts/musicxml2ly.py
@@ -1247,7 +1247,7 @@ def musicxml_dynamics_to_lily_event(dynentry):
               " = #(make-dynamic-script \"" + dynamicstext + "\")"
         needed_additional_definitions.append(dynamicsname)
     event = musicexp.DynamicsEvent()
-    event.type = dynamicsname.encode('utf-8')
+    event.type = dynamicsname
     return event
 
 # Convert single-color two-byte strings to numbers 0.0 - 1.0
@@ -3100,14 +3100,13 @@ def read_musicxml(filename, compressed, use_lxml):
              sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0) # Make sys.stdin binary
              bytes_read = sys.stdin.read(8192)
              while bytes_read:
-                 for b in bytes_read:
-                     tmp.write(b)
+                 tmp.write(bytes_read)
                  bytes_read = sys.stdin.read(8192)
              z = zipfile.ZipFile(tmp, "r")
         else:
             ly.progress(_("Input file %s is compressed, extracting raw MusicXML data") % filename, True)
             z = zipfile.ZipFile(filename, "r")
-        container_xml = z.read("META-INF/container.xml")
+        container_xml = z.read("META-INF/container.xml").decode('utf-8')
         if not container_xml:
             return None
         container = read_xml(io.StringIO(container_xml), use_lxml)
@@ -3121,7 +3120,7 @@ def read_musicxml(filename, compressed, use_lxml):
         if len(rootfile_list) > 0:
             mxml_file = getattr(rootfile_list[0], 'full-path', None)
         if mxml_file:
-            raw_string = z.read(mxml_file)
+            raw_string = z.read(mxml_file).decode('utf-8')
 
     if raw_string:
         io_object = io.StringIO(raw_string)
@@ -3173,9 +3172,9 @@ def convert(filename, options):
     printer = musicexp.Output_printer()
     #ly.progress(_("Output to `%s'") % defs_ly_name, True)
     if (options.output_name == "-"):
-      printer.set_file(codecs.getwriter("utf-8")(sys.stdout))
+      printer.set_file(sys.stdout)
     else:
-      printer.set_file(codecs.open(output_ly_name, 'wb', encoding='utf-8'))
+      printer.set_file(open(output_ly_name, 'w'))
     print_ly_preamble(printer, filename)
     print_ly_additional_definitions(printer, filename)
     if score_information:
@@ -3255,7 +3254,7 @@ def main():
     conversion_settings.convert_stem_directions = options.convert_stem_directions
 
     # Allow the user to leave out the .xml or xml on the filename
-    basefilename = args[0].decode('utf-8')
+    basefilename = args[0]
     if basefilename == "-": # Read from stdin
         filename = "-"
     else:
-- 
2.23.0

From c5f2e5d07a66846b8251d771eb4a7178c6f03bfb Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <hah...@hahnjo.de>
Date: Sat, 21 Sep 2019 13:45:47 +0200
Subject: [PATCH 4/4] musicxml2ly: Fix integer calculations for Python 3

Python 3 changed the semantics of / to result in a floating point
value, use // to get a (truncated) integer.
---
 python/musicexp.py     |  6 +++---
 python/musicxml.py     |  6 +++---
 python/rational.py     | 13 ++++++++++---
 scripts/musicxml2ly.py | 20 ++++++++++----------
 4 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/python/musicexp.py b/python/musicexp.py
index 01faa1b75d..5805827243 100644
--- a/python/musicexp.py
+++ b/python/musicexp.py
@@ -396,7 +396,7 @@ class Pitch:
         while c.step < 0:
             c.step += 7
             c.octave -= 1
-        c.octave += c.step / 7
+        c.octave += c.step // 7
         c.step = c.step % 7
 
     def lisp_expression (self):
@@ -461,9 +461,9 @@ class Pitch:
         pitch_diff = (this_pitch_steps - previous_pitch_steps)
         previous_pitch = self
         if pitch_diff > 3:
-            return "'" * ((pitch_diff + 3) / 7)
+            return "'" * ((pitch_diff + 3) // 7)
         elif pitch_diff < -3:
-            return "," * ((-pitch_diff + 3) / 7)
+            return "," * ((-pitch_diff + 3) // 7)
         else:
             return ""
 
diff --git a/python/musicxml.py b/python/musicxml.py
index 0d58983715..fdf6e24c0e 100644
--- a/python/musicxml.py
+++ b/python/musicxml.py
@@ -957,7 +957,7 @@ class Syllabic(Music_xml_node):
 
 class Lyric(Music_xml_node):
 
-    def number(self):
+    def get_number(self):
         """
         Return the number attribute(if it exists) of the lyric element.
 
@@ -965,7 +965,7 @@ class Lyric(Music_xml_node):
         @return: The value of the number attribute
         """
         if hasattr(self, 'number'):
-            return self.number
+            return int(self.number)
         else:
             return -1
 
@@ -1239,7 +1239,7 @@ class Musicxml_voice:
           self.has_lyrics = len(lyrics) > 0
 
         for l in lyrics:
-            nr = l.number
+            nr = l.get_number()
             if(nr > 0) and not(nr in self._lyrics):
                 self._lyrics.append(nr)
 
diff --git a/python/rational.py b/python/rational.py
index 4a6eaa5823..c43f0a5576 100644
--- a/python/rational.py
+++ b/python/rational.py
@@ -3,6 +3,7 @@
 
 
 import math as _math
+from functools import total_ordering
 
 def _gcf(a, b):
     """Returns the greatest common factor of a and b."""
@@ -12,6 +13,7 @@ def _gcf(a, b):
         a, b = b, a % b
     return a
 
+@total_ordering
 class Rational(object):
     """
     This class provides an exact representation of rational numbers.
@@ -161,11 +163,16 @@ class Rational(object):
         return other - other // self * self
     def __divmod__(self, other):
         return self // other, self % other
-    def __cmp__(self, other):
+    def __eq__(self, other):
         if other == 0:
-            return cmp(self._n, 0)
+            return self._n == 0
         else:
-            return cmp(self - other, 0)
+            return (self - other)._n == 0
+    def __lt__(self, other):
+        if other == 0:
+            return self._n < 0
+        else:
+            return (self - other) < 0
     def __pow__(self, other):
         if isinstance(other, int):
             if other < 0:
diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py
index e5584f6851..4be0f617c5 100755
--- a/scripts/musicxml2ly.py
+++ b/scripts/musicxml2ly.py
@@ -73,7 +73,7 @@ additional_definitions = {
 }
 
 def round_to_two_digits(val):
-    return round(val * 100) / 100
+    return round(val * 100) // 100
 
 def extract_paper_information(score_partwise):
     defaults = score_partwise.get_maybe_exist_named_child('defaults')
@@ -856,7 +856,7 @@ def musicxml_transpose_to_lily(attributes):
         (3, 0), (3, 1), (4, 0), (5, -1), (5, 0),
         (6, -1), (6, 0)][chromatic_shift_normalized];
 
-    shift.octave += (chromatic_shift - chromatic_shift_normalized) / 12
+    shift.octave += (chromatic_shift - chromatic_shift_normalized) // 12
 
     diatonic = transpose.get_maybe_exist_named_child('diatonic')
     if diatonic:
@@ -1256,7 +1256,7 @@ def hexcolorval_to_nr(hex_val):
         v = int(hex_val, 16)
         if v == 255:
             v = 256
-        return v / 256.
+        return v // 256.
     except ValueError:
         return 0.
 
@@ -1684,8 +1684,8 @@ def musicxml_get_string_tunings(lines):
         string_tunings = [musicexp.Pitch()] * lines
         for i in range(0, lines):
             p = musicexp.Pitch()
-            p.step = musicxml2ly_conversion.musicxml_step_to_lily(((("E","A","D","G","B")*(lines/5+1))[0:lines])[i])
-            p.octave = (([-2+int(x%5>1)+2*(x/5) for x in range(0,lines)][0:lines])[i])
+            p.step = musicxml2ly_conversion.musicxml_step_to_lily(((("E","A","D","G","B")*(lines//5+1))[0:lines])[i])
+            p.octave = (([-2+int(x%5>1)+2*(x//5) for x in range(0,lines)][0:lines])[i])
             p.alteration = 0
             p._force_absolute_pitch = True
             string_tunings[i] = p
@@ -1933,7 +1933,7 @@ class LilyPondVoiceBuilder:
         r = musicexp.MultiMeasureRest()
         lenfrac = self.measure_length
         r.duration = musicxml2ly_conversion.rational_to_lily_duration(lenfrac)
-        r.duration.factor *= self.pending_multibar / lenfrac
+        r.duration.factor *= self.pending_multibar // lenfrac
         self.elements.append(r)
         self.begin_moment = self.end_moment
         self.end_moment = self.begin_moment + self.pending_multibar
@@ -2130,7 +2130,7 @@ def get_all_lyric_parts_in_voice(voice):
         lyrics = elem.get_typed_children(musicxml.Lyric)
         if lyrics:
             for lyric in lyrics:
-                index = lyric.number
+                index = lyric.get_number()
                 if not index in all_lyric_parts:
                     all_lyric_parts.append(index)
     return all_lyric_parts
@@ -2157,17 +2157,17 @@ def extract_lyrics(voice, lyric_key, lyrics_dict):
 
     def has_lyric_belonging_to_lyric_part(note, lyric_part_id):
         lyric_elements = get_lyric_elements(note)
-        lyric_numbers = [lyric.number for lyric in lyric_elements]
+        lyric_numbers = [lyric.get_number() for lyric in lyric_elements]
         return any([lyric_number == lyric_part_id for lyric_number in lyric_numbers])
 
     for idx, elem in enumerate(voice._elements):
         lyrics = get_lyric_elements(elem)
-        lyric_keys = [lyric.number for lyric in lyrics]
+        lyric_keys = [lyric.get_number() for lyric in lyrics]
         note_has_lyric_belonging_to_lyric_part = lyric_key in lyric_keys
         # Current note has lyric with 'number' matching 'lyric_key'.
         if note_has_lyric_belonging_to_lyric_part:
             for lyric in lyrics:
-                if lyric.number == lyric_key:
+                if lyric.get_number() == lyric_key:
                     text = musicxml_lyrics_to_text(lyric, None)
                     result.append(text)
         # Note has any lyric.
-- 
2.23.0

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel

Reply via email to