SQLAlchemy 2.0.47__cp313-cp313t-win32.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.
- sqlalchemy/__init__.py +283 -0
- sqlalchemy/connectors/__init__.py +18 -0
- sqlalchemy/connectors/aioodbc.py +184 -0
- sqlalchemy/connectors/asyncio.py +429 -0
- sqlalchemy/connectors/pyodbc.py +250 -0
- sqlalchemy/cyextension/__init__.py +6 -0
- sqlalchemy/cyextension/collections.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/collections.pyx +409 -0
- sqlalchemy/cyextension/immutabledict.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/immutabledict.pxd +8 -0
- sqlalchemy/cyextension/immutabledict.pyx +133 -0
- sqlalchemy/cyextension/processors.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/processors.pyx +68 -0
- sqlalchemy/cyextension/resultproxy.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/resultproxy.pyx +102 -0
- sqlalchemy/cyextension/util.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/util.pyx +90 -0
- sqlalchemy/dialects/__init__.py +62 -0
- sqlalchemy/dialects/_typing.py +30 -0
- sqlalchemy/dialects/mssql/__init__.py +88 -0
- sqlalchemy/dialects/mssql/aioodbc.py +63 -0
- sqlalchemy/dialects/mssql/base.py +4093 -0
- sqlalchemy/dialects/mssql/information_schema.py +285 -0
- sqlalchemy/dialects/mssql/json.py +129 -0
- sqlalchemy/dialects/mssql/provision.py +185 -0
- sqlalchemy/dialects/mssql/pymssql.py +126 -0
- sqlalchemy/dialects/mssql/pyodbc.py +760 -0
- sqlalchemy/dialects/mysql/__init__.py +104 -0
- sqlalchemy/dialects/mysql/aiomysql.py +250 -0
- sqlalchemy/dialects/mysql/asyncmy.py +231 -0
- sqlalchemy/dialects/mysql/base.py +3949 -0
- sqlalchemy/dialects/mysql/cymysql.py +106 -0
- sqlalchemy/dialects/mysql/dml.py +225 -0
- sqlalchemy/dialects/mysql/enumerated.py +282 -0
- sqlalchemy/dialects/mysql/expression.py +146 -0
- sqlalchemy/dialects/mysql/json.py +91 -0
- sqlalchemy/dialects/mysql/mariadb.py +72 -0
- sqlalchemy/dialects/mysql/mariadbconnector.py +322 -0
- sqlalchemy/dialects/mysql/mysqlconnector.py +302 -0
- sqlalchemy/dialects/mysql/mysqldb.py +314 -0
- sqlalchemy/dialects/mysql/provision.py +153 -0
- sqlalchemy/dialects/mysql/pymysql.py +158 -0
- sqlalchemy/dialects/mysql/pyodbc.py +157 -0
- sqlalchemy/dialects/mysql/reflection.py +727 -0
- sqlalchemy/dialects/mysql/reserved_words.py +570 -0
- sqlalchemy/dialects/mysql/types.py +835 -0
- sqlalchemy/dialects/oracle/__init__.py +81 -0
- sqlalchemy/dialects/oracle/base.py +3802 -0
- sqlalchemy/dialects/oracle/cx_oracle.py +1555 -0
- sqlalchemy/dialects/oracle/dictionary.py +507 -0
- sqlalchemy/dialects/oracle/oracledb.py +941 -0
- sqlalchemy/dialects/oracle/provision.py +297 -0
- sqlalchemy/dialects/oracle/types.py +316 -0
- sqlalchemy/dialects/oracle/vector.py +365 -0
- sqlalchemy/dialects/postgresql/__init__.py +167 -0
- sqlalchemy/dialects/postgresql/_psycopg_common.py +189 -0
- sqlalchemy/dialects/postgresql/array.py +519 -0
- sqlalchemy/dialects/postgresql/asyncpg.py +1284 -0
- sqlalchemy/dialects/postgresql/base.py +5378 -0
- sqlalchemy/dialects/postgresql/dml.py +339 -0
- sqlalchemy/dialects/postgresql/ext.py +540 -0
- sqlalchemy/dialects/postgresql/hstore.py +406 -0
- sqlalchemy/dialects/postgresql/json.py +404 -0
- sqlalchemy/dialects/postgresql/named_types.py +524 -0
- sqlalchemy/dialects/postgresql/operators.py +129 -0
- sqlalchemy/dialects/postgresql/pg8000.py +669 -0
- sqlalchemy/dialects/postgresql/pg_catalog.py +326 -0
- sqlalchemy/dialects/postgresql/provision.py +183 -0
- sqlalchemy/dialects/postgresql/psycopg.py +862 -0
- sqlalchemy/dialects/postgresql/psycopg2.py +892 -0
- sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
- sqlalchemy/dialects/postgresql/ranges.py +1031 -0
- sqlalchemy/dialects/postgresql/types.py +313 -0
- sqlalchemy/dialects/sqlite/__init__.py +57 -0
- sqlalchemy/dialects/sqlite/aiosqlite.py +482 -0
- sqlalchemy/dialects/sqlite/base.py +3056 -0
- sqlalchemy/dialects/sqlite/dml.py +263 -0
- sqlalchemy/dialects/sqlite/json.py +92 -0
- sqlalchemy/dialects/sqlite/provision.py +229 -0
- sqlalchemy/dialects/sqlite/pysqlcipher.py +157 -0
- sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
- sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
- sqlalchemy/engine/__init__.py +62 -0
- sqlalchemy/engine/_py_processors.py +136 -0
- sqlalchemy/engine/_py_row.py +128 -0
- sqlalchemy/engine/_py_util.py +74 -0
- sqlalchemy/engine/base.py +3390 -0
- sqlalchemy/engine/characteristics.py +155 -0
- sqlalchemy/engine/create.py +893 -0
- sqlalchemy/engine/cursor.py +2298 -0
- sqlalchemy/engine/default.py +2394 -0
- sqlalchemy/engine/events.py +965 -0
- sqlalchemy/engine/interfaces.py +3471 -0
- sqlalchemy/engine/mock.py +134 -0
- sqlalchemy/engine/processors.py +61 -0
- sqlalchemy/engine/reflection.py +2102 -0
- sqlalchemy/engine/result.py +2399 -0
- sqlalchemy/engine/row.py +400 -0
- sqlalchemy/engine/strategies.py +16 -0
- sqlalchemy/engine/url.py +924 -0
- sqlalchemy/engine/util.py +167 -0
- sqlalchemy/event/__init__.py +26 -0
- sqlalchemy/event/api.py +220 -0
- sqlalchemy/event/attr.py +676 -0
- sqlalchemy/event/base.py +472 -0
- sqlalchemy/event/legacy.py +258 -0
- sqlalchemy/event/registry.py +390 -0
- sqlalchemy/events.py +17 -0
- sqlalchemy/exc.py +832 -0
- sqlalchemy/ext/__init__.py +11 -0
- sqlalchemy/ext/associationproxy.py +2027 -0
- sqlalchemy/ext/asyncio/__init__.py +25 -0
- sqlalchemy/ext/asyncio/base.py +281 -0
- sqlalchemy/ext/asyncio/engine.py +1471 -0
- sqlalchemy/ext/asyncio/exc.py +21 -0
- sqlalchemy/ext/asyncio/result.py +965 -0
- sqlalchemy/ext/asyncio/scoping.py +1599 -0
- sqlalchemy/ext/asyncio/session.py +1947 -0
- sqlalchemy/ext/automap.py +1701 -0
- sqlalchemy/ext/baked.py +570 -0
- sqlalchemy/ext/compiler.py +600 -0
- sqlalchemy/ext/declarative/__init__.py +65 -0
- sqlalchemy/ext/declarative/extensions.py +564 -0
- sqlalchemy/ext/horizontal_shard.py +478 -0
- sqlalchemy/ext/hybrid.py +1535 -0
- sqlalchemy/ext/indexable.py +364 -0
- sqlalchemy/ext/instrumentation.py +450 -0
- sqlalchemy/ext/mutable.py +1085 -0
- sqlalchemy/ext/mypy/__init__.py +6 -0
- sqlalchemy/ext/mypy/apply.py +324 -0
- sqlalchemy/ext/mypy/decl_class.py +515 -0
- sqlalchemy/ext/mypy/infer.py +590 -0
- sqlalchemy/ext/mypy/names.py +335 -0
- sqlalchemy/ext/mypy/plugin.py +303 -0
- sqlalchemy/ext/mypy/util.py +357 -0
- sqlalchemy/ext/orderinglist.py +439 -0
- sqlalchemy/ext/serializer.py +185 -0
- sqlalchemy/future/__init__.py +16 -0
- sqlalchemy/future/engine.py +15 -0
- sqlalchemy/inspection.py +174 -0
- sqlalchemy/log.py +288 -0
- sqlalchemy/orm/__init__.py +171 -0
- sqlalchemy/orm/_orm_constructors.py +2661 -0
- sqlalchemy/orm/_typing.py +179 -0
- sqlalchemy/orm/attributes.py +2845 -0
- sqlalchemy/orm/base.py +971 -0
- sqlalchemy/orm/bulk_persistence.py +2135 -0
- sqlalchemy/orm/clsregistry.py +571 -0
- sqlalchemy/orm/collections.py +1627 -0
- sqlalchemy/orm/context.py +3334 -0
- sqlalchemy/orm/decl_api.py +2004 -0
- sqlalchemy/orm/decl_base.py +2192 -0
- sqlalchemy/orm/dependency.py +1302 -0
- sqlalchemy/orm/descriptor_props.py +1092 -0
- sqlalchemy/orm/dynamic.py +300 -0
- sqlalchemy/orm/evaluator.py +379 -0
- sqlalchemy/orm/events.py +3252 -0
- sqlalchemy/orm/exc.py +237 -0
- sqlalchemy/orm/identity.py +302 -0
- sqlalchemy/orm/instrumentation.py +754 -0
- sqlalchemy/orm/interfaces.py +1496 -0
- sqlalchemy/orm/loading.py +1686 -0
- sqlalchemy/orm/mapped_collection.py +557 -0
- sqlalchemy/orm/mapper.py +4444 -0
- sqlalchemy/orm/path_registry.py +809 -0
- sqlalchemy/orm/persistence.py +1788 -0
- sqlalchemy/orm/properties.py +935 -0
- sqlalchemy/orm/query.py +3459 -0
- sqlalchemy/orm/relationships.py +3508 -0
- sqlalchemy/orm/scoping.py +2148 -0
- sqlalchemy/orm/session.py +5280 -0
- sqlalchemy/orm/state.py +1168 -0
- sqlalchemy/orm/state_changes.py +196 -0
- sqlalchemy/orm/strategies.py +3470 -0
- sqlalchemy/orm/strategy_options.py +2568 -0
- sqlalchemy/orm/sync.py +164 -0
- sqlalchemy/orm/unitofwork.py +796 -0
- sqlalchemy/orm/util.py +2403 -0
- sqlalchemy/orm/writeonly.py +674 -0
- sqlalchemy/pool/__init__.py +44 -0
- sqlalchemy/pool/base.py +1524 -0
- sqlalchemy/pool/events.py +375 -0
- sqlalchemy/pool/impl.py +588 -0
- sqlalchemy/py.typed +0 -0
- sqlalchemy/schema.py +69 -0
- sqlalchemy/sql/__init__.py +145 -0
- sqlalchemy/sql/_dml_constructors.py +132 -0
- sqlalchemy/sql/_elements_constructors.py +1872 -0
- sqlalchemy/sql/_orm_types.py +20 -0
- sqlalchemy/sql/_py_util.py +75 -0
- sqlalchemy/sql/_selectable_constructors.py +763 -0
- sqlalchemy/sql/_typing.py +482 -0
- sqlalchemy/sql/annotation.py +587 -0
- sqlalchemy/sql/base.py +2293 -0
- sqlalchemy/sql/cache_key.py +1057 -0
- sqlalchemy/sql/coercions.py +1404 -0
- sqlalchemy/sql/compiler.py +8081 -0
- sqlalchemy/sql/crud.py +1752 -0
- sqlalchemy/sql/ddl.py +1444 -0
- sqlalchemy/sql/default_comparator.py +551 -0
- sqlalchemy/sql/dml.py +1850 -0
- sqlalchemy/sql/elements.py +5589 -0
- sqlalchemy/sql/events.py +458 -0
- sqlalchemy/sql/expression.py +159 -0
- sqlalchemy/sql/functions.py +2158 -0
- sqlalchemy/sql/lambdas.py +1442 -0
- sqlalchemy/sql/naming.py +209 -0
- sqlalchemy/sql/operators.py +2623 -0
- sqlalchemy/sql/roles.py +323 -0
- sqlalchemy/sql/schema.py +6222 -0
- sqlalchemy/sql/selectable.py +7265 -0
- sqlalchemy/sql/sqltypes.py +3930 -0
- sqlalchemy/sql/traversals.py +1024 -0
- sqlalchemy/sql/type_api.py +2368 -0
- sqlalchemy/sql/util.py +1485 -0
- sqlalchemy/sql/visitors.py +1164 -0
- sqlalchemy/testing/__init__.py +96 -0
- sqlalchemy/testing/assertions.py +994 -0
- sqlalchemy/testing/assertsql.py +520 -0
- sqlalchemy/testing/asyncio.py +135 -0
- sqlalchemy/testing/config.py +434 -0
- sqlalchemy/testing/engines.py +483 -0
- sqlalchemy/testing/entities.py +117 -0
- sqlalchemy/testing/exclusions.py +476 -0
- sqlalchemy/testing/fixtures/__init__.py +28 -0
- sqlalchemy/testing/fixtures/base.py +384 -0
- sqlalchemy/testing/fixtures/mypy.py +332 -0
- sqlalchemy/testing/fixtures/orm.py +227 -0
- sqlalchemy/testing/fixtures/sql.py +482 -0
- sqlalchemy/testing/pickleable.py +155 -0
- sqlalchemy/testing/plugin/__init__.py +6 -0
- sqlalchemy/testing/plugin/bootstrap.py +51 -0
- sqlalchemy/testing/plugin/plugin_base.py +828 -0
- sqlalchemy/testing/plugin/pytestplugin.py +892 -0
- sqlalchemy/testing/profiling.py +329 -0
- sqlalchemy/testing/provision.py +603 -0
- sqlalchemy/testing/requirements.py +1945 -0
- sqlalchemy/testing/schema.py +198 -0
- sqlalchemy/testing/suite/__init__.py +19 -0
- sqlalchemy/testing/suite/test_cte.py +237 -0
- sqlalchemy/testing/suite/test_ddl.py +389 -0
- sqlalchemy/testing/suite/test_deprecations.py +153 -0
- sqlalchemy/testing/suite/test_dialect.py +776 -0
- sqlalchemy/testing/suite/test_insert.py +630 -0
- sqlalchemy/testing/suite/test_reflection.py +3557 -0
- sqlalchemy/testing/suite/test_results.py +504 -0
- sqlalchemy/testing/suite/test_rowcount.py +258 -0
- sqlalchemy/testing/suite/test_select.py +2010 -0
- sqlalchemy/testing/suite/test_sequence.py +317 -0
- sqlalchemy/testing/suite/test_types.py +2147 -0
- sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
- sqlalchemy/testing/suite/test_update_delete.py +139 -0
- sqlalchemy/testing/util.py +535 -0
- sqlalchemy/testing/warnings.py +52 -0
- sqlalchemy/types.py +74 -0
- sqlalchemy/util/__init__.py +162 -0
- sqlalchemy/util/_collections.py +712 -0
- sqlalchemy/util/_concurrency_py3k.py +288 -0
- sqlalchemy/util/_has_cy.py +40 -0
- sqlalchemy/util/_py_collections.py +541 -0
- sqlalchemy/util/compat.py +421 -0
- sqlalchemy/util/concurrency.py +110 -0
- sqlalchemy/util/deprecations.py +401 -0
- sqlalchemy/util/langhelpers.py +2203 -0
- sqlalchemy/util/preloaded.py +150 -0
- sqlalchemy/util/queue.py +322 -0
- sqlalchemy/util/tool_support.py +201 -0
- sqlalchemy/util/topological.py +120 -0
- sqlalchemy/util/typing.py +734 -0
- sqlalchemy-2.0.47.dist-info/METADATA +243 -0
- sqlalchemy-2.0.47.dist-info/RECORD +274 -0
- sqlalchemy-2.0.47.dist-info/WHEEL +5 -0
- sqlalchemy-2.0.47.dist-info/licenses/LICENSE +19 -0
- sqlalchemy-2.0.47.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# orm/state_changes.py
|
|
2
|
+
# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
|
|
3
|
+
# <see AUTHORS file>
|
|
4
|
+
#
|
|
5
|
+
# This module is part of SQLAlchemy and is released under
|
|
6
|
+
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
|
7
|
+
|
|
8
|
+
"""State tracking utilities used by :class:`_orm.Session`."""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import contextlib
|
|
13
|
+
from enum import Enum
|
|
14
|
+
from typing import Any
|
|
15
|
+
from typing import Callable
|
|
16
|
+
from typing import cast
|
|
17
|
+
from typing import Iterator
|
|
18
|
+
from typing import NoReturn
|
|
19
|
+
from typing import Optional
|
|
20
|
+
from typing import Tuple
|
|
21
|
+
from typing import TypeVar
|
|
22
|
+
from typing import Union
|
|
23
|
+
|
|
24
|
+
from .. import exc as sa_exc
|
|
25
|
+
from .. import util
|
|
26
|
+
from ..util.typing import Literal
|
|
27
|
+
|
|
28
|
+
_F = TypeVar("_F", bound=Callable[..., Any])
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class _StateChangeState(Enum):
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class _StateChangeStates(_StateChangeState):
|
|
36
|
+
ANY = 1
|
|
37
|
+
NO_CHANGE = 2
|
|
38
|
+
CHANGE_IN_PROGRESS = 3
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class _StateChange:
|
|
42
|
+
"""Supplies state assertion decorators.
|
|
43
|
+
|
|
44
|
+
The current use case is for the :class:`_orm.SessionTransaction` class. The
|
|
45
|
+
:class:`_StateChange` class itself is agnostic of the
|
|
46
|
+
:class:`_orm.SessionTransaction` class so could in theory be generalized
|
|
47
|
+
for other systems as well.
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
_next_state: _StateChangeState = _StateChangeStates.ANY
|
|
52
|
+
_state: _StateChangeState = _StateChangeStates.NO_CHANGE
|
|
53
|
+
_current_fn: Optional[Callable[..., Any]] = None
|
|
54
|
+
|
|
55
|
+
def _raise_for_prerequisite_state(
|
|
56
|
+
self, operation_name: str, state: _StateChangeState
|
|
57
|
+
) -> NoReturn:
|
|
58
|
+
raise sa_exc.IllegalStateChangeError(
|
|
59
|
+
f"Can't run operation '{operation_name}()' when Session "
|
|
60
|
+
f"is in state {state!r}",
|
|
61
|
+
code="isce",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def declare_states(
|
|
66
|
+
cls,
|
|
67
|
+
prerequisite_states: Union[
|
|
68
|
+
Literal[_StateChangeStates.ANY], Tuple[_StateChangeState, ...]
|
|
69
|
+
],
|
|
70
|
+
moves_to: _StateChangeState,
|
|
71
|
+
) -> Callable[[_F], _F]:
|
|
72
|
+
"""Method decorator declaring valid states.
|
|
73
|
+
|
|
74
|
+
:param prerequisite_states: sequence of acceptable prerequisite
|
|
75
|
+
states. Can be the single constant _State.ANY to indicate no
|
|
76
|
+
prerequisite state
|
|
77
|
+
|
|
78
|
+
:param moves_to: the expected state at the end of the method, assuming
|
|
79
|
+
no exceptions raised. Can be the constant _State.NO_CHANGE to
|
|
80
|
+
indicate state should not change at the end of the method.
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
assert prerequisite_states, "no prerequisite states sent"
|
|
84
|
+
has_prerequisite_states = (
|
|
85
|
+
prerequisite_states is not _StateChangeStates.ANY
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
prerequisite_state_collection = cast(
|
|
89
|
+
"Tuple[_StateChangeState, ...]", prerequisite_states
|
|
90
|
+
)
|
|
91
|
+
expect_state_change = moves_to is not _StateChangeStates.NO_CHANGE
|
|
92
|
+
|
|
93
|
+
@util.decorator
|
|
94
|
+
def _go(fn: _F, self: Any, *arg: Any, **kw: Any) -> Any:
|
|
95
|
+
current_state = self._state
|
|
96
|
+
|
|
97
|
+
if (
|
|
98
|
+
has_prerequisite_states
|
|
99
|
+
and current_state not in prerequisite_state_collection
|
|
100
|
+
):
|
|
101
|
+
self._raise_for_prerequisite_state(fn.__name__, current_state)
|
|
102
|
+
|
|
103
|
+
next_state = self._next_state
|
|
104
|
+
existing_fn = self._current_fn
|
|
105
|
+
expect_state = moves_to if expect_state_change else current_state
|
|
106
|
+
|
|
107
|
+
if (
|
|
108
|
+
# destination states are restricted
|
|
109
|
+
next_state is not _StateChangeStates.ANY
|
|
110
|
+
# method seeks to change state
|
|
111
|
+
and expect_state_change
|
|
112
|
+
# destination state incorrect
|
|
113
|
+
and next_state is not expect_state
|
|
114
|
+
):
|
|
115
|
+
if existing_fn and next_state in (
|
|
116
|
+
_StateChangeStates.NO_CHANGE,
|
|
117
|
+
_StateChangeStates.CHANGE_IN_PROGRESS,
|
|
118
|
+
):
|
|
119
|
+
raise sa_exc.IllegalStateChangeError(
|
|
120
|
+
f"Method '{fn.__name__}()' can't be called here; "
|
|
121
|
+
f"method '{existing_fn.__name__}()' is already "
|
|
122
|
+
f"in progress and this would cause an unexpected "
|
|
123
|
+
f"state change to {moves_to!r}",
|
|
124
|
+
code="isce",
|
|
125
|
+
)
|
|
126
|
+
else:
|
|
127
|
+
raise sa_exc.IllegalStateChangeError(
|
|
128
|
+
f"Can't run operation '{fn.__name__}()' here; "
|
|
129
|
+
f"will move to state {moves_to!r} where we are "
|
|
130
|
+
f"expecting {next_state!r}",
|
|
131
|
+
code="isce",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
self._current_fn = fn
|
|
135
|
+
self._next_state = _StateChangeStates.CHANGE_IN_PROGRESS
|
|
136
|
+
try:
|
|
137
|
+
ret_value = fn(self, *arg, **kw)
|
|
138
|
+
except:
|
|
139
|
+
raise
|
|
140
|
+
else:
|
|
141
|
+
if self._state is expect_state:
|
|
142
|
+
return ret_value
|
|
143
|
+
|
|
144
|
+
if self._state is current_state:
|
|
145
|
+
raise sa_exc.IllegalStateChangeError(
|
|
146
|
+
f"Method '{fn.__name__}()' failed to "
|
|
147
|
+
"change state "
|
|
148
|
+
f"to {moves_to!r} as expected",
|
|
149
|
+
code="isce",
|
|
150
|
+
)
|
|
151
|
+
elif existing_fn:
|
|
152
|
+
raise sa_exc.IllegalStateChangeError(
|
|
153
|
+
f"While method '{existing_fn.__name__}()' was "
|
|
154
|
+
"running, "
|
|
155
|
+
f"method '{fn.__name__}()' caused an "
|
|
156
|
+
"unexpected "
|
|
157
|
+
f"state change to {self._state!r}",
|
|
158
|
+
code="isce",
|
|
159
|
+
)
|
|
160
|
+
else:
|
|
161
|
+
raise sa_exc.IllegalStateChangeError(
|
|
162
|
+
f"Method '{fn.__name__}()' caused an unexpected "
|
|
163
|
+
f"state change to {self._state!r}",
|
|
164
|
+
code="isce",
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
finally:
|
|
168
|
+
self._next_state = next_state
|
|
169
|
+
self._current_fn = existing_fn
|
|
170
|
+
|
|
171
|
+
return _go
|
|
172
|
+
|
|
173
|
+
@contextlib.contextmanager
|
|
174
|
+
def _expect_state(self, expected: _StateChangeState) -> Iterator[Any]:
|
|
175
|
+
"""called within a method that changes states.
|
|
176
|
+
|
|
177
|
+
method must also use the ``@declare_states()`` decorator.
|
|
178
|
+
|
|
179
|
+
"""
|
|
180
|
+
assert self._next_state is _StateChangeStates.CHANGE_IN_PROGRESS, (
|
|
181
|
+
"Unexpected call to _expect_state outside of "
|
|
182
|
+
"state-changing method"
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
self._next_state = expected
|
|
186
|
+
try:
|
|
187
|
+
yield
|
|
188
|
+
except:
|
|
189
|
+
raise
|
|
190
|
+
else:
|
|
191
|
+
if self._state is not expected:
|
|
192
|
+
raise sa_exc.IllegalStateChangeError(
|
|
193
|
+
f"Unexpected state change to {self._state!r}", code="isce"
|
|
194
|
+
)
|
|
195
|
+
finally:
|
|
196
|
+
self._next_state = _StateChangeStates.CHANGE_IN_PROGRESS
|