langfun 0.1.2.dev202510310805__py3-none-any.whl → 0.1.2.dev202511020804__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/core/eval/v2/runners_test.py +3 -0
- langfun/env/__init__.py +5 -3
- langfun/env/base_environment.py +74 -24
- langfun/env/base_environment_test.py +473 -0
- langfun/env/base_feature.py +77 -15
- langfun/env/base_feature_test.py +228 -0
- langfun/env/base_sandbox.py +40 -124
- langfun/env/{base_test.py → base_sandbox_test.py} +274 -730
- langfun/env/event_handlers/__init__.py +1 -1
- langfun/env/event_handlers/chain.py +233 -0
- langfun/env/event_handlers/chain_test.py +253 -0
- langfun/env/event_handlers/event_logger.py +95 -98
- langfun/env/event_handlers/event_logger_test.py +19 -19
- langfun/env/event_handlers/metric_writer.py +193 -157
- langfun/env/event_handlers/metric_writer_test.py +1 -1
- langfun/env/interface.py +677 -47
- langfun/env/interface_test.py +30 -1
- langfun/env/test_utils.py +111 -82
- {langfun-0.1.2.dev202510310805.dist-info → langfun-0.1.2.dev202511020804.dist-info}/METADATA +1 -1
- {langfun-0.1.2.dev202510310805.dist-info → langfun-0.1.2.dev202511020804.dist-info}/RECORD +23 -20
- langfun/env/event_handlers/base.py +0 -350
- {langfun-0.1.2.dev202510310805.dist-info → langfun-0.1.2.dev202511020804.dist-info}/WHEEL +0 -0
- {langfun-0.1.2.dev202510310805.dist-info → langfun-0.1.2.dev202511020804.dist-info}/licenses/LICENSE +0 -0
- {langfun-0.1.2.dev202510310805.dist-info → langfun-0.1.2.dev202511020804.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,228 @@
|
|
|
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
|
+
import unittest
|
|
15
|
+
|
|
16
|
+
from langfun.env import test_utils
|
|
17
|
+
|
|
18
|
+
TestingEnvironment = test_utils.TestingEnvironment
|
|
19
|
+
TestingNonSandboxBasedFeature = test_utils.TestingNonSandboxBasedFeature
|
|
20
|
+
TestingEventHandler = test_utils.TestingEventHandler
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class NonSandboxBasedFeatureTests(unittest.TestCase):
|
|
24
|
+
|
|
25
|
+
def test_basics(self):
|
|
26
|
+
feature = TestingNonSandboxBasedFeature()
|
|
27
|
+
event_handler = TestingEventHandler(
|
|
28
|
+
log_session_setup=True,
|
|
29
|
+
log_feature_setup=True,
|
|
30
|
+
log_sandbox_status=True
|
|
31
|
+
)
|
|
32
|
+
env = TestingEnvironment(
|
|
33
|
+
image_ids=[],
|
|
34
|
+
features={'test_feature': feature},
|
|
35
|
+
event_handler=event_handler,
|
|
36
|
+
)
|
|
37
|
+
self.assertFalse(env.is_online)
|
|
38
|
+
self.assertEqual(len(list(env.non_sandbox_based_features())), 1)
|
|
39
|
+
with env:
|
|
40
|
+
self.assertTrue(env.is_online)
|
|
41
|
+
with env.test_feature('session1') as feature:
|
|
42
|
+
self.assertIsNone(feature.sandbox)
|
|
43
|
+
self.assertEqual(feature.session_id, 'session1')
|
|
44
|
+
|
|
45
|
+
self.assertEqual(
|
|
46
|
+
event_handler.logs,
|
|
47
|
+
[
|
|
48
|
+
'[testing-env/test_feature] feature setup',
|
|
49
|
+
'[testing-env] environment started',
|
|
50
|
+
'[testing-env/test_feature@session1] feature setup session',
|
|
51
|
+
'[testing-env/test_feature@session1] feature teardown session',
|
|
52
|
+
'[testing-env/test_feature] feature teardown',
|
|
53
|
+
'[testing-env] environment shutdown'
|
|
54
|
+
]
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def test_feature_setup_error(self):
|
|
58
|
+
event_handler = TestingEventHandler(
|
|
59
|
+
log_session_setup=True,
|
|
60
|
+
log_feature_setup=True,
|
|
61
|
+
log_sandbox_status=True
|
|
62
|
+
)
|
|
63
|
+
env = TestingEnvironment(
|
|
64
|
+
image_ids=[],
|
|
65
|
+
features={
|
|
66
|
+
'test_feature': TestingNonSandboxBasedFeature(
|
|
67
|
+
simulate_setup_error=ValueError
|
|
68
|
+
)
|
|
69
|
+
},
|
|
70
|
+
event_handler=event_handler,
|
|
71
|
+
)
|
|
72
|
+
with self.assertRaises(ValueError):
|
|
73
|
+
with env:
|
|
74
|
+
pass
|
|
75
|
+
self.assertEqual(
|
|
76
|
+
event_handler.logs,
|
|
77
|
+
[
|
|
78
|
+
'[testing-env/test_feature] feature setup with ValueError',
|
|
79
|
+
'[testing-env] environment started with ValueError',
|
|
80
|
+
'[testing-env/test_feature] feature teardown',
|
|
81
|
+
'[testing-env] environment shutdown'
|
|
82
|
+
]
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def test_feature_teardown_error(self):
|
|
86
|
+
event_handler = TestingEventHandler(
|
|
87
|
+
log_session_setup=True,
|
|
88
|
+
log_feature_setup=True,
|
|
89
|
+
log_sandbox_status=True
|
|
90
|
+
)
|
|
91
|
+
env = TestingEnvironment(
|
|
92
|
+
image_ids=[],
|
|
93
|
+
features={
|
|
94
|
+
'test_feature': TestingNonSandboxBasedFeature(
|
|
95
|
+
simulate_teardown_error=ValueError
|
|
96
|
+
)
|
|
97
|
+
},
|
|
98
|
+
event_handler=event_handler,
|
|
99
|
+
)
|
|
100
|
+
with env:
|
|
101
|
+
pass
|
|
102
|
+
self.assertEqual(
|
|
103
|
+
event_handler.logs,
|
|
104
|
+
[
|
|
105
|
+
'[testing-env/test_feature] feature setup',
|
|
106
|
+
'[testing-env] environment started',
|
|
107
|
+
'[testing-env/test_feature] feature teardown with ValueError',
|
|
108
|
+
'[testing-env] environment shutdown'
|
|
109
|
+
]
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def test_feature_setup_session_error(self):
|
|
113
|
+
event_handler = TestingEventHandler(
|
|
114
|
+
log_session_setup=True,
|
|
115
|
+
log_feature_setup=True,
|
|
116
|
+
log_sandbox_status=True
|
|
117
|
+
)
|
|
118
|
+
env = TestingEnvironment(
|
|
119
|
+
image_ids=[],
|
|
120
|
+
features={
|
|
121
|
+
'test_feature': TestingNonSandboxBasedFeature(
|
|
122
|
+
simulate_setup_session_error=ValueError
|
|
123
|
+
)
|
|
124
|
+
},
|
|
125
|
+
event_handler=event_handler,
|
|
126
|
+
)
|
|
127
|
+
with env:
|
|
128
|
+
with self.assertRaises(ValueError):
|
|
129
|
+
with env.test_feature('session1'):
|
|
130
|
+
pass
|
|
131
|
+
self.assertEqual(
|
|
132
|
+
event_handler.logs,
|
|
133
|
+
[
|
|
134
|
+
# pylint: disable=line-too-long
|
|
135
|
+
'[testing-env/test_feature] feature setup',
|
|
136
|
+
'[testing-env] environment started',
|
|
137
|
+
'[testing-env/test_feature@session1] feature setup session with ValueError',
|
|
138
|
+
'[testing-env/test_feature@session1] feature teardown session',
|
|
139
|
+
'[testing-env/test_feature] feature teardown',
|
|
140
|
+
'[testing-env] environment shutdown',
|
|
141
|
+
# pylint: enable=line-too-long
|
|
142
|
+
]
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
def test_feature_teardown_session_error(self):
|
|
146
|
+
event_handler = TestingEventHandler(
|
|
147
|
+
log_session_setup=True,
|
|
148
|
+
log_feature_setup=True,
|
|
149
|
+
log_sandbox_status=True
|
|
150
|
+
)
|
|
151
|
+
env = TestingEnvironment(
|
|
152
|
+
image_ids=[],
|
|
153
|
+
features={
|
|
154
|
+
'test_feature': TestingNonSandboxBasedFeature(
|
|
155
|
+
simulate_teardown_session_error=ValueError
|
|
156
|
+
)
|
|
157
|
+
},
|
|
158
|
+
event_handler=event_handler,
|
|
159
|
+
)
|
|
160
|
+
with env:
|
|
161
|
+
with env.test_feature('session1'):
|
|
162
|
+
pass
|
|
163
|
+
self.assertEqual(
|
|
164
|
+
event_handler.logs,
|
|
165
|
+
[
|
|
166
|
+
# pylint: disable=line-too-long
|
|
167
|
+
'[testing-env/test_feature] feature setup',
|
|
168
|
+
'[testing-env] environment started',
|
|
169
|
+
'[testing-env/test_feature@session1] feature setup session',
|
|
170
|
+
'[testing-env/test_feature@session1] feature teardown session with ValueError',
|
|
171
|
+
'[testing-env/test_feature] feature teardown',
|
|
172
|
+
'[testing-env] environment shutdown',
|
|
173
|
+
# pylint: enable=line-too-long
|
|
174
|
+
]
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
def test_feature_housekeeping(self):
|
|
178
|
+
event_handler = TestingEventHandler(
|
|
179
|
+
log_sandbox_status=False,
|
|
180
|
+
log_feature_setup=False,
|
|
181
|
+
log_housekeep=True
|
|
182
|
+
)
|
|
183
|
+
env = TestingEnvironment(
|
|
184
|
+
image_ids=[],
|
|
185
|
+
features={
|
|
186
|
+
'test_feature': TestingNonSandboxBasedFeature(
|
|
187
|
+
housekeep_interval=0.1
|
|
188
|
+
)
|
|
189
|
+
},
|
|
190
|
+
event_handler=event_handler,
|
|
191
|
+
housekeep_interval=0.2
|
|
192
|
+
)
|
|
193
|
+
with env:
|
|
194
|
+
env.wait_for_housekeeping()
|
|
195
|
+
self.assertIn(
|
|
196
|
+
'[testing-env/test_feature] feature housekeeping 0',
|
|
197
|
+
event_handler.logs
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
def test_feature_housekeeping_error(self):
|
|
201
|
+
event_handler = TestingEventHandler(
|
|
202
|
+
log_sandbox_status=False,
|
|
203
|
+
log_feature_setup=False,
|
|
204
|
+
log_housekeep=True
|
|
205
|
+
)
|
|
206
|
+
env = TestingEnvironment(
|
|
207
|
+
image_ids=[],
|
|
208
|
+
features={
|
|
209
|
+
'test_feature': TestingNonSandboxBasedFeature(
|
|
210
|
+
simulate_housekeep_error=ValueError,
|
|
211
|
+
housekeep_interval=0.1
|
|
212
|
+
)
|
|
213
|
+
},
|
|
214
|
+
event_handler=event_handler,
|
|
215
|
+
housekeep_interval=0.2
|
|
216
|
+
)
|
|
217
|
+
with env:
|
|
218
|
+
env.wait_for_housekeeping()
|
|
219
|
+
self.assertFalse(env.is_online)
|
|
220
|
+
self.assertIn(
|
|
221
|
+
'[testing-env/test_feature] feature housekeeping 0 with ValueError',
|
|
222
|
+
event_handler.logs
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
if __name__ == '__main__':
|
|
227
|
+
unittest.main()
|
|
228
|
+
|
langfun/env/base_sandbox.py
CHANGED
|
@@ -29,7 +29,6 @@ import time
|
|
|
29
29
|
from typing import Annotated, Any, Iterator
|
|
30
30
|
|
|
31
31
|
from langfun.env import interface
|
|
32
|
-
from langfun.env.event_handlers import base as event_handler_base
|
|
33
32
|
import pyglove as pg
|
|
34
33
|
|
|
35
34
|
|
|
@@ -198,7 +197,7 @@ class BaseSandbox(interface.Sandbox):
|
|
|
198
197
|
for name, feature in self.environment.features.items()
|
|
199
198
|
if feature.is_applicable(self.image_id)
|
|
200
199
|
})
|
|
201
|
-
self.
|
|
200
|
+
self._event_handler = self.environment.event_handler
|
|
202
201
|
self._enable_pre_session_setup = (
|
|
203
202
|
self.reusable and self.proactive_session_setup
|
|
204
203
|
)
|
|
@@ -247,20 +246,6 @@ class BaseSandbox(interface.Sandbox):
|
|
|
247
246
|
"""Returns the housekeeping counter."""
|
|
248
247
|
return self._housekeep_counter
|
|
249
248
|
|
|
250
|
-
def add_event_handler(
|
|
251
|
-
self,
|
|
252
|
-
event_handler: event_handler_base.EventHandler | None
|
|
253
|
-
) -> None:
|
|
254
|
-
"""Sets the event handler for the sandbox."""
|
|
255
|
-
self._event_handlers.append(event_handler)
|
|
256
|
-
|
|
257
|
-
def remove_event_handler(
|
|
258
|
-
self,
|
|
259
|
-
event_handler: event_handler_base.EventHandler | None
|
|
260
|
-
) -> None:
|
|
261
|
-
"""Removes the event handler for the sandbox."""
|
|
262
|
-
self._event_handlers.remove(event_handler)
|
|
263
|
-
|
|
264
249
|
@property
|
|
265
250
|
def state_errors(self) -> list[interface.SandboxStateError]:
|
|
266
251
|
"""Returns all errors encountered during sandbox lifecycle."""
|
|
@@ -648,7 +633,6 @@ class BaseSandbox(interface.Sandbox):
|
|
|
648
633
|
shutdown_sandbox = True
|
|
649
634
|
|
|
650
635
|
self._session_start_time = None
|
|
651
|
-
self._session_event_handler = None
|
|
652
636
|
|
|
653
637
|
if shutdown_sandbox:
|
|
654
638
|
self.shutdown()
|
|
@@ -664,7 +648,6 @@ class BaseSandbox(interface.Sandbox):
|
|
|
664
648
|
def track_activity(
|
|
665
649
|
self,
|
|
666
650
|
name: str,
|
|
667
|
-
feature: interface.Feature | None = None,
|
|
668
651
|
**kwargs: Any
|
|
669
652
|
) -> Iterator[None]:
|
|
670
653
|
"""Tracks an activity for the sandbox."""
|
|
@@ -678,7 +661,6 @@ class BaseSandbox(interface.Sandbox):
|
|
|
678
661
|
finally:
|
|
679
662
|
self.on_activity(
|
|
680
663
|
name=name,
|
|
681
|
-
feature=feature,
|
|
682
664
|
duration=time.time() - start_time,
|
|
683
665
|
error=error,
|
|
684
666
|
**kwargs
|
|
@@ -771,8 +753,7 @@ class BaseSandbox(interface.Sandbox):
|
|
|
771
753
|
error: BaseException | None = None
|
|
772
754
|
) -> None:
|
|
773
755
|
"""Called when the sandbox is started."""
|
|
774
|
-
|
|
775
|
-
handler.on_sandbox_start(self.environment, self, duration, error)
|
|
756
|
+
self._event_handler.on_sandbox_start(self, duration, error)
|
|
776
757
|
|
|
777
758
|
def on_status_change(
|
|
778
759
|
self,
|
|
@@ -781,14 +762,9 @@ class BaseSandbox(interface.Sandbox):
|
|
|
781
762
|
) -> None:
|
|
782
763
|
"""Called when the sandbox status changes."""
|
|
783
764
|
status_duration = time.time() - self._status_start_time
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
self,
|
|
788
|
-
old_status,
|
|
789
|
-
new_status,
|
|
790
|
-
status_duration
|
|
791
|
-
)
|
|
765
|
+
self._event_handler.on_sandbox_status_change(
|
|
766
|
+
self, old_status, new_status, status_duration
|
|
767
|
+
)
|
|
792
768
|
|
|
793
769
|
def on_shutdown(
|
|
794
770
|
self,
|
|
@@ -796,14 +772,13 @@ class BaseSandbox(interface.Sandbox):
|
|
|
796
772
|
error: BaseException | None = None
|
|
797
773
|
) -> None:
|
|
798
774
|
"""Called when the sandbox is shutdown."""
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
)
|
|
775
|
+
self._event_handler.on_sandbox_shutdown(
|
|
776
|
+
sandbox=self,
|
|
777
|
+
duration=duration,
|
|
778
|
+
lifetime=(0.0 if self._start_time is None
|
|
779
|
+
else (time.time() - self._start_time)),
|
|
780
|
+
error=error
|
|
781
|
+
)
|
|
807
782
|
|
|
808
783
|
def on_housekeep(
|
|
809
784
|
self,
|
|
@@ -812,72 +787,13 @@ class BaseSandbox(interface.Sandbox):
|
|
|
812
787
|
**kwargs
|
|
813
788
|
) -> None:
|
|
814
789
|
"""Called when the sandbox finishes a round of housekeeping."""
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
self,
|
|
823
|
-
feature: interface.Feature,
|
|
824
|
-
duration: float,
|
|
825
|
-
error: BaseException | None = None
|
|
826
|
-
) -> None:
|
|
827
|
-
"""Called when a feature is setup."""
|
|
828
|
-
for handler in self._event_handlers:
|
|
829
|
-
handler.on_feature_setup(
|
|
830
|
-
self.environment, self, feature, duration, error
|
|
831
|
-
)
|
|
832
|
-
|
|
833
|
-
def on_feature_teardown(
|
|
834
|
-
self,
|
|
835
|
-
feature: interface.Feature,
|
|
836
|
-
duration: float,
|
|
837
|
-
error: BaseException | None = None
|
|
838
|
-
) -> None:
|
|
839
|
-
"""Called when a feature is teardown."""
|
|
840
|
-
for handler in self._event_handlers:
|
|
841
|
-
handler.on_feature_teardown(
|
|
842
|
-
self.environment, self, feature, duration, error
|
|
843
|
-
)
|
|
844
|
-
|
|
845
|
-
def on_feature_setup_session(
|
|
846
|
-
self,
|
|
847
|
-
feature: interface.Feature,
|
|
848
|
-
duration: float,
|
|
849
|
-
error: BaseException | None = None
|
|
850
|
-
) -> None:
|
|
851
|
-
"""Called when a feature is setup for a user session."""
|
|
852
|
-
for handler in self._event_handlers:
|
|
853
|
-
handler.on_feature_setup_session(
|
|
854
|
-
self.environment, self, feature, self.session_id, duration, error
|
|
855
|
-
)
|
|
856
|
-
|
|
857
|
-
def on_feature_teardown_session(
|
|
858
|
-
self,
|
|
859
|
-
feature: interface.Feature,
|
|
860
|
-
duration: float,
|
|
861
|
-
error: BaseException | None = None
|
|
862
|
-
) -> None:
|
|
863
|
-
"""Called when a feature is teardown for a user session."""
|
|
864
|
-
for handler in self._event_handlers:
|
|
865
|
-
handler.on_feature_teardown_session(
|
|
866
|
-
self.environment, self, feature, self.session_id, duration, error
|
|
867
|
-
)
|
|
868
|
-
|
|
869
|
-
def on_feature_housekeep(
|
|
870
|
-
self,
|
|
871
|
-
feature: interface.Feature,
|
|
872
|
-
counter: int,
|
|
873
|
-
duration: float,
|
|
874
|
-
error: BaseException | None = None
|
|
875
|
-
) -> None:
|
|
876
|
-
"""Called when a feature is housekeeping."""
|
|
877
|
-
for handler in self._event_handlers:
|
|
878
|
-
handler.on_feature_housekeep(
|
|
879
|
-
self.environment, self, feature, counter, duration, error
|
|
880
|
-
)
|
|
790
|
+
self._event_handler.on_sandbox_housekeep(
|
|
791
|
+
sandbox=self,
|
|
792
|
+
counter=self._housekeep_counter,
|
|
793
|
+
duration=duration,
|
|
794
|
+
error=error,
|
|
795
|
+
**kwargs
|
|
796
|
+
)
|
|
881
797
|
|
|
882
798
|
def on_session_start(
|
|
883
799
|
self,
|
|
@@ -886,31 +802,29 @@ class BaseSandbox(interface.Sandbox):
|
|
|
886
802
|
error: BaseException | None = None
|
|
887
803
|
) -> None:
|
|
888
804
|
"""Called when the user session starts."""
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
805
|
+
self._event_handler.on_sandbox_session_start(
|
|
806
|
+
sandbox=self,
|
|
807
|
+
session_id=session_id,
|
|
808
|
+
duration=duration,
|
|
809
|
+
error=error
|
|
810
|
+
)
|
|
893
811
|
|
|
894
812
|
def on_activity(
|
|
895
813
|
self,
|
|
896
814
|
name: str,
|
|
897
815
|
duration: float,
|
|
898
|
-
feature: interface.Feature | None = None,
|
|
899
816
|
error: BaseException | None = None,
|
|
900
817
|
**kwargs
|
|
901
818
|
) -> None:
|
|
902
819
|
"""Called when a sandbox activity is performed."""
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
error=error,
|
|
912
|
-
**kwargs
|
|
913
|
-
)
|
|
820
|
+
self._event_handler.on_sandbox_activity(
|
|
821
|
+
name=name,
|
|
822
|
+
sandbox=self,
|
|
823
|
+
session_id=self.session_id,
|
|
824
|
+
duration=duration,
|
|
825
|
+
error=error,
|
|
826
|
+
**kwargs
|
|
827
|
+
)
|
|
914
828
|
|
|
915
829
|
def on_session_end(
|
|
916
830
|
self,
|
|
@@ -919,8 +833,10 @@ class BaseSandbox(interface.Sandbox):
|
|
|
919
833
|
error: BaseException | None = None
|
|
920
834
|
) -> None:
|
|
921
835
|
"""Called when the user session ends."""
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
836
|
+
self._event_handler.on_sandbox_session_end(
|
|
837
|
+
sandbox=self,
|
|
838
|
+
session_id=session_id,
|
|
839
|
+
duration=duration,
|
|
840
|
+
lifetime=time.time() - self._session_start_time,
|
|
841
|
+
error=error
|
|
842
|
+
)
|