pydocmaker 2.2.2__tar.gz → 2.2.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pydocmaker-2.2.2/src/pydocmaker.egg-info → pydocmaker-2.2.5}/PKG-INFO +1 -1
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/__init__.py +1 -1
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/baseformatter.py +3 -1
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_tex.py +7 -1
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/pdf_maker.py +21 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/core.py +50 -26
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/templating.py +8 -1
- {pydocmaker-2.2.2 → pydocmaker-2.2.5/src/pydocmaker.egg-info}/PKG-INFO +1 -1
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/LICENSE +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/README.md +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/setup.cfg +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/setup.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/__init__.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_docx.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_html.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_ipynb.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_markdown.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_redmine.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/mdx_latex.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/pandoc_api.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/util.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker.egg-info/SOURCES.txt +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker.egg-info/dependency_links.txt +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker.egg-info/requires.txt +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker.egg-info/top_level.txt +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/tests/test_backend_pandoc.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/tests/test_convert_all.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/tests/test_core.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/tests/test_ex_html.py +0 -0
- {pydocmaker-2.2.2 → pydocmaker-2.2.5}/tests/test_util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pydocmaker
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.5
|
|
4
4
|
Summary: a minimal document maker to make docx, markdown, html, textile, redmine, and tex documents from python. Written in pure python.
|
|
5
5
|
Home-page: https://github.com/TobiasGlaubach/pydocmaker
|
|
6
6
|
Author: Tobias Glaubach
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
__version__ = '2.2.
|
|
1
|
+
__version__ = '2.2.5'
|
|
2
2
|
|
|
3
3
|
from pydocmaker.core import DocBuilder, construct, constr, buildingblocks, print_to_pdf, get_latex_compiler, set_latex_compiler, make_pdf_from_tex, show_pdf
|
|
4
4
|
from pydocmaker.util import upload_report_to_redmine, bcolors, txtcolor, colors_dc
|
|
@@ -7,7 +7,7 @@ import os
|
|
|
7
7
|
from jinja2 import Template
|
|
8
8
|
|
|
9
9
|
def _handle_template(template, default_template):
|
|
10
|
-
if
|
|
10
|
+
if template is None:
|
|
11
11
|
template = default_template
|
|
12
12
|
|
|
13
13
|
attachments = {}
|
|
@@ -16,6 +16,8 @@ def _handle_template(template, default_template):
|
|
|
16
16
|
elif isinstance(template, str) and os.path.exists(template):
|
|
17
17
|
with open(template, 'r') as fp:
|
|
18
18
|
template_obj = Template(fp.read())
|
|
19
|
+
elif isinstance(template, str) and not template:
|
|
20
|
+
template_obj = Template('{{ body }}')
|
|
19
21
|
elif isinstance(template, str):
|
|
20
22
|
template_obj = Template(template)
|
|
21
23
|
else:
|
|
@@ -16,6 +16,7 @@ import sys
|
|
|
16
16
|
import tempfile
|
|
17
17
|
import shutil
|
|
18
18
|
from io import BytesIO
|
|
19
|
+
import warnings
|
|
19
20
|
|
|
20
21
|
import zipfile
|
|
21
22
|
import latex
|
|
@@ -119,7 +120,7 @@ def auto_escape_latex(params):
|
|
|
119
120
|
elif isinstance(params, dict):
|
|
120
121
|
return {k:auto_escape_latex(v) for k, v in params.items()}
|
|
121
122
|
elif isinstance(params, list):
|
|
122
|
-
return [auto_escape_latex(v) for
|
|
123
|
+
return [auto_escape_latex(v) for v in params]
|
|
123
124
|
else:
|
|
124
125
|
return params
|
|
125
126
|
|
|
@@ -149,6 +150,11 @@ def convert(doc:List[dict], with_attachments=True, files_to_upload=None, templat
|
|
|
149
150
|
body = '\n'.join(s) if isinstance(s, list) else s
|
|
150
151
|
|
|
151
152
|
template_obj, attachments = _handle_template(template, __default_template)
|
|
153
|
+
if template == '':
|
|
154
|
+
s = 'It seems you have provided an empty template to use.'
|
|
155
|
+
s += '\nThis will most likely fail, since LaTeX actually needs imports etc. to work.'
|
|
156
|
+
s += '\nI will try anyways though.'
|
|
157
|
+
warnings.warn(s)
|
|
152
158
|
|
|
153
159
|
kw = copy.deepcopy(template_params)
|
|
154
160
|
if do_escape_template_params:
|
|
@@ -102,6 +102,24 @@ def _procrun(args, verb=0, ignore_error=False, **kwargs):
|
|
|
102
102
|
raise Exception(s)
|
|
103
103
|
return process.returncode
|
|
104
104
|
|
|
105
|
+
def _get_platform_tempdir():
|
|
106
|
+
import platform
|
|
107
|
+
# HACK: Stupid windows sometimes has a tilde in the user path and PDFlatex does not like this
|
|
108
|
+
# therefore we need to expand the user name using ctypes.
|
|
109
|
+
# NOTE: os.path.expanduser(tempfile.tempdir) does not work for this either
|
|
110
|
+
if platform.system().lower() == "windows":
|
|
111
|
+
# Use the Windows API to get the full long path (remove tilde)
|
|
112
|
+
import ctypes
|
|
113
|
+
buf_size = ctypes.windll.kernel32.GetLongPathNameW(tempfile.gettempdir(), None, 0)
|
|
114
|
+
if buf_size == 0:
|
|
115
|
+
return tempfile.gettempdir() # In case GetLongPathNameW fails, return original path
|
|
116
|
+
buffer = ctypes.create_unicode_buffer(buf_size)
|
|
117
|
+
ctypes.windll.kernel32.GetLongPathNameW(tempfile.gettempdir(), buffer, buf_size)
|
|
118
|
+
return buffer.value
|
|
119
|
+
else:
|
|
120
|
+
# For Unix-like systems (Linux, macOS), plug in None to indicate to use
|
|
121
|
+
return None
|
|
122
|
+
|
|
105
123
|
|
|
106
124
|
def make_pdf_from_tex(input_latex_text, attachments_dc=None, docname='', out_format='pdf', base_dir=None, latex_compiler=None, n_times_make=None, verb=0, ignore_error=False) -> bytes:
|
|
107
125
|
"""Converts a LaTeX document to a PDF or a ZIP file containing the PDF and all attachments.
|
|
@@ -156,6 +174,9 @@ def make_pdf_from_tex(input_latex_text, attachments_dc=None, docname='', out_for
|
|
|
156
174
|
|
|
157
175
|
if verb: print(f'Running with {latex_compiler=}')
|
|
158
176
|
|
|
177
|
+
if base_dir is None:
|
|
178
|
+
base_dir = _get_platform_tempdir() # need this to deal with windows and tilde chars
|
|
179
|
+
|
|
159
180
|
# open a temp folder at base dir which will be deleted after completion
|
|
160
181
|
with tempfile.TemporaryDirectory(dir=base_dir) as output_dir:
|
|
161
182
|
out_file_tex = f'{docname}.tex'
|
|
@@ -483,7 +483,8 @@ class DocBuilder(UserList):
|
|
|
483
483
|
except KeyError as err:
|
|
484
484
|
if 'my_template_id=' in str(err):
|
|
485
485
|
tformat = 'Any' if not tformat else tformat
|
|
486
|
-
|
|
486
|
+
s = f'The {template_id=} was defined for this document, and the current serializer tried to get it with the format="{tformat}", but it could not be resolved.\nWill continue without template. Original Error message\n' + str(err)
|
|
487
|
+
warnings.warn(s)
|
|
487
488
|
return None
|
|
488
489
|
else:
|
|
489
490
|
raise
|
|
@@ -593,32 +594,40 @@ class DocBuilder(UserList):
|
|
|
593
594
|
self.update_meta(dc)
|
|
594
595
|
return dc
|
|
595
596
|
|
|
596
|
-
def set_meta(self,
|
|
597
|
+
def set_meta(self, *args, **kwargs):
|
|
597
598
|
"""
|
|
598
|
-
Sets the metadata for
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
599
|
+
Sets the metadata for this document.
|
|
600
|
+
Use by either
|
|
601
|
+
.set_meta({'doc_name': 'test'})
|
|
602
|
+
or
|
|
603
|
+
.set_meta(doc_name='test')
|
|
603
604
|
|
|
604
605
|
Returns:
|
|
605
606
|
dict: The updated metadata.
|
|
606
607
|
"""
|
|
608
|
+
data = next(iter(args), {})
|
|
609
|
+
data.update(kwargs)
|
|
610
|
+
|
|
607
611
|
meta = self.get_meta()
|
|
608
612
|
if meta is None:
|
|
609
|
-
return self.add_meta(data
|
|
613
|
+
return self.add_meta(data)
|
|
610
614
|
else:
|
|
611
615
|
if not 'data' in meta:
|
|
612
616
|
meta['data'] = {}
|
|
613
617
|
meta['data'].clear()
|
|
614
618
|
meta['data'].update(data)
|
|
615
|
-
meta['data'].update(**kwargs)
|
|
616
619
|
return meta['data']
|
|
617
620
|
|
|
618
621
|
def get_meta(self, default=None):
|
|
619
|
-
"""gets the (first)
|
|
622
|
+
"""gets the (first) meta element in this document if it exists. If not returns None"""
|
|
620
623
|
return next((k for k in self if isinstance(k, dict) and k.get('typ') == 'meta'), default)
|
|
621
624
|
|
|
625
|
+
def get_metadata(self):
|
|
626
|
+
"""Equivalent to self.get_meta(default={}).get('data', {})
|
|
627
|
+
Gets the data of the (first) meta element in this document if it exists.
|
|
628
|
+
If not exists an new empty dict is returned"""
|
|
629
|
+
return self.get_meta(default={}).get('data', {})
|
|
630
|
+
|
|
622
631
|
def has_meta(self) -> bool:
|
|
623
632
|
"""tests if this document has one or more metadata objects"""
|
|
624
633
|
return False if self.get_meta() is None else True
|
|
@@ -639,7 +648,7 @@ class DocBuilder(UserList):
|
|
|
639
648
|
|
|
640
649
|
data = next(iter(args), {})
|
|
641
650
|
meta = self.get_meta()
|
|
642
|
-
data.update(
|
|
651
|
+
data.update(kwargs)
|
|
643
652
|
if meta is None:
|
|
644
653
|
return self.add_meta(data)
|
|
645
654
|
else:
|
|
@@ -662,7 +671,7 @@ class DocBuilder(UserList):
|
|
|
662
671
|
dict: the meta elements data (content)
|
|
663
672
|
"""
|
|
664
673
|
data = next(iter(args), {})
|
|
665
|
-
data.update(
|
|
674
|
+
data.update(kwargs)
|
|
666
675
|
|
|
667
676
|
if self.has_meta():
|
|
668
677
|
return self.update_meta(data)
|
|
@@ -962,7 +971,7 @@ class DocBuilder(UserList):
|
|
|
962
971
|
|
|
963
972
|
|
|
964
973
|
|
|
965
|
-
def to_pdf(self, path_or_stream=None, docname='', files_to_upload=None, base_dir=None, latex_compiler=None, n_times_make=None, verb=1, ignore_error=True, template=None, template_params=None, do_escape_template_params='auto'):
|
|
974
|
+
def to_pdf(self, path_or_stream=None, docname='', files_to_upload=None, base_dir=None, latex_compiler=None, n_times_make=None, verb=1, ignore_error=True, template=None, template_params=None, do_escape_template_params='auto', **kwargs):
|
|
966
975
|
"""Converts the current object to a PDF file or zipped latex project folder.
|
|
967
976
|
|
|
968
977
|
Args:
|
|
@@ -994,6 +1003,8 @@ class DocBuilder(UserList):
|
|
|
994
1003
|
if files_to_upload is None:
|
|
995
1004
|
files_to_upload = {}
|
|
996
1005
|
|
|
1006
|
+
files_to_upload.update(kwargs.pop('additional_files', {}))
|
|
1007
|
+
|
|
997
1008
|
params = {}
|
|
998
1009
|
meta = self.get_meta(default={}).get('data', {})
|
|
999
1010
|
mytemplate = self.get_template_from_meta(tformat='tex')
|
|
@@ -1063,7 +1074,7 @@ class DocBuilder(UserList):
|
|
|
1063
1074
|
|
|
1064
1075
|
|
|
1065
1076
|
|
|
1066
|
-
def to_tex(self, path_or_stream=None, additional_files=None, template = None, do_escape_template_params='auto', template_params=None):
|
|
1077
|
+
def to_tex(self, path_or_stream=None, additional_files=None, template = None, do_escape_template_params='auto', template_params=None, text_only=False):
|
|
1067
1078
|
"""Converts the current object to a TEX file (and attachments).
|
|
1068
1079
|
|
|
1069
1080
|
Args:
|
|
@@ -1072,6 +1083,7 @@ class DocBuilder(UserList):
|
|
|
1072
1083
|
template (str, optional): The LaTeX template to use.
|
|
1073
1084
|
do_escape_template_params (bool, optional): Whether to escape the template parameters. "auto" will scan for %%latex at the start of a string to determine if its a latex string. Defaults to 'auto'.
|
|
1074
1085
|
template_params (dict, optional): Additional parameters to pass to the LaTeX template.
|
|
1086
|
+
text_only (bool, optional): Only valid if path_or_stream is None. Whether or not to return attachments as well. Defaults to False
|
|
1075
1087
|
|
|
1076
1088
|
Returns:
|
|
1077
1089
|
If saving to a file or stream:
|
|
@@ -1122,9 +1134,12 @@ class DocBuilder(UserList):
|
|
|
1122
1134
|
path_or_stream.write(m)
|
|
1123
1135
|
return True
|
|
1124
1136
|
else:
|
|
1125
|
-
|
|
1137
|
+
if text_only:
|
|
1138
|
+
return tex
|
|
1139
|
+
else:
|
|
1140
|
+
return tex, files
|
|
1126
1141
|
|
|
1127
|
-
def to_textile(self, path_or_stream=None):
|
|
1142
|
+
def to_textile(self, path_or_stream=None, text_only=False):
|
|
1128
1143
|
"""
|
|
1129
1144
|
Converts the current object to a TEXTILE file (and attachments).
|
|
1130
1145
|
If path_or_stream is given it will zip all contents and write it to the stream or file path given.
|
|
@@ -1132,6 +1147,7 @@ class DocBuilder(UserList):
|
|
|
1132
1147
|
|
|
1133
1148
|
Args:
|
|
1134
1149
|
path_or_stream (str or io.IOBase, optional): The path to save the file to, or a file-like object to write the data to. If not provided, the data will be returned as string.
|
|
1150
|
+
text_only (bool, optional): Only valid if path_or_stream is None. Whether or not to return attachments as well. Defaults to False
|
|
1135
1151
|
"""
|
|
1136
1152
|
|
|
1137
1153
|
textile, files = to_textile(self.dump(), with_attachments=True, aformat_redmine=False)
|
|
@@ -1152,7 +1168,10 @@ class DocBuilder(UserList):
|
|
|
1152
1168
|
path_or_stream.write(m)
|
|
1153
1169
|
return True
|
|
1154
1170
|
else:
|
|
1155
|
-
|
|
1171
|
+
if text_only:
|
|
1172
|
+
return textile
|
|
1173
|
+
else:
|
|
1174
|
+
return textile, files
|
|
1156
1175
|
|
|
1157
1176
|
def to_redmine(self):
|
|
1158
1177
|
"""
|
|
@@ -1394,24 +1413,29 @@ class DocBuilder(UserList):
|
|
|
1394
1413
|
|
|
1395
1414
|
engine = engine.lower()
|
|
1396
1415
|
|
|
1416
|
+
|
|
1417
|
+
if engine in ['html', 'pdf', 'tex']:
|
|
1418
|
+
kwargs['additional_files'] = files_to_upload
|
|
1419
|
+
kwargs['template'] = template
|
|
1420
|
+
kwargs['template_params'] = template_params
|
|
1421
|
+
|
|
1422
|
+
if engine in ['pdf', 'tex']:
|
|
1423
|
+
kwargs['do_escape_template_params'] = do_escape_template_params
|
|
1424
|
+
|
|
1397
1425
|
if index:
|
|
1398
|
-
DocBuilder([self[index]]).show()
|
|
1426
|
+
DocBuilder([self[index]]).show(**kwargs)
|
|
1399
1427
|
elif chapter:
|
|
1400
|
-
DocBuilder(self.get_chapter(chapter)).show()
|
|
1428
|
+
DocBuilder(self.get_chapter(chapter)).show(**kwargs)
|
|
1401
1429
|
|
|
1402
1430
|
if is_notebook():
|
|
1403
|
-
from IPython.display import display, HTML, Markdown,
|
|
1431
|
+
from IPython.display import display, HTML, Markdown, Code
|
|
1404
1432
|
if engine in 'html'.split():
|
|
1405
1433
|
display(HTML(self.to_html(**kwargs)))
|
|
1406
1434
|
elif engine in 'markdown md'.split():
|
|
1407
1435
|
display(Markdown(self.to_markdown()))
|
|
1408
1436
|
elif engine in 'tex latex'.split():
|
|
1409
|
-
display(Code(self.to_tex(**kwargs)
|
|
1437
|
+
display(Code(self.to_tex(text_only=True, **kwargs), language='tex'))
|
|
1410
1438
|
elif engine == 'pdf':
|
|
1411
|
-
kwargs['files_to_upload'] = files_to_upload
|
|
1412
|
-
kwargs['template'] = template
|
|
1413
|
-
kwargs['template_params'] = template_params
|
|
1414
|
-
kwargs['do_escape_template_params'] = do_escape_template_params
|
|
1415
1439
|
pdf_bytes = self.to_pdf(**kwargs)
|
|
1416
1440
|
show_pdf(pdf_bytes)
|
|
1417
1441
|
else:
|
|
@@ -1423,7 +1447,7 @@ class DocBuilder(UserList):
|
|
|
1423
1447
|
elif engine in 'markdown md'.split():
|
|
1424
1448
|
print(self.to_markdown(embed_images=False, **kwargs))
|
|
1425
1449
|
elif engine in 'tex latex'.split():
|
|
1426
|
-
print(self.to_tex(**kwargs)
|
|
1450
|
+
print(self.to_tex(text_only=True, **kwargs))
|
|
1427
1451
|
else:
|
|
1428
1452
|
raise KeyError(f'engine must be in: "html", "markdown", "md", "tex", or "latex", but was {engine=}')
|
|
1429
1453
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import os
|
|
3
3
|
import json
|
|
4
|
+
from typing import List
|
|
4
5
|
|
|
5
6
|
from jinja2 import Environment, FileSystemLoader, ChoiceLoader
|
|
6
7
|
|
|
@@ -118,7 +119,7 @@ class TemplateDirSource():
|
|
|
118
119
|
"""
|
|
119
120
|
|
|
120
121
|
|
|
121
|
-
def __init__(self, template_dirs:
|
|
122
|
+
def __init__(self, template_dirs:List[str]=None) -> None:
|
|
122
123
|
|
|
123
124
|
if template_dirs is None:
|
|
124
125
|
template_dirs = get_registered_template_dirs(include_default=True)
|
|
@@ -337,6 +338,12 @@ class DocTemplate():
|
|
|
337
338
|
self.env = env
|
|
338
339
|
self.template_id = template_id
|
|
339
340
|
|
|
341
|
+
def __str__(self):
|
|
342
|
+
return f"TemplateObject(id={self.template_id}, template={self.template}, params.keys()={self.params.keys()})"
|
|
343
|
+
|
|
344
|
+
def __repr__(self):
|
|
345
|
+
return self.__str__()
|
|
346
|
+
|
|
340
347
|
def render(self, **kwargs):
|
|
341
348
|
"""Render the Jinja2 template with given parameters.
|
|
342
349
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pydocmaker
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.5
|
|
4
4
|
Summary: a minimal document maker to make docx, markdown, html, textile, redmine, and tex documents from python. Written in pure python.
|
|
5
5
|
Home-page: https://github.com/TobiasGlaubach/pydocmaker
|
|
6
6
|
Author: Tobias Glaubach
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|