Clean code with black and create setup.py.

This commit is contained in:
Mikaël Capelle 2020-04-27 13:54:48 +02:00
parent 833d16752a
commit 6a65529e06
22 changed files with 337 additions and 248 deletions

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
*~ *~
**/__pycache__ **/__pycache__
**/.mypy_cache
*.egg-info

View File

@ -17,26 +17,25 @@ class CompileResult(enum.Enum):
class documentclass(element): class documentclass(element):
classname = 'standalone' classname = "standalone"
templates = { templates = {
'package': '\\usepackage{pkgoptions}{{{pkgname}}}', "package": "\\usepackage{pkgoptions}{{{pkgname}}}",
'options': '[{content}]', "options": "[{content}]",
'def': '\\def\\{name}{nargs}{{{value}}}', "def": "\\def\\{name}{nargs}{{{value}}}",
'content': """\\documentclass{options}{{{classname}}} "content": """\\documentclass{options}{{{classname}}}
{packages} {packages}
{preamble} {preamble}
\\begin{{document}} \\begin{{document}}
{content} {content}
\\end{{document}} \\end{{document}}
""" """,
} }
output_aux_folder = '.pyltk' output_aux_folder = ".pyltk"
auto_tex_folder_name = 'tex2pdf' auto_tex_folder_name = "tex2pdf"
def __init__(self, classname, childrens=[], options=[], def __init__(self, classname, childrens=[], options=[], packages=[], preamble=[]):
packages=[], preamble=[]):
super().__init__(parent=None, childrens=childrens) super().__init__(parent=None, childrens=childrens)
self.options = options self.options = options
self.classname = classname self.classname = classname
@ -60,38 +59,44 @@ class documentclass(element):
self.preamble.append(value) self.preamble.append(value)
def add_def(self, name, nargs, value): def add_def(self, name, nargs, value):
self.preamble.append(self.fmt().format('def', { self.preamble.append(
'name': name, self.fmt().format(
'nargs': '#{}'.format(nargs) if nargs > 0 else '', "def",
'value': value {
})) "name": name,
"nargs": "#{}".format(nargs) if nargs > 0 else "",
"value": value,
},
)
)
def format_preamble(self, defs): def format_preamble(self, defs):
return '\n'.join(str(p) for p in self.preamble) return "\n".join(str(p) for p in self.preamble)
def format_packages(self, pkgs): def format_packages(self, pkgs):
out = [] out = []
for pkg in sorted(pkgs): for pkg in sorted(pkgs):
options = '' options = ""
if pkgs[pkg] is not True: if pkgs[pkg] is not True:
options = self.format_options(pkgs[pkg]) options = self.format_options(pkgs[pkg])
out.append(self.fmt().format('package', { out.append(
'pkgname': pkg, self.fmt().format("package", {"pkgname": pkg, "pkgoptions": options})
'pkgoptions': options )
})) return "\n".join(out)
return '\n'.join(out)
def content(self): def content(self):
return self.fmt().format('content', { return self.fmt().format(
'options': self.format_options(self.options), "content",
'packages': self.format_packages(self.packages), {
'preamble': self.format_preamble(self.preamble), "options": self.format_options(self.options),
'classname': self.classname, "packages": self.format_packages(self.packages),
'content': super().content() "preamble": self.format_preamble(self.preamble),
}) "classname": self.classname,
"content": super().content(),
},
)
def compile(self, outfile, infile='auto', outlog=None, def compile(self, outfile, infile="auto", outlog=None, compile_twice=False):
compile_twice=False):
""" Compile the given document into a PDF file. """ Compile the given document into a PDF file.
If infile is not None, and infile already exists, the document If infile is not None, and infile already exists, the document
@ -116,55 +121,62 @@ class documentclass(element):
res = CompileResult.ERROR res = CompileResult.ERROR
output_aux_folder = os.path.join(outdir, self.output_aux_folder) output_aux_folder = os.path.join(outdir, self.output_aux_folder)
auto_tex_folder = os.path.join(output_aux_folder, auto_tex_folder = os.path.join(output_aux_folder, self.auto_tex_folder_name)
self.auto_tex_folder_name)
# Make aux directory # Make aux directory
os.makedirs(output_aux_folder, exist_ok=True) os.makedirs(output_aux_folder, exist_ok=True)
# Remove extension if exists # Remove extension if exists
if outfile.endswith('.pdf'): if outfile.endswith(".pdf"):
outfile = outfile[:-4] outfile = outfile[:-4]
to_delete = False to_delete = False
if infile == 'auto': if infile == "auto":
os.makedirs(auto_tex_folder, exist_ok=True) os.makedirs(auto_tex_folder, exist_ok=True)
infile = '{}/{}.tex'.format(auto_tex_folder, outfile) infile = "{}/{}.tex".format(auto_tex_folder, outfile)
if infile is None: if infile is None:
to_delete = True to_delete = True
infile = os.path.join(outdir, '.pyltk-{}.tex'.format(outfile)) infile = os.path.join(outdir, ".pyltk-{}.tex".format(outfile))
to_create = True to_create = True
new_content = self.content() new_content = self.content()
# If the input file already exists... # If the input file already exists...
if os.path.exists(infile): if os.path.exists(infile):
with open(infile, 'r') as infd: with open(infile, "r") as infd:
old_content = infd.read() old_content = infd.read()
# Content has not changed # Content has not changed
if old_content == new_content \ if (
and os.path.exists(os.path.join(outdir, outfile) + '.pdf') \ old_content == new_content
and os.path.getctime(infile) <= \ and os.path.exists(os.path.join(outdir, outfile) + ".pdf")
os.path.getctime(os.path.join(outdir, outfile) + '.pdf'): and os.path.getctime(infile)
<= os.path.getctime(os.path.join(outdir, outfile) + ".pdf")
):
to_create = False to_create = False
if to_create: if to_create:
with open(infile, 'w') as infd: with open(infile, "w") as infd:
infd.write(self.content()) infd.write(self.content())
call = ['pdflatex', '-halt-on-error', call = [
'-output-directory', output_aux_folder, "pdflatex",
'-jobname', outfile, infile] "-halt-on-error",
"-output-directory",
output_aux_folder,
"-jobname",
outfile,
infile,
]
res = subprocess.call(call, stdout=outlog) res = subprocess.call(call, stdout=outlog)
if compile_twice: if compile_twice:
res = subprocess.call(call, stdout=outlog) res = subprocess.call(call, stdout=outlog)
if res == 0: if res == 0:
os.replace( os.replace(
os.path.join( os.path.join(output_aux_folder, outfile + ".pdf"),
output_aux_folder, outfile + '.pdf'), os.path.join(outdir, outfile + ".pdf"),
os.path.join(outdir, outfile + '.pdf')) )
res = CompileResult.SUCCESS res = CompileResult.SUCCESS
else: else:
res = CompileResult.ERROR res = CompileResult.ERROR

View File

@ -18,7 +18,7 @@ class element:
are no subclasses of `element`. """ are no subclasses of `element`. """
# Joiner for childrens # Joiner for childrens
sep = '\n' sep = "\n"
# Automatically add label after element if present # Automatically add label after element if present
autolabel = True autolabel = True
@ -26,8 +26,7 @@ class element:
# Do not wrap non-element in wrapper_element # Do not wrap non-element in wrapper_element
raw = False raw = False
def __init__(self, parent=None, childrens=[], label=None, def __init__(self, parent=None, childrens=[], label=None, raw=False, **kargs):
raw=False, **kargs):
""" Create a new element with given parameters. """ Create a new element with given parameters.
Parameters: Parameters:
@ -80,25 +79,25 @@ class element:
if isinstance(value, dict): if isinstance(value, dict):
value = self.format_options_dict(value) value = self.format_options_dict(value)
elif isinstance(value, list) or isinstance(value, tuple): elif isinstance(value, list) or isinstance(value, tuple):
value = ','.join(value) value = ",".join(value)
else: else:
value = str(value).strip() value = str(value).strip()
if value[0] == '{' and value[1] == '}': if value[0] == "{" and value[1] == "}":
value = value[1:-1] value = value[1:-1]
opts.append('{key}={{{value}}}'.format(key=k, value=value)) opts.append("{key}={{{value}}}".format(key=k, value=value))
return ', '.join(opts) return ", ".join(opts)
def format_options(self, options): def format_options(self, options):
if not options: if not options:
return '' return ""
return self.fmt().format('options', { return self.fmt().format(
'content': self.format_options_dict(options) "options", {"content": self.format_options_dict(options)}
}) )
def format_label(self, label): def format_label(self, label):
if not label: if not label:
return '' return ""
return '\\label{{{}}}'.format(label) return "\\label{{{}}}".format(label)
def __str__(self): def __str__(self):
out = self.content().strip() out = self.content().strip()
@ -111,7 +110,7 @@ class wrapper_element(element):
""" Wrapper for standard python types working as latex elements. """ """ Wrapper for standard python types working as latex elements. """
escape_list = ['_', '#', '%'] escape_list = ["_", "#", "%"]
def __init__(self, data, parent=None, autoescape=True): def __init__(self, data, parent=None, autoescape=True):
super().__init__(parent=parent) super().__init__(parent=parent)
@ -122,7 +121,7 @@ class wrapper_element(element):
if not self.autoescape: if not self.autoescape:
return s return s
for e in self.escape_list: for e in self.escape_list:
s = s.replace(e, '\\' + e) s = s.replace(e, "\\" + e)
return s return s
def content(self): def content(self):

