lyx2lyx: use parseopt instead of getopt (the documentation of options

is kept in sync with its usage)

LyX.py:  make source more readable, place whitespaces, break long
         lines, add documentation strings, etc.



git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@20279 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
José Matox 2007-09-14 14:37:14 +00:00
parent 97811b4116
commit dbe7b13f65
2 changed files with 158 additions and 154 deletions

View File

@ -17,7 +17,9 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from parser_tools import get_value, check_token, find_token,\
" The LyX module has all the rules related with different lyx file formats."
from parser_tools import get_value, check_token, find_token, \
find_tokens, find_end_of
import os.path
import gzip
@ -28,11 +30,11 @@ import time
try:
import lyx2lyx_version
version_lyx2lyx = lyx2lyx_version.version
version__ = lyx2lyx_version.version
except: # we are running from build directory so assume the last version
version_lyx2lyx = '1.6.0svn'
version__ = '1.6.0svn'
default_debug_level = 2
default_debug__ = 2
####################################################################
# Private helper functions
@ -41,13 +43,13 @@ def find_end_of_inset(lines, i):
" Find beginning of inset, where lines[i] is included."
return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
def generate_minor_versions(major, last_minor_version):
def minor_versions(major, last_minor_version):
""" Generate minor versions, using major as prefix and minor
versions from 0 until last_minor_version, plus the generic version.
Example:
generate_minor_versions("1.2", 4) ->
minor_versions("1.2", 4) ->
[ "1.2", "1.2.0", "1.2.1", "1.2.2", "1.2.3"]
"""
return [major] + [major + ".%d" % i for i in range(last_minor_version + 1)]
@ -65,20 +67,20 @@ original_version = re.compile(r".*?LyX ([\d.]*)")
##
# file format information:
# file, supported formats, stable release versions
format_relation = [("0_06", [200], generate_minor_versions("0.6" , 4)),
("0_08", [210], generate_minor_versions("0.8" , 6) + ["0.7"]),
("0_10", [210], generate_minor_versions("0.10", 7) + ["0.9"]),
("0_12", [215], generate_minor_versions("0.12", 1) + ["0.11"]),
("1_0", [215], generate_minor_versions("1.0" , 4)),
("1_1", [215], generate_minor_versions("1.1" , 4)),
format_relation = [("0_06", [200], minor_versions("0.6" , 4)),
("0_08", [210], minor_versions("0.8" , 6) + ["0.7"]),
("0_10", [210], minor_versions("0.10", 7) + ["0.9"]),
("0_12", [215], minor_versions("0.12", 1) + ["0.11"]),
("1_0", [215], minor_versions("1.0" , 4)),
("1_1", [215], minor_versions("1.1" , 4)),
("1_1_5", [216], ["1.1.5","1.1.5.1","1.1.5.2","1.1"]),
("1_1_6_0", [217], ["1.1.6","1.1.6.1","1.1.6.2","1.1"]),
("1_1_6_3", [218], ["1.1.6.3","1.1.6.4","1.1"]),
("1_2", [220], generate_minor_versions("1.2" , 4)),
("1_3", [221], generate_minor_versions("1.3" , 7)),
("1_4", range(222,246), generate_minor_versions("1.4" , 5)),
("1_5", range(246,277), generate_minor_versions("1.5" , 1)),
("1_6", range(277,286), generate_minor_versions("1.6" , 0))]
("1_2", [220], minor_versions("1.2" , 4)),
("1_3", [221], minor_versions("1.3" , 7)),
("1_4", range(222,246), minor_versions("1.4" , 5)),
("1_5", range(246,277), minor_versions("1.5" , 1)),
("1_6", range(277,286), minor_versions("1.6" , 0))]
def formats_list():
@ -114,6 +116,7 @@ def trim_eol(line):
def get_encoding(language, inputencoding, format, cjk_encoding):
" Returns enconding of the lyx file"
if format > 248:
return "utf8"
# CJK-LyX encodes files using the current locale encoding.
@ -122,7 +125,7 @@ def get_encoding(language, inputencoding, format, cjk_encoding):
# argument.
if cjk_encoding == 'auto':
return locale.getpreferredencoding()
elif cjk_encoding != '':
elif cjk_encoding:
return cjk_encoding
from lyx2lyx_lang import lang
if inputencoding == "auto" or inputencoding == "default":
@ -137,11 +140,11 @@ def get_encoding(language, inputencoding, format, cjk_encoding):
##
# Class
#
class LyX_Base:
class LyX_base:
"""This class carries all the information of the LyX file."""
def __init__(self, end_format = 0, input = "", output = "", error
= "", debug = default_debug_level, try_hard = 0, cjk_encoding = '',
def __init__(self, end_format = 0, input = "", output = "", error = "",
debug = default_debug__, try_hard = 0, cjk_encoding = '',
language = "english", encoding = "auto"):
"""Arguments:
@ -182,8 +185,9 @@ class LyX_Base:
self.language = language
def warning(self, message, debug_level= default_debug_level):
" Emits warning to self.error, if the debug_level is less than the self.debug."
def warning(self, message, debug_level= default_debug__):
""" Emits warning to self.error, if the debug_level is less
than the self.debug."""
if debug_level <= self.debug:
self.err.write("Warning: " + message + "\n")
@ -199,9 +203,10 @@ class LyX_Base:
def read(self):
"""Reads a file into the self.header, self.manifest and self.body parts, from self.input."""
"""Reads a file into the self.header, self.manifest and
self.body parts, from self.input."""
while 1:
while True:
line = self.input.readline()
if not line:
self.error("Invalid LyX file.")
@ -217,9 +222,13 @@ class LyX_Base:
if check_token(line, '\\end_preamble'):
break
if line.split()[:0] in ("\\layout", "\\begin_layout", "\\begin_body"):
self.warning("Malformed LyX file: Missing '\\end_preamble'.")
self.warning("Adding it now and hoping for the best.")
if line.split()[:0] in ("\\layout",
"\\begin_layout", "\\begin_body"):
self.warning("Malformed LyX file:"
"Missing '\\end_preamble'."
"\nAdding it now and hoping"
"for the best.")
self.preamble.append(line)
@ -236,9 +245,11 @@ class LyX_Base:
if check_token(line, "\\end_manifest"):
break
if not line.startswith('\\filename') and not line.startswith('\\inzipName') \
and not line.startswith('\\embed'):
self.warning("Malformed LyX file: Missing '\\end_manifest'.")
if not line.startswith('\\filename') and \
not line.startswith('\\inzipName') and \
not line.startswith('\\embed'):
self.warning("Malformed LyX file: Missing"
"'\\end_manifest'.")
self.manifest.append(line)
@ -249,7 +260,8 @@ class LyX_Base:
if not line:
continue
if line.split()[0] in ("\\layout", "\\begin_layout", "\\begin_body", "\\begin_deeper"):
if line.split()[0] in ("\\layout", "\\begin_layout",
"\\begin_body", "\\begin_deeper"):
self.body.append(line)
break
@ -258,9 +270,13 @@ class LyX_Base:
self.textclass = get_value(self.header, "\\textclass", 0)
self.backend = get_backend(self.textclass)
self.format = self.read_format()
self.language = get_value(self.header, "\\language", 0, default = "english")
self.inputencoding = get_value(self.header, "\\inputencoding", 0, default = "auto")
self.encoding = get_encoding(self.language, self.inputencoding, self.format, self.cjk_encoding)
self.language = get_value(self.header, "\\language", 0,
default = "english")
self.inputencoding = get_value(self.header, "\\inputencoding",
0, default = "auto")
self.encoding = get_encoding(self.language,
self.inputencoding, self.format,
self.cjk_encoding)
self.initial_version = self.read_version()
# Second pass over header and preamble, now we know the file encoding
@ -283,8 +299,8 @@ class LyX_Base:
self.set_format()
self.set_textclass()
if self.encoding == "auto":
self.encoding = get_encoding(self.language, self.encoding, self.format, self.cjk_encoding)
self.encoding = get_encoding(self.language, self.encoding,
self.format, self.cjk_encoding)
if self.preamble:
i = find_token(self.header, '\\textclass', 0) + 1
preamble = ['\\begin_preamble'] + self.preamble + ['\\end_preamble']
@ -346,8 +362,9 @@ class LyX_Base:
def read_version(self):
""" Searchs for clues of the LyX version used to write the file, returns the
most likely value, or None otherwise."""
""" Searchs for clues of the LyX version used to write the
file, returns the most likely value, or None otherwise."""
for line in self.header:
if line[0] != "#":
return None
@ -370,7 +387,8 @@ class LyX_Base:
def set_version(self):
" Set the header with the version used."
self.header[0] = "#LyX %s created this file. For more info see http://www.lyx.org/" % version_lyx2lyx
self.header[0] = " ".join(["#LyX %s created this file." % version__,
"For more info see http://www.lyx.org/"])
if self.header[1][0] == '#':
del self.header[1]
@ -426,9 +444,11 @@ class LyX_Base:
for step in convertion_chain:
steps = getattr(__import__("lyx_" + step), mode)
self.warning("Convertion step: %s - %s" % (step, mode), default_debug_level + 1)
self.warning("Convertion step: %s - %s" % (step, mode),
default_debug__ + 1)
if not steps:
self.error("The convertion to an older format (%s) is not implemented." % self.format)
self.error("The convertion to an older "
"format (%s) is not implemented." % self.format)
multi_conv = len(steps) != 1
for version, table in steps:
@ -442,24 +462,26 @@ class LyX_Base:
try:
conv(self)
except:
self.warning("An error ocurred in %s, %s" % (version, str(conv)),
default_debug_level)
self.warning("An error ocurred in %s, %s" %
(version, str(conv)),
default_debug__)
if not self.try_hard:
raise
self.status = 2
else:
self.warning("%lf: Elapsed time on %s" % (time.time() - init_t, str(conv)),
default_debug_level + 1)
self.warning("%lf: Elapsed time on %s" %
(time.time() - init_t,
str(conv)), default_debug__ +
1)
self.format = version
if self.end_format == self.format:
return
def chain(self):
""" This is where all the decisions related with the convertion are taken.
It returns a list of modules needed to convert the LyX file from
self.format to self.end_format"""
""" This is where all the decisions related with the
convertion are taken. It returns a list of modules needed to
convert the LyX file from self.format to self.end_format"""
self.start = self.format
format = self.format
@ -474,7 +496,9 @@ class LyX_Base:
if not correct_version:
if format <= 215:
self.warning("Version does not match file format, discarding it. (Version %s, format %d)" %(self.initial_version, self.format))
self.warning("Version does not match file format, "
"discarding it. (Version %s, format %d)" %
(self.initial_version, self.format))
for rel in format_relation:
if format in rel[1]:
initial_step = rel[0]
@ -522,10 +546,12 @@ class LyX_Base:
def get_toc(self, depth = 4):
" Returns the TOC of this LyX document."
paragraphs_filter = {'Title' : 0,'Chapter' : 1, 'Section' : 2, 'Subsection' : 3, 'Subsubsection': 4}
paragraphs_filter = {'Title' : 0,'Chapter' : 1, 'Section' : 2,
'Subsection' : 3, 'Subsubsection': 4}
allowed_insets = ['Quotes']
allowed_parameters = '\\paragraph_spacing', '\\noindent', '\\align', '\\labelwidthstring', "\\start_of_appendix", "\\leftindent"
allowed_parameters = ('\\paragraph_spacing', '\\noindent',
'\\align', '\\labelwidthstring',
"\\start_of_appendix", "\\leftindent")
sections = []
for section in paragraphs_filter.keys():
sections.append('\\begin_layout %s' % section)
@ -550,8 +576,9 @@ class LyX_Base:
k = i + 1
# skip paragraph parameters
while not self.body[k].strip() or self.body[k].split()[0] in allowed_parameters:
k = k +1
while not self.body[k].strip() or self.body[k].split()[0] \
in allowed_parameters:
k += 1
while k < j:
if check_token(self.body[k], '\\begin_inset'):
@ -565,7 +592,7 @@ class LyX_Base:
k = end + 1
else:
par.append(self.body[k])
k = k + 1
k += 1
# trim empty lines in the end.
while par and par[-1].strip() == '':
@ -578,19 +605,23 @@ class LyX_Base:
return toc_par
class File(LyX_Base):
class File(LyX_base):
" This class reads existing LyX files."
def __init__(self, end_format = 0, input = "", output = "", error = "", debug = default_debug_level, try_hard = 0, cjk_encoding = ''):
LyX_Base.__init__(self, end_format, input, output, error, debug, try_hard, cjk_encoding)
def __init__(self, end_format = 0, input = "", output = "", error = "",
debug = default_debug__, try_hard = 0, cjk_encoding = ''):
LyX_base.__init__(self, end_format, input, output, error,
debug, try_hard, cjk_encoding)
self.read()
class NewFile(LyX_Base):
class NewFile(LyX_base):
" This class is to create new LyX files."
def set_header(self, **params):
# set default values
self.header.extend([
"#LyX xxxx created this file. For more info see http://www.lyx.org/",
"#LyX xxxx created this file."
"For more info see http://www.lyx.org/",
"\\lyxformat xxx",
"\\begin_document",
"\\begin_header",
@ -639,7 +670,8 @@ class NewFile(LyX_Base):
class Paragraph:
# unfinished implementation, it is missing the Text and Insets representation.
# unfinished implementation, it is missing the Text and Insets
# representation.
" This class represents the LyX paragraphs."
def __init__(self, name, body=[], settings = [], child = []):
""" Parameters:
@ -653,7 +685,9 @@ class Paragraph:
self.child = child
def asLines(self):
" Converts the paragraph to a list of strings, representing it in the LyX file."
""" Converts the paragraph to a list of strings, representing
it in the LyX file."""
result = ['','\\begin_layout %s' % self.name]
result.extend(self.settings)
result.append('')
@ -669,13 +703,3 @@ class Paragraph:
result.append('\\end_deeper')
return result
class Inset:
" This class represents the LyX insets."
pass
class Text:
" This class represents simple chuncks of text."
pass

View File

@ -1,6 +1,7 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2002-2004 José Matos <jamatos@lyx.org>
# Copyright (C) 2002-2007 José Matos <jamatos@lyx.org>
# Copyright (C) 2002-2004 Dekel Tsur <dekel@lyx.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@ -16,86 +17,65 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import getopt
" Program used to convert between different versions of the lyx file format."
import optparse
import sys
import LyX
def usage():
print """Usage: lyx2lyx [options] [file]
Convert old lyx file <file> to newer format, files can be compressed with gzip.
If there no file is specified then the standard input is assumed, in this case
gziped files are not handled.
Options:
-h, --help this information
-v, --version output version information and exit
-l, --list list all available formats
-d, --debug level level=0..2 (O_ no debug information, 2_verbose)
default: level=1
-e, --err error_file name of the error file or else goes to stderr
-f, --from version initial version (optional)
-t, --to version final version (optional)
-o, --output name name of the output file or else goes to stdout
-n, --try-hard try hard (ignore any convertion errors)
-c, --cjk [encoding] files in format 248 and lower are read and
written in the format of CJK-LyX.
If encoding is not given or 'auto' the encoding
is determined from the locale.
-q, --quiet same as --debug=0"""
def parse_options(argv):
_options = ["help", "version", "list", "debug=", "err=", "from=", "to=", "output=", "try-hard", "cjk", "quiet"]
try:
opts, args = getopt.getopt(argv[1:], "c:d:e:f:hlno:qt:v", _options)
except getopt.error:
usage()
sys.exit(2)
end_format, input, output, error, debug, try_hard = 0, "", "", "", LyX.default_debug_level, 0
cjk_encoding = ''
for o, a in opts:
if o in ("-h", "--help"):
usage()
sys.exit()
if o in ("-v", "--version"):
print "lyx2lyx, version %s" %(LyX.version_lyx2lyx)
print "Copyright (C) 2002-2004 José Matos and Dekel Tsur"
sys.exit()
if o in ("-d", "--debug"):
debug = int(a)
if o in ("-q", "--quiet"):
debug = 0
if o in ("-l", "--list"):
print LyX.formats_list()
sys.exit()
if o in ("-o", "--output"):
output = a
if o in ("-t", "--to"):
end_format = a
if o in ("-e","--err"):
error = a
if o in ("-n", "--try-hard"):
try_hard = 1
if o in ("-c", "--cjk"):
if a == '':
cjk_encoding = 'auto'
else:
cjk_encoding = a
if args:
input = args[0]
return end_format, input, output, error, debug, try_hard, cjk_encoding
def main(argv):
end_format, input, output, error, debug, try_hard, cjk_encoding = parse_options(argv)
file = LyX.File(end_format, input, output, error, debug, try_hard, cjk_encoding)
file.convert()
file.write()
return file.status
if __name__ == "__main__":
sys.exit(main(sys.argv))
args = {}
args["usage"] = "usage: %prog [options] [file]"
args["version"] = """lyx2lyx, version %s
Copyright (C) 2007 José Matos and Dekel Tsur""" % LyX.version__
args["description"] = """Convert old lyx file <file> to newer format,
files can be compressed with gzip. If there no file is specified then
the standard input is assumed, in this case gziped files are not
handled."""
parser = optparse.OptionParser(**args)
parser.set_defaults(debug=LyX.default_debug__, cjk_encoding = 'auto')
parser.add_option("-d", "--debug", type="int",
help="level=0..2 (O_ quiet, 2_verbose) default: 1")
parser.add_option("-q", "--quiet",
action="store_const", const=0, dest="debug")
parser.add_option("-v", "--verbose",
action="store_const", const=1, dest="debug")
parser.add_option("--noisy",
action="store_const", const=2, dest="debug")
parser.add_option("-c", "--encoding", dest="cjk_encoding",
help="files in format 248 and lower are read and"
" written in the format of CJK-LyX."
"If encoding is not given or 'auto' the encoding"
"is determined from the locale.")
parser.add_option("-e", "--err", dest="error",
help= "file name of the error file else goes to stderr")
parser.add_option("-o", "--output",
help= "name of the output file else goes to stdout")
parser.add_option("-t", "--to", dest= "end_format",
help= "destination file format, default (latest)")
parser.add_option("-l", "--list", action="store_true",
help = "list all available formats")
parser.add_option("-n", "--try-hard", action="store_true",
help = "try hard (ignore any convertion errors)")
(options, args) = parser.parse_args()
if args:
options.input = args[0]
else:
options.input = None
if options.list:
print LyX.formats_list()
sys.exit()
else:
del options.list
doc = LyX.File(**options.__dict__)
doc.convert()
doc.write()
sys.exit(doc.status)