langfun 0.1.2.dev202509250804__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.

langfun/env/interface.py CHANGED
@@ -22,60 +22,6 @@ from typing import Annotated, Any, ContextManager, ClassVar, Iterator, Optional
22
22
 
23
23
  import pyglove as pg
24
24
 
25
- #
26
- # Environemnt identifiers.
27
- #
28
-
29
-
30
- @dataclasses.dataclass(frozen=True)
31
- class EnvironmentId:
32
- """Identifier for an environment."""
33
- environment_id: str
34
-
35
- def __str__(self) -> str:
36
- return self.environment_id
37
-
38
- def working_dir(self, root_dir: str | None) -> str | None:
39
- """Returns the download directory for the service."""
40
- if root_dir is None:
41
- return None
42
- return os.path.join(root_dir, _make_path_compatible(self.environment_id))
43
-
44
- # Enable automatic conversion from str to EnvironmentId.
45
- pg.typing.register_converter(str, EnvironmentId, EnvironmentId)
46
-
47
-
48
- @dataclasses.dataclass(frozen=True)
49
- class SandboxId:
50
- """Identifier for a sandbox."""
51
- environment_id: EnvironmentId
52
- sandbox_id: str
53
-
54
- def __str__(self) -> str:
55
- return f'{self.environment_id}/{self.sandbox_id}'
56
-
57
- def working_dir(self, root_dir: str | None) -> str | None:
58
- """Returns the download directory for the sandbox."""
59
- if root_dir is None:
60
- return None
61
- return os.path.join(
62
- self.environment_id.working_dir(root_dir),
63
- _make_path_compatible(self.sandbox_id)
64
- )
65
-
66
-
67
- def _make_path_compatible(id_str: str) -> str:
68
- """Makes a path compatible with CNS."""
69
- return id_str.translate(
70
- str.maketrans({
71
- '@': '_',
72
- ':': '_',
73
- '#': '_',
74
- ' ': '',
75
- })
76
- )
77
-
78
-
79
25
  #
80
26
  # Environment errors.
81
27
  #
@@ -216,262 +162,6 @@ class SessionTeardownError(SandboxError):
216
162
  not isinstance(e, SandboxStateError) for e in self.errors.values()
217
163
  )
218
164
 
