On Thu, 2024-12-19 at 15:57 +0100, Scott Kostyshak wrote: > Is the problem that the object should not be a string?
Yes, it was expecting bytes. > $ python3 --version > Python 3.12.3 Do you know the Whac-A-Mole game? :-) It was the same game that I was playing here. I modernized the code a bit, changing from bytes to str as soon as possible since that is now possible. I use kate that uses already some plugins to reformat the code on save and so the patch it is a lot larger... Tell me if this works. Best regards, -- José Abílio
diff --git a/lib/scripts/lyxpak.py b/lib/scripts/lyxpak.py index 38cd4c62b8..9a3fdd1b61 100755 --- a/lib/scripts/lyxpak.py +++ b/lib/scripts/lyxpak.py @@ -13,7 +13,10 @@ # a gzip compressed tar archive on *nix. This can be controlled by command # line options, however. -import gzip, os, re, sys +import gzip +import os +import re +import sys from io import BytesIO import subprocess @@ -21,7 +24,7 @@ import subprocess # this case we revert to simply calling "python" from the path. PYTHON_BIN = sys.executable if sys.executable else "python" -running_on_windows = (os.name == 'nt') +running_on_windows = os.name == "nt" if running_on_windows: from shutil import copyfile @@ -31,20 +34,24 @@ else: from getopt import getopt # Pre-compiled regular expressions. -re_lyxfile = re.compile(br"\.lyx$") -re_input = re.compile(b'^(.*)\\\\(input|include){(\\s*)(.+)(\\s*)}.*$') -re_ertinput = re.compile(b'^(input|include)({)(\\s*)(.+)(\\s*)}.*$') -re_package = re.compile(b'^(.*)\\\\(usepackage){(\\s*)(.+)(\\s*)}.*$') -re_class = re.compile(b'^(\\\\)(textclass)(\\s+)(.+)\\s*$') -re_norecur = re.compile(b'^(.*)\\\\(verbatiminput|lstinputlisting|includegraphics\\[*.*\\]*){(\\s*)(.+)(\\s*)}.*$') -re_ertnorecur = re.compile(b'^(verbatiminput|lstinputlisting|includegraphics\\[*.*\\]*)({)(\\s*)(.+)(\\s*)}.*$') -re_filename = re.compile(b'^(\\s*)(filename)(\\s+)(.+)\\s*$') -re_options = re.compile(b'^(\\s*)options(\\s+)(.+)\\s*$') -re_bibfiles = re.compile(b'^(\\s*)bibfiles(\\s+)(.+)\\s*$') +re_lyxfile = re.compile(r"\.lyx$") +re_input = re.compile("^(.*)\\\\(input|include){(\\s*)(.+)(\\s*)}.*$") +re_ertinput = re.compile("^(input|include)({)(\\s*)(.+)(\\s*)}.*$") +re_package = re.compile("^(.*)\\\\(usepackage){(\\s*)(.+)(\\s*)}.*$") +re_class = re.compile("^(\\\\)(textclass)(\\s+)(.+)\\s*$") +re_norecur = re.compile( + "^(.*)\\\\(verbatiminput|lstinputlisting|includegraphics\\[*.*\\]*){(\\s*)(.+)(\\s*)}.*$" +) +re_ertnorecur = re.compile( + "^(verbatiminput|lstinputlisting|includegraphics\\[*.*\\]*)({)(\\s*)(.+)(\\s*)}.*$" +) +re_filename = re.compile("^(\\s*)(filename)(\\s+)(.+)\\s*$") +re_options = re.compile("^(\\s*)options(\\s+)(.+)\\s*$") +re_bibfiles = re.compile("^(\\s*)bibfiles(\\s+)(.+)\\s*$") def usage(prog_name): - msg = ''' + msg = """ Usage: %s [-t] [-z] [-l path] [-o output_dir] file.lyx Options: -l: Path to lyx2lyx script @@ -54,26 +61,20 @@ Options: By default, we create file.zip on Windows and file.tar.gz on *nix, with the file output to where file.lyx is, and we look for lyx2lyx in the known locations, querying LyX itself if necessary. -''' +""" return msg % prog_name def error(message): - sys.stderr.write(message + '\n') + sys.stderr.write(message + "\n") sys.exit(1) -def tostr(message): - return message.decode(sys.getfilesystemencoding()) - - def gzopen(file): - input = open(file.decode('utf-8'), 'rb') - magicnum = input.read(2) - input.close() - if magicnum == b"\x1f\x8b": - return gzip.open(file.decode('utf-8')) - return open(file.decode('utf-8'), 'rb') + with open(file, "rb") as f: + magicnum = f.read(2) + + return gzip.open(file) if magicnum == b"\x1f\x8b" else open(file) def find_exe(candidates, extlist, path): @@ -87,7 +88,7 @@ def find_exe(candidates, extlist, path): def abspath(name): - " Resolve symlinks and returns the absolute normalized name." + "Resolve symlinks and returns the absolute normalized name." newname = os.path.normpath(os.path.abspath(name)) if not running_on_windows: newname = os.path.realpath(newname) @@ -95,7 +96,7 @@ def abspath(name): def gather_files(curfile, incfiles, lyx2lyx): - " Recursively gather files." + "Recursively gather files." curdir = os.path.dirname(abspath(curfile)) is_lyxfile = re_lyxfile.search(curfile) @@ -106,35 +107,34 @@ def gather_files(curfile, incfiles, lyx2lyx): # code page. So, we resort to running lyx2lyx on a copy. tmp = NamedTemporaryFile(delete=False) tmp.close() - copyfile(curfile.decode('utf-8'), tmp.name) + copyfile(curfile, tmp.name) try: l2l_stdout = subprocess.check_output([PYTHON_BIN, lyx2lyx, tmp.name]) except subprocess.CalledProcessError: - error(f'{lyx2lyx} failed to convert "{tostr(curfile)}"') + error(f'{lyx2lyx} failed to convert "{curfile}"') os.unlink(tmp.name) else: try: l2l_stdout = subprocess.check_output([PYTHON_BIN, lyx2lyx, curfile]) except subprocess.CalledProcessError: - error(f'{lyx2lyx} failed to convert "{tostr(curfile)}"') + error(f'{lyx2lyx} failed to convert "{curfile}"') if l2l_stdout.startswith(b"\x1f\x8b"): l2l_stdout = gzip.GzipFile("", "rb", 0, BytesIO(l2l_stdout)).read() elif running_on_windows: # For some unknown reason, there can be a spurious '\r' in the line # separators, causing spurious empty lines when calling splitlines. - l2l_stdout = l2l_stdout.replace(b'\r\r\n', b'\r\n') - lines = l2l_stdout.splitlines() + l2l_stdout = l2l_stdout.replace(b"\r\r\n", b"\r\n") + lines = l2l_stdout.decode("utf-8").splitlines() else: - input = gzopen(curfile) - lines = input.readlines() - input.close() + with gzopen(curfile) as f: + lines = f.readlines() maybe_in_ert = False i = 0 while i < len(lines): # Gather used files. recursive = True - extlist = [b''] + extlist = [""] match = re_filename.match(lines[i]) if not match: if maybe_in_ert: @@ -143,20 +143,20 @@ def gather_files(curfile, incfiles, lyx2lyx): match = re_input.match(lines[i]) if not match: match = re_package.match(lines[i]) - extlist = [b'.sty'] + extlist = [".sty"] if not match: match = re_class.match(lines[i]) - extlist = [b'.cls'] + extlist = [".cls"] if not match: if maybe_in_ert: match = re_ertnorecur.match(lines[i]) else: match = re_norecur.match(lines[i]) - extlist = [b'', b'.eps', b'.pdf', b'.png', b'.jpg'] + extlist = ["", ".eps", ".pdf", ".png", ".jpg"] recursive = False - maybe_in_ert = is_lyxfile and lines[i] == b"\\backslash" + maybe_in_ert = is_lyxfile and lines[i] == "\\backslash" if match: - file = match.group(4).strip(b'"') + file = match.group(4).strip('"') if not os.path.isabs(file): file = os.path.join(curdir, file) file_exists = False @@ -180,12 +180,12 @@ def gather_files(curfile, incfiles, lyx2lyx): # Gather bibtex *.bst files. match = re_options.match(lines[i]) if match: - file = match.group(3).strip(b'"') - if file.startswith(b"bibtotoc,"): + file = match.group(3).strip('"') + if file.startswith("bibtotoc,"): file = file[9:] ext = os.path.splitext(file)[-1] - if ext != b'.bst': - file = file + b'.bst' + if ext != ".bst": + file = file + ".bst" if not os.path.isabs(file): file = os.path.join(curdir, file) if os.path.exists(file): @@ -196,13 +196,13 @@ def gather_files(curfile, incfiles, lyx2lyx): # Gather bibtex *.bib files. match = re_bibfiles.match(lines[i]) if match: - bibfiles = match.group(3).strip(b'"').split(b',') + bibfiles = match.group(3).strip('"').split(",") j = 0 while j < len(bibfiles): file = bibfiles[j] ext = os.path.splitext(file)[-1] - if ext != b'.bib': - file = file + b'.bib' + if ext != ".bib": + file = file + ".bib" if not os.path.isabs(file): file = os.path.join(curdir, file) if os.path.exists(file): @@ -217,32 +217,34 @@ def gather_files(curfile, incfiles, lyx2lyx): def find_lyx2lyx(progloc, path): - " Find a usable version of the lyx2lyx script. " + "Find a usable version of the lyx2lyx script." # first we will see if the script is roughly where we are # i.e., we will assume we are in $SOMEDIR/scripts and look # for $SOMEDIR/lyx2lyx/lyx2lyx. ourpath = os.path.dirname(abspath(progloc)) (upone, discard) = os.path.split(ourpath) if running_on_windows: - tryit = os.path.join(upone, b"lyx2lyx", b"lyx2lyx") + tryit = os.path.join(upone, "lyx2lyx", "lyx2lyx") else: tryit = os.path.join(upone, "lyx2lyx", "lyx2lyx") if os.access(tryit, os.X_OK): return tryit # now we will try to query LyX itself to find the path. - extlist = [''] + extlist = [""] if "PATHEXT" in os.environ: extlist = extlist + os.environ["PATHEXT"].split(os.pathsep) lyx_exe, full_path = find_exe(["lyxc", "lyx"], extlist, path) if lyx_exe is None: - error('Cannot find the LyX executable in the path.') + error("Cannot find the LyX executable in the path.") try: - cmd_stdout = subprocess.check_output([lyx_exe, '-version'], stderr=subprocess.STDOUT) + cmd_stdout = subprocess.check_output( + [lyx_exe, "-version"], stderr=subprocess.STDOUT + ) except subprocess.CalledProcessError: - error('Cannot query LyX about the lyx2lyx script.') - re_msvc = re.compile(r'^(\s*)(Host type:)(\s+)(win32)$') - re_sysdir = re.compile(r'^(\s*)(LyX files dir:)(\s+)(\S+)$') + error("Cannot query LyX about the lyx2lyx script.") + re_msvc = re.compile(r"^(\s*)(Host type:)(\s+)(win32)$") + re_sysdir = re.compile(r"^(\s*)(LyX files dir:)(\s+)(\S+)$") lines = cmd_stdout.splitlines() for line in lines: match = re_msvc.match(line) @@ -250,15 +252,15 @@ def find_lyx2lyx(progloc, path): # The LyX executable was built with MSVC, so the # "LyX files dir:" line is unusable basedir = os.path.dirname(os.path.dirname(full_path)) - tryit = os.path.join(basedir, 'Resources', 'lyx2lyx', 'lyx2lyx') + tryit = os.path.join(basedir, "Resources", "lyx2lyx", "lyx2lyx") break match = re_sysdir.match(line) if match: - tryit = os.path.join(match.group(4), 'lyx2lyx', 'lyx2lyx') + tryit = os.path.join(match.group(4), "lyx2lyx", "lyx2lyx") break if not os.access(tryit, os.X_OK): - error('Unable to find the lyx2lyx script.') + error("Unable to find the lyx2lyx script.") return tryit @@ -268,7 +270,7 @@ def main(args): try: if running_on_windows: - (options, argv) = getopt(args[1:], b"htzl:o:") + (options, argv) = getopt(args[1:], "htzl:o:") else: (options, argv) = getopt(args[1:], "htzl:o:") except: @@ -282,7 +284,7 @@ def main(args): outdir = "" lyx2lyx = None - for (opt, param) in options: + for opt, param in options: if opt == "-h": print(usage(ourprog)) sys.exit(0) @@ -299,25 +301,25 @@ def main(args): lyxfile = argv[0] if not os.path.exists(lyxfile): - error('File "%s" not found.' % tostr(lyxfile)) + error(f'File "{lyxfile}" not found.') # Check that it actually is a LyX document - input = gzopen(lyxfile) - line = input.readline() - input.close() - if not (line and line.startswith(b'#LyX')): - error('File "%s" is not a LyX document.' % tostr(lyxfile)) + with gzopen(lyxfile) as f: + line = f.readline() + + if not (line and line.startswith("#LyX")): + error(f'File "{lyxfile}" is not a LyX document.') if makezip: import zipfile else: import tarfile - ar_ext = b".tar.gz" + ar_ext = ".tar.gz" if makezip: - ar_ext = b".zip" + ar_ext = ".zip" - ar_name = re_lyxfile.sub(ar_ext, abspath(lyxfile)).decode('utf-8') + ar_name = re_lyxfile.sub(ar_ext, abspath(lyxfile)) if outdir: ar_name = os.path.join(abspath(outdir), os.path.basename(ar_name)) @@ -332,7 +334,7 @@ def main(args): gather_files(lyxfile, incfiles, lyx2lyx) # Find the topmost dir common to all files - path_sep = os.path.sep.encode('utf-8') + path_sep = os.path.sep if len(incfiles) > 1: topdir = os.path.commonprefix(incfiles) # As os.path.commonprefix() works on a character by character basis, @@ -344,32 +346,28 @@ def main(args): # Remove the prefix common to all paths in the list i = 0 while i < len(incfiles): - incfiles[i] = incfiles[i].replace(topdir, b'', 1) + incfiles[i] = incfiles[i].replace(topdir, "", 1) i += 1 # Remove duplicates and sort the list incfiles = list(set(incfiles)) incfiles.sort() - if topdir != '': + if topdir != "": os.chdir(topdir) # Create the archive - try: - if makezip: - zip = zipfile.ZipFile(ar_name, "w", zipfile.ZIP_DEFLATED) + # try: + if makezip: + with zipfile.ZipFile(ar_name, "w", zipfile.ZIP_DEFLATED) as zip: for file in incfiles: - zip.write(file.decode('utf-8')) - zip.close() - else: - tar = tarfile.open(ar_name, "w:gz") + zip.write(file) + else: + with tarfile.open(ar_name, "w:gz") as tar: for file in incfiles: - tar.add(file.decode('utf-8')) - tar.close() - except: - error('Failed to create LyX archive "%s"' % ar_name) + tar.add(file) - print('LyX archive "%s" created successfully.' % ar_name) + print(f'LyX archive "{ar_name}" created successfully.') return 0 @@ -388,15 +386,18 @@ if __name__ == "__main__": # as all other paths are extracted from the document in utf-8 format. from ctypes import WINFUNCTYPE, windll, POINTER, byref, c_int from ctypes.wintypes import LPWSTR, LPCWSTR + GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) - CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))(("CommandLineToArgvW", windll.shell32)) + CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ("CommandLineToArgvW", windll.shell32) + ) argc = c_int(0) argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc)) # unicode_argv[0] is the Python interpreter, so skip that. - argv = [argv_unicode[i].encode('utf-8') for i in range(1, argc.value)] + argv = [argv_unicode[i].encode("utf-8") for i in range(1, argc.value)] # Also skip option arguments to the Python interpreter. while len(argv) > 0: - if not argv[0].startswith(b"-"): + if not argv[0].startswith("-"): break argv = argv[1:] sys.argv = argv
-- lyx-devel mailing list lyx-devel@lists.lyx.org https://lists.lyx.org/mailman/listinfo/lyx-devel