View File

@ -7,19 +7,25 @@ class figure(element):
""" Class representing a latex figure. """ """ Class representing a latex figure. """
templates = { templates = {
'caption': '\\caption{{{content}}}', "caption": "\\caption{{{content}}}",
'content': """\\begin{{figure}}[{options}] "content": """\\begin{{figure}}[{options}]
{centered} {centered}
{inner} {inner}
{caption}{label} {caption}{label}
\\end{{figure}}""" \\end{{figure}}""",
} }
autolabel = False autolabel = False
def __init__(self, childrens=None, parent=None, def __init__(
caption=None, options='!h', self,
centered=True, label=None): childrens=None,
parent=None,
caption=None,
options="!h",
centered=True,
label=None,
):
""" Create a figure with given options. """ Create a figure with given options.
Parameters: Parameters:
@ -29,18 +35,21 @@ class figure(element):
super().__init__(parent, childrens, label=label) super().__init__(parent, childrens, label=label)
self.options = options self.options = options
self.caption = caption self.caption = caption
self.centered = '' self.centered = ""
if centered: if centered:
self.centered = '\\centering' self.centered = "\\centering"
def content(self): def content(self):
caption = '' caption = ""
if self.caption: if self.caption:
caption = self.fmt().format('caption', {'content': self.caption}) caption = self.fmt().format("caption", {"content": self.caption})
return self.fmt().format('content', { return self.fmt().format(
'options': self.options, "content",
'centered': self.centered, {
'caption': caption, "options": self.options,
'label': self.format_label(self.label), "centered": self.centered,
'inner': super().content() "caption": caption,
}) "label": self.format_label(self.label),
"inner": super().content(),
},
)

View File

@ -7,8 +7,8 @@ class includegraphics(element):
""" Class representing a latex includegrahics. """ """ Class representing a latex includegrahics. """
templates = { templates = {
'options': '[{content}]', "options": "[{content}]",
'element': '\\includegraphics{options}{{{filename}}}' "element": "\\includegraphics{options}{{{filename}}}",
} }
autolabel = False autolabel = False
@ -18,7 +18,7 @@ class includegraphics(element):
self.filename = filename self.filename = filename
def content(self): def content(self):
return self.fmt().format('element', { return self.fmt().format(
'filename': self.filename, "element",
'options': self.format_options(self.options) {"filename": self.filename, "options": self.format_options(self.options)},
}) )

View File

