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.
Files changed (30) hide show
  1. {pydocmaker-2.2.2/src/pydocmaker.egg-info → pydocmaker-2.2.5}/PKG-INFO +1 -1
  2. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/__init__.py +1 -1
  3. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/baseformatter.py +3 -1
  4. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_tex.py +7 -1
  5. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/pdf_maker.py +21 -0
  6. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/core.py +50 -26
  7. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/templating.py +8 -1
  8. {pydocmaker-2.2.2 → pydocmaker-2.2.5/src/pydocmaker.egg-info}/PKG-INFO +1 -1
  9. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/LICENSE +0 -0
  10. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/README.md +0 -0
  11. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/setup.cfg +0 -0
  12. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/setup.py +0 -0
  13. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/__init__.py +0 -0
  14. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_docx.py +0 -0
  15. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_html.py +0 -0
  16. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_ipynb.py +0 -0
  17. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_markdown.py +0 -0
  18. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/ex_redmine.py +0 -0
  19. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/mdx_latex.py +0 -0
  20. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/backend/pandoc_api.py +0 -0
  21. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker/util.py +0 -0
  22. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker.egg-info/SOURCES.txt +0 -0
  23. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker.egg-info/dependency_links.txt +0 -0
  24. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker.egg-info/requires.txt +0 -0
  25. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/src/pydocmaker.egg-info/top_level.txt +0 -0
  26. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/tests/test_backend_pandoc.py +0 -0
  27. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/tests/test_convert_all.py +0 -0
  28. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/tests/test_core.py +0 -0
  29. {pydocmaker-2.2.2 → pydocmaker-2.2.5}/tests/test_ex_html.py +0 -0
  30. {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.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.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 not template:
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 k, v in params.items()]
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
- warnings.warn(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) )
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, data, **kwargs):
597
+ def set_meta(self, *args, **kwargs):
597
598
  """
598
- Sets the metadata for the object.
599
-
600
- Args:
601
- data (dict): The metadata to be set.
602
- **kwargs: Additional keyword arguments to be added to the metadata.
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, **kwargs)
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) metadata element in this document if it exists. If not returns None"""
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(**kwargs)
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(**kwargs)
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
- return tex, files
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
- return textile, files
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, IFrame, Code
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)[0], language='tex'))
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)[0])
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:list[str]=None) -> None:
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.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