MCPcopy Create free account
hub / github.com/sqlalchemy/sqlalchemy / PyWrapper

Class PyWrapper

lib/sqlalchemy/sql/lambdas.py:1277–1436  ·  view source on GitHub ↗

A wrapper object that is injected into the ``__globals__`` and ``__closure__`` of a Python function. When the function is instrumented with :class:`.PyWrapper` objects, it is then invoked just once in order to set up the wrappers. We look through all the :class:`.PyWrapper` objects

Source from the content-addressed store, hash-verified

1275
1276
1277class PyWrapper(ColumnOperators):
1278 """A wrapper object that is injected into the ``__globals__`` and
1279 ``__closure__`` of a Python function.
1280
1281 When the function is instrumented with :class:`.PyWrapper` objects, it is
1282 then invoked just once in order to set up the wrappers. We look through
1283 all the :class:`.PyWrapper` objects we made to find the ones that generated
1284 a :class:`.BindParameter` object, e.g. the expression system interpreted
1285 something as a literal. Those positions in the globals/closure are then
1286 ones that we will look at, each time a new lambda comes in that refers to
1287 the same ``__code__`` object. In this way, we keep a single version of
1288 the SQL expression that this lambda produced, without calling upon the
1289 Python function that created it more than once, unless its other closure
1290 variables have changed. The expression is then transformed to have the
1291 new bound values embedded into it.
1292
1293 """
1294
1295 def __init__(
1296 self,
1297 fn,
1298 name,
1299 to_evaluate,
1300 closure_index=None,
1301 getter=None,
1302 track_bound_values=True,
1303 ):
1304 self.fn = fn
1305 self._name = name
1306 self._to_evaluate = to_evaluate
1307 self._param = None
1308 self._has_param = False
1309 self._bind_paths = {}
1310 self._getter = getter
1311 self._closure_index = closure_index
1312 self.track_bound_values = track_bound_values
1313
1314 def __call__(self, *arg, **kw):
1315 elem = object.__getattribute__(self, "_to_evaluate")
1316 value = elem(*arg, **kw)
1317 if (
1318 self._sa_track_bound_values
1319 and coercions._deep_is_literal(value)
1320 and not isinstance(
1321 # TODO: coverage where an ORM option or similar is here
1322 value,
1323 _cache_key.HasCacheKey,
1324 )
1325 ):
1326 name = object.__getattribute__(self, "_name")
1327 raise exc.InvalidRequestError(
1328 "Can't invoke Python callable %s() inside of lambda "
1329 "expression argument at %s; lambda SQL constructs should "
1330 "not invoke functions from closure variables to produce "
1331 "literal values since the "
1332 "lambda SQL system normally extracts bound values without "
1333 "actually "
1334 "invoking the lambda or any functions within it. Call the "

Callers 2

_add_getterMethod · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected