langfun 0.1.2.dev202412020805__py3-none-any.whl → 0.1.2.dev202412030804__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.
@@ -13,13 +13,12 @@
13
13
  # limitations under the License.
14
14
  """Tests for Gemini models."""
15
15
 
16
+ import base64
16
17
  import os
17
18
  from typing import Any
18
19
  import unittest
19
20
  from unittest import mock
20
21
 
21
- from google.cloud.aiplatform import models as aiplatform_models
22
- from vertexai import generative_models
23
22
  import langfun.core as lf
24
23
  from langfun.core import modalities as lf_modalities
25
24
  from langfun.core.llms import vertexai
@@ -39,33 +38,6 @@ example_image = (
39
38
  )
40
39
 
41
40
 
42
- def mock_generate_content(content, generation_config, **kwargs):
43
- del kwargs
44
- c = pg.Dict(generation_config.to_dict())
45
- return generative_models.GenerationResponse.from_dict({
46
- 'candidates': [
47
- {
48
- 'index': 0,
49
- 'content': {
50
- 'role': 'model',
51
- 'parts': [
52
- {
53
- 'text': (
54
- f'This is a response to {content[0]} with '
55
- f'temperature={c.temperature}, '
56
- f'top_p={c.top_p}, '
57
- f'top_k={c.top_k}, '
58
- f'max_tokens={c.max_output_tokens}, '
59
- f'stop={"".join(c.stop_sequences)}.'
60
- )
61
- },
62
- ],
63
- },
64
- },
65
- ]
66
- })
67
-
68
-
69
41
  def mock_requests_post(url: str, json: dict[str, Any], **kwargs):
70
42
  del url, kwargs
71
43
  c = pg.Dict(json['generationConfig'])
@@ -100,273 +72,7 @@ def mock_requests_post(url: str, json: dict[str, Any], **kwargs):
100
72
  return response
101
73
 
102
74
 
103
- def mock_endpoint_predict(instances, **kwargs):
104
- del kwargs
105
- assert len(instances) == 1
106
- return aiplatform_models.Prediction(
107
- predictions=[
108
- f"This is a response to {instances[0]['prompt']} with"
109
- f" temperature={instances[0]['temperature']},"
110
- f" top_p={instances[0]['top_p']}, top_k={instances[0]['top_k']},"
111
- f" max_tokens={instances[0]['max_tokens']}."
112
- ],
113
- deployed_model_id='',
114
- )
115
-
116
-
117
75
  class VertexAITest(unittest.TestCase):
118
- """Tests for Vertex model."""
119
-
120
- def test_content_from_message_text_only(self):
121
- text = 'This is a beautiful day'
122
- model = vertexai.VertexAIGeminiPro1Vision()
123
- chunks = model._content_from_message(lf.UserMessage(text))
124
- self.assertEqual(chunks, [text])
125
-
126
- def test_content_from_message_mm(self):
127
- message = lf.UserMessage(
128
- 'This is an <<[[image]]>>, what is it?',
129
- image=lf_modalities.Image.from_bytes(example_image),
130
- )
131
-
132
- # Non-multimodal model.
133
- with self.assertRaisesRegex(lf.ModalityError, 'Unsupported modality'):
134
- vertexai.VertexAIPalm2()._content_from_message(message)
135
-
136
- model = vertexai.VertexAIGeminiPro1Vision()
137
- chunks = model._content_from_message(message)
138
- self.maxDiff = None
139
- self.assertEqual([chunks[0], chunks[2]], ['This is an', ', what is it?'])
140
- self.assertIsInstance(chunks[1], generative_models.Part)
141
-
142
- def test_generation_response_to_message_text_only(self):
143
- response = generative_models.GenerationResponse.from_dict({
144
- 'candidates': [
145
- {
146
- 'index': 0,
147
- 'content': {
148
- 'role': 'model',
149
- 'parts': [
150
- {
151
- 'text': 'hello world',
152
- },
153
- ],
154
- },
155
- },
156
- ],
157
- })
158
- model = vertexai.VertexAIGeminiPro1Vision()
159
- message = model._generation_response_to_message(response)
160
- self.assertEqual(message, lf.AIMessage('hello world'))
161
-
162
- def test_model_hub(self):
163
- with mock.patch(
164
- 'vertexai.generative_models.'
165
- 'GenerativeModel.__init__'
166
- ) as mock_model_init:
167
- mock_model_init.side_effect = lambda *args, **kwargs: None
168
- model = vertexai._VERTEXAI_MODEL_HUB.get_generative_model(
169
- 'gemini-1.0-pro'
170
- )
171
- self.assertIsNotNone(model)
172
- self.assertIs(
173
- vertexai._VERTEXAI_MODEL_HUB.get_generative_model('gemini-1.0-pro'),
174
- model,
175
- )
176
-
177
- with mock.patch(
178
- 'vertexai.language_models.'
179
- 'TextGenerationModel.from_pretrained'
180
- ) as mock_model_init:
181
-
182
- class TextGenerationModel:
183
- pass
184
-
185
- mock_model_init.side_effect = lambda *args, **kw: TextGenerationModel()
186
- model = vertexai._VERTEXAI_MODEL_HUB.get_text_generation_model(
187
- 'text-bison'
188
- )
189
- self.assertIsNotNone(model)
190
- self.assertIs(
191
- vertexai._VERTEXAI_MODEL_HUB.get_text_generation_model('text-bison'),
192
- model,
193
- )
194
-
195
- def test_project_and_location_check(self):
196
- with self.assertRaisesRegex(ValueError, 'Please specify `project`'):
197
- _ = vertexai.VertexAIGeminiPro1Vision()._api_initialized
198
-
199
- with self.assertRaisesRegex(ValueError, 'Please specify `location`'):
200
- _ = vertexai.VertexAIGeminiPro1Vision(project='abc')._api_initialized
201
-
202
- self.assertTrue(
203
- vertexai.VertexAIGeminiPro1Vision(
204
- project='abc', location='us-central1'
205
- )._api_initialized
206
- )
207
-
208
- os.environ['VERTEXAI_PROJECT'] = 'abc'
209
- os.environ['VERTEXAI_LOCATION'] = 'us-central1'
210
- self.assertTrue(vertexai.VertexAIGeminiPro1Vision()._api_initialized)
211
- del os.environ['VERTEXAI_PROJECT']
212
- del os.environ['VERTEXAI_LOCATION']
213
-
214
- def test_generation_config(self):
215
- model = vertexai.VertexAIGeminiPro1Vision()
216
- json_schema = {
217
- 'type': 'object',
218
- 'properties': {
219
- 'name': {'type': 'string'},
220
- },
221
- 'required': ['name'],
222
- 'title': 'Person',
223
- }
224
- config = model._generation_config(
225
- lf.UserMessage('hi', json_schema=json_schema),
226
- lf.LMSamplingOptions(
227
- temperature=2.0,
228
- top_p=1.0,
229
- top_k=20,
230
- max_tokens=1024,
231
- stop=['\n'],
232
- ),
233
- )
234
- actual = config.to_dict()
235
- # There is a discrepancy between the `property_ordering` in the
236
- # Google-internal version and the open-source version.
237
- actual['response_schema'].pop('property_ordering', None)
238
- if pg.KeyPath.parse('response_schema.type_').get(actual):
239
- actual['response_schema']['type'] = actual['response_schema'].pop('type_')
240
- if pg.KeyPath.parse('response_schema.properties.name.type_').get(actual):
241
- actual['response_schema']['properties']['name']['type'] = actual[
242
- 'response_schema']['properties']['name'].pop('type_')
243
-
244
- self.assertEqual(
245
- actual,
246
- dict(
247
- temperature=2.0,
248
- top_p=1.0,
249
- top_k=20.0,
250
- max_output_tokens=1024,
251
- stop_sequences=['\n'],
252
- response_mime_type='application/json',
253
- response_schema={
254
- 'type': 'OBJECT',
255
- 'properties': {
256
- 'name': {'type': 'STRING'}
257
- },
258
- 'required': ['name'],
259
- 'title': 'Person',
260
- }
261
- ),
262
- )
263
- with self.assertRaisesRegex(
264
- ValueError, '`json_schema` must be a dict, got'
265
- ):
266
- model._generation_config(
267
- lf.UserMessage('hi', json_schema='not a dict'),
268
- lf.LMSamplingOptions(),
269
- )
270
-
271
- def test_call_generative_model(self):
272
- with mock.patch(
273
- 'vertexai.generative_models.'
274
- 'GenerativeModel.__init__'
275
- ) as mock_model_init:
276
- mock_model_init.side_effect = lambda *args, **kwargs: None
277
-
278
- with mock.patch(
279
- 'vertexai.generative_models.'
280
- 'GenerativeModel.generate_content'
281
- ) as mock_generate:
282
- mock_generate.side_effect = mock_generate_content
283
-
284
- lm = vertexai.VertexAIGeminiPro1Vision(
285
- project='abc', location='us-central1'
286
- )
287
- self.assertEqual(
288
- lm(
289
- 'hello',
290
- temperature=2.0,
291
- top_p=1.0,
292
- top_k=20,
293
- max_tokens=1024,
294
- stop='\n',
295
- ).text,
296
- (
297
- 'This is a response to hello with temperature=2.0, '
298
- 'top_p=1.0, top_k=20.0, max_tokens=1024, stop=\n.'
299
- ),
300
- )
301
-
302
- def test_call_text_generation_model(self):
303
- with mock.patch(
304
- 'vertexai.language_models.'
305
- 'TextGenerationModel.from_pretrained'
306
- ) as mock_model_init:
307
-
308
- class TextGenerationModel:
309
-
310
- def predict(self, prompt, **kwargs):
311
- c = pg.Dict(kwargs)
312
- return pg.Dict(
313
- text=(
314
- f'This is a response to {prompt} with '
315
- f'temperature={c.temperature}, '
316
- f'top_p={c.top_p}, '
317
- f'top_k={c.top_k}, '
318
- f'max_tokens={c.max_output_tokens}, '
319
- f'stop={"".join(c.stop_sequences)}.'
320
- )
321
- )
322
-
323
- mock_model_init.side_effect = lambda *args, **kw: TextGenerationModel()
324
- lm = vertexai.VertexAIPalm2(project='abc', location='us-central1')
325
- self.assertEqual(
326
- lm(
327
- 'hello',
328
- temperature=2.0,
329
- top_p=1.0,
330
- top_k=20,
331
- max_tokens=1024,
332
- stop='\n',
333
- ).text,
334
- (
335
- 'This is a response to hello with temperature=2.0, '
336
- 'top_p=1.0, top_k=20, max_tokens=1024, stop=\n.'
337
- ),
338
- )
339
-
340
- def test_call_endpoint_model(self):
341
- with mock.patch(
342
- 'google.cloud.aiplatform.models.Endpoint.__init__'
343
- ) as mock_model_init:
344
- mock_model_init.side_effect = lambda *args, **kwargs: None
345
- with mock.patch(
346
- 'google.cloud.aiplatform.models.Endpoint.predict'
347
- ) as mock_model_predict:
348
-
349
- mock_model_predict.side_effect = mock_endpoint_predict
350
- lm = vertexai.VertexAI(
351
- 'custom',
352
- endpoint_name='123',
353
- project='abc',
354
- location='us-central1',
355
- )
356
- self.assertEqual(
357
- lm(
358
- 'hello',
359
- temperature=2.0,
360
- top_p=1.0,
361
- top_k=20,
362
- max_tokens=50,
363
- ),
364
- 'This is a response to hello with temperature=2.0, top_p=1.0,'
365
- ' top_k=20, max_tokens=50.',
366
- )
367
-
368
-
369
- class VertexRestfulAITest(unittest.TestCase):
370
76
  """Tests for Vertex model with REST API."""
