dp_wizard_templates 0.3.0__py2.py3-none-any.whl → 0.4.0__py2.py3-none-any.whl

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.

Potentially problematic release.


This version of dp_wizard_templates might be problematic. Click here for more details.

@@ -1 +1 @@
1
- 0.3.0
1
+ 0.4.0
@@ -1,8 +1,13 @@
1
- from typing import Optional, Callable
1
+ from typing import Optional, Callable, Iterable
2
2
  from pathlib import Path
3
3
  import inspect
4
4
  import re
5
5
  import black
6
+ import json
7
+
8
+
9
+ class TemplateException(Exception):
10
+ pass
6
11
 
7
12
 
8
13
  def _get_body(func):
@@ -12,46 +17,71 @@ def _get_body(func):
12
17
  if not re.match(r"def \w+\((\w+(, \w+)*)?\):", first_line.strip()):
13
18
  # Parsing to AST and unparsing is a more robust option,
14
19
  # but more complicated.
15
- raise Exception(f"def and parameters should fit on one line: {first_line}")
20
+ raise TemplateException(
21
+ f"def and parameters should fit on one line: {first_line}"
22
+ )
16
23
 
17
24
  # The "def" should not be in the output,
18
25
  # and cleandoc handles the first line differently.
19
26
  source_lines[0] = ""
20
27
  body = inspect.cleandoc("\n".join(source_lines))
21
- body = re.sub(
22
- r"\s*#\s+type:\s+ignore\s*",
23
- "\n",
24
- body,
25
- )
26
- body = re.sub(
27
- r"\s*#\s+noqa:.+",
28
- "",
29
- body,
30
- )
28
+ comments_to_strip = [
29
+ r"\s+#\s+type:\s+ignore\s*",
30
+ r"\s+#\s+noqa:.+\s*",
31
+ r"\s+#\s+pragma:\s+no cover\s*",
32
+ ]
33
+ for comment_re in comments_to_strip:
34
+ body = re.sub(
35
+ comment_re,
36
+ "\n",
37
+ body,
38
+ )
39
+
31
40
  return body
32
41
 
33
42
 
43
+ def _check_repr(value):
44
+ """
45
+ Confirms that the string returned by repr()
46
+ can be evaluated to recreate the original value.
47
+ Takes a conservative approach by checking
48
+ if the value can be serialized to JSON.
49
+ """
50
+ try:
51
+ json.dumps(value)
52
+ except TypeError as e:
53
+ raise TemplateException(e)
54
+ return repr(value)
55
+
56
+
34
57
  class Template:
35
58
  def __init__(
36
59
  self,
37
60
  template: str | Callable,
38
61
  root: Optional[Path] = None,
62
+ ignore: Iterable[str] = ("TODO",),
39
63
  ):
40
- if root is not None:
41
- template_name = f"_{template}.py"
42
- template_path = root / template_name
43
- self._source = f"'{template_name}'"
44
- self._template = template_path.read_text()
45
- else:
64
+ if root is None:
46
65
  if callable(template):
47
66
  self._source = "function template"
48
67
  self._template = _get_body(template)
49
68
  else:
50
69
  self._source = "string template"
51
70
  self._template = template
71
+ else:
72
+ if callable(template):
73
+ raise TemplateException(
74
+ "If template is function, root kwarg not allowed"
75
+ )
76
+ else:
77
+ template_name = f"_{template}.py"
78
+ template_path = root / template_name
79
+ self._source = f"'{template_name}'"
80
+ self._template = template_path.read_text()
52
81
  # We want a list of the initial slots, because substitutions
53
82
  # can produce sequences of upper case letters that could be mistaken for slots.
54
83
  self._initial_slots = self._find_slots()
84
+ self._ignore = ignore
55
85
 
56
86
  def _find_slots(self) -> set[str]:
57
87
  # Slots:
@@ -75,7 +105,7 @@ class Template:
75
105
  for k, v in kwargs.items():
76
106
  function(k, v, errors)
