langfun 0.1.2.dev202409170804__py3-none-any.whl → 0.1.2.dev202409190804__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.
@@ -275,9 +275,19 @@ class Matching(base.Evaluation):
275
275
  for i, (example, output, message) in enumerate(self.matches):
276
276
  bgcolor = 'white' if i % 2 == 0 else '#DDDDDD'
277
277
  s.write(f'<tr style="background-color: {bgcolor}"><td>{i + 1}</td>')
278
- input_str = pg.format(example, verbose=False, max_bytes_len=32)
278
+ input_str = lf.repr_utils.escape_quoted(
279
+ pg.format(
280
+ example, verbose=False, max_bytes_len=32,
281
+ custom_format='_repr_html_'
282
+ )
283
+ )
279
284
  s.write(f'<td style="color:green;white-space:pre-wrap">{input_str}</td>')
280
- output_str = pg.format(output, verbose=False, max_bytes_len=32)
285
+ output_str = lf.repr_utils.escape_quoted(
286
+ pg.format(
287
+ output, verbose=False, max_bytes_len=32,
288
+ custom_format='_repr_html_'
289
+ )
290
+ )
281
291
  s.write(f'<td style="color:blue;white-space:pre-wrap">{output_str}</td>')
282
292
  s.write('<td>')
283
293
  self._render_message(message, s)
@@ -94,7 +94,7 @@ def write_maybe_shared(s: io.StringIO, content: str) -> bool:
94
94
 
95
95
 
