benchling-sdk 1.10.0a2__py3-none-any.whl → 1.10.0a3__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.
@@ -1,44 +1,21 @@
1
1
  from __future__ import annotations
2
2
 
3
- import collections
4
- from typing import Dict, List, Optional, OrderedDict, Protocol, Tuple, TypeVar
5
-
6
- from benchling_api_client.v2.extensions import UnknownType
7
- from ordered_set import OrderedSet
8
-
9
- from benchling_sdk.apps import helpers
10
- from benchling_sdk.apps.config.errors import UnsupportedConfigItemError
11
- from benchling_sdk.apps.config.types import ConfigItemPath, ConfigurationReference
3
+ from typing import Optional
4
+
5
+ from benchling_sdk.apps.config.framework import BenchlingConfigProvider, ConfigItemStore
6
+ from benchling_sdk.apps.status.framework import (
7
+ continue_session_context,
8
+ new_session_context,
9
+ SessionContextEnterHandler,
10
+ SessionContextExitHandler,
11
+ SessionContextManager,
12
+ )
12
13
  from benchling_sdk.benchling import Benchling
13
14
  from benchling_sdk.helpers.logging_helpers import log_stability_warning, StabilityLevel
14
- from benchling_sdk.models import AppConfigItem, ListAppConfigurationItemsSort
15
15
 
16
16
  log_stability_warning(StabilityLevel.ALPHA)
17
17
 
18
18
 
19
- AppType = TypeVar("AppType", bound="App")
20
-
21
-
22
- class ConfigProvider(Protocol):
23
- """
24
- Config provider.
25
-
26
- Provides a list of ConfigurationReference.
27
- """
28
-
29
- def config(self) -> List[ConfigurationReference]:
30
- """Implement to provide a list of configuration items, for instance from Benchling APIs."""
31
- pass
32
-
33
-
34
- class ConfigItemStoreProvider(Protocol):
35
- """Return a config item store."""
36
-
37
- def __call__(self, app_id: str) -> ConfigItemStore:
38
- """Return a config item store."""
39
- pass
40
-
41
-
42
19
  class App:
43
20
  """
44
21
  App.
@@ -88,220 +65,28 @@ class App:
88
65
  return self._config_store
89
66
 
90
67
  def create_session_context(
91
- self: AppType,
68
+ self,
92
69
  name: str,
93
70
  timeout_seconds: int,
94
- context_enter_handler: Optional[helpers.session_helpers.SessionContextEnterHandler[AppType]] = None,
95
- context_exit_handler: Optional[helpers.session_helpers.SessionContextExitHandler[AppType]] = None,
96
- ) -> helpers.session_helpers.SessionContextManager[AppType]:
71
+ context_enter_handler: Optional[SessionContextEnterHandler] = None,
72
+ context_exit_handler: Optional[SessionContextExitHandler] = None,
73
+ ) -> SessionContextManager:
97
74
  """
98
75
  Create Session Context.
99
76
 
100
77
  Create a new app session in Benchling.
101
78
  """
102
- # Avoid circular import + MyPy "is not defined" if using relative like above
103
- from benchling_sdk.apps.helpers.session_helpers import new_session_context
104
-
105
79
  return new_session_context(self, name, timeout_seconds, context_enter_handler, context_exit_handler)
106
80
 
107
81
  def continue_session_context(
108
- self: AppType,
82
+ self,
109
83
  session_id: str,
110
- context_enter_handler: Optional[helpers.session_helpers.SessionContextEnterHandler[AppType]] = None,
111
- context_exit_handler: Optional[helpers.session_helpers.SessionContextExitHandler[AppType]] = None,
112
- ) -> helpers.session_helpers.SessionContextManager[AppType]:
84
+ context_enter_handler: Optional[SessionContextEnterHandler] = None,
85
+ context_exit_handler: Optional[SessionContextExitHandler] = None,
86
+ ) -> SessionContextManager:
113
87
  """
114
88
  Continue Session Context.
115
89
 