371
77
 
372
78
  def test_content_from_message_text_only(self):
@@ -376,9 +82,9 @@ class VertexRestfulAITest(unittest.TestCase):
376
82
  self.assertEqual(chunks, {'role': 'user', 'parts': [{'text': text}]})
377
83
 
378
84
  def test_content_from_message_mm(self):
85
+ image = lf_modalities.Image.from_bytes(example_image)
379
86
  message = lf.UserMessage(
380
- 'This is an <<[[image]]>>, what is it?',
381
- image=lf_modalities.Image.from_bytes(example_image),
87
+ 'This is an <<[[image]]>>, what is it?', image=image
382
88
  )
383
89
 
384
90
  # Non-multimodal model.
@@ -386,46 +92,25 @@ class VertexRestfulAITest(unittest.TestCase):
386
92
  vertexai.VertexAIGeminiPro1()._content_from_message(message)
387
93
 
388
94
  model = vertexai.VertexAIGeminiPro1Vision()
389
- chunks = model._content_from_message(message)
390
- self.maxDiff = None
391
- self.assertEqual([chunks[0], chunks[2]], ['This is an', ', what is it?'])
392
- self.assertIsInstance(chunks[1], generative_models.Part)
393
-
394
- def test_generation_response_to_message_text_only(self):
395
- response = generative_models.GenerationResponse.from_dict({
396
- 'candidates': [
397
- {
398
- 'index': 0,
399
- 'content': {
400
- 'role': 'model',
401
- 'parts': [
402
- {
403
- 'text': 'hello world',
404
- },
405
- ],
95
+ content = model._content_from_message(message)
96
+ self.assertEqual(
97
+ content,
98
+ {
99
+ 'role': 'user',
100
+ 'parts': [
101
+ {'text': 'This is an'},
102
+ {
103
+ 'inlineData': {
104
+ 'data': base64.b64encode(example_image).decode(),
105
+ 'mimeType': 'image/png',
106
+ }
406
107
  },
407
- },
408
- ],
409
- })
410
- model = vertexai.VertexAIGeminiPro1Vision()
411
- message = model._generation_response_to_message(response)
412
- self.assertEqual(message, lf.AIMessage('hello world'))
413
-
414
- def test_model_hub(self):
415
- with mock.patch(
416
- 'vertexai.generative_models.'
417
- 'GenerativeModel.__init__'
418
- ) as mock_model_init:
419
- mock_model_init.side_effect = lambda *args, **kwargs: None
420
- model = vertexai._VERTEXAI_MODEL_HUB.get_generative_model(
421
- 'gemini-1.0-pro'
422
- )
423
- self.assertIsNotNone(model)
424
- self.assertIs(
425
- vertexai._VERTEXAI_MODEL_HUB.get_generative_model('gemini-1.0-pro'),
426
- model,
427
- )
108
+ {'text': ', what is it?'},
109
+ ],
110
+ },
111
+ )
428
112
 
113
+ @mock.patch.object(vertexai.VertexAI, 'credentials', new=True)
429
114
  def test_project_and_location_check(self):
430
115
  with self.assertRaisesRegex(ValueError, 'Please specify `project`'):
431
116
  _ = vertexai.VertexAIGeminiPro1()._api_initialized
@@ -496,6 +181,7 @@ class VertexRestfulAITest(unittest.TestCase):
496
181
  lf.LMSamplingOptions(),
497
182
  )