219
-
220
- #
221
- # Event handler.
222
- #
223
-
224
-
225
- class SessionEventHandler:
226
- """Base class for session event handlers."""
227
-
228
- def on_session_start(
229
- self,
230
- environment: 'Environment',
231
- sandbox: 'Sandbox',
232
- session_id: str,
233
- duration: float,
234
- error: BaseException | None
235
- ) -> None:
236
- """Called when a sandbox session starts.
237
-
238
- Args:
239
- environment: The environment.
240
- sandbox: The sandbox.
241
- session_id: The session ID.
242
- duration: The time spent on starting the session.
243
- error: The error that caused the session to start. If None, the session
244
- started normally.
245
- """
246
-
247
- def on_session_end(
248
- self,
249
- environment: 'Environment',
250
- sandbox: 'Sandbox',
251
- session_id: str,
252
- lifetime: float,
253
- error: BaseException | None
254
- ) -> None:
255
- """Called when a sandbox session ends.
256
-
257
- Args:
258
- environment: The environment.
259
- sandbox: The sandbox.
260
- session_id: The session ID.
261
- lifetime: The session lifetime in seconds.
262
- error: The error that caused the session to end. If None, the session
263
- ended normally.
264
- """
265
-
266
-
267
- class FeatureEventHandler:
268
- """Base class for feature event handlers."""
269
-
270
- def on_feature_setup(
271
- self,
272
- environment: 'Environment',
273
- sandbox: 'Sandbox',
274
- feature: 'Feature',
275
- duration: float,
276
- error: BaseException | None
277
- ) -> None:
278
- """Called when a sandbox feature is setup."""
279
-
280
- def on_feature_teardown(
281
- self,
282
- environment: 'Environment',
283
- sandbox: 'Sandbox',
284
- feature: 'Feature',
285
- duration: float,
286
- error: BaseException | None
287
- ) -> None:
288
- """Called when a sandbox feature is teardown."""
289
-
290
- def on_feature_teardown_session(
291
- self,
292
- environment: 'Environment',
293
- sandbox: 'Sandbox',
294
- feature: 'Feature',
295
- session_id: str,
296
- duration: float,
297
- error: BaseException | None
298
- ) -> None:
299
- """Called when a feature is teardown with a session."""
300
-
301
- def on_feature_setup_session(
302
- self,
303
- environment: 'Environment',
304
- sandbox: 'Sandbox',
305
- feature: 'Feature',
306
- session_id: str | None,
307
- duration: float,
308
- error: BaseException | None
309
- ) -> None:
310
- """Called when a feature is setup with a session."""
311
-
312
- def on_feature_housekeep(
313
- self,
314
- environment: 'Environment',
315
- sandbox: 'Sandbox',
316
- feature: 'Feature',
317
- counter: int,
318
- duration: float,
319
- error: BaseException | None
320
- ) -> None:
321
- """Called when a sandbox feature is housekeeping."""
322
-
323
-
324
- class SandboxEventHandler(FeatureEventHandler, SessionEventHandler):
325
- """Base class for sandbox event handlers."""
326
-
327
- def on_sandbox_start(
328
- self,
329
- environment: 'Environment',
330
- sandbox: 'Sandbox',
331
- duration: float,
332
- error: BaseException | None
333
- ) -> None:
334
- """Called when a sandbox is started.
335
-
336
- Args:
337
- environment: The environment.
338
- sandbox: The sandbox.
339
- duration: The time spent on starting the sandbox.
340
- error: The error that caused the sandbox to start. If None, the sandbox
341
- started normally.
342
- """
343
-
344
- def on_sandbox_status_change(
345
- self,
346
- environment: 'Environment',
347
- sandbox: 'Sandbox',
348
- old_status: 'Sandbox.Status',
349
- new_status: 'Sandbox.Status',
350
- span: float,
351
- ) -> None:
352
- """Called when a sandbox status changes.
353
-
354
- Args:
355
- environment: The environment.
356
- sandbox: The sandbox.
357
- old_status: The old sandbox status.
358
- new_status: The new sandbox status.
359
- span: Time spent on the old status in seconds.
360
- """
361
-
362
- def on_sandbox_shutdown(
363
- self,
364
- environment: 'Environment',
365
- sandbox: 'Sandbox',
366
- lifetime: float,
367
- error: BaseException | None
368
- ) -> None:
369
- """Called when a sandbox is shutdown.
370
-
371
- Args:
372
- environment: The environment.
373
- sandbox: The sandbox.
374
- lifetime: The sandbox lifetime in seconds.
375
- error: The error that caused the sandbox to shutdown. If None, the
376
- sandbox shutdown normally.
377
- """
378
-
379
- def on_sandbox_activity(
380
- self,
381
- name: str,
382
- environment: 'Environment',
383
- sandbox: 'Sandbox',
384
- feature: Optional['Feature'],
385
- session_id: str | None,
386
- duration: float,
387
- error: BaseException | None,
388
- **kwargs
389
- ) -> None:
390
- """Called when a sandbox activity is performed.
391
-
392
- Args:
393
- name: The name of the sandbox activity.
394
- environment: The environment.
395
- sandbox: The sandbox.
396
- feature: The feature that is associated with the sandbox activity.
397
- session_id: The session ID.
398
- duration: The sandbox activity duration in seconds.
399
- error: The error that caused the sandbox activity to perform. If None,
400
- the sandbox activity performed normally.
401
- **kwargs: The keyword arguments of the sandbox activity.
402
- """
403
-
404
- def on_sandbox_housekeep(
405
- self,
406
- environment: 'Environment',
407
- sandbox: 'Sandbox',
408
- counter: int,
409
- duration: float,
410
- error: BaseException | None
411
- ) -> None:
412
- """Called when a sandbox finishes a round of housekeeping.
413
-
414
- Args:
415
- environment: The environment.
416
- sandbox: The sandbox.
417
- counter: Zero-based counter of the housekeeping round.
418
- duration: The sandbox housekeeping duration in seconds.
419
- error: The error that caused the sandbox to housekeeping. If None, the
420
- sandbox housekeeping normally.
421
- """
422
-
423
-
424
- class EnvironmentEventHandler(SandboxEventHandler):
425
- """Base class for environment event handlers."""
426
-
427
- def on_environment_start(
428
- self,
429
- environment: 'Environment',
430
- duration: float,
431
- error: BaseException | None
432
- ) -> None:
433
- """Called when the environment is started.
434
-
435
- Args:
436
- environment: The environment.
437
- duration: The environment start duration in seconds.
438
- error: The error that failed the environment start. If None, the
439
- environment started normally.
440
- """
441
-
442
- def on_environment_housekeep(
443
- self,
444
- environment: 'Environment',
445
- counter: int,
446
- duration: float,
447
- error: BaseException | None
448
- ) -> None:
449
- """Called when the environment finishes a round of housekeeping.
450
-
451
- Args:
452
- environment: The environment.
453
- counter: Zero-based counter of the housekeeping round.
454
- duration: The environment start duration in seconds.
455
- error: The error that failed the housekeeping. If None, the
456
- housekeeping succeeded.
457
- """
458
-
459
- def on_environment_shutdown(
460
- self,
461
- environment: 'Environment',
462
- lifetime: float,
463
- error: BaseException | None
464
- ) -> None:
465
- """Called when the environment is shutdown.
466
-
467
- Args:
468
- environment: The environment.
469
- lifetime: The environment lifetime in seconds.
470
- error: The error that caused the environment to shutdown. If None, the
471
- environment shutdown normally.
472
- """
473
-
474
-
475
165
  #