@ -11,23 +11,19 @@ class inline_element(element):
def __init__(self, content, parent=None): def __init__(self, content, parent=None):
super().__init__(parent=parent) super().__init__(parent=parent)
self.value = content self.value = content
self.templates = { self.templates = {"wrapper": self.wrapper}
'wrapper': self.wrapper
}
def content(self): def content(self):
return self.fmt().format('wrapper', { return self.fmt().format("wrapper", {"value": self.value})
'value': self.value
})
class it(inline_element): class it(inline_element):
wrapper = '\\textit{{{value}}}' wrapper = "\\textit{{{value}}}"
class bf(inline_element): class bf(inline_element):
wrapper = '\\textbf{{{value}}}' wrapper = "\\textbf{{{value}}}"
class mt(inline_element): class mt(inline_element):
wrapper = '${value}$' wrapper = "${value}$"

View File

@ -5,15 +5,11 @@ from .element import element
class input_element(element): class input_element(element):
templates = { templates = {"element": "\\input{{{filename}}}"}
'element': '\\input{{{filename}}}'
}
def __init__(self, filename, parent=None): def __init__(self, filename, parent=None):
super().__init__(parent) super().__init__(parent)
self.filename = filename.replace('.tex', '') self.filename = filename.replace(".tex", "")
def content(self): def content(self):
return self.fmt().format('element', { return self.fmt().format("element", {"filename": self.filename})
'filename': self.filename
})

View File

@ -6,10 +6,7 @@ from .element import element
class generic_element(element): class generic_element(element):
templates = { templates = {"element": "\\{name}{options}{attributes}", "options": "[{content}]"}
'element': '\\{name}{options}{attributes}',
'options': '[{content}]'
}
autolabel = False autolabel = False
@ -17,22 +14,23 @@ class generic_element(element):
super().__init__(parent, **kargs) super().__init__(parent, **kargs)
self.name = name self.name = name
if not args: if not args:
self.attributes = '{}' self.attributes = "{}"
else: else:
self.attributes = '' self.attributes = ""
for arg in args: for arg in args:
self.attributes += '{{{}}}'.format(arg) self.attributes += "{{{}}}".format(arg)
def content(self): def content(self):
return self.fmt().format('element', { return self.fmt().format(
'name': self.name, "element",
'attributes': self.attributes, {
'options': self.format_options(self.options) "name": self.name,
}) "attributes": self.attributes,
"options": self.format_options(self.options),
},
)
class factory: class factory:
def __getattr__(self, name): def __getattr__(self, name):
return lambda *args, **kargs: \ return lambda *args, **kargs: generic_element(name, *args, **kargs)
generic_element(name, *args, **kargs)

View File

@ -7,7 +7,7 @@ class makebox(element):
""" Class representing an unindented makebox. """ """ Class representing an unindented makebox. """
templates = { templates = {
'content': """{noindent}\\makebox[{width}]{{ "content": """{noindent}\\makebox[{width}]{{
{inner} {inner}
}}""" }}"""
} }
@ -25,17 +25,20 @@ class makebox(element):
self.width = width self.width = width
if self.width is None: if self.width is None:
self.width = '\\textwidth' self.width = "\\textwidth"
elif type(self.width) != 'str': elif type(self.width) != "str":
self.width = '{}\\textwidth'.format(self.width) self.width = "{}\\textwidth".format(self.width)
self.noindent = '' self.noindent = ""
if self.noindent: if self.noindent:
self.noindent = '\\noindent' self.noindent = "\\noindent"
def content(self): def content(self):
return self.fmt().format('content', { return self.fmt().format(
'inner': super().content(), "content",
'width': self.width, {
'noindent': self.noindent "inner": super().content(),
}) "width": self.width,
"noindent": self.noindent,
},
)

View File

