Update documentclass.
This commit is contained in:
		| @@ -6,6 +6,7 @@ from .documentclass import * | ||||
| from .figure import figure | ||||
| from .formatter import formatter | ||||
| from .input_element import input_element | ||||
| from .includegraphics import includegraphics | ||||
| from .makebox import makebox | ||||
| from .resizebox import resizebox | ||||
| from .subfloat import subfloat | ||||
|   | ||||
| @@ -3,20 +3,41 @@ | ||||
| from collections import Iterable | ||||
| from .element import element | ||||
|  | ||||
| import enum | ||||
| import os | ||||
| import subprocess | ||||
|  | ||||
|  | ||||
| class change_directory: | ||||
|  | ||||
|     """Context manager for changing the current working directory""" | ||||
|  | ||||
|     def __init__(self, newPath): | ||||
|         self.newPath = os.path.expanduser(newPath) | ||||
|  | ||||
|     def __enter__(self): | ||||
|         self.savedPath = os.getcwd() | ||||
|         os.chdir(self.newPath) | ||||
|  | ||||
|     def __exit__(self, etype, value, traceback): | ||||
|         os.chdir(self.savedPath) | ||||
|  | ||||
|  | ||||
| class CompileResult(enum.Enum): | ||||
|  | ||||
|     ALREADY_EXISTS = 1 | ||||
|     SUCCESS = 2 | ||||
|     ERROR = 3 | ||||
|  | ||||
|  | ||||
| class documentclass(element): | ||||
|  | ||||
|     packages = {} | ||||
|     preamble = [] | ||||
|     options = [] | ||||
|     classname = 'standalone' | ||||
|  | ||||
|     templates = { | ||||
|         'package': '\\usepackage{pkgoptions}{{{pkgname}}}', | ||||
|         'options': '[{content}]', | ||||
|         'def': '\\def\\{name}#{nargs}{{{value}}}', | ||||
|         'def': '\\def\\{name}{nargs}{{{value}}}', | ||||
|         'content': """\\documentclass{options}{{{classname}}} | ||||
| {packages} | ||||
| {preamble} | ||||
| @@ -26,11 +47,18 @@ class documentclass(element): | ||||
| """ | ||||
|     } | ||||
|  | ||||
|     def __init__(self, classname, childrens=[], options=[], packages=[]): | ||||
|     output_aux_folder = '.pyltk' | ||||
|     auto_tex_folder = '{}/tex2pdf'.format(output_aux_folder) | ||||
|  | ||||
|     def __init__(self, classname, childrens=[], options=[], | ||||
|                  packages=[], preamble=[]): | ||||
|         super().__init__(parent=None, childrens=childrens) | ||||
|         self.options = options | ||||
|         self.classname = classname | ||||
|         self.packages = {} | ||||
|         self.add_packages(packages) | ||||
|         self.preamble = [] | ||||
|         self.add2preamble(preamble) | ||||
|  | ||||
|     def add_packages(self, packages): | ||||
|         if type(packages) is str: | ||||
| @@ -49,19 +77,19 @@ class documentclass(element): | ||||
|     def add_def(self, name, nargs, value): | ||||
|         self.preamble.append(self.fmt().format('def', { | ||||
|             'name': name, | ||||
|             'nargs': nargs, | ||||
|             'nargs': '#{}'.format(nargs) if nargs > 0 else '', | ||||
|             'value': value | ||||
|         })) | ||||
|  | ||||
|     def format_preamble(self, defs): | ||||
|         return '\n'.join(self.preamble) | ||||
|         return '\n'.join(str(p) for p in self.preamble) | ||||
|  | ||||
|     def format_packages(self, pkgs): | ||||
|         out = [] | ||||
|         for pkg, opts in self.packages.items(): | ||||
|         for pkg in sorted(pkgs): | ||||
|             options = '' | ||||
|             if opts is not True: | ||||
|                 options = self.format_options(opts) | ||||
|             if pkgs[pkg] is not True: | ||||
|                 options = self.format_options(pkgs[pkg]) | ||||
|             out.append(self.fmt().format('package', { | ||||
|                 'pkgname': pkg, | ||||
|                 'pkgoptions': options | ||||
| @@ -77,12 +105,78 @@ class documentclass(element): | ||||
|             'content': super().content() | ||||
|         }) | ||||
|  | ||||
|     def compile(self, outfile, infile=None, outlog=None): | ||||
|         if infile is None: | ||||
|             infile = '/tmp/pyltk-{}.tex'.format(id(self)) | ||||
|     def compile(self, outfile, infile='auto', outlog=None): | ||||
|         """ Compile the given document into a PDF file. | ||||
|  | ||||
|         with open(infile, 'w') as infd: | ||||
|             infd.write(self.content()) | ||||
|         If infile is not None, and infile already exists, the document | ||||
|         will only be compiled if the content of infile is different | ||||
|         from this document or if infile is newer than the output | ||||
|         document. | ||||
|  | ||||
|         call = ['pdflatex', '-halt-on-error', '-jobname', outfile, infile] | ||||
|         subprocess.call(call, stdout=outlog) | ||||
|         Parameters: | ||||
|           - outfile Name of the output file (pdf extension may | ||||
|             be omitted). | ||||
|           - infile Name of the file to which latex code must be | ||||
|             written. If None, a temporary file will be created | ||||
|             and then erased. If 'auto', file will be saved in | ||||
|             an automatic folder for future use. | ||||
|           - outlog | ||||
|         """ | ||||
|  | ||||
|         outdir = os.path.dirname(outfile) | ||||
|         outfile = os.path.basename(outfile) | ||||
|  | ||||
|         res = CompileResult.ERROR | ||||
|  | ||||
|         with change_directory(outdir): | ||||
|  | ||||
|             os.makedirs(self.output_aux_folder, exist_ok=True) | ||||
|  | ||||
|             if outfile.endswith('.pdf'): | ||||
|                 outfile = outfile[:-4] | ||||
|  | ||||
|             to_delete = False | ||||
|  | ||||
|             if infile == 'auto': | ||||
|                 os.makedirs(self.auto_tex_folder, exist_ok=True) | ||||
|                 infile = '{}/{}.tex'.format(self.auto_tex_folder, outfile) | ||||
|  | ||||
|             if infile is None: | ||||
|                 to_delete = True | ||||
|                 infile = '.pyltk-{}.tex'.format(outfile) | ||||
|  | ||||
|             to_create = True | ||||
|             new_content = self.content() | ||||
|  | ||||
|             # If the input file already exists... | ||||
|             if os.path.exists(infile): | ||||
|                 with open(infile, 'r') as infd: | ||||
|                     old_content = infd.read() | ||||
|  | ||||
|                 # Content has not changed | ||||
|                 if old_content == new_content \ | ||||
|                     and os.path.exists('{}.pdf'.format(outfile)) \ | ||||
|                     and os.path.getctime(infile) <= \ | ||||
|                         os.path.getctime('{}.pdf'.format(outfile)): | ||||
|                     to_create = False | ||||
|  | ||||
|             if to_create: | ||||
|                 with open(infile, 'w') as infd: | ||||
|                     infd.write(self.content()) | ||||
|                 call = ['pdflatex', '-halt-on-error', | ||||
|                         '-output-directory', self.output_aux_folder, | ||||
|                         '-jobname', outfile, infile] | ||||
|                 if subprocess.call(call, stdout=outlog) == 0: | ||||
|                     os.rename('{}/{}.pdf'.format( | ||||
|                         self.output_aux_folder, outfile), | ||||
|                         '{}.pdf'.format(outfile)) | ||||
|                     res = CompileResult.SUCCESS | ||||
|                 else: | ||||
|                     res = CompileResult.ERROR | ||||
|             else: | ||||
|                 res = CompileResult.ALREADY_EXISTS | ||||
|  | ||||
|             if to_delete: | ||||
|                 os.remove(infile) | ||||
|  | ||||
|         return res | ||||
|   | ||||
| @@ -26,7 +26,8 @@ class element: | ||||
|     # Do not wrap non-element in wrapper_element | ||||
|     raw = False | ||||
|  | ||||
|     def __init__(self, parent=None, childrens=[], label=None, raw=False): | ||||
|     def __init__(self, parent=None, childrens=[], label=None, | ||||
|                  raw=False, **kargs): | ||||
|         """ Create a new element with given parameters. | ||||
|  | ||||
|         Parameters: | ||||
| @@ -34,7 +35,8 @@ class element: | ||||
|           - childrens Childrens of the element - Single element or list of | ||||
|             objects (element or not). | ||||
|           - label Label of the element. | ||||
|           - raw Raw childrens (see description of `element`). """ | ||||
|           - raw Raw childrens (see description of `element`). | ||||
|           - kargs Options for the element. """ | ||||
|         self.parent = parent | ||||
|         self.raw = raw | ||||
|         if childrens is None: | ||||
| @@ -44,6 +46,7 @@ class element: | ||||
|         self.childrens = [] | ||||
|         self.add(childrens) | ||||
|         self.label = label | ||||
|         self.options = kargs | ||||
|  | ||||
|     def add(self, childrens): | ||||
|         if not isinstance(childrens, Iterable): | ||||
| @@ -69,8 +72,9 @@ class element: | ||||
|         if not options: | ||||
|             return '' | ||||
|         opts = [] | ||||
|         for k, v in options.items(): | ||||
|             opts.append('{key} = {{{value}}}'.format(key=k, value=v)) | ||||
|         # Note: Sorted to have a guaranteed output | ||||
|         for k in sorted(options): | ||||
|             opts.append('{key} = {{{value}}}'.format(key=k, value=options[k])) | ||||
|         return self.fmt().format('options', { | ||||
|             'content': ', '.join(opts) | ||||
|         }) | ||||
|   | ||||
							
								
								
									
										23
									
								
								pyltk/includegraphics.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								pyltk/includegraphics.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # -*- encoding: utf-8 -*- | ||||
|  | ||||
| from .element import element | ||||
|  | ||||
|  | ||||
| class includegraphics(element): | ||||
|     """ Class representing a latex includegrahics. """ | ||||
|  | ||||
|     templates = { | ||||
|         'element': '\\includegraphics[{options}]{{{filename}}}' | ||||
|     } | ||||
|  | ||||
|     autolabel = False | ||||
|  | ||||
|     def __init__(self, filename, parent=None, **kargs): | ||||
|         super().__init__(parent, **kargs) | ||||
|         self.filename = filename | ||||
|  | ||||
|     def content(self): | ||||
|         return self.fmt().format('element', { | ||||
|             'filename': self.filename, | ||||
|             'options': self.format_options(self.options) | ||||
|         }) | ||||
| @@ -7,11 +7,13 @@ class subfloat(element): | ||||
|     """ Class representing a latex subfloat. """ | ||||
|  | ||||
|     templates = { | ||||
|         'content': """\\subfloat[{caption}]{{ | ||||
|         'content': """\\subfloat[{caption}{label}]{{ | ||||
| {inner} | ||||
| }}""" | ||||
|     } | ||||
|  | ||||
|     autolabel = False | ||||
|  | ||||
|     def __init__(self, caption, parent=None, childrens=None, label=None): | ||||
|         super().__init__(parent, childrens, label=label) | ||||
|         self.caption = caption | ||||
| @@ -19,5 +21,6 @@ class subfloat(element): | ||||
|     def content(self): | ||||
|         return self.fmt().format('content', { | ||||
|             'caption': self.caption, | ||||
|             'label': self.format_label(self.label), | ||||
|             'inner': super().content() | ||||
|         }) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user