476
166
  # Interface for sandbox-based environment.
477
167
  #
@@ -480,6 +170,20 @@ class EnvironmentEventHandler(SandboxEventHandler):
480
170
  class Environment(pg.Object):
481
171
  """Base class for an environment."""
482
172
 
173
+ @dataclasses.dataclass(frozen=True)
174
+ class Id:
175
+ """Identifier for an environment."""
176
+ environment_id: str
177
+
178
+ def __str__(self) -> str:
179
+ return self.environment_id
180
+
181
+ def working_dir(self, root_dir: str | None) -> str | None:
182
+ """Returns the download directory for the service."""
183
+ if root_dir is None:
184
+ return None
185
+ return os.path.join(root_dir, _make_path_compatible(self.environment_id))
186
+
483
187
  class Status(enum.Enum):
484
188
  """Environment state.
485
189
 
@@ -502,13 +206,6 @@ class Environment(pg.Object):
502
206
  'Features to be exposed by the environment.'
503
207
  ] = {}
504
208
 
505
- event_handlers: Annotated[
506
- list[EnvironmentEventHandler],
507
- (
508
- 'User handler for the environment events.'
509
- )
510
- ] = []
511
-
512
209
  _ENV_STACK: Annotated[
513
210
  ClassVar[list['Environment']],
514
211
  'Recording the environments stacked through context managers.'
@@ -520,7 +217,7 @@ class Environment(pg.Object):
520
217
 
521
218
  @property
522
219
  @abc.abstractmethod
523
- def id(self) -> EnvironmentId:
220
+ def id(self) -> Id:
524
221
  """Returns the identifier for the environment."""
525
222
 
526
223
  @property
@@ -584,6 +281,10 @@ class Environment(pg.Object):
584
281
  Environment._ENV_STACK.pop()
585
282
  self.shutdown()
586
283
 
284
+ def __del__(self):
285
+ """Deletes the environment."""
286
+ self.shutdown()
287
+
587
288
  @classmethod
588
289
  def current(cls) -> Optional['Environment']:
589
290
  """Returns the current environment."""
@@ -624,56 +325,78 @@ class Environment(pg.Object):
624
325
  raise AttributeError(name)
625
326
 
626
327
 
328
+ # Enable automatic conversion from str to Environment.Id.
329
+ pg.typing.register_converter(str, Environment.Id, Environment.Id)
330
+
331
+
627
332
  class Sandbox(pg.Object):
628
333
  """Interface for sandboxes."""
629
334
 
335
+ @dataclasses.dataclass(frozen=True, slots=True)
336
+ class Id:
337
+ """Identifier for a sandbox."""
338
+ environment_id: Environment.Id
339
+ sandbox_id: str
340
+
341
+ def __str__(self) -> str:
342
+ return f'{self.environment_id}/{self.sandbox_id}'
343
+
344
+ def working_dir(self, root_dir: str | None) -> str | None:
345
+ """Returns the download directory for the sandbox."""
346
+ if root_dir is None:
347
+ return None
348
+ return os.path.join(
349
+ self.environment_id.working_dir(root_dir),
350
+ _make_path_compatible(self.sandbox_id)
351
+ )
352
+
630
353
  class Status(enum.Enum):
631
- """Sandbox state.
354
+ r"""Sandbox state.
632
355
 
633
356
  State transitions:
634
357
 
635
- +---------------+ +---------------+
636
- | <OFFLINE> | <------ | SHUTTING_DOWN |
637
- +---------------+ +---------------+
638
- ^ ^
639
- | |
640
- (shutdown)| +------------------------+
641
- | |
642
- +-----------+ (call start) +------------+ |
643
- | <CREATED> | -------------> | SETTING_UP | <----------------+ |
644
- +-----------+ +------------+ | |
645
- | | |
646
- | (start succeeded) | |
647
- | OR (_setup_session) | |
648
- v | |
649
- +---------+ | |
650
- | READY | | |
651
- +---------+ | |
652
- | | |
653
- | (set_acquired) | |
654
- v | |
655
- +----------+ | |
656
- | ACQUIRED | | |
657
- +----------+ | |
658
- | | |
659
- | (call start_session) | |
660
- +------------+ | |
661
- | SETTING_UP |--(failed, call shutdown)-+
662
- +------------+ | |
663
- | | |
664
- v (succeeded) | |
665
- +--------------+ | |
666
- | IN_SESSION | | |
667
- +--------------+ | |
668
- | | |
669
- (call end_session) | |
670
- | | |
671
- v | |
672
- +-----------------+ | |
673
- | EXITING_SESSION |--(succeeded)--+ |
674
- +-----------------+ |
675
- | |
676
- +------(failed, call shutdown)--+
358
+ (sandbox / feature
359
+ +------------+ teardown) +---------------+
360
+ | <OFFLINE> | <--------------------- | SHUTTING_DOWN |
361
+ +------------+ +---------------+
362
+ ^ ^
363
+ / \
364
+ (setup failed) / \
365
+ / \
366
+ +-----------+ (start) +------------+ \
367
+ | <CREATED> | --------> | SETTING_UP | \
368
+ +-----------+ ^ +------------+ \
369
+ / | \
370
+ / | (sandbox / \
371
+ / | feature /session \
372
+ / v setup succeeded) \
373
+ / +---------+ \
374
+ / | READY | \
375
+ / +---------+ \
376
+ / | \
377
+ / | (acquire) \
378
+ / v \
379
+ / +----------+ \
380
+ | | ACQUIRED | \
381
+ | +----------+ |
382
+ | | |
383
+ | | (start_session) |
384
+ | +------------+ |
385
+ | | SETTING_UP |-- (setup failed) ------>+
386
+ | +------------+ |
387
+ | | |
388
+ | v (succeeded) |
389
+ | +--------------+ |
390
+ | | IN_SESSION |- (op failed) -------->+
391
+ | +--------------+ |
392
+ | | |
393
+ | | (end_session) |
394
+ | | |
395
+ | v (session teardown |
396
+ (setup next +-----------------+ failed OR |
397
+ session for <---------| EXITING_SESSION |- non-reusable -----+
398
+ reusable sandbox) +-----------------+ sandbox)
399
+
677
400
  """