@ -7,12 +7,12 @@ class axis(element):
""" Class representing an axis. """ """ Class representing an axis. """
templates = { templates = {
'options': '[{content}]', "options": "[{content}]",
'legends': '\\legend{{{content}}}', "legends": "\\legend{{{content}}}",
'content': """\\begin{{axis}}{options} "content": """\\begin{{axis}}{options}
{inner} {inner}
{legend} {legend}
\\end{{axis}}""" \\end{{axis}}""",
} }
def __init__(self, *args, parent=None, legend=None, label=None, **kwargs): def __init__(self, *args, parent=None, legend=None, label=None, **kwargs):
@ -23,17 +23,24 @@ class axis(element):
self.add(arg) self.add(arg)
def content(self): def content(self):
leg = '' leg = ""
if self.legend: if self.legend:
if type(self.legend) is str: if type(self.legend) is str:
leg = self.legend leg = self.legend
else: else:
leg = self.fmt().format('legends', { leg = self.fmt().format(
'content': ', '.join('{{{}}}'.format(p.legend) "legends",
for p in self.childrens) {
}) "content": ", ".join(
return self.fmt().format('content', { "{{{}}}".format(p.legend) for p in self.childrens
'options': self.format_options(self.options), )
'inner': super().content(), },
'legend': leg )
}) return self.fmt().format(
"content",
{
"options": self.format_options(self.options),
"inner": super().content(),
"legend": leg,
},
)

View File

@ -4,13 +4,11 @@ from .generic_plot import generic_plot
class coordinates_plot(generic_plot): class coordinates_plot(generic_plot):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
super().__init__(*args, **kargs) super().__init__(*args, **kargs)
def format_data(self, data): def format_data(self, data):
pts = [] pts = []
for d in data: for d in data:
pts.append('({}, {})'.format( pts.append("({}, {})".format(*self.format_values(d)))
*self.format_values(d))) return "coordinates {{{}}}".format("".join(pts))
return 'coordinates {{{}}}'.format(''.join(pts))

View File

@ -4,10 +4,8 @@ from .generic_plot import generic_plot
class errorbars_plot(generic_plot): class errorbars_plot(generic_plot):
def __init__(self, legend, data, precision=5, label=None, options=[]): def __init__(self, legend, data, precision=5, label=None, options=[]):
options = options + [ options = options + ["error bars/.cd", ("y dir", "both"), ("y explicit")]
'error bars/.cd', ('y dir', 'both'), ('y explicit')]
super().__init__(legend, data, label=label, options=options) super().__init__(legend, data, label=label, options=options)
def format_data(self, data): def format_data(self, data):
@ -19,7 +17,12 @@ class errorbars_plot(generic_plot):
except TypeError: except TypeError:
p = d[2] p = d[2]
n = p n = p
rows.append('({x}, {y}) += (0, {p}) -= (0, {n})'.format( rows.append(
x=self.format_value(x), y=self.format_value(y), "({x}, {y}) += (0, {p}) -= (0, {n})".format(
p=self.format_value(p), n=self.format_value(n))) x=self.format_value(x),
return 'coordinates {{{}}}'.format('\n'.join(rows)) y=self.format_value(y),
p=self.format_value(p),
n=self.format_value(n),
)
)
return "coordinates {{{}}}".format("\n".join(rows))

View File

@ -7,9 +7,9 @@ class generic_plot(element):
""" Class representing a pgfplots plot. """ """ Class representing a pgfplots plot. """
templates = { templates = {
'options': '+[{content}]', "options": "+[{content}]",
'content': """\\addplot{options} {data};{legend}""", "content": """\\addplot{options} {data};{legend}""",
'legend': """\\addlegendentry{{{content}}}""" "legend": """\\addlegendentry{{{content}}}""",
} }
def __init__(self, legend, data, precision=6, label=None, options=[]): def __init__(self, legend, data, precision=6, label=None, options=[]):
@ -21,32 +21,31 @@ class generic_plot(element):
def format_options(self, options): def format_options(self, options):
if not options: if not options:
return '' return ""
opts = [] opts = []
for opt in options: for opt in options:
if type(opt) is not str: if type(opt) is not str:
opt = '{}={}'.format(*opt) opt = "{}={}".format(*opt)
opts.append(str(opt)) opts.append(str(opt))
return self.fmt().format('options', { return self.fmt().format("options", {"content": ", ".join(opts)})
'content': ', '.join(opts)
})
def format_value(self, value): def format_value(self, value):
return '{:.{prec}f}'.format(value, prec=self.precision) return "{:.{prec}f}".format(value, prec=self.precision)
def format_values(self, values): def format_values(self, values):
return [self.format_value(value) for value in values] return [self.format_value(value) for value in values]
def format_legend(self, legend): def format_legend(self, legend):
if not legend: if not legend:
return '' return ""
return self.fmt().format('legend', { return self.fmt().format("legend", {"content": legend})
'content': legend
})
def content(self): def content(self):
return self.fmt().format('content', { return self.fmt().format(
'data': self.format_data(self.data), "content",
'options': self.format_options(self.options), {
'legend': self.format_legend(self.legend) "data": self.format_data(self.data),
}) "options": self.format_options(self.options),
"legend": self.format_legend(self.legend),
},
)