116
90
  Fetch an existing app session from Benchling and enter a context with it.
117
91
  """
118
- # Avoid circular import + MyPy "is not defined" if using relative like above
119
- from benchling_sdk.apps.helpers.session_helpers import continue_session_context
120
-
121
92
  return continue_session_context(self, session_id, context_enter_handler, context_exit_handler)
122
-
123
-
124
- class BenchlingConfigProvider(ConfigProvider):
125
- """
126
- Benchling Config provider.
127
-
128
- Provides a BenchlingAppConfiguration retrieved from Benchling's API.
129
- """
130
-
131
- _app_id: str
132
- _benchling: Benchling
133
-
134
- def __init__(self, benchling: Benchling, app_id: str):
135
- """
136
- Initialize Benchling Config Provider.
137
-
138
- :param benchling_provider: A provider for a Benchling instance.
139
- :param tenant_url_provider: A provider for a tenant url.
140
- :param app_id: The app_id from which to retrieve configuration.
141
- """
142
- self._app_id = app_id
143
- self._benchling = benchling
144
-
145
- def config(self) -> List[ConfigurationReference]:
146
- """Provide a Benchling app configuration from Benchling's APIs."""
147
- app_pages = self._benchling.apps.list_app_configuration_items(
148
- app_id=self._app_id,
149
- page_size=100,
150
- sort=ListAppConfigurationItemsSort.CREATEDATASC,
151
- )
152
-
153
- # Eager load all config items for now since we don't yet have a way of lazily querying by path
154
- all_config_pages = list(app_pages)
155
- # Punt on UnknownType for now as apps using manifests with new types + older client could lead to unpredictable results
156
- all_config_items = [
157
- _supported_config_item(config_item) for page in all_config_pages for config_item in page
158
- ]
159
-
160
- return all_config_items
161
-
162
-
163
- class StaticConfigProvider(ConfigProvider):
164
- """
165
- Static Config provider.
166
-
167
- Provides a BenchlingAppConfiguration from a static declaration. Useful for mocking or testing.
168
- """
169
-
170
- _configuration_items: List[ConfigurationReference]
171
-
172
- def __init__(self, configuration_items: List[ConfigurationReference]):
173
- """
174
- Initialize Static Config Provider.
175
-
176
- :param configuration_items: The configuration items to return.
177
- """
178
- self._configuration_items = configuration_items
179
-
180
- def config(self) -> List[ConfigurationReference]:
181
- """Provide Benchling app configuration items from a static reference."""
182
- return self._configuration_items
183
-
184
-
185
- class ConfigItemStore:
186
- """
187
- Dependency Link Store.
188
-
189
- Marshalls an app configuration from the configuration provider into an indexable structure.
190
- Only retrieves app configuration once unless its cache is invalidated.
191
- """
192
-
193
- _configuration_provider: ConfigProvider
194
- _configuration: Optional[List[ConfigurationReference]] = None
195
- _configuration_map: Optional[Dict[ConfigItemPath, ConfigurationReference]] = None
196
- _array_path_row_names: Dict[Tuple[str, ...], OrderedSet[str]] = dict()
197
-
198
- def __init__(self, configuration_provider: ConfigProvider):
199
- """
200
- Initialize Dependency Link Store.
201
-
202
- :param configuration_provider: A ConfigProvider that will be invoked to provide the
203
- underlying config from which to organize dependency links.
204
- """
205
- self._configuration_provider = configuration_provider
206
- self._array_path_row_names = dict()
207
-
208
- @property
209
- def configuration(self) -> List[ConfigurationReference]:
210
- """
211
- Get the underlying configuration.
212
-
213
- Return the raw, stored configuration. Can be used if the provided accessors are inadequate
214
- to find particular configuration items.
215
- """
216
- if not self._configuration:
217
- self._configuration = self._configuration_provider.config()
218
- return self._configuration
219
-
220
- @property
221
- def configuration_path_map(self) -> Dict[ConfigItemPath, ConfigurationReference]:
222
- """
223
- Config links.
224
-
225
- Return a map of configuration item paths to their corresponding configuration items.
226
- """
227
- if not self._configuration_map:
228
- self._configuration_map = {tuple(item.path): item for item in self.configuration}
229
- return self._configuration_map
230
-
231
- def config_by_path(self, path: List[str]) -> Optional[ConfigurationReference]:
232
- """
233
- Config by path.
234
-
235
- Find an app config item by its exact path match, if it exists. Does not search partial paths.
236
- """
237
- # Since we eager load all config now, we know that missing path means it's not configured in Benchling
238
- # Later if we support lazy loading, we'll need to differentiate what's in our cache versus missing
239
- return self.configuration_path_map.get(tuple(path))
240
-
241
- def config_keys_by_path(self, path: List[str]) -> OrderedSet[str]:
242
- """
243
- Config keys by path.
244
-
245
- Find a set of app config keys at the specified path, if any. Does not return keys that are nested
246
- beyond the current level.
247
-
248
- For instance, given paths:
249
- ["One", "Two"]
250
- ["One", "Two", "Three"]
251
- ["One", "Two", "Four"]
252
- ["One", "Two", "Three", "Five"]
253
- ["Zero", "One", "Two", "Three"]
254
-
255
- The expected return from this method when path=["One", "Two"] is a set {"Three", "Four"}.
256
- """
257
- # Convert path to tuple, as list is not hashable for dict keys
258
- path_tuple = tuple(path)
259
- if path_tuple not in self._array_path_row_names:
260
- self._array_path_row_names[path_tuple] = OrderedSet(
261
- [
262
- config_item.path[len(path)]
263
- # Use the list instead of configuration_map to preserve order
264
- for config_item in self.configuration
265
- # The +1 is the name of the array row
266
- if len(config_item.path) >= len(path) + 1
267
- # Ignoring flake8 error E203 because black keeps putting in whitespace padding :
268
- and config_item.path[0 : len(path_tuple)] == path # noqa: E203
269
- and config_item.value is not None
270
- ]
271
- )
272
- return self._array_path_row_names[path_tuple]
273
-
274
- def array_rows_to_dict(self, path: List[str]) -> OrderedDict[str, Dict[str, ConfigurationReference]]:
275
- """Given a path to the root of a config array, return each element as a named dict."""
276
- # TODO BNCH-52772 Improve docstring if we keep this method
277
- array_keys = self.config_keys_by_path(path)
278
- # Although we don't have a way of preserving order when pulling array elements from the API right now
279
- # we should intentionally order these to accommodate a potential ordered future
280
- array_elements_map = collections.OrderedDict()
281
- for key in array_keys:
282
- # Don't care about order for the keys within a row, only the order of the rows themselves
283
- array_elements_map[key] = {
284
- array_element_key: self.config_by_path([*path, key, array_element_key])
285
- for array_element_key in self.config_keys_by_path([*path, key])
286
- if self.config_by_path([*path, key, array_element_key]) is not None
287
- }
288
- # TODO BNCH-52772 MyPy thinks the inner dict values can be None
289
- return array_elements_map # type: ignore
290
-
291
- def invalidate_cache(self) -> None:
292
- """
293
- Invalidate Cache.
294
-
295
- Will force retrieval of configuration from the ConfigProvider the next time the link store is accessed.
296
- """
297
- self._configuration = None
298
- self._configuration_map = None
299
- self._array_path_row_names = dict()
300
-
301
-
302
- def _supported_config_item(config_item: AppConfigItem) -> ConfigurationReference:
303
- if isinstance(config_item, UnknownType):
304
- raise UnsupportedConfigItemError(
305
- f"Unable to read app configuration with unsupported type: {config_item}"
306
- )
307
- return config_item
File without changes
@@ -0,0 +1,82 @@
1
+ from typing import List, Union
2
+
3
+ from benchling_sdk.models import AppSessionMessageCreate, AppSessionMessageStyle
4
+
5
+
6
+ class SessionClosedError(Exception):
7
+ """
8
+ Session Closed Error.
9
+
10
+ A session was inoperable because its status in Benchling was terminal.
11
+ """
12
+
13
+ pass
14
+
15
+
16
+ class SessionContextClosedError(Exception):
17
+ """
18
+ Session Context Closed Error.
19
+
20
+ An operation was attempted using the session context manager after it was closed.
21
+ """
22
+
23
+ pass
24
+
25
+
26
+ class InvalidSessionTimeoutError(Exception):
27
+ """
28
+ Invalid Session Timeout Error.
29
+
30
+ A session's timeout value was set to an invalid value.
31
+ """
32
+
33
+ pass
34
+
35
+
36
+ class MissingAttachedCanvasError(Exception):
37
+ """
38
+ Missing Attached Canvas Error.
39
+
40
+ A canvas operation was requested, but a session context has no attached canvas.
41
+ """
42
+
43
+ pass
44
+
45
+
46
+ class AppUserFacingError(Exception):
47
+ """
48
+ App User Facing Error.
49
+
50
+ Extend this class with custom exceptions you want to be written back to the user as a SessionMessage.
51
+
52
+ SessionClosingContextExitHandler will invoke messages() and write them to a user. Callers choosing to
53
+ write their own SessionContextExitHandler may need to replicate this behavior themselves.
54
+
55
+ This is useful for control flow where an app wants to terminate with an error state that is resolvable
56
+ by the user.
57
+
58
+ For example:
59
+
60
+ class InvalidUserInputError(AppUserFacingError):
61
+ pass
62
+
63
+ raise InvalidUserInputError("Please enter a number between 1 and 10")
64
+
65
+ This would create a message shown to the user like:
66
+
67
+ AppSessionMessageCreate("Please enter a number between 1 and 10", style=AppSessionMessageStyle.ERROR)
68
+ """
69
+
70
+ _messages: List[str]
71
+
72
+ def __init__(self, messages: Union[str, List[str]], *args) -> None:
73
+ """Initialize an AppUserFacingError with one message or a list."""
74
+ self._messages = [messages] if isinstance(messages, str) else messages
75
+ super().__init__(args)
76
+
77
+ def messages(self) -> List[AppSessionMessageCreate]:
78
+ """Create a series of AppSessionMessageCreate to write to a Session and displayed to the user."""
79
+ return [
80
+ AppSessionMessageCreate(content=message, style=AppSessionMessageStyle.ERROR)
81
+ for message in self._messages
82
+ ]
@@ -3,15 +3,21 @@ from __future__ import annotations
3
3
  from abc import ABC, abstractmethod
4
4
  from contextlib import AbstractContextManager
5
5
  from types import TracebackType
6
- from typing import cast, Generic, Iterable, List, Optional, Protocol, Type, Union
6
+ from typing import cast, Iterable, List, Optional, Protocol, Type, TYPE_CHECKING, Union
7
7
 
8
8
  from benchling_api_client.v2.stable.types import Unset, UNSET
9
9
 
10
- from benchling_sdk.apps.framework import AppType
10
+ from benchling_sdk.apps.status.errors import (
11
+ AppUserFacingError,
12
+ InvalidSessionTimeoutError,
13
+ MissingAttachedCanvasError,
14
+ SessionClosedError,
15
+ SessionContextClosedError,
16
+ )
17
+ from benchling_sdk.apps.status.types import _ReferencedSessionLinkType
11
18
  from benchling_sdk.errors import BenchlingError
12
19
  from benchling_sdk.helpers.logging_helpers import log_stability_warning, sdk_logger, StabilityLevel
13
20
  from benchling_sdk.models import (
14
- AaSequence,
15
21
  AppCanvasUpdate,
16
22
  AppSession,
17
23
  AppSessionCreate,
@@ -22,132 +28,16 @@ from benchling_sdk.models import (
22
28
  AppSessionUpdateStatus,
23
29
  BadRequestError,
24
30
  BadRequestErrorBulkError,
25
- Blob,
26
- Box,
27
- Container,
28
- CustomEntity,
29
- DnaOligo,
30
- DnaSequence,
31
- Entry,
32
- Folder,
33
- Location,
34
- Mixture,
35
- Molecule,
36
- Plate,
37
- Request,
38
- RnaOligo,
39
- RnaSequence,
40
- WorkflowOutput,
41
- WorkflowTask,
42
31
  )
43
32
 
44
- # Taken from CHIP_SUPPORTED_COLUMN_TYPES in Benchling server
45
- # Anything we miss, they can still embed the ID themselves in a message
46
- _ReferencedSessionLinkType = Union[
47
- AaSequence,
48
- Blob,
49
- Box,
50
- Container,
51
- CustomEntity,
52
- DnaSequence,
53
- DnaOligo,
54
- Entry,
55
- Folder,
56
- Location,
57
- Mixture,
58
- Plate,
59
- RnaOligo,
60
- Molecule,
61
- RnaSequence,
62
- Request,
63
- WorkflowOutput,
64
- WorkflowTask,
65
- ]
33
+ if TYPE_CHECKING:
34
+ from benchling_sdk.apps.framework import App
66
35
 
67
36
  _DEFAULT_APP_ERROR_MESSAGE = "An unexpected error occurred in the app"
68
37
 
69
38
  log_stability_warning(StabilityLevel.BETA)
70
39
 
71
40
 
72
- class SessionClosedError(Exception):
73
- """
74
- Session Closed Error.
75
-
76
- A session was inoperable because its status in Benchling was terminal.
77
- """
78
-
79
- pass
80
-
81
-
82
- class SessionContextClosedError(Exception):
83
- """
84
- Session Context Closed Error.
85
-
86
- An operation was attempted using the session context manager after it was closed.
87
- """
88
-
89
- pass
90
-
91
-
92
- class InvalidSessionTimeoutError(Exception):
93
- """
94
- Invalid Session Timeout Error.
95
-
96
- A session's timeout value was set to an invalid value.
97
- """
98
-
99
- pass
100
-
101
-
102
- class MissingAttachedCanvasError(Exception):
103
- """
104
- Missing Attached Canvas Error.
105
-
106
- A canvas operation was requested, but a session context has no attached canvas.
107
- """
108
-
109
- pass
110
-
111
-
112
- class AppUserFacingError(Exception):
113
- """
114
- App User Facing Error.
115
-
116
- Extend this class with custom exceptions you want to be written back to the user as a SessionMessage.
117
-
118
- SessionClosingContextExitHandler will invoke messages() and write them to a user. Callers choosing to
119
- write their own SessionContextExitHandler may need to replicate this behavior themselves.
120
-
121
- This is useful for control flow where an app wants to terminate with an error state that is resolvable
122
- by the user.
123
-
124
- For example:
125
-
126
- class InvalidUserInputError(AppUserFacingError):
127
- pass
128
-
129
- raise InvalidUserInputError("Please enter a number between 1 and 10")
130
-
131
- This would create a message shown to the user like:
132
-
133
- AppSessionMessageCreate("Please enter a number between 1 and 10", style=AppSessionMessageStyle.ERROR)
134
- """
135
-
136
- _messages: List[str]
137
-
138
- def __init__(self, messages: Union[str, List[str]], *args) -> None:
139
- """Initialize an AppUserFacingError with one message or a list."""
140
- self._messages = [messages] if isinstance(messages, str) else messages
141
- super().__init__(args)
142
-
143
- def messages(self) -> List[AppSessionMessageCreate]:
144
- """Create a series of AppSessionMessageCreate to write to a Session and displayed to the user."""
145
- return [
146
- AppSessionMessageCreate(content=message, style=AppSessionMessageStyle.ERROR)
147
- for message in self._messages
148
- ]
149
-
150
-
151
41
  class SessionProvider(Protocol):
152
42
  """Provide a Benchling App Session to convey app status."""
153
43
 
@@ -181,7 +71,7 @@ class SessionContextErrorProcessor(ABC):
181
71
  @abstractmethod
182
72
  def process_error(
183
73
  cls,
184
- context: SessionContextManager[AppType],
74
+ context: SessionContextManager,
185
75
  exc_type: Type[BaseException],
186
76
  exc_value: BaseException,
187
77
  exc_traceback: TracebackType,
@@ -220,7 +110,7 @@ class AppUserFacingErrorProcessor(SessionContextErrorProcessor):
220
110
  @classmethod
221
111
  def process_error(
222
112
  cls,
223
- context: SessionContextManager[AppType],
113
+ context: SessionContextManager,
224
114
  exc_type: Type[BaseException],
225
115
  exc_value: BaseException,
226
116
  exc_traceback: TracebackType,
@@ -269,7 +159,7 @@ class BenchlingBadRequestErrorProcessor(AppUserFacingErrorProcessor):
269
159
  @classmethod
270
160
  def process_error(
271
161
  cls,
272
- context: SessionContextManager[AppType],
162
+ context: SessionContextManager,
273
163
  exc_type: Type[BaseException],
274
164
  exc_value: BaseException,
275
165
  exc_traceback: TracebackType,
@@ -318,7 +208,7 @@ class BenchlingBadRequestErrorProcessor(AppUserFacingErrorProcessor):
318
208
  return messages
319
209
 
320
210
 
321
- class SessionContextEnterHandler(ABC, Generic[AppType]):
211
+ class SessionContextEnterHandler(ABC):
322
212
  """
323
213
  Session Context Enter Handler.
324
214
 
@@ -326,12 +216,12 @@ class SessionContextEnterHandler(ABC, Generic[AppType]):
326
216
  """
327
217
 
328
218
  @abstractmethod
329
- def on_enter(self, context: SessionContextManager[AppType]) -> None:
219
+ def on_enter(self, context: SessionContextManager) -> None:
330
220
  """Perform on session context enter after a Session has been started with Benchling."""
331
221
  pass
332
222
 
333
223
 
334
- class SessionContextExitHandler(ABC, Generic[AppType]):
224
+ class SessionContextExitHandler(ABC):
335
225
  """
336
226
  Session Context Exit Handler.
337
227
 
@@ -339,7 +229,7 @@ class SessionContextExitHandler(ABC, Generic[AppType]):
339
229
  """
340
230
 
341
231
  @abstractmethod
342
- def on_success(self, context: SessionContextManager[AppType]) -> bool:
232
+ def on_success(self, context: SessionContextManager) -> bool:
343
233
  """
344
234
  Perform on session context exit when no errors are present.
345
235
 
@@ -354,7 +244,7 @@ class SessionContextExitHandler(ABC, Generic[AppType]):
354
244
  @abstractmethod
355
245
  def on_error(
356
246
  self,
357
- context: SessionContextManager[AppType],
247
+ context: SessionContextManager,
358
248
  exc_type: Type[BaseException],
359
249
  exc_value: BaseException,
360
250
  exc_traceback: TracebackType,
@@ -412,7 +302,7 @@ class SessionClosingContextExitHandler(SessionContextExitHandler):
412
302
  self._error_messages = error_messages
413
303
  self._error_processors = error_processors
414
304
 
415
- def on_success(self, context: SessionContextManager[AppType]) -> bool:
305
+ def on_success(self, context: SessionContextManager) -> bool:
416
306
  """
417
307
  Close Active Session on Success.
418
308
 
@@ -443,7 +333,7 @@ class SessionClosingContextExitHandler(SessionContextExitHandler):
443
333
 
444
334
  def on_error(
445
335
  self,
446
- context: SessionContextManager[AppType],
336
+ context: SessionContextManager,
447
337
  exc_type: Type[BaseException],
448
338
  exc_value: BaseException,
449
339
  exc_traceback: TracebackType,
@@ -497,7 +387,7 @@ class SessionClosingContextExitHandler(SessionContextExitHandler):
497
387
  return None
498
388
 
499
389
 
500
- def create_session_provider(app: AppType, name: str, timeout_seconds: int) -> SessionProvider:
390
+ def create_session_provider(app: App, name: str, timeout_seconds: int) -> SessionProvider:
501
391
  """
502
392
  Create Session Provider.
503
393
 
@@ -512,7 +402,7 @@ def create_session_provider(app: AppType, name: str, timeout_seconds: int) -> Se
512
402
  return _new_session
513
403
 
514
404
 
515
- def existing_session_provider(app: AppType, session_id: str) -> SessionProvider:
405
+ def existing_session_provider(app: App, session_id: str) -> SessionProvider:
516
406
  """
517
407
  Existing Session Provider.
518
408
 
@@ -537,7 +427,7 @@ def _ordered_messages(messages: Iterable[AppSessionMessageCreate]) -> List[AppSe
537
427
  return list(messages)
538
428
 
539
429
 
540
- class SessionContextManager(AbstractContextManager, Generic[AppType]):
430
+ class SessionContextManager(AbstractContextManager):
541
431
  """
542
432
  Manage Benchling App Session.
543
433
 
@@ -546,19 +436,19 @@ class SessionContextManager(AbstractContextManager, Generic[AppType]):
546
436
  success_exit_handler.
547
437
  """
548
438
 
549
- _app: AppType
439
+ _app: App
550
440
  _session_provider: SessionProvider
551
- _context_enter_handler: Optional[SessionContextEnterHandler[AppType]]
552
- _context_exit_handler: SessionContextExitHandler[AppType]
441
+ _context_enter_handler: Optional[SessionContextEnterHandler]
442
+ _context_exit_handler: SessionContextExitHandler
553
443
  _session: Optional[AppSession]
554
444
  _attached_canvas_id: Optional[str]
555
445
 
556
446
  def __init__(
557
447
  self,
558
- app: AppType,
448
+ app: App,
559
449
  session_provider: SessionProvider,
560
- context_enter_handler: Optional[SessionContextEnterHandler[AppType]] = None,
561
- context_exit_handler: Optional[SessionContextExitHandler[AppType]] = None,
450
+ context_enter_handler: Optional[SessionContextEnterHandler] = None,
451
+ context_exit_handler: Optional[SessionContextExitHandler] = None,
562
452
  ):
563
453
  """
564
454
  Initialize SessionContextManager.
@@ -595,7 +485,7 @@ class SessionContextManager(AbstractContextManager, Generic[AppType]):
595
485
  return self._context_exit_handler.on_success(self)
596
486
 
597
487
  @property
598
- def app(self) -> AppType:
488
+ def app(self) -> App:
599
489
  """Return the app for the session."""
600
490
  return self._app
601
491
 
@@ -759,12 +649,12 @@ class SessionContextManager(AbstractContextManager, Generic[AppType]):
759
649
 
760
650
 
761
651
  def new_session_context(
762
- app: AppType,
652
+ app: App,
763
653
  name: str,
764
654
  timeout_seconds: int,
765
655
  context_enter_handler: Optional[SessionContextEnterHandler] = None,
766
656
  context_exit_handler: Optional[SessionContextExitHandler] = None,
767
- ) -> SessionContextManager[AppType]:
657
+ ) -> SessionContextManager:
768
658
  """
769
659
  Create New Session Context.
770
660
 
@@ -779,11 +669,11 @@ def new_session_context(
779
669
 
780
670
 
781
671
  def continue_session_context(
782
- app: AppType,
672
+ app: App,
783
673
  session_id: str,
784
674
  context_enter_handler: Optional[SessionContextEnterHandler] = None,
785
675
  context_exit_handler: Optional[SessionContextExitHandler] = None,
786
- ) -> SessionContextManager[AppType]:
676
+ ) -> SessionContextManager:
787
677
  """
788
678
  Continue Session Context.
789
679