678
401
 
679
402
  # The sandbox is created, but not yet started.
@@ -712,7 +435,7 @@ class Sandbox(pg.Object):
712
435
 
713
436
  @property
714
437
  @abc.abstractmethod
715
- def id(self) -> SandboxId:
438
+ def id(self) -> Id:
716
439
  """Returns the identifier for the sandbox."""
717
440
 
718
441
  @property
@@ -735,24 +458,6 @@ class Sandbox(pg.Object):
735
458
  """Returns True if the sandbox is online."""
736
459
  return self.status.is_online
737
460
 
738
- @abc.abstractmethod
739
- def set_acquired(self) -> None:
740
- """Marks the sandbox as acquired."""
741
-
742
- @abc.abstractmethod
743
- def add_event_handler(
744
- self,
745
- event_handler: EnvironmentEventHandler
746
- ) -> None:
747
- """Sets the status of the sandbox."""
748
-
749
- @abc.abstractmethod
750
- def remove_event_handler(
751
- self,
752
- event_handler: EnvironmentEventHandler
753
- ) -> None:
754
- """Removes the status of the sandbox."""
755
-
756
461
  @property
757
462
  @abc.abstractmethod
758
463
  def state_errors(self) -> list[SandboxStateError]:
@@ -970,6 +675,10 @@ class Sandbox(pg.Object):
970
675
  return self.features[name]