498
183
 
184
+ @mock.patch.object(vertexai.VertexAI, 'credentials', new=True)
499
185
  def test_call_model(self):
500
186
  with mock.patch('requests.Session.post') as mock_generate:
501
187
  mock_generate.side_effect = mock_requests_post
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langfun
3
- Version: 0.1.2.dev202412020805
3
+ Version: 0.1.2.dev202412030804
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -30,9 +30,7 @@ Requires-Dist: jinja2>=3.1.2; extra == "all"
30
30
  Requires-Dist: requests>=2.31.0; extra == "all"
31
31
  Requires-Dist: termcolor==1.1.0; extra == "all"
32
32
  Requires-Dist: tqdm>=4.64.1; extra == "all"
33
- Requires-Dist: google-cloud-aiplatform>=1.5.0; extra == "all"
34
33
  Requires-Dist: google-generativeai>=0.3.2; extra == "all"
35
- Requires-Dist: openai>=0.27.2; extra == "all"
36
34
  Requires-Dist: python-magic>=0.4.27; extra == "all"
37
35
  Requires-Dist: python-docx>=0.8.11; extra == "all"
38
36
  Requires-Dist: pillow>=10.0.0; extra == "all"
@@ -42,18 +40,11 @@ Provides-Extra: ui
42
40
  Requires-Dist: termcolor==1.1.0; extra == "ui"
43
41
  Requires-Dist: tqdm>=4.64.1; extra == "ui"
44
42
  Provides-Extra: llm
45
- Requires-Dist: google-cloud-aiplatform>=1.5.0; extra == "llm"
46
43
  Requires-Dist: google-generativeai>=0.3.2; extra == "llm"
47
- Requires-Dist: openai>=0.27.2; extra == "llm"
48
44
  Provides-Extra: llm-google
49
- Requires-Dist: google-cloud-aiplatform>=1.5.0; extra == "llm-google"
50
45
  Requires-Dist: google-generativeai>=0.3.2; extra == "llm-google"
51
- Provides-Extra: llm-google-vertex
52
- Requires-Dist: google-cloud-aiplatform>=1.5.0; extra == "llm-google-vertex"
53
46
  Provides-Extra: llm-google-genai
54
47
  Requires-Dist: google-generativeai>=0.3.2; extra == "llm-google-genai"
55
- Provides-Extra: llm-openai
56
- Requires-Dist: openai>=0.27.2; extra == "llm-openai"
57
48
  Provides-Extra: mime
58
49
  Requires-Dist: python-magic>=0.4.27; extra == "mime"
59
50
  Requires-Dist: python-docx>=0.8.11; extra == "mime"
@@ -212,9 +203,7 @@ If you want to customize your installation, you can select specific features usi
212
203
  | all | All Langfun features. |
213
204
  | llm | All supported LLMs. |
214
205
  | llm-google | All supported Google-powered LLMs. |
215
- | llm-google-vertexai | LLMs powered by Google Cloud VertexAI |
216
206
  | llm-google-genai | LLMs powered by Google Generative AI API |
217
- | llm-openai | LLMs powered by OpenAI |
218
207
  | mime | All MIME supports. |
219
208
  | mime-auto | Automatic MIME type detection. |
220
209
  | mime-docx | DocX format support. |
@@ -79,7 +79,7 @@ langfun/core/eval/v2/reporting_test.py,sha256=JxffbUPWInUyLjo-AQVFrllga884Mdfm05
79
79
  langfun/core/eval/v2/runners.py,sha256=zJmu-amUiYv1g0Ek4c3mXkBgp-AFvSF7WpXVZCCf7Y4,14245
80
80
  langfun/core/eval/v2/runners_test.py,sha256=UeiUNygux_U6iGVG18rhp68ZE4hoWeoT6XsXvSjxNQg,11620
81
81
  langfun/core/eval/v2/test_helper.py,sha256=pDpZTBnWRR5xjJv3Uy3NWEzArqlL8FTMOgeR4C53F5M,2348
82
- langfun/core/llms/__init__.py,sha256=5djybv30-27qaVjZY50IkT66UdvLa-2xfGX-vOfeM0I,6573
82
+ langfun/core/llms/__init__.py,sha256=C4hyLflqOQT841nMfclcxcnOhdP83zR0GGW29PnA-vU,6216
83
83
  langfun/core/llms/anthropic.py,sha256=uJXVgaFONL8okOSVQ4VGMGht_VZ30m1hoLzmDbIjmks,13990
84
84
  langfun/core/llms/anthropic_test.py,sha256=-2U4kc_pgBM7wqxu8RuxzyHPGww1EAWqKUvN4PW8Btw,8058
85
85
  langfun/core/llms/compositional.py,sha256=csW_FLlgL-tpeyCOTVvfUQkMa_zCN5Y2I-YbSNuK27U,2872
@@ -92,12 +92,12 @@ langfun/core/llms/groq.py,sha256=dCnR3eAECEKuKKAAj-PDTs8NRHl6CQPdf57m1f6a79U,103
92
92
  langfun/core/llms/groq_test.py,sha256=GYF_Qtq5S1H1TrKH38t6_lkdroqT7v-joYLDKnmS9e0,5274
93
93
  langfun/core/llms/llama_cpp.py,sha256=9tXQntSCDtjTF3bnyJrAPCr4N6wycy5nXYvp9uduygE,2843