77
107
  if errors:
78
- raise Exception(self._make_message(errors))
108
+ raise TemplateException(self._make_message(errors))
79
109
 
80
110
  def _fill_inline_slots(
81
111
  self,
@@ -141,7 +171,7 @@ class Template:
141
171
  """
142
172
  Fill in string or numeric values. `repr` is called before filling.
143
173
  """
144
- self._fill_inline_slots(stringifier=repr, **kwargs)
174
+ self._fill_inline_slots(stringifier=_check_repr, **kwargs)
145
175
  return self
146
176
 
147
177
  def fill_code_blocks(self, **kwargs) -> "Template":
@@ -168,10 +198,10 @@ class Template:
168
198
  return self
169
199
 
170
200
  def finish(self, reformat: bool = False) -> str:
171
- unfilled_slots = self._initial_slots & self._find_slots()
201
+ unfilled_slots = (self._initial_slots & self._find_slots()) - set(self._ignore)
172
202
  if unfilled_slots:
173
203
  errors = [f"'{slot}' slot not filled" for slot in unfilled_slots]
174
- raise Exception(self._make_message(errors))
204
+ raise TemplateException(self._make_message(errors))
175
205
 
176
206
  if reformat:
177
207
  self._template = black.format_str(self._template, mode=black.Mode())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dp_wizard_templates
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Code templating tools
5
5
  Author-email: The OpenDP Project <info@opendp.org>
6
6
  Description-Content-Type: text/markdown
@@ -0,0 +1,9 @@
1
+ dp_wizard_templates/VERSION,sha256=zXhTTtFa1GkStxM50UF9DQQ9gwnCuUQV8-0bnR_frtA,5
2
+ dp_wizard_templates/__init__.py,sha256=E2xrnvZGY24pU3PCryH4TmvhNYsLmxXCtfvIcYNbTYw,126
3
+ dp_wizard_templates/code_template.py,sha256=mHJKN0pzPHIGSF3K_ffwM1m1VPAjQ-zdwQawzPgKoQk,6606
4
+ dp_wizard_templates/converters.py,sha256=0Ml_V71Z6zce2SaxDQMzYXg-5jQw2-NWChrY_9SCGIo,4359
5
+ dp_wizard_templates/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ dp_wizard_templates-0.4.0.dist-info/licenses/LICENSE,sha256=FDrIMeZPiT4g_4w0i1Ec4Bc8h9wfNytroheQN4508yU,1063
7
+ dp_wizard_templates-0.4.0.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
8
+ dp_wizard_templates-0.4.0.dist-info/METADATA,sha256=zXPD9TDjoYP-T3kIO_yJMARkU3L50Qte8zyEVLwbQYs,1881
9
+ dp_wizard_templates-0.4.0.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- dp_wizard_templates/VERSION,sha256=VQYTU3_EiPOzcq90pAAYefASyEZbgW8bhcbTRGss-0k,5
2
- dp_wizard_templates/__init__.py,sha256=E2xrnvZGY24pU3PCryH4TmvhNYsLmxXCtfvIcYNbTYw,126
3
- dp_wizard_templates/code_template.py,sha256=BAt9vsvrusqR3mETsUE4HfsPgF3D0yPHgL8Q0no01h4,5735
4
- dp_wizard_templates/converters.py,sha256=0Ml_V71Z6zce2SaxDQMzYXg-5jQw2-NWChrY_9SCGIo,4359
5
- dp_wizard_templates/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- dp_wizard_templates-0.3.0.dist-info/licenses/LICENSE,sha256=FDrIMeZPiT4g_4w0i1Ec4Bc8h9wfNytroheQN4508yU,1063
7
- dp_wizard_templates-0.3.0.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
8
- dp_wizard_templates-0.3.0.dist-info/METADATA,sha256=uBCyEVM3KWsLChzbFCYT8nxjwdxvQeWMsGAKSKCiEYA,1881
9
- dp_wizard_templates-0.3.0.dist-info/RECORD,,