From fec475b5ef949d168a61db2ac59077ec566ccce3 Mon Sep 17 00:00:00 2001 From: Louis Date: Wed, 7 Oct 2015 15:46:11 +0200 Subject: [PATCH 1/8] Added a command line tool to convert between file formats --- patacrep/songs/chordpro/__init__.py | 16 ++++++---- patacrep/songs/convert/__main__.py | 48 +++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 patacrep/songs/convert/__main__.py diff --git a/patacrep/songs/chordpro/__init__.py b/patacrep/songs/chordpro/__init__.py index 6d4c0e39..e5579d97 100644 --- a/patacrep/songs/chordpro/__init__.py +++ b/patacrep/songs/chordpro/__init__.py @@ -1,8 +1,9 @@ """Chordpro parser""" from jinja2 import Environment, FileSystemLoader, contextfunction -import pkg_resources +import jinja2 import os +import pkg_resources from patacrep import encoding, files from patacrep.songs import Song @@ -63,11 +64,14 @@ class ChordproSong(Song): jinjaenv.filters['search_image'] = self.search_image jinjaenv.filters['search_partition'] = self.search_partition - return Renderer( - template=template, - encoding='utf8', - jinjaenv=jinjaenv, - ).template.render(context) + try: + return Renderer( + template=template, + encoding='utf8', + jinjaenv=jinjaenv, + ).template.render(context) + except jinja2.exceptions.TemplateNotFound: + raise NotImplementedError() @staticmethod @contextfunction diff --git a/patacrep/songs/convert/__main__.py b/patacrep/songs/convert/__main__.py new file mode 100644 index 00000000..5271637f --- /dev/null +++ b/patacrep/songs/convert/__main__.py @@ -0,0 +1,48 @@ +"""Conversion between formats + +See the :meth:`__usage` method for more information. +""" + +import logging +import sys + +from patacrep.build import DEFAULT_CONFIG +from patacrep import files + +LOGGER = logging.getLogger(__name__) + +def __usage(): + return "python3 -m patacrep.songs.convert chordpro latex FILE" + +if __name__ == "__main__": + if len(sys.argv) != 4: + LOGGER.error("Invalid number of arguments.") + LOGGER.error("Usage: %s", __usage()) + sys.exit(1) + + source = sys.argv[1] + dest = sys.argv[2] + file = sys.argv[3] + + song_parsers = files.load_plugins( + datadirs=DEFAULT_CONFIG.get('datadir', []), + root_modules=['songs'], + keyword='SONG_PARSERS', + ) + + if source not in song_parsers: + LOGGER.error( + "Unknown file format '%s'. Available ones are %s.", + source, + ", ".join(["'{}'".format(key) for key in song_parsers.keys()]) + ) + sys.exit(1) + + song = song_parsers[source](".", file, DEFAULT_CONFIG) + try: + print(song.render(dest)) + except NotImplementedError: + LOGGER.error("Cannot convert to format '%s'.", dest) + sys.exit(1) + + sys.exit(0) From 82db9f39b62c20d3f0546c3e9a6674640774e2f5 Mon Sep 17 00:00:00 2001 From: Louis Date: Thu, 8 Oct 2015 00:23:57 +0200 Subject: [PATCH 2/8] Add more precise error message --- patacrep/songs/chordpro/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patacrep/songs/chordpro/__init__.py b/patacrep/songs/chordpro/__init__.py index e5579d97..5df4a7b9 100644 --- a/patacrep/songs/chordpro/__init__.py +++ b/patacrep/songs/chordpro/__init__.py @@ -71,7 +71,7 @@ class ChordproSong(Song): jinjaenv=jinjaenv, ).template.render(context) except jinja2.exceptions.TemplateNotFound: - raise NotImplementedError() + raise NotImplementedError("Cannot convert to format '{}'.".format(output_format)) @staticmethod @contextfunction From 354e3582c8728e495f3bb192726e62134f20983a Mon Sep 17 00:00:00 2001 From: Louis Date: Mon, 12 Oct 2015 21:42:00 +0200 Subject: [PATCH 3/8] Can now convert several files in a single command --- patacrep/songs/convert/__main__.py | 42 +++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/patacrep/songs/convert/__main__.py b/patacrep/songs/convert/__main__.py index 5271637f..53fc9607 100644 --- a/patacrep/songs/convert/__main__.py +++ b/patacrep/songs/convert/__main__.py @@ -3,6 +3,7 @@ See the :meth:`__usage` method for more information. """ +import os import logging import sys @@ -12,17 +13,28 @@ from patacrep import files LOGGER = logging.getLogger(__name__) def __usage(): - return "python3 -m patacrep.songs.convert chordpro latex FILE" + return "python3 -m patacrep.songs.convert INPUTFORMAT OUTPUTFORMAT FILES" + +def yesno(prompt): + while True: + answer = input("{} [yn] ".format(prompt)) + if answer.strip().lower() == "y": + return True + if answer.strip().lower() == "n": + return False + +def confirm(destname): + return yesno("File '{}' already exist. Overwrite?".format(destname)) if __name__ == "__main__": - if len(sys.argv) != 4: + if len(sys.argv) < 4: LOGGER.error("Invalid number of arguments.") LOGGER.error("Usage: %s", __usage()) sys.exit(1) source = sys.argv[1] dest = sys.argv[2] - file = sys.argv[3] + song_files = sys.argv[3:] song_parsers = files.load_plugins( datadirs=DEFAULT_CONFIG.get('datadir', []), @@ -38,11 +50,23 @@ if __name__ == "__main__": ) sys.exit(1) - song = song_parsers[source](".", file, DEFAULT_CONFIG) - try: - print(song.render(dest)) - except NotImplementedError: - LOGGER.error("Cannot convert to format '%s'.", dest) - sys.exit(1) + for file in song_files: + song = song_parsers[source](".", file, DEFAULT_CONFIG) + try: + converted = song.render(dest) + destname = "{}.{}".format(".".join(file.split(".")[:-1]), dest) + if os.path.exists(destname): + if not confirm(destname): + continue + with open(destname, "w") as destfile: + destfile.write(converted) + + except NotImplementedError: + LOGGER.error("Cannot convert to format '%s'.", dest) + sys.exit(1) + except KeyboardInterrupt: + print() + LOGGER.info("Aborted by user.") + sys.exit(0) sys.exit(0) From 3e2be8112a1e35ff812d078d70a30427a63007c9 Mon Sep 17 00:00:00 2001 From: Louis Date: Mon, 12 Oct 2015 21:51:07 +0200 Subject: [PATCH 4/8] Command `convert` no longer creates cache --- patacrep/songs/convert/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patacrep/songs/convert/__main__.py b/patacrep/songs/convert/__main__.py index 53fc9607..8e007418 100644 --- a/patacrep/songs/convert/__main__.py +++ b/patacrep/songs/convert/__main__.py @@ -51,7 +51,7 @@ if __name__ == "__main__": sys.exit(1) for file in song_files: - song = song_parsers[source](".", file, DEFAULT_CONFIG) + song = song_parsers[source]("", file, DEFAULT_CONFIG) try: converted = song.render(dest) destname = "{}.{}".format(".".join(file.split(".")[:-1]), dest) From 0ea1cde0e09895186584c35b201688e323f06960 Mon Sep 17 00:00:00 2001 From: Oliverpool Date: Mon, 12 Oct 2015 22:07:27 +0200 Subject: [PATCH 5/8] Add an option to remember the confirmation choice with a * --- patacrep/songs/convert/__main__.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/patacrep/songs/convert/__main__.py b/patacrep/songs/convert/__main__.py index 8e007418..a6766452 100644 --- a/patacrep/songs/convert/__main__.py +++ b/patacrep/songs/convert/__main__.py @@ -17,11 +17,14 @@ def __usage(): def yesno(prompt): while True: - answer = input("{} [yn] ".format(prompt)) - if answer.strip().lower() == "y": - return True - if answer.strip().lower() == "n": - return False + answer = input("{} [yn](folllow with * to remember) ".format(prompt)).strip().lower() + remember = (answer[-1] == "*") + if remember: + answer = answer[0:-1] + if answer == "y": + return True, remember + if answer == "n": + return False, remember def confirm(destname): return yesno("File '{}' already exist. Overwrite?".format(destname)) @@ -50,14 +53,16 @@ if __name__ == "__main__": ) sys.exit(1) + remember = False for file in song_files: song = song_parsers[source]("", file, DEFAULT_CONFIG) try: converted = song.render(dest) destname = "{}.{}".format(".".join(file.split(".")[:-1]), dest) - if os.path.exists(destname): - if not confirm(destname): - continue + if os.path.exists(destname) and not remember: + overwrite, remember = confirm(destname) + if not overwrite: + continue with open(destname, "w") as destfile: destfile.write(converted) From e6acaab45e6dddc47ebfcc47547037fdcbb49564 Mon Sep 17 00:00:00 2001 From: Oliverpool Date: Mon, 12 Oct 2015 22:09:06 +0200 Subject: [PATCH 6/8] Convert the song only if necessary --- patacrep/songs/convert/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patacrep/songs/convert/__main__.py b/patacrep/songs/convert/__main__.py index a6766452..0620ecf6 100644 --- a/patacrep/songs/convert/__main__.py +++ b/patacrep/songs/convert/__main__.py @@ -57,12 +57,12 @@ if __name__ == "__main__": for file in song_files: song = song_parsers[source]("", file, DEFAULT_CONFIG) try: - converted = song.render(dest) destname = "{}.{}".format(".".join(file.split(".")[:-1]), dest) if os.path.exists(destname) and not remember: overwrite, remember = confirm(destname) if not overwrite: continue + converted = song.render(dest) with open(destname, "w") as destfile: destfile.write(converted) From 3ae9a20d52c52a6fcbe77caf151561ae803378e8 Mon Sep 17 00:00:00 2001 From: Oliverpool Date: Mon, 12 Oct 2015 22:12:42 +0200 Subject: [PATCH 7/8] Typo in confirmation message --- patacrep/songs/convert/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patacrep/songs/convert/__main__.py b/patacrep/songs/convert/__main__.py index 0620ecf6..f289fdc8 100644 --- a/patacrep/songs/convert/__main__.py +++ b/patacrep/songs/convert/__main__.py @@ -17,7 +17,7 @@ def __usage(): def yesno(prompt): while True: - answer = input("{} [yn](folllow with * to remember) ".format(prompt)).strip().lower() + answer = input("{} [yn](append * to remember) ".format(prompt)).strip().lower() remember = (answer[-1] == "*") if remember: answer = answer[0:-1] From c2bd2db84ccb21312311199787614b387b183521 Mon Sep 17 00:00:00 2001 From: Oliverpool Date: Mon, 12 Oct 2015 22:15:24 +0200 Subject: [PATCH 8/8] Only skip if the dest did not exist --- patacrep/songs/convert/__main__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/patacrep/songs/convert/__main__.py b/patacrep/songs/convert/__main__.py index f289fdc8..42728af7 100644 --- a/patacrep/songs/convert/__main__.py +++ b/patacrep/songs/convert/__main__.py @@ -58,9 +58,10 @@ if __name__ == "__main__": song = song_parsers[source]("", file, DEFAULT_CONFIG) try: destname = "{}.{}".format(".".join(file.split(".")[:-1]), dest) - if os.path.exists(destname) and not remember: + dest_exists = os.path.exists(destname) + if dest_exists and not remember: overwrite, remember = confirm(destname) - if not overwrite: + if dest_exists and not overwrite: continue converted = song.render(dest) with open(destname, "w") as destfile: