langfun 0.1.2.dev202509240805__py3-none-any.whl → 0.1.2.dev202509260805__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 langfun might be problematic. Click here for more details.

@@ -0,0 +1,459 @@
1
+ # Copyright 2025 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
+ """Test utils for base environment."""
15
+
16
+ import contextlib
17
+ import time
18
+ from typing import Iterator, Type
19
+
20
+ from langfun.env import base_environment
21
+ from langfun.env import base_feature
22
+ from langfun.env import base_sandbox
23
+ from langfun.env import interface
24
+ from langfun.env.event_handlers import base as event_handler_base
25
+ import pyglove as pg
26
+
27
+
28
+ class TestingEnvironment(base_environment.BaseEnvironment):
29
+ """Testing environment for unit tests."""
30
+
31
+ housekeep_interval: float = 0.0
32
+ simulate_start_error: Type[BaseException] | None = None
33
+ simulate_shutdown_error: Type[BaseException] | None = None
34
+ simulate_ping_error: Type[BaseException] | None = None
35
+ offline: bool = False
36
+
37
+ @property
38
+ def id(self) -> interface.Environment.Id:
39
+ return interface.Environment.Id('testing-env')
40
+
41
+ def wait_for_housekeeping(self):
42
+ housekeep_counter = self.housekeep_counter
43
+ while self.housekeep_counter == housekeep_counter:
44
+ time.sleep(0.01)
45
+
46
+ def _create_sandbox(
47
+ self,
48
+ sandbox_id: str,
49
+ reusable: bool,
50
+ proactive_session_setup: bool,
51
+ keepalive_interval: float | None,
52
+ ) -> base_sandbox.BaseSandbox:
53
+ return TestingSandbox(
54
+ environment=self,
55
+ id=interface.Sandbox.Id(
56
+ environment_id=self.id,
57
+ sandbox_id=sandbox_id
58
+ ),
59
+ reusable=reusable,
60
+ proactive_session_setup=proactive_session_setup,
61
+ keepalive_interval=keepalive_interval,
62
+ simulate_start_error=self.simulate_start_error,
63
+ simulate_shutdown_error=self.simulate_shutdown_error,
64
+ simulate_ping_error=self.simulate_ping_error,
65
+ )
66
+
67
+
68
+ class TestingSandbox(base_sandbox.BaseSandbox):
69
+ """Testing sandbox for unit tests."""
70
+
71
+ simulate_start_error: Type[BaseException] | None = None
72
+ simulate_shutdown_error: Type[BaseException] | None = None
73
+ simulate_ping_error: Type[BaseException] | None = None
74
+
75
+ def _on_bound(self) -> None:
76
+ super()._on_bound()
77
+ self._shell_history = []
78
+ self._ping_history = []
79
+
80
+ def _raise_error(self, message, error_type: Type[BaseException], **kwargs):
81
+ if (error_type is interface.SandboxStateError or
82
+ issubclass(error_type, interface.SandboxStateError)):
83
+ kwargs['sandbox'] = self
84
+ raise error_type(message, **kwargs)
85
+ else:
86
+ raise error_type(message)
87
+
88
+ def wait_until_not(
89
+ self,
90
+ status: interface.Sandbox.Status | tuple[interface.Sandbox.Status, ...]
91
+ ) -> None:
92
+ if not isinstance(status, tuple):
93
+ status = (status,)
94
+ while self.status in status:
95
+ time.sleep(0.01)
96
+
97
+ def wait_until_next_housekeep(self) -> None:
98
+ housekeep_counter = self.housekeep_counter
99
+ while self.housekeep_counter == housekeep_counter:
100
+ time.sleep(0.01)
101
+
102
+ def _start(self) -> None:
103
+ if self.simulate_start_error:
104
+ self._raise_error('Sandbox start error', self.simulate_start_error)
105
+ super()._start()
106
+
107
+ def _shutdown(self) -> None:
108
+ if self.simulate_shutdown_error:
109
+ self._raise_error('Sandbox shutdown error', self.simulate_shutdown_error)
110
+ super()._shutdown()
111
+
112
+ @base_sandbox.sandbox_service(critical_errors=(RuntimeError,))
113
+ def shell(
114
+ self,
115
+ code: str,
116
+ raise_error: Type[BaseException] | None = None,
117
+ ) -> str:
118
+ self._shell_history.append(code)
119
+ if raise_error is not None:
120
+ self._raise_error(f'shell "{code}" failed', raise_error)
121
+ return f'shell "{code}" succeeded'
122
+
123
+ def _ping(self) -> None:
124
+ self._ping_history.append(not self.simulate_ping_error)
125
+ if self.simulate_ping_error:
126
+ self._raise_error('Ping error', self.simulate_ping_error, code='ping')
127
+
128
+
129
+ class TestingFeature(base_feature.BaseFeature):
130
+ """Testing feature for unit tests."""
131
+
132
+ housekeep_interval = 0
133
+ setup_session_delay: float = 0.0
134
+ simulate_housekeep_error: Type[BaseException] | None = None
135
+ simulate_setup_error: Type[BaseException] | None = None
136
+ simulate_teardown_error: Type[BaseException] | None = None
137
+ simulate_setup_session_error: Type[BaseException] | None = None
138
+ simulate_teardown_session_error: Type[BaseException] | None = None
139
+ call_end_session_on_teardown_session: bool = False
140
+
141
+ class Service:
142
+ """Sandbox."""
143
+
144
+ def __init__(self, sandbox: interface.Sandbox):
145
+ self._sandbox = sandbox
146
+
147
+ def do(self, code: str, raise_error: Type[BaseException] | None = None):
148
+ self._sandbox.shell(code, raise_error=raise_error)
149
+
150
+ def _raise_error(self, message, error_type: Type[BaseException], **kwargs):
151
+ self._sandbox._raise_error(message, error_type, **kwargs) # pylint: disable=protected-access
152
+
153
+ def _setup(self) -> None:
154
+ if self.simulate_setup_error:
155
+ self._raise_error(f'{self.name} setup error', self.simulate_setup_error)
156
+ self.sandbox.shell(f'"{self.name}" setup')
157
+
158
+ def _teardown(self) -> None:
159
+ if self.simulate_teardown_error:
160
+ self._raise_error(
161
+ f'{self.name} teardown error', self.simulate_teardown_error
162
+ )
163
+ self.sandbox.shell(f'"{self.name}" teardown')
164
+
165
+ def _setup_session(self) -> None:
166
+ if self.setup_session_delay > 0:
167
+ time.sleep(self.setup_session_delay)
168
+
169
+ if self.simulate_setup_session_error:
170
+ self._raise_error(
171
+ 'Feature session setup error', self.simulate_setup_session_error
172
+ )
173
+ self.sandbox.shell(f'"{self.name}" setup session')
174
+
175
+ def _teardown_session(self) -> None:
176
+ if self.simulate_teardown_session_error:
177
+ self._raise_error(
178
+ 'Feature session teardown error', self.simulate_teardown_session_error
179
+ )
180
+ self.sandbox.shell(f'"{self.name}" teardown session')
181
+ if self.call_end_session_on_teardown_session:
182
+ self.sandbox.end_session()
183
+
184
+ @base_sandbox.sandbox_service()
185
+ def num_shell_calls(self) -> int:
186
+ return len(self.sandbox._shell_history) # pylint: disable=protected-access
187
+
188
+ @base_sandbox.sandbox_service()
189
+ def bad_shell_call(self) -> None:
190
+ self.sandbox.shell('bad command', raise_error=RuntimeError)
191
+
192
+ @base_sandbox.sandbox_service()
193
+ def show_session_id(self):
194
+ return self.session_id
195
+
196
+ @base_sandbox.sandbox_service()
197
+ def call_with_varargs(self, code: str, *args, **kwargs):
198
+ del code, args, kwargs
199
+ return 0
200
+
201
+ def _on_bound(self) -> None:
202
+ super()._on_bound()
203
+ self._service = None
204
+
205
+ @base_sandbox.sandbox_service()
206
+ @contextlib.contextmanager
207
+ def my_service(self) -> Iterator[Service]:
208
+ try:
209
+ self._service = TestingFeature.Service(sandbox=self.sandbox)
210
+ yield self._service
211
+ finally:
212
+ self._service = None
213
+
214
+ def _housekeep(self) -> None:
215
+ if self.simulate_housekeep_error:
216
+ raise interface.SandboxStateError(
217
+ 'House keeping error', sandbox=self.sandbox
218
+ )
219
+
220
+
221
+ class TestingEventHandler(
222
+ pg.Object, event_handler_base.EventHandler
223
+ ):
224
+ """Testing environment event handler for unit tests."""
225
+
226
+ log_sandbox_status: bool = False
227
+ log_feature_setup: bool = True
228
+ log_session_setup: bool = False
229
+ log_housekeep: bool = False
230
+
231
+ def _on_bound(self) -> None:
232
+ super()._on_bound()
233
+ self._logs = []
234
+
235
+ @property
236
+ def logs(self) -> list[str]:
237
+ return self._logs
238
+
239
+ def _add_message(self, message: str, error: BaseException | None) -> None:
240
+ """Adds a message to the history."""
241
+ if error is None:
242
+ self._logs.append(message)
243
+ else:
244
+ self._logs.append(f'{message} with {error.__class__.__name__}')
245
+
246
+ def on_environment_start(
247
+ self,
248
+ environment: interface.Environment,
249
+ duration: float,
250
+ error: BaseException | None
251
+ ) -> None:
252
+ """Called when the environment is started."""
253
+ assert duration > 0
254
+ self._add_message(f'[{environment.id}] environment started', error)
255
+
256
+ def on_environment_housekeep(
257
+ self,
258
+ environment: interface.Environment,
259
+ counter: int,
260
+ duration: float,
261
+ error: BaseException | None
262
+ ) -> None:
263
+ """Called when the environment finishes a round of housekeeping."""
264
+ assert duration > 0
265
+ if self.log_housekeep:
266
+ self._add_message(
267
+ f'[{environment.id}] environment housekeeping {counter}', error
268
+ )
269
+
270
+ def on_environment_shutdown(
271
+ self,
272
+ environment: interface.Environment,
273
+ lifetime: float,
274
+ error: BaseException | None
275
+ ) -> None:
276
+ """Called when the environment is shutdown."""
277
+ assert lifetime is not None
278
+ self._add_message(f'[{environment.id}] environment shutdown', error)
279
+
280
+ def on_sandbox_start(
281
+ self,
282
+ environment: interface.Environment,
283
+ sandbox: interface.Sandbox,
284
+ duration: float,
285
+ error: BaseException | None
286
+ ) -> None:
287
+ assert duration > 0
288
+ self._add_message(f'[{sandbox.id}] sandbox started', error)
289
+
290
+ def on_sandbox_status_change(
291
+ self,
292
+ environment: interface.Environment,
293
+ sandbox: interface.Sandbox,
294
+ old_status: interface.Sandbox.Status,
295
+ new_status: interface.Sandbox.Status,
296
+ span: float
297
+ ) -> None:
298
+ assert span > 0
299
+ if self.log_sandbox_status:
300
+ self._add_message(
301
+ f'[{sandbox.id}] {old_status.value} -> {new_status.value}',
302
+ None,
303
+ )
304
+
305
+ def on_sandbox_shutdown(
306
+ self,
307
+ environment: interface.Environment,
308
+ sandbox: interface.Sandbox,
309
+ lifetime: float,
310
+ error: BaseException | None
311
+ ) -> None:
312
+ assert lifetime is not None
313
+ self._add_message(f'[{sandbox.id}] sandbox shutdown', error)
314
+
315
+ def on_sandbox_housekeep(
316
+ self,
317
+ environment: interface.Environment,
318
+ sandbox: interface.Sandbox,
319
+ counter: int,
320
+ duration: float,
321
+ error: BaseException | None
322
+ ) -> None:
323
+ assert duration > 0
324
+ if self.log_housekeep:
325
+ self._add_message(
326
+ f'[{sandbox.id}] sandbox housekeeping {counter}', error
327
+ )
328
+
329
+ def on_feature_setup(
330
+ self,
331
+ environment: interface.Environment,
332
+ sandbox: interface.Sandbox,
333
+ feature: interface.Feature,
334
+ duration: float,
335
+ error: BaseException | None
336
+ ) -> None:
337
+ """Called when a sandbox feature is setup."""
338
+ assert duration > 0
339
+ if self.log_feature_setup:
340
+ self._add_message(
341
+ f'[{sandbox.id}/{feature.name}] feature setup', error
342
+ )
343
+
344
+ def on_feature_teardown(
345
+ self,
346
+ environment: interface.Environment,
347
+ sandbox: interface.Sandbox,
348
+ feature: interface.Feature,
349
+ duration: float,
350
+ error: BaseException | None
351
+ ) -> None:
352
+ """Called when a sandbox feature is teardown."""
353
+ assert duration > 0
354
+ if self.log_feature_setup:
355
+ self._add_message(
356
+ f'[{sandbox.id}/{feature.name}] feature teardown', error
357
+ )
358
+
359
+ def on_feature_setup_session(
360
+ self,
361
+ environment: interface.Environment,
362
+ sandbox: interface.Sandbox,
363
+ feature: interface.Feature,
364
+ session_id: str | None,
365
+ duration: float,
366
+ error: BaseException | None
367
+ ) -> None:
368
+ """Called when a sandbox feature is setup."""
369
+ assert duration > 0
370
+ if self.log_session_setup:
371
+ self._add_message(
372
+ f'[{sandbox.id}/{feature.name}] feature setup session', error
373
+ )
374
+
375
+ def on_feature_teardown_session(
376
+ self,
377
+ environment: interface.Environment,
378
+ sandbox: interface.Sandbox,
379
+ feature: interface.Feature,
380
+ session_id: str,
381
+ duration: float,
382
+ error: BaseException | None
383
+ ) -> None:
384
+ """Called when a sandbox feature is teardown."""
385
+ assert duration > 0
386
+ if self.log_session_setup:
387
+ self._add_message(
388
+ f'[{sandbox.id}/{feature.name}] feature teardown session', error
389
+ )
390
+
391
+ def on_feature_housekeep(
392
+ self,
393
+ environment: interface.Environment,
394
+ sandbox: interface.Sandbox,
395
+ feature: interface.Feature,
396
+ counter: int,
397
+ duration: float,
398
+ error: BaseException | None
399
+ ) -> None:
400
+ """Called when a sandbox feature is housekeeping."""
401
+ assert duration > 0
402
+ if self.log_housekeep:
403
+ self._add_message(
404
+ f'[{sandbox.id}/{feature.name}] feature housekeeping {counter}', error
405
+ )
406
+
407
+ def on_session_start(
408
+ self,
409
+ environment: interface.Environment,
410
+ sandbox: interface.Sandbox,
411
+ session_id: str,
412
+ duration: float,
413
+ error: BaseException | None
414
+ ) -> None:
415
+ """Called when a sandbox session starts."""
416
+ assert duration > 0
417
+ self._add_message(
418
+ f'[{sandbox.id}] session {session_id!r} started', error
419
+ )
420
+
421
+ def on_session_end(
422
+ self,
423
+ environment: interface.Environment,
424
+ sandbox: interface.Sandbox,
425
+ session_id: str,
426
+ lifetime: float,
427
+ error: BaseException | None
428
+ ) -> None:
429
+ """Called when a sandbox session ends."""
430
+ assert lifetime > 0
431
+ self._add_message(
432
+ f'[{sandbox.id}] session {session_id!r} ended', error
433
+ )
434
+
435
+ def on_sandbox_activity(
436
+ self,
437
+ name: str,
438
+ environment: interface.Environment,
439
+ sandbox: interface.Sandbox,
440
+ feature: interface.Feature | None,
441
+ session_id: str | None,
442
+ duration: float,
443
+ error: BaseException | None,
444
+ *,
445
+ code: str | None = None,
446
+ **kwargs
447
+ ) -> None:
448
+ """Called when a sandbox activity is performed."""
449
+ del environment, kwargs
450
+ if session_id is None:
451
+ log_id = sandbox.id
452
+ else:
453
+ log_id = f'{sandbox.id}/{session_id}'
454
+
455
+ if feature is not None:
456
+ log_id = f'{log_id}/{feature.name}'
457
+ self._add_message(
458
+ f'[{log_id}] {name}: {code}', error
459
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langfun
3
- Version: 0.1.2.dev202509240805
3
+ Version: 0.1.2.dev202509260805
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -165,17 +165,22 @@ langfun/core/templates/demonstration.py,sha256=vCrgYubdZM5Umqcgp8NUVGXgr4P_c-fik
165
165
  langfun/core/templates/demonstration_test.py,sha256=SafcDQ0WgI7pw05EmPI2S4v1t3ABKzup8jReCljHeK4,2162
166
166
  langfun/core/templates/selfplay.py,sha256=yhgrJbiYwq47TgzThmHrDQTF4nDrTI09CWGhuQPNv-s,2273
167
167
  langfun/core/templates/selfplay_test.py,sha256=Ot__1P1M8oJfoTp-M9-PQ6HUXqZKyMwvZ5f7yQ3yfyM,2326
168
- langfun/env/__init__.py,sha256=WOht-DaYtVmO8U-viQbWmCUCCPcJwBELBiQYUfGAG5w,1532
169
- langfun/env/base_environment.py,sha256=73d6hs2XhJd2IK--H7Pfs-1PG5TfJ89x_yk94doq0G0,16465
170
- langfun/env/base_feature.py,sha256=lphS2GmwCYR-ypPGIzn0KcLzxUcO2l9R2ZbJqcqOkOI,5794
171
- langfun/env/base_sandbox.py,sha256=c-HskeubKOH-P2ZrQG3HFKkhtX3ZADYj4QIMemQNGbo,32202
172
- langfun/env/base_test.py,sha256=CIzZjfSkZEDsHARF4aoOZfq5T8DN8i8AW-swFsFw0Gk,60328
173
- langfun/env/interface.py,sha256=wOu_yQO8uEt5lU88FeqqaInBLg7WgYYtVeGtPsanE90,29031
174
- langfun/env/interface_test.py,sha256=nrqFLtpHd0vnOjoIX9cjV5WD1c-7J3WW29aogNu_94A,1395
168
+ langfun/env/__init__.py,sha256=m6Y8y16ms9lytvO_r-Br8HmTp2rNDhb3R6JJaH5dEEk,1491
169
+ langfun/env/base_environment.py,sha256=Vjpmck3k3UE3KaHq69dIuGbevbRJFlY6PvQEeZ18MtY,18087
170
+ langfun/env/base_feature.py,sha256=dztFq1lcdXgUh3m8pNRC3vruyIdHCob27reiXz_02q8,6436
171
+ langfun/env/base_sandbox.py,sha256=tR__USJZojDrGtnhmDqkbCHrvcrNUDrTwc9mpStyYZ0,36721
172
+ langfun/env/base_test.py,sha256=cBZEcoJG16L_XLVyTgSCxUxy1cukrkpSNNEgiM5LZb4,59137
173
+ langfun/env/interface.py,sha256=2Amf-_op7dGRF8c4-wYxcFxs1UCBYz1AB20Lk7__V4E,25724
174
+ langfun/env/interface_test.py,sha256=hfQn4RRTEo1YfVHXTPzH1puzD14BTo8R_5v1IpXVZ90,1398
175
175
  langfun/env/load_balancers.py,sha256=qRhCthqzjZIQBwta8qC1C0s0J-VQAVomJQqI7Nqv-r4,1948
176
- langfun/env/load_balancers_test.py,sha256=gJKJ3K5_WS7hsz9Jv3nPEjlb04Z6MmrZpfCu86siYKU,3967
177
- langfun-0.1.2.dev202509240805.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
178
- langfun-0.1.2.dev202509240805.dist-info/METADATA,sha256=r1KTHcsTEVX6kFjs88_yhZ3xY-k0urqHENZadNUnyi8,7380
179
- langfun-0.1.2.dev202509240805.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
180
- langfun-0.1.2.dev202509240805.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
181
- langfun-0.1.2.dev202509240805.dist-info/RECORD,,
176
+ langfun/env/load_balancers_test.py,sha256=KIDIwZeQHcW0fCL5ScZD0lm0QV4_X2y-rMqdd6R1gLc,3737
177
+ langfun/env/test_utils.py,sha256=Cx4J69r_dLcmDyzEVqOzAZ1Gtk5CnbM2K6nSnRHzIAc,13874
178
+ langfun/env/event_handlers/__init__.py,sha256=sZTUeYpnUMzfH6AghhT-hnBHnFxg5UaH-AOmw3YbyMM,376
179
+ langfun/env/event_handlers/base.py,sha256=w2pdAKfGL-TDTQD2lQ-c_BD3jWeAXF5SYBkAj2GNRz0,7532
180
+ langfun/env/event_handlers/event_logger.py,sha256=4jDV6siGRXR95QFJj_9rnQ_BYMaR6IaPb-wuZ7YzCls,11200
181
+ langfun/env/event_handlers/event_logger_test.py,sha256=OpObIB9IXuuNaRFxOuYcmV4RV6sUTbH5zr3-R7B5UGQ,8536
182
+ langfun-0.1.2.dev202509260805.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
183
+ langfun-0.1.2.dev202509260805.dist-info/METADATA,sha256=Tee4run8k20LEd7W2ZXxM6E_TzH4g6GFQF-ude-fhS4,7380
184
+ langfun-0.1.2.dev202509260805.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
185
+ langfun-0.1.2.dev202509260805.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
186
+ langfun-0.1.2.dev202509260805.dist-info/RECORD,,