View File

@ -7,12 +7,12 @@ class semilogyaxis(axis):
""" Class representing an axis. """ """ Class representing an axis. """
templates = { templates = {
'options': '[{content}]', "options": "[{content}]",
'legends': '\\legend{{{content}}}', "legends": "\\legend{{{content}}}",
'content': """\\begin{{semilogyaxis}}{options} "content": """\\begin{{semilogyaxis}}{options}
{inner} {inner}
{legend} {legend}
\\end{{semilogyaxis}}""" \\end{{semilogyaxis}}""",
} }
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
@ -23,12 +23,12 @@ class semilogxaxis(axis):
""" Class representing an axis. """ """ Class representing an axis. """
templates = { templates = {
'options': '[{content}]', "options": "[{content}]",
'legends': '\\legend{{{content}}}', "legends": "\\legend{{{content}}}",
'content': """\\begin{{semilogxaxis}}{options} "content": """\\begin{{semilogxaxis}}{options}
{inner} {inner}
{legend} {legend}
\\end{{semilogxaxis}}""" \\end{{semilogxaxis}}""",
} }
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):

View File

@ -7,13 +7,12 @@ class resizebox(element):
""" Class representing a latex resizebox. """ """ Class representing a latex resizebox. """
templates = { templates = {
'content': """\\resizebox{{{width}}}{{{height}}}{{ "content": """\\resizebox{{{width}}}{{{height}}}{{
{inner} {inner}
}}""" }}"""
} }
def __init__(self, content=None, parent=None, def __init__(self, content=None, parent=None, width="\\linewidth", height="!"):
width="\\linewidth", height="!"):
""" Create a resizebox with given width and height. """ Create a resizebox with given width and height.
Parameters: Parameters:
@ -28,12 +27,11 @@ class resizebox(element):
super().__init__(parent, content) super().__init__(parent, content)
self.width = width self.width = width
if type(width) is not str: if type(width) is not str:
self.width = '{}\\linewidth'.format(width) self.width = "{}\\linewidth".format(width)
self.height = height self.height = height
def content(self): def content(self):
return self.fmt().format('content', { return self.fmt().format(
'width': self.width, "content",
'height': self.height, {"width": self.width, "height": self.height, "inner": super().content()},
'inner': super().content() )
})

View File

@ -4,7 +4,6 @@ from .element import element
class strelement(element): class strelement(element):
def __init__(self, content, parent=None): def __init__(self, content, parent=None):
self.inner = content self.inner = content

View File

@ -7,7 +7,7 @@ class subfloat(element):
""" Class representing a latex subfloat. """ """ Class representing a latex subfloat. """
templates = { templates = {
'content': """\\subfloat[{caption}{label}]{{ "content": """\\subfloat[{caption}{label}]{{
{inner} {inner}
}}""" }}"""
} }
@ -19,8 +19,11 @@ class subfloat(element):
self.caption = caption self.caption = caption
def content(self): def content(self):
return self.fmt().format('content', { return self.fmt().format(
'caption': self.caption, "content",
'label': self.format_label(self.label), {
'inner': super().content() "caption": self.caption,
}) "label": self.format_label(self.label),
"inner": super().content(),
},
)

View File

@ -8,19 +8,25 @@ class table(element):
""" Class representing a latex figure. """ """ Class representing a latex figure. """
templates = { templates = {
'caption': '\\caption{{{content}}}', "caption": "\\caption{{{content}}}",
'content': """\\begin{{table}}[{options}] "content": """\\begin{{table}}[{options}]
{centered} {centered}
{inner} {inner}
{caption}{label} {caption}{label}
\\end{{table}}""" \\end{{table}}""",
} }
autolabel = False autolabel = False
def __init__(self, childrens=None, parent=None, def __init__(
caption=None, options='!ht', self,
centered=True, label=None): childrens=None,
parent=None,
caption=None,
options="!ht",
centered=True,
label=None,
):
""" Create a table with given options. """ Create a table with given options.
Parameters: Parameters:
@ -30,25 +36,27 @@ class table(element):
super().__init__(parent, childrens, label=label) super().__init__(parent, childrens, label=label)
self.options = options self.options = options
self.caption = caption self.caption = caption
self.centered = '' self.centered = ""
if centered: if centered:
self.centered = '\\centering' self.centered = "\\centering"
def content(self): def content(self):
caption = '' caption = ""
if self.caption: if self.caption:
caption = self.fmt().format('caption', {'content': self.caption}) caption = self.fmt().format("caption", {"content": self.caption})
return self.fmt().format('content', { return self.fmt().format(
'options': self.options, "content",
'centered': self.centered, {
'caption': caption, "options": self.options,
'label': self.format_label(self.label), "centered": self.centered,
'inner': super().content() "caption": caption,
}) "label": self.format_label(self.label),
"inner": super().content(),
},
)
class tabledf(table): class tabledf(table):
def __init__(self, df, header=None, multilevels=False, fmt=None, **kargs): def __init__(self, df, header=None, multilevels=False, fmt=None, **kargs):
super().__init__(**kargs) super().__init__(**kargs)
self.add(tabulardf(df, header, multilevels, fmt)) self.add(tabulardf(df, header, multilevels, fmt))

View File

@ -14,8 +14,9 @@ class row_element(element):
""" Class representing a row of a tabular element. """ """ Class representing a row of a tabular element. """
def __init__(self, columns, parent, label=None, def __init__(
wrapper=False, endline=False, fmt=None): self, columns, parent, label=None, wrapper=False, endline=False, fmt=None
):
super().__init__(parent, columns, label=label, raw=(fmt is not None)) super().__init__(parent, columns, label=label, raw=(fmt is not None))
self.wrapper = wrapper self.wrapper = wrapper
self.endline = endline self.endline = endline
@ -31,20 +32,19 @@ class row_element(element):
cw = 1 / len(self.childrens) cw = 1 / len(self.childrens)
wp = lambda c: self.wrapper(c, width=cw) wp = lambda c: self.wrapper(c, width=cw)
row = map(wp, row) row = map(wp, row)
out = ' & '.join(map(str, row)) out = " & ".join(map(str, row))
if self.endline: if self.endline:
out += '\\\\' out += "\\\\"
return out return out
class hline_element(row_element): class hline_element(row_element):
def __init__(self, command="hline", parent=None):
def __init__(self, command='hline', parent=None):
super().__init__([], parent) super().__init__([], parent)
self.command = command self.command = command
def content(self): def content(self):
return '\\' + self.command return "\\" + self.command
# instance of hline element # instance of hline element
@ -55,13 +55,20 @@ class tabular(element):
""" Class representing a latex tabular. """ """ Class representing a latex tabular. """
templates = { templates = {
'content': """\\begin{{{name}}}{{{columns}}} "content": """\\begin{{{name}}}{{{columns}}}
{inner} {inner}
\\end{{{name}}}""" \\end{{{name}}}"""
} }
def __init__(self, parent=None, rows=[], columns=None, def __init__(
autowrap=False, label=None, name='tabular'): self,
parent=None,
rows=[],
columns=None,
autowrap=False,
label=None,
name="tabular",
):
""" Create a tabular with given rows and column specification. """ Create a tabular with given rows and column specification.
Parameters: Parameters:
@ -103,21 +110,18 @@ class tabular(element):
self.addrow(row, **kargs) self.addrow(row, **kargs)
def content(self): def content(self):
return self.fmt().format('content', { return self.fmt().format(
'name': self.name, "content",
'columns': self.columns, {"name": self.name, "columns": self.columns, "inner": super().content()},
'inner': super().content() )
})
class multicolumn(element): class multicolumn(element):
""" Class representing a multicolumn element. """ """ Class representing a multicolumn element. """
templates = { templates = {"content": """\\multicolumn{{{ncolumns}}}{{{align}}}{{{content}}}"""}
'content': """\\multicolumn{{{ncolumns}}}{{{align}}}{{{content}}}"""
}
def __init__(self, ncolumns, content='', alignment='c', **kargs): def __init__(self, ncolumns, content="", alignment="c", **kargs):
super().__init__(**kargs) super().__init__(**kargs)
self.ncolumns = ncolumns self.ncolumns = ncolumns
self.inner = content self.inner = content
@ -126,15 +130,13 @@ class multicolumn(element):
def content(self): def content(self):
if self.ncolumns == 1: if self.ncolumns == 1:
return self.inner return self.inner
return self.fmt().format('content', { return self.fmt().format(
'ncolumns': self.ncolumns, "content",
'content': self.inner, {"ncolumns": self.ncolumns, "content": self.inner, "align": self.alignment},
'align': self.alignment )
})
class tabulardf(tabular): class tabulardf(tabular):
def __init__(self, df, header=None, multilevels=False, fmt=None, **kargs): def __init__(self, df, header=None, multilevels=False, fmt=None, **kargs):
if header is None: if header is None:
multilevels, header = self.create_header(df) multilevels, header = self.create_header(df)
@ -145,7 +147,7 @@ class tabulardf(tabular):
ncols = len(header) ncols = len(header)
header = [header] header = [header]
kargs.setdefault('columns', 'r' * ncols) kargs.setdefault("columns", "r" * ncols)
super().__init__(**kargs) super().__init__(**kargs)
self.addrows(header) self.addrows(header)
self.addhline() self.addhline()

