langfun 0.1.2.dev202412310804__py3-none-any.whl → 0.1.2.dev202501050804__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.
@@ -32,6 +32,13 @@ SUPPORTED_MODELS_AND_SETTINGS = {
32
32
  # o1 (preview) models.
33
33
  # Pricing in US dollars, from https://openai.com/api/pricing/
34
34
  # as of 2024-10-10.
35
+ 'o1': pg.Dict(
36
+ in_service=True,
37
+ rpm=10000,
38
+ tpm=5000000,
39
+ cost_per_1k_input_tokens=0.015,
40
+ cost_per_1k_output_tokens=0.06,
41
+ ),
35
42
  'o1-preview': pg.Dict(
36
43
  in_service=True,
37
44
  rpm=10000,
@@ -255,25 +262,17 @@ SUPPORTED_MODELS_AND_SETTINGS = {
255
262
  ),
256
263
  # GPT-3.5 models
257
264
  'text-davinci-003': pg.Dict(
258
- in_service=False,
259
- rpm=_DEFAULT_RPM,
260
- tpm=_DEFAULT_TPM
265
+ in_service=False, rpm=_DEFAULT_RPM, tpm=_DEFAULT_TPM
261
266
  ),
262
267
  'text-davinci-002': pg.Dict(
263
- in_service=False,
264
- rpm=_DEFAULT_RPM,
265
- tpm=_DEFAULT_TPM
268
+ in_service=False, rpm=_DEFAULT_RPM, tpm=_DEFAULT_TPM
266
269
  ),
267
270
  'code-davinci-002': pg.Dict(
268
- in_service=False,
269
- rpm=_DEFAULT_RPM,
270
- tpm=_DEFAULT_TPM
271
+ in_service=False, rpm=_DEFAULT_RPM, tpm=_DEFAULT_TPM
271
272
  ),
272
273
  # GPT-3 instruction-tuned models (Deprecated)
273
274
  'text-curie-001': pg.Dict(
274
- in_service=False,
275
- rpm=_DEFAULT_RPM,
276
- tpm=_DEFAULT_TPM
275
+ in_service=False, rpm=_DEFAULT_RPM, tpm=_DEFAULT_TPM
277
276
  ),
278
277
  'text-babbage-001': pg.Dict(
279
278
  in_service=False,
@@ -290,32 +289,12 @@ SUPPORTED_MODELS_AND_SETTINGS = {
290
289
  rpm=_DEFAULT_RPM,
291
290
  tpm=_DEFAULT_TPM,
292
291
  ),
293
- 'curie': pg.Dict(
294
- in_service=False,
295
- rpm=_DEFAULT_RPM,
296
- tpm=_DEFAULT_TPM
297
- ),
298
- 'babbage': pg.Dict(
299
- in_service=False,
300
- rpm=_DEFAULT_RPM,
301
- tpm=_DEFAULT_TPM
302
- ),
303
- 'ada': pg.Dict(
304
- in_service=False,
305
- rpm=_DEFAULT_RPM,
306
- tpm=_DEFAULT_TPM
307
- ),
292
+ 'curie': pg.Dict(in_service=False, rpm=_DEFAULT_RPM, tpm=_DEFAULT_TPM),
293
+ 'babbage': pg.Dict(in_service=False, rpm=_DEFAULT_RPM, tpm=_DEFAULT_TPM),
294
+ 'ada': pg.Dict(in_service=False, rpm=_DEFAULT_RPM, tpm=_DEFAULT_TPM),
308
295
  # GPT-3 base models that are still in service.
309
- 'babbage-002': pg.Dict(
310
- in_service=True,
311
- rpm=_DEFAULT_RPM,
312
- tpm=_DEFAULT_TPM
313
- ),
314
- 'davinci-002': pg.Dict(
315
- in_service=True,
316
- rpm=_DEFAULT_RPM,
317
- tpm=_DEFAULT_TPM
318
- ),
296
+ 'babbage-002': pg.Dict(in_service=True, rpm=_DEFAULT_RPM, tpm=_DEFAULT_TPM),
297
+ 'davinci-002': pg.Dict(in_service=True, rpm=_DEFAULT_RPM, tpm=_DEFAULT_TPM),
319
298
  }
320
299
 
321
300
 
@@ -569,6 +548,13 @@ class OpenAI(rest.REST):
569
548
  )
570
549
 
571
550
 
551
+ class GptO1(OpenAI):
552
+ """GPT-O1."""
553
+
554
+ model = 'o1'
555
+ multimodal = True
556
+
557
+
572
558
  class GptO1Preview(OpenAI):
573
559
  """GPT-O1."""
574
560
  model = 'o1-preview'
@@ -110,7 +110,13 @@ SUPPORTED_MODELS_AND_SETTINGS = {
110
110
  ),
111
111
  # TODO(sharatsharat): Update costs when published
112
112
  'gemini-2.0-flash-exp': pg.Dict(
113
- rpm=20,
113
+ rpm=10,
114
+ cost_per_1k_input_chars=0.000,
115
+ cost_per_1k_output_chars=0.000,
116
+ ),
117
+ # TODO(yifenglu): Update costs when published
118
+ 'gemini-2.0-flash-thinking-exp-1219': pg.Dict(
119
+ rpm=10,
114
120
  cost_per_1k_input_chars=0.000,
115
121
  cost_per_1k_output_chars=0.000,
116
122
  ),
@@ -415,6 +421,12 @@ class VertexAIGeminiFlash2_0Exp(VertexAIGemini2_0): # pylint: disable=invalid-n
415
421
  model = 'gemini-2.0-flash-exp'
416
422
 
417
423
 
424
+ class VertexAIGeminiFlash2_0ThinkingExp(VertexAIGemini2_0): # pylint: disable=invalid-name
425
+ """Vertex AI Gemini 2.0 Flash model."""
426
+
427
+ model = 'gemini-2.0-flash-thinking-exp-1219'
428
+
429
+
418
430
  class VertexAIGemini1_5(VertexAI): # pylint: disable=invalid-name
419
431
  """Vertex AI Gemini 1.5 model."""
420
432
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langfun
3
- Version: 0.1.2.dev202412310804
3
+ Version: 0.1.2.dev202501050804
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -1,5 +1,5 @@
1
1
  langfun/__init__.py,sha256=fhfPXpHN7GoGqixpFfqhQkYxFs_siP_LhbjZhd3lhio,2497
2
- langfun/core/__init__.py,sha256=xlvFTXc7IKUTs8aCFRFhzOLTmmeuhXgk9yx2InBLNiA,4937
2
+ langfun/core/__init__.py,sha256=oboXhlpA93wk4p1K52-tx0pbBt49r6Y1aCmiavBV03Y,4830
3
3
  langfun/core/component.py,sha256=HVrEoTL1Y01iqOHC3FYdbAOnffqfHHtGJXoK1vkdEwo,11583
4
4
  langfun/core/component_test.py,sha256=sG-T2wpvBfHqWGZE7sc4NayJj2aj5QFBzSwFiwrGEIc,10376
5
5
  langfun/core/concurrent.py,sha256=QMNYhB_PyjvVJtabMokpzotZRYvyE9iYu2QsgwDk7M4,29552
@@ -19,8 +19,6 @@ langfun/core/modality.py,sha256=K8pUGuMpfWcOtVcXC_OqVjro1-RhHF6ddQni61DuYzM,4166
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=yyc2xeK8sKQOOLcxwIV9E50Wf-B0TjXrnS07tSx_ea8,6491
23
- langfun/core/repr_utils_test.py,sha256=ULG7gvgoyqQFWi0m6g2-E0GorNEr1nnZ0J_sZVQKz80,3036
24
22
  langfun/core/sampling.py,sha256=SCnS5PFJWNVxSKvSkSCNRUmruvScun8UcNN4gafuXcw,5866
25
23
  langfun/core/sampling_test.py,sha256=U7PANpMsl9E_pa4_Y4FzesSjcwg-u-LKHGCWSgv-8FY,3663
26
24
  langfun/core/subscription.py,sha256=euawEuSZP-BHydaT-AQpfYFL0m5pWPGcW0upFhrojqc,10930
@@ -51,22 +49,22 @@ langfun/core/coding/python/permissions_test.py,sha256=w5EDb8QxpxgJyZkojyzVWQvDfg
51
49
  langfun/core/eval/__init__.py,sha256=OEXr1ZRuvLuhJJfuQ1ZWQ-SvYzjyrtiAAEogYaB7E6o,1933
52
50
  langfun/core/eval/base.py,sha256=ajHUS_BdzBIDKEwAmMzne0lJi8HcDhPmyw_plO0p7G0,75814
53
51
  langfun/core/eval/base_test.py,sha256=-LsIV9DXlDal0EnOlaWpibJvfef0NbxtZAm0OH_abAE,27189
54
- langfun/core/eval/matching.py,sha256=UnjdM_ebPqXKJamY4lvL3AYxrMIz3LqkjRTnHJ5xsYc,9349
52
+ langfun/core/eval/matching.py,sha256=AVKkGoc-BaHEzgSBamaAk3194TgqckDe_dinpS6LrXI,9323
55
53
  langfun/core/eval/matching_test.py,sha256=QCoYEuf4b_1bkHqUCuRzKMbXHrV3AB2FCOBivo1stC4,5249
56
54
  langfun/core/eval/patching.py,sha256=R0s2eAd1m97exQt06dmUL0V_MBG0W2Hxg7fhNB7cXW0,3866
57
55
  langfun/core/eval/patching_test.py,sha256=8kCd54Egjju22FMgtJuxEsrXkW8ifs-UUBHtrCG1L6w,4775
58
- langfun/core/eval/scoring.py,sha256=B69IsIxiPs1xZcOBFIhZF70YmDue2Siik-CPL2bh33s,6254
56
+ langfun/core/eval/scoring.py,sha256=_DvnlgI1SdRVaOojao_AkV3pnenfCPOqyhvlg-Sw-5M,6322
59
57
  langfun/core/eval/scoring_test.py,sha256=O8olHbrUEg60gMxwOkWzKBJZpZoUlmVnBANX5Se2SXM,4546
60
58
  langfun/core/eval/v2/__init__.py,sha256=qoa6zKdFXOFyCX6vay6OdgPf1eUhYGoHYAxe35qECGk,1628
61
- langfun/core/eval/v2/checkpointing.py,sha256=5Koc9IM5OFAhLaO7sAZC979vEFxR8a_ssXcaqG_iVw0,10325
62
- langfun/core/eval/v2/checkpointing_test.py,sha256=i9qmEJk90kz6SB7OBGAHCogKVyazUZxAZlKXZt9hccI,4435
63
- langfun/core/eval/v2/eval_test_helper.py,sha256=pDpZTBnWRR5xjJv3Uy3NWEzArqlL8FTMOgeR4C53F5M,2348
64
- langfun/core/eval/v2/evaluation.py,sha256=NFBGAWw2BtW7H0zcoZhfWtz59Psra84eshJm73uAFwg,21807
65
- langfun/core/eval/v2/evaluation_test.py,sha256=GmV1TiqX1V15st2qpcGWooM5hudomQVjW5kajovGDvE,6231
66
- langfun/core/eval/v2/example.py,sha256=fURrvdNmMsVMqoEErcsmLmC6Xq3ny16dYsnLH8HVlcY,9626
67
- langfun/core/eval/v2/example_test.py,sha256=WcJmU7IQQXvjFia63mokySC4CqxzVL9Wso1sC5F0YK8,3032
68
- langfun/core/eval/v2/experiment.py,sha256=DuuqTJA0jmep-CM098MYutKkarLIcd1Do9P0W_HhdBg,29800
69
- langfun/core/eval/v2/experiment_test.py,sha256=zSMHYqC9cA0k61U71pCSYTAJ6yK2_b6Dml5btc-bKzQ,9133
59
+ langfun/core/eval/v2/checkpointing.py,sha256=u-MrnwQbm0T-BDcn9pPXs_FeKPzMYm1-pVos0DiTqgM,11769
60
+ langfun/core/eval/v2/checkpointing_test.py,sha256=R-R8SFzworuYnMmGGcvE9f4oiYkb8HMoZ0m4euF3pus,8466
61
+ langfun/core/eval/v2/eval_test_helper.py,sha256=A9w0FbRKieB3yym8x34kY24FfptHrp7m6_z3i8HXSFI,3922
62
+ langfun/core/eval/v2/evaluation.py,sha256=kARf0pG6SrpN__IMeFsw8DV_5mT_tl52pJrr6wIZdsw,22482
63
+ langfun/core/eval/v2/evaluation_test.py,sha256=0l0DqJTF8PZGA2Q1OlaF4YIax4ZhSk0ewOCvuVW1XAk,6658
64
+ langfun/core/eval/v2/example.py,sha256=4-LNr8Ke-fhaF6gyeXX4JMyw0s8YkVTC63pXZ-CXKrE,10144
65
+ langfun/core/eval/v2/example_test.py,sha256=1DNm6EuyZOq827DKvf3oTRVFkMNM_qTnLUpvOjpgz5I,3419
66
+ langfun/core/eval/v2/experiment.py,sha256=qYWx22KMfoUa4ieSq1bt7NE8L9dgoiJpuNOQGT1IBQw,32723
67
+ langfun/core/eval/v2/experiment_test.py,sha256=CqpDsDai2DiIU-SzpVmqFzM_ZxxkVYKd0Gr1Uvcvkuw,13546
70
68
  langfun/core/eval/v2/metric_values.py,sha256=_B905bC-jxrYPLSEcP2M8MaHZOVMz_bVrUw8YC4arCE,4660
71
69
  langfun/core/eval/v2/metric_values_test.py,sha256=ab2oF_HsIwrSy459108ggyjgefHSPn8UVILR4dRwx14,2634
72
70
  langfun/core/eval/v2/metrics.py,sha256=bl8i6u-ZHRBz4hAc3LzsZ2Dc7ZRQcuTYeUhhH-GxfF0,10628
@@ -75,28 +73,28 @@ langfun/core/eval/v2/progress.py,sha256=azZgssQgNdv3IgjKEaQBuGI5ucFDNbdi02P4z_nQ
75
73
  langfun/core/eval/v2/progress_test.py,sha256=YU7VHzmy5knPZwj9vpBN3rQQH2tukj9eKHkuBCI62h8,2540
76
74
  langfun/core/eval/v2/progress_tracking.py,sha256=l9fEkz4oP5McpZzf72Ua7PYm3lAWtRru7gRWNf8H0ms,6083
77
75
  langfun/core/eval/v2/progress_tracking_test.py,sha256=fouMVJkFJqHjbhQJngGLGCmA9x3n0dU4USI2dY163mg,2291
78
- langfun/core/eval/v2/reporting.py,sha256=qFxoxqQhNGxh1APg6-JVDlIfniGdty2Rh8aXQMc1aak,6612
79
- langfun/core/eval/v2/reporting_test.py,sha256=4nobW6pcaatiZh8u4xciexciaiZNDlDoJci157Wp_RI,1492
80
- langfun/core/eval/v2/runners.py,sha256=t6_yHAJ4HWufK4wvh_OntKcok2KquA5ARIHIk1vvEwc,15870
76
+ langfun/core/eval/v2/reporting.py,sha256=KF4pE2H1qj3mJcgkv_c5YYFjrU-uJCk_-fuu891Olzs,8061
77
+ langfun/core/eval/v2/reporting_test.py,sha256=UmYSAQvD3AIXsSyWQ-WD2uLtEISYpmBeoKY5u5Qwc8E,5696
78
+ langfun/core/eval/v2/runners.py,sha256=DKEmSlGXjOXKWFdBhTpLy7tMsBHZHd1Brl3hWIngsSQ,15931
81
79
  langfun/core/eval/v2/runners_test.py,sha256=A37fKK2MvAVTiShsg_laluJzJ9AuAQn52k7HPbfD0Ks,11666
82
- langfun/core/llms/__init__.py,sha256=lWXKjGHv66ShG7AE_Bc4QM7SDTxJdfoQMn3PF0lr0sU,6461
83
- langfun/core/llms/anthropic.py,sha256=afKZmdiLcosS_UEBlB8WKyf1K-zeXgwtPAx6ofg2Gww,13989
80
+ langfun/core/llms/__init__.py,sha256=6mi0IKTNfq6kymZPlPGA2V7YF1xDLrBCPytojeFMMeA,6716
81
+ langfun/core/llms/anthropic.py,sha256=a5MmnFsBA0CbfvwzXT1v_0fqLRMrhUNdh1tx6469PQ4,14357
84
82
  langfun/core/llms/anthropic_test.py,sha256=-2U4kc_pgBM7wqxu8RuxzyHPGww1EAWqKUvN4PW8Btw,8058
85
83
  langfun/core/llms/compositional.py,sha256=csW_FLlgL-tpeyCOTVvfUQkMa_zCN5Y2I-YbSNuK27U,2872
86
84
  langfun/core/llms/compositional_test.py,sha256=4eTnOer-DncRKGaIJW2ZQQMLnt5r2R0UIx_DYOvGAQo,2027
87
85
  langfun/core/llms/fake.py,sha256=gCHBYBLvBCsC78HI1hpoqXCS-p1FMTgY1P1qh_sGBPk,3070
88
86
  langfun/core/llms/fake_test.py,sha256=2h13qkwEz_JR0mtUDPxdAhQo7MueXaFSwsD2DIRDW9g,7653
89
- langfun/core/llms/google_genai.py,sha256=AAYOsSyeNIfHduIL9ZBzLhA8_acZUDMzHhS7AwUbOlM,11603
87
+ langfun/core/llms/google_genai.py,sha256=3iAmLMcBXxkfiiI8BN0S6trKCfyfuajCIHIGpnCrtTg,11973
90
88
  langfun/core/llms/google_genai_test.py,sha256=zw14sgWmk0P_irHyb7vpPy1WAuLEE0PmyfiFElu03sA,7686
91
89
  langfun/core/llms/groq.py,sha256=dCnR3eAECEKuKKAAj-PDTs8NRHl6CQPdf57m1f6a79U,10312
92
90
  langfun/core/llms/groq_test.py,sha256=GYF_Qtq5S1H1TrKH38t6_lkdroqT7v-joYLDKnmS9e0,5274
93
91
  langfun/core/llms/llama_cpp.py,sha256=9tXQntSCDtjTF3bnyJrAPCr4N6wycy5nXYvp9uduygE,2843
94
92
  langfun/core/llms/llama_cpp_test.py,sha256=MWO_qaOeKjRniGjcaWPDScd7HPaIJemqUZoslrt4FPs,1806
95
- langfun/core/llms/openai.py,sha256=l49v6RubfInvV0iG114AymTKNogTX4u4N-UFCeSgIxw,20963
93
+ langfun/core/llms/openai.py,sha256=dLDVBB47nJ30XCwjJpAZMc55ZlZXB__PcfcICCRNuXQ,20995
96
94
  langfun/core/llms/openai_test.py,sha256=kOWa1nf-nJvtYY10REUw5wojh3ZgfU8tRaCZ8wUgJbA,16623
97
95
  langfun/core/llms/rest.py,sha256=sWbYUV8S3SuOg9giq7xwD-xDRfaF7NP_ig7bI52-Rj4,3442
98
96
  langfun/core/llms/rest_test.py,sha256=NZ3Nf0XQVpT9kLP5cBVo_yBHLI7vWTYhWQxYEJVMGs4,3472
99
- langfun/core/llms/vertexai.py,sha256=oEd665IBwzCTlHuLEMrCdwgQzrFB5ERcnxw6nrYNSyk,14990
97
+ langfun/core/llms/vertexai.py,sha256=EPPswgaTfPZQ_GGa_dWsqWPV9uRjCmIH2Iwgm1YXOqM,15377
100
98
  langfun/core/llms/vertexai_test.py,sha256=ffcA5yPecnQy_rhkuYAw_6o1iLW8AR8FgswmHt6aAys,6725
101
99
  langfun/core/llms/cache/__init__.py,sha256=QAo3InUMDM_YpteNnVCSejI4zOsnjSMWKJKzkb3VY64,993
102
100
  langfun/core/llms/cache/base.py,sha256=rt3zwmyw0y9jsSGW-ZbV1vAfLxQ7_3AVk0l2EySlse4,3918
@@ -148,8 +146,8 @@ langfun/core/templates/demonstration.py,sha256=vCrgYubdZM5Umqcgp8NUVGXgr4P_c-fik
148
146
  langfun/core/templates/demonstration_test.py,sha256=SafcDQ0WgI7pw05EmPI2S4v1t3ABKzup8jReCljHeK4,2162
149
147
  langfun/core/templates/selfplay.py,sha256=yhgrJbiYwq47TgzThmHrDQTF4nDrTI09CWGhuQPNv-s,2273
150
148
  langfun/core/templates/selfplay_test.py,sha256=Ot__1P1M8oJfoTp-M9-PQ6HUXqZKyMwvZ5f7yQ3yfyM,2326
151
- langfun-0.1.2.dev202412310804.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
152
- langfun-0.1.2.dev202412310804.dist-info/METADATA,sha256=NXUwqSAFDqcqo2k0EyFp4e4WFxfAyUyYL--hw9BBK10,8281
153
- langfun-0.1.2.dev202412310804.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
154
- langfun-0.1.2.dev202412310804.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
155
- langfun-0.1.2.dev202412310804.dist-info/RECORD,,
149
+ langfun-0.1.2.dev202501050804.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
150
+ langfun-0.1.2.dev202501050804.dist-info/METADATA,sha256=kNngwBqJlzR5sCW7VWtWMwZLA2uItkoRB8q1mXZe5ys,8281
151
+ langfun-0.1.2.dev202501050804.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
152
+ langfun-0.1.2.dev202501050804.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
153
+ langfun-0.1.2.dev202501050804.dist-info/RECORD,,
@@ -1,204 +0,0 @@
1
- # Copyright 2024 The Langfun Authors
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """Helpers for implementing _repr_xxx_ methods."""
15
-
16
- import collections
17
- import contextlib
18
- import html
19
- import io
20
- from typing import Any, Callable, Iterator
21
-
22
- from langfun.core import component
23
- import pyglove as pg
24
-
25
-
26
- class Html(pg.Object):
27
- """A HTML adapter for rendering."""
28
- content: str
29
-
30
- def _repr_html_(self) -> str:
31
- return self.content
32
-
33
-
34
- @contextlib.contextmanager
35
- def share_parts() -> Iterator[dict[str, int]]:
36
- """Context manager for defining the context (scope) of shared content.
37
-
38
- Under the context manager, call to `lf.write_shared` with the same content
39
- will be written only once. This is useful for writing shared content such as
40
- shared style and script sections in the HTML.
41
-
42
- Example:
43
- ```
44
- class Foo(pg.Object):
45
- def _repr_html_(self) -> str:
46
- s = io.StringIO()
47
- lf.repr_utils.write_shared_part(s, '<style>..</style>')
48
- lf.repr_utils.write_shared_part(s, '<script>..</script>')
49
- return s.getvalue()
50
-
51
- with lf.repr_utils.share_parts() as share_parts:
52
- # The <style> and <script> section will be written only once.
53
- lf.console.display(Foo())
54
- lf.console.display(Foo())
55
-
56
- # Assert that the shared content is attempted to be written twice.
57
- assert share_parts['<style>..</style>'] == 2
58
- ```
59
-
60
- Yields:
61
- A dictionary mapping the shared content to the number of times it is
62
- attempted to be written.
63
- """
64
- context = component.context_value(
65
- '__shared_parts__', collections.defaultdict(int)
66
- )
67
- with component.context(__shared_parts__=context):
68
- try:
69
- yield context
70
- finally:
71
- pass
72
-
73
-
74
- def write_maybe_shared(s: io.StringIO, content: str) -> bool:
75
- """Writes a maybe shared part to an string stream.
76
-
77
- Args:
78
- s: The string stream to write to.
79
- content: A maybe shared content to write.
80
-
81
- Returns:
82
- True if the content is written to the string. False if the content is
83
- already written under the same share context.
84
- """
85
- context = component.context_value('__shared_parts__', None)
86
- if context is None:
87
- s.write(content)
88
- return True
89
- written = content in context
90
- if not written:
91
- s.write(content)
92
- context[content] += 1
93
- return not written
94
-
95
-
96
- def html_repr(
97
- value: dict[str, Any],
98
- item_color: Callable[
99
- [str, str],
100
- tuple[
101
- str | None, # Label text color
102
- str | None, # Label background color
103
- str | None, # Value text color
104
- str | None, # Value background color
105
- ]
106
- ] | None = None # pylint: disable=bad-whitespace
107
- ) -> str:
108
- """Writes a list of key-value pairs to an string stream.
109
-
110
- Args:
111
- value: A value to be rendered in HTML.
112
- item_color: A function that takes the key and value and returns a tuple
113
- of four strings, the text color and background color of the label and
114
- value respectively. If None, a default color scheme will be used.
115
-
116
- Returns:
117
- The HTML representation of the value.
118
- """
119
- s = io.StringIO()
120
- s.write('<div style="padding-left: 20px; margin-top: 10px">')
121
- s.write('<table style="border-top: 1px solid #EEEEEE;">')
122
- item_color = item_color or (lambda k, v: (None, '#F1C40F', None, None))
123
-
124
- def maybe_html_format(v: Any, root_indent: int) -> str | None:
125
- del root_indent
126
- if hasattr(v, '_repr_html_'):
127
- return v._repr_html_() # pylint: disable=protected-access
128
- # Fall back to the default format.
129
- return None
130
-
131
- with (pg.str_format(custom_format=maybe_html_format),
132
- pg.repr_format(custom_format=maybe_html_format)):
133
- for k, v in pg.object_utils.flatten(value).items():
134
- if isinstance(v, pg.Ref):
135
- v = v.value
136
- if hasattr(v, '_repr_html_'):
137
- cs = v._repr_html_() # pylint: disable=protected-access
138
- else:
139
- cs = html.escape(v) if isinstance(v, str) else escape_quoted(str(v))
140
- cs = f'<span style="white-space: pre-wrap">{cs}</span>'
141
-
142
- key_color, key_bg_color, value_color, value_bg_color = item_color(k, v)
143
- key_span = html_round_text(
144
- k,
145
- text_color=key_color,
146
- background_color=key_bg_color,
147
- margin_bottom='0px'
148
- )
149
- value_color_style = f'color: {value_color};' if value_color else ''
150
- value_bg_color_style = (
151
- f'background-color: {value_bg_color};' if value_bg_color else ''
152
- )
153
- s.write(
154
- '<tr>'
155
- '<td style="padding: 5px; vertical-align: top; '
156
- f'border-bottom: 1px solid #EEEEEE">{key_span}</td>'
157
- '<td style="padding: 15px 5px 5px 5px; vertical-align: top; '
158
- 'border-bottom: 1px solid #EEEEEE;'
159
- f'{value_color_style}{value_bg_color_style}">{cs}</td></tr>'
160
- )
161
- s.write('</table></div>')
162
- return s.getvalue()
163
-
164
-
165
- def html_round_text(
166
- text: str,
167
- *,
168
- text_color: str = 'black',
169
- background_color: str = '#EEEEEE',
170
- display: str = 'inline-block',
171
- margin_top: str = '5px',
172
- margin_bottom: str = '5px',
173
- whitespace: str = 'pre-wrap') -> str:
174
- """Renders a HTML span with rounded corners."""
175
- color_style = f'color: {text_color};' if text_color else ''
176
- bg_color_style = (
177
- f'background-color: {background_color};' if background_color else ''
178
- )
179
- return (
180
- f'<span style="{color_style}{bg_color_style}'
181
- f'display:{display}; border-radius:10px; padding:5px; '
182
- f'margin-top: {margin_top}; margin-bottom: {margin_bottom}; '
183
- f'white-space: {whitespace}">{text}</span>'
184
- )
185
-
186
-
187
- def escape_quoted(s: str):
188
- """Escape quoted parts within a string."""
189
- r = io.StringIO()
190
- quote_char = None
191
- quote_start = -1
192
- for i, c in enumerate(s):
193
- if c in ('\'', '"'):
194
- if quote_char is None:
195
- quote_char = c
196
- quote_start = i
197
- elif quote_char == c:
198
- r.write(c)
199
- r.write(html.escape(s[quote_start + 1:i]))
200
- r.write(c)
201
- quote_char = None
202
- elif quote_char is None:
203
- r.write(c)
204
- return r.getvalue()
@@ -1,90 +0,0 @@
1
- # Copyright 2024 The Langfun Authors
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """Tests for langfun.core.repr_utils."""
15
-
16
- import io
17
- import unittest
18
-
19
- from langfun.core import repr_utils
20
- import pyglove as pg
21
-
22
-
23
- class SharingContentTest(unittest.TestCase):
24
-
25
- def test_sharing(self):
26
- s = io.StringIO()
27
-
28
- self.assertTrue(repr_utils.write_maybe_shared(s, '<hr>'))
29
- self.assertTrue(repr_utils.write_maybe_shared(s, '<hr>'))
30
-
31
- with repr_utils.share_parts() as ctx1:
32
- self.assertTrue(repr_utils.write_maybe_shared(s, '<style></style>'))
33
- self.assertFalse(repr_utils.write_maybe_shared(s, '<style></style>'))
34
-
35
- with repr_utils.share_parts() as ctx2:
36
- self.assertIs(ctx2, ctx1)
37
- self.assertFalse(repr_utils.write_maybe_shared(s, '<style></style>'))
38
- self.assertTrue(repr_utils.write_maybe_shared(s, '<style>a</style>'))
39
- self.assertFalse(repr_utils.write_maybe_shared(s, '<style>a</style>'))
40
- self.assertTrue(repr_utils.write_maybe_shared(s, '<style>b</style>'))
41
-
42
- with repr_utils.share_parts() as ctx3:
43
- self.assertIs(ctx3, ctx1)
44
- self.assertFalse(repr_utils.write_maybe_shared(s, '<style></style>'))
45
- self.assertFalse(repr_utils.write_maybe_shared(s, '<style>a</style>'))
46
- self.assertFalse(repr_utils.write_maybe_shared(s, '<style>a</style>'))
47
- self.assertFalse(repr_utils.write_maybe_shared(s, '<style>b</style>'))
48
-
49
- self.assertEqual(
50
- s.getvalue(),
51
- '<hr><hr><style></style><style>a</style><style>b</style>'
52
- )
53
- self.assertEqual(ctx1['<style></style>'], 4)
54
- self.assertEqual(ctx1['<style>b</style>'], 2)
55
- self.assertEqual(ctx1['<style>a</style>'], 4)
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
-
66
- def test_html(self):
67
- html = repr_utils.Html('<div>foo</div>')
68
- self.assertEqual(html.content, '<div>foo</div>')
69
- self.assertEqual(html._repr_html_(), '<div>foo</div>')
70
-
71
- def test_html_repr(self):
72
- class Foo(pg.Object):
73
- x: int
74
-
75
- class Bar(pg.Object):
76
-
77
- def _repr_html_(self):
78
- return '<bar>'
79
-
80
- html = repr_utils.html_repr(
81
- {'foo': pg.Ref(Foo(1)), 'bar': Bar(), 'baz': '<lf_image>'}
82
- )
83
- self.assertIn('foo</span>', html)
84
- self.assertIn('<bar>', html)
85
- self.assertIn('&lt;lf_image&gt;', html)
86
- self.assertNotIn('Ref', html)
87
-
88
-
89
- if __name__ == '__main__':
90
- unittest.main()