94
94
  langfun/core/llms/llama_cpp_test.py,sha256=MWO_qaOeKjRniGjcaWPDScd7HPaIJemqUZoslrt4FPs,1806
95
- langfun/core/llms/openai.py,sha256=_VwOSuDsyXDngUM2iiES0CW1aN0BzMjXNBMegLzm4J4,23209
96
- langfun/core/llms/openai_test.py,sha256=_8cd3VRNEUfE0-Ko1RiM6MlC5hjalRj7nYTJNhG1p3E,18907
95
+ langfun/core/llms/openai.py,sha256=l49v6RubfInvV0iG114AymTKNogTX4u4N-UFCeSgIxw,20963
96
+ langfun/core/llms/openai_test.py,sha256=kOWa1nf-nJvtYY10REUw5wojh3ZgfU8tRaCZ8wUgJbA,16623
97
97
  langfun/core/llms/rest.py,sha256=sWbYUV8S3SuOg9giq7xwD-xDRfaF7NP_ig7bI52-Rj4,3442
98
98
  langfun/core/llms/rest_test.py,sha256=NZ3Nf0XQVpT9kLP5cBVo_yBHLI7vWTYhWQxYEJVMGs4,3472
99
- langfun/core/llms/vertexai.py,sha256=EZhJrdN-SsZVV0KT3NHzaJLVKsNMxCT6M3W6f5fpIWQ,27068
100
- langfun/core/llms/vertexai_test.py,sha256=nGv59yE4xu1zUxqmP_U941QjSBrr_sW15Q2YakuxMv4,16982
99
+ langfun/core/llms/vertexai.py,sha256=48GFuf04NOeInvwHeLhs-iEyxL03VCjtw05BGcKio0s,14172
100
+ langfun/core/llms/vertexai_test.py,sha256=ffcA5yPecnQy_rhkuYAw_6o1iLW8AR8FgswmHt6aAys,6725
101
101
  langfun/core/llms/cache/__init__.py,sha256=QAo3InUMDM_YpteNnVCSejI4zOsnjSMWKJKzkb3VY64,993
102
102
  langfun/core/llms/cache/base.py,sha256=rt3zwmyw0y9jsSGW-ZbV1vAfLxQ7_3AVk0l2EySlse4,3918
103
103
  langfun/core/llms/cache/in_memory.py,sha256=l6b-iU9OTfTRo9Zmg4VrQIuArs4cCJDOpXiEpvNocjo,5004
@@ -148,8 +148,8 @@ langfun/core/templates/demonstration.py,sha256=vCrgYubdZM5Umqcgp8NUVGXgr4P_c-fik
148
148
  langfun/core/templates/demonstration_test.py,sha256=SafcDQ0WgI7pw05EmPI2S4v1t3ABKzup8jReCljHeK4,2162
149
149
  langfun/core/templates/selfplay.py,sha256=yhgrJbiYwq47TgzThmHrDQTF4nDrTI09CWGhuQPNv-s,2273
150
150
  langfun/core/templates/selfplay_test.py,sha256=Ot__1P1M8oJfoTp-M9-PQ6HUXqZKyMwvZ5f7yQ3yfyM,2326
151
- langfun-0.1.2.dev202412020805.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
152
- langfun-0.1.2.dev202412020805.dist-info/METADATA,sha256=c3yjg186RyrDaIHGLMpmXsI7-Kqj4V1vLGxYsjJJN2Y,8890
153
- langfun-0.1.2.dev202412020805.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
154
- langfun-0.1.2.dev202412020805.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
155
- langfun-0.1.2.dev202412020805.dist-info/RECORD,,
151
+ langfun-0.1.2.dev202412030804.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
152
+ langfun-0.1.2.dev202412030804.dist-info/METADATA,sha256=BG5zoGi1sstPc97R4aTE51aiVfa02LLq-BRHRb8R_3Q,8281
153
+ langfun-0.1.2.dev202412030804.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
154
+ langfun-0.1.2.dev202412030804.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
155
+ langfun-0.1.2.dev202412030804.dist-info/RECORD,,