View File

@ -7,17 +7,17 @@ class tikzpicture(element):
""" Class representing a latex tikzfigure. """ """ Class representing a latex tikzfigure. """
templates = { templates = {
'options': '[{content}]', "options": "[{content}]",
'content': """\\begin{{tikzpicture}}{options} "content": """\\begin{{tikzpicture}}{options}
{inner} {inner}
\\end{{tikzpicture}}""" \\end{{tikzpicture}}""",
} }
def __init__(self, childrens=None, parent=None, label=None, **kargs): def __init__(self, childrens=None, parent=None, label=None, **kargs):
super().__init__(parent, childrens, label=label, **kargs) super().__init__(parent, childrens, label=label, **kargs)
def content(self): def content(self):
return self.fmt().format('content', { return self.fmt().format(
'inner': super().content(), "content",
'options': self.format_options(self.options) {"inner": super().content(), "options": self.format_options(self.options)},
}) )

20
setup.cfg Normal file
View File

@ -0,0 +1,20 @@
[flake8]
# Use black line length:
max-line-length = 88
extend-ignore =
# See https://github.com/PyCQA/pycodestyle/issues/373
E203,
[mypy]
warn_return_any = True
warn_unused_configs = True
namespace_packages = True
[tox:tox]
envlist = py36,py37,py38,py36-lint
[testenv]
deps =
pytest
commands =
pytest tests

37
setup.py Normal file
View File

@ -0,0 +1,37 @@
# -*- encoding: utf-8 -*-
from setuptools import setup, find_packages
dev_requires = [
"black",
"flake8",
"flake8-black",
"mypy",
"pytest",
]
setup(
# Name of the package:
name="pyltk",
# Version of the package:
version="0.0.1",
# Find the package automatically (include everything):
packages=find_packages(),
# Author information:
author="Mikaël Capelle",
author_email="capelle.mikael@gmail.com",
# Description of the package:
description="Python library to generate and build LaTeX files",
include_package_data=True,
classifiers=[
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
],
# License:
license="MIT",
# Requirements:
install_requires=[],
extras_require={"dev": dev_requires},
)