96
96
  def html_repr(
97
- value: Any,
97
+ value: dict[str, Any],
98
98
  item_color: Callable[
99
99
  [str, str],
100
100
  tuple[
@@ -121,35 +121,38 @@ def html_repr(
121
121
  s.write('<table style="border-top: 1px solid #EEEEEE;">')
122
122
  item_color = item_color or (lambda k, v: (None, '#F1C40F', None, None))
123
123
 
124
- for k, v in pg.object_utils.flatten(value).items():
125
- if isinstance(v, pg.Ref):
126
- v = v.value
127
- if hasattr(v, '_repr_html_'):
128
- cs = v._repr_html_() # pylint: disable=protected-access
129
- else:
130
- cs = f'<span style="white-space: pre-wrap">{html.escape(str(v))}</span>'
131
-
132
- key_color, key_bg_color, value_color, value_bg_color = item_color(k, v)
133
- key_span = html_round_text(
134
- k,
135
- text_color=key_color,
136
- background_color=key_bg_color,
137
- margin_bottom='0px'
138
- )
139
- value_color_style = f'color: {value_color};' if value_color else ''
140
- value_bg_color_style = (
141
- f'background-color: {value_bg_color};' if value_bg_color else ''
142
- )
143
- s.write(
144
- '<tr>'
145
- '<td style="padding: 5px; vertical-align: top; '
146
- f'border-bottom: 1px solid #EEEEEE">{key_span}</td>'
147
- '<td style="padding: 15px 5px 5px 5px; vertical-align: top; '
148
- 'border-bottom: 1px solid #EEEEEE;'
149
- f'{value_color_style}{value_bg_color_style}">{cs}</td></tr>'
150
- )
151
- s.write('</table></div>')
152
- return s.getvalue()
124
+ with (pg.str_format(custom_format='_repr_html_'),
125
+ pg.repr_format(custom_format='_repr_html_')):
126
+ for k, v in pg.object_utils.flatten(value).items():
127
+ if isinstance(v, pg.Ref):
128
+ v = v.value
129
+ if hasattr(v, '_repr_html_'):
130
+ cs = v._repr_html_() # pylint: disable=protected-access
131
+ else:
132
+ cs = html.escape(v) if isinstance(v, str) else escape_quoted(str(v))
133
+ cs = f'<span style="white-space: pre-wrap">{cs}</span>'
134
+
135
+ key_color, key_bg_color, value_color, value_bg_color = item_color(k, v)
136
+ key_span = html_round_text(
137
+ k,
138
+ text_color=key_color,
139
+ background_color=key_bg_color,
140
+ margin_bottom='0px'
141
+ )
142
+ value_color_style = f'color: {value_color};' if value_color else ''
143
+ value_bg_color_style = (
144
+ f'background-color: {value_bg_color};' if value_bg_color else ''
145
+ )
146
+ s.write(
147
+ '<tr>'
148
+ '<td style="padding: 5px; vertical-align: top; '
149
+ f'border-bottom: 1px solid #EEEEEE">{key_span}</td>'
150
+ '<td style="padding: 15px 5px 5px 5px; vertical-align: top; '
151
+ 'border-bottom: 1px solid #EEEEEE;'
152
+ f'{value_color_style}{value_bg_color_style}">{cs}</td></tr>'
153
+ )
154
+ s.write('</table></div>')
155
+ return s.getvalue()
153
156
 
154
157
 
155
158
  def html_round_text(
@@ -172,3 +175,23 @@ def html_round_text(
172
175
  f'margin-top: {margin_top}; margin-bottom: {margin_bottom}; '
173
176
  f'white-space: {whitespace}">{text}</span>'
174
177
  )
178
+
179
+
180
+ def escape_quoted(s: str):
181
+ """Escape quoted parts within a string."""
182
+ r = io.StringIO()
183
+ quote_char = None
184
+ quote_start = -1
185
+ for i, c in enumerate(s):
186
+ if c in ('\'', '"'):
187
+ if quote_char is None:
188
+ quote_char = c
189
+ quote_start = i
190
+ elif quote_char == c:
191
+ r.write(c)
192
+ r.write(html.escape(s[quote_start + 1:i]))
193
+ r.write(c)
194
+ quote_char = None
195
+ elif quote_char is None:
196
+ r.write(c)
197
+ return r.getvalue()
@@ -54,6 +54,15 @@ class SharingContentTest(unittest.TestCase):
54
54
  self.assertEqual(ctx1['<style>b</style>'], 2)
55
55
  self.assertEqual(ctx1['<style>a</style>'], 4)
56
56
 
57
+ def test_escape_quoted(self):
58
+ self.assertEqual(
59
+ repr_utils.escape_quoted(str('<a>')), '<a>'
60
+ )
61
+ self.assertEqual(
62
+ repr_utils.escape_quoted('x=<a>, b="<a>"'),
63
+ 'x=<a>, b="&lt;a&gt;"'
64
+ )
65
+
57
66
  def test_html(self):
58
67
  html = repr_utils.Html('<div>foo</div>')
59
68
  self.assertEqual(html.content, '<div>foo</div>')
@@ -63,12 +72,18 @@ class SharingContentTest(unittest.TestCase):
63
72
  class Foo(pg.Object):
64
73
  x: int
65
74
 
75
+ class Bar(pg.Object):
76
+
77
+ def _repr_html_(self):
78
+ return '<bar>'
79
+
66
80
  html = repr_utils.html_repr(
67
- {'foo': pg.Ref(Foo(1)), 'bar': '<lf_image>'}
81
+ {'foo': pg.Ref(Foo(1)), 'bar': Bar(), 'baz': '<lf_image>'}
68
82
  )
69
83
  self.assertIn('foo</span>', html)
70
- self.assertNotIn('Ref', html)
84
+ self.assertIn('<bar>', html)
71
85
  self.assertIn('&lt;lf_image&gt;', html)
86
+ self.assertNotIn('Ref', html)
72
87
 
73
88
 
74
89
  if __name__ == '__main__':
langfun/core/template.py CHANGED
@@ -231,6 +231,16 @@ class Template(
231
231
  """Returns the missing variable names."""
232
232
  return self.vars(closure=True, specified=False)
233
233
 
234
+ @classmethod
235
+ def raw_str(cls, text: str) -> str:
236
+ """Returns a template string that preserve the text as original."""
237
+ return '{% raw %}' + text + '{% endraw %}'
238
+
239
+ @classmethod
240
+ def from_raw_str(cls, text: str) -> 'Template':
241
+ """Returns a template that preserve the text as original."""
242
+ return cls(cls.raw_str(text), clean=False)
243
+
234
244
  def render(
235
245
  self,
236
246
  *,
@@ -98,6 +98,21 @@ class BasicTest(unittest.TestCase):
98
98
  self.assertEqual(d.z.render(), 'Bye, 1')
99
99
  self.assertEqual(d.p.render(), 'Again Hello, 1')
100
100
 
101
+ def test_raw_text(self):
102
+ self.assertEqual(
103
+ Template(
104
+ '{{a}}' + Template.raw_str('\n{{d}}, {%x%}\n') + '{{b}}',
105
+ a='hi', b=1
106
+ ).render().text,
107
+ 'hi\n{{d}}, {%x%}\n1'
108
+ )
109
+
110
+ def test_from_raw_str(self):
111
+ self.assertEqual(
112
+ Template.from_raw_str('\n{{d}}, {%x%}\n').render().text,
113
+ '\n{{d}}, {%x%}\n'
114
+ )
115
+
101
116
 
102
117
  class DefinitionTest(unittest.TestCase):
103
118
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langfun
3
- Version: 0.1.2.dev202409170804
3
+ Version: 0.1.2.dev202409190804
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -19,14 +19,14 @@ langfun/core/modality.py,sha256=g9wGx347oVofAJlMu_CpzTMIyTT9DJW8NfO4E-d-oNM,3879
19
19
  langfun/core/modality_test.py,sha256=7SwhixFME2Q1sIXRgJx97EZFiIyC31A9NVr6_nDtFv4,2441
20
20
  langfun/core/natural_language.py,sha256=3ynSnaYQnjE60LIPK5fyMgdIjubnPYZwzGq4rWPeloE,1177
21
21
  langfun/core/natural_language_test.py,sha256=LHGU_1ytbkGuSZQFIFP7vP3dBlcY4-A12fT6dbjUA0E,1424
22
- langfun/core/repr_utils.py,sha256=Y6ccoQUMpRxDv_jUy2QtnP9cdz3QBjJtTIgxGIU-kfM,5537
23
- langfun/core/repr_utils_test.py,sha256=_VhWpDbtlWaGadXL0gpmwQVmACenvzmLUng_AqR6zaE,2685
22
+ langfun/core/repr_utils.py,sha256=S2aZQllHuy2syduFiYKJm--GPoJWRGS5cXvbC1pdEUs,6243
23
+ langfun/core/repr_utils_test.py,sha256=ULG7gvgoyqQFWi0m6g2-E0GorNEr1nnZ0J_sZVQKz80,3036
24
24
  langfun/core/sampling.py,sha256=vygWvgC8MFw0_AKNSmz-ywMXJYWf8cl0tI8QycvAmyI,5795
25
25
  langfun/core/sampling_test.py,sha256=U7PANpMsl9E_pa4_Y4FzesSjcwg-u-LKHGCWSgv-8FY,3663
26
26
  langfun/core/subscription.py,sha256=euawEuSZP-BHydaT-AQpfYFL0m5pWPGcW0upFhrojqc,10930
27
27
  langfun/core/subscription_test.py,sha256=Y4ZdbZEwm83YNZBxHff0QR4QUa4rdaNXA3_jfIcArBo,8717
28
- langfun/core/template.py,sha256=UhNNGUDJ4StUhPBKzHmjym36khxHOGWGr9MDxBwgxQA,22284
29
- langfun/core/template_test.py,sha256=cb005qM_3dvJikaPDB3rirfIrMAIIVRpoiXGREGJ43o,15468
28
+ langfun/core/template.py,sha256=AWHJwWjsPgf8r584_HOleBqgN90oKCpW8OMx-gdljuM,22635
29
+ langfun/core/template_test.py,sha256=YCBa9YMYtc_8X2gNSJvvQKpSovZy5A4YgIniCvm-1Ys,15843
30
30
  langfun/core/text_formatting.py,sha256=d7t9vaY6aCn1dkfkikpNYnBy5E_i93vHbfyDWFclGZU,5284
31
31
  langfun/core/text_formatting_test.py,sha256=ck0Xzdd4YF4CtCUj7VE0GybfbAyKQ8p3xkM1FBGrqIk,2096
32
32
  langfun/core/coding/__init__.py,sha256=5utju_fwEsImaiftx4oXKl9FAM8p281k8-Esdh_-m1w,835
@@ -46,7 +46,7 @@ langfun/core/coding/python/permissions_test.py,sha256=w5EDb8QxpxgJyZkojyzVWQvDfg
46
46
  langfun/core/eval/__init__.py,sha256=Ogdr9OtTywhhLPHi3AZzOD2mXX2oyaHWflrSTMm96uA,1899
47
47
  langfun/core/eval/base.py,sha256=xDZQ3lu5oJaPDZCE5-QbBEajq--HRU64GVKb3xB64aI,74738
48
48
  langfun/core/eval/base_test.py,sha256=VEraWaRybSxOCOcZrZouNkiroDEPR6uyFBJoAz-1pQg,26930
49
- langfun/core/eval/matching.py,sha256=foqHIfEbmgWMfGv3ia0bCsf6m6PTr_Oeb8FZobbyud8,9900
49
+ langfun/core/eval/matching.py,sha256=vjA7g413kAV7VASwNIVUayMhhXvtjttY0nr3UdHqXwk,10132
50
50
  langfun/core/eval/matching_test.py,sha256=f7iVyXH5KGJBWt4Wp14Bt9J3X59A6Ayfog9MbuFvPew,5532
51
51
  langfun/core/eval/patching.py,sha256=R0s2eAd1m97exQt06dmUL0V_MBG0W2Hxg7fhNB7cXW0,3866
52
52
  langfun/core/eval/patching_test.py,sha256=8kCd54Egjju22FMgtJuxEsrXkW8ifs-UUBHtrCG1L6w,4775
@@ -119,8 +119,8 @@ langfun/core/templates/demonstration.py,sha256=vCrgYubdZM5Umqcgp8NUVGXgr4P_c-fik
119
119
  langfun/core/templates/demonstration_test.py,sha256=SafcDQ0WgI7pw05EmPI2S4v1t3ABKzup8jReCljHeK4,2162
120
120
  langfun/core/templates/selfplay.py,sha256=yhgrJbiYwq47TgzThmHrDQTF4nDrTI09CWGhuQPNv-s,2273
121
121
  langfun/core/templates/selfplay_test.py,sha256=rBW2Qr8yi-aWYwoTwRR-n1peKyMX9QXPZXURjLgoiRs,2264
122
- langfun-0.1.2.dev202409170804.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
123
- langfun-0.1.2.dev202409170804.dist-info/METADATA,sha256=atoHFAR24zaLtcMo2sp5-Wpbt6zWK8IHVx8RkjltNMc,8890
124
- langfun-0.1.2.dev202409170804.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
125
- langfun-0.1.2.dev202409170804.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
126
- langfun-0.1.2.dev202409170804.dist-info/RECORD,,
122
+ langfun-0.1.2.dev202409190804.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
123
+ langfun-0.1.2.dev202409190804.dist-info/METADATA,sha256=jXSHbJHya-kBejre47rbdqgVk2jtBoX5lEbegEyaK18,8890
124
+ langfun-0.1.2.dev202409190804.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
125
+ langfun-0.1.2.dev202409190804.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
126
+ langfun-0.1.2.dev202409190804.dist-info/RECORD,,