971
676
  raise AttributeError(name)
972
677
 
678
+ def __del__(self):
679
+ """Deletes the sandbox."""
680
+ self.shutdown()
681
+
973
682
 
974
683
  class Feature(pg.Object):
975
684
  """Interface for sandbox features."""
@@ -1101,3 +810,17 @@ class Feature(pg.Object):
1101
810
  """Returns the current user session identifier."""
1102
811
  assert self.sandbox is not None
1103
812
  return self.sandbox.session_id
813
+
814
+
815
+ def _make_path_compatible(id_str: str) -> str:
816
+ """Makes a path compatible with CNS."""
817
+ return id_str.translate(
818
+ str.maketrans({
819
+ '@': '_',
820
+ ':': '_',
821
+ '#': '_',
822
+ ' ': '',
823
+ '<': '',
824
+ '>': '',
825
+ })
826
+ )
@@ -18,7 +18,7 @@ from langfun.env import interface
18
18
  class IdTest(unittest.TestCase):
19
19
 
20
20
  def test_environment_id(self):
21
- env_id = interface.EnvironmentId('env@1/a b:c#def')
21
+ env_id = interface.Environment.Id('env@1/a b:c#def')
22
22
  self.assertEqual(str(env_id), 'env@1/a b:c#def')
23
23
  self.assertEqual(
24
24
  env_id.working_dir(root_dir='/tmp'),
@@ -27,8 +27,8 @@ class IdTest(unittest.TestCase):
27
27
  self.assertIsNone(env_id.working_dir(root_dir=None))
28
28
 
29
29
  def test_sandbox_id(self):
30
- sandbox_id = interface.SandboxId(
31
- environment_id=interface.EnvironmentId('env'),
30
+ sandbox_id = interface.Sandbox.Id(
31
+ environment_id=interface.Environment.Id('env'),
32
32
  sandbox_id='sandbox'
33
33
  )
34
34
  self.assertEqual(str(sandbox_id), 'env/sandbox')
@@ -28,9 +28,9 @@ class TestingSandbox(interface.Sandbox):
28
28
  self._session_id = None
29
29
 
30
30
  @property
31
- def id(self) -> interface.SandboxId:
32
- return interface.SandboxId(
33
- environment_id=interface.EnvironmentId('testing-env'),
31
+ def id(self) -> interface.Sandbox.Id:
32
+ return interface.Sandbox.Id(
33
+ environment_id=interface.Environment.Id('testing-env'),
34
34
  sandbox_id=self.sandbox_id
35
35
  )
36
36
 
@@ -52,18 +52,6 @@ class TestingSandbox(interface.Sandbox):
52
52
  def set_acquired(self) -> None:
53
53
  self.set_status(self.Status.ACQUIRED)
54
54
 
55
- def add_event_handler(
56
- self,
57
- event_handler: interface.EnvironmentEventHandler
58
- ) -> None:
59
- pass
60
-
61
- def remove_event_handler(
62
- self,
63
- event_handler: interface.EnvironmentEventHandler
64
- ) -> None:
65
- pass
66
-
67
55
  def start(self) -> None:
68
56
  self.set_alive()
69
57