create.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. # engine/create.py
  2. # Copyright (C) 2005-2024 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. from __future__ import annotations
  8. import inspect
  9. import typing
  10. from typing import Any
  11. from typing import Callable
  12. from typing import cast
  13. from typing import Dict
  14. from typing import List
  15. from typing import Optional
  16. from typing import overload
  17. from typing import Type
  18. from typing import Union
  19. from . import base
  20. from . import url as _url
  21. from .interfaces import DBAPIConnection
  22. from .mock import create_mock_engine
  23. from .. import event
  24. from .. import exc
  25. from .. import util
  26. from ..pool import _AdhocProxiedConnection
  27. from ..pool import ConnectionPoolEntry
  28. from ..sql import compiler
  29. from ..util import immutabledict
  30. if typing.TYPE_CHECKING:
  31. from .base import Engine
  32. from .interfaces import _ExecuteOptions
  33. from .interfaces import _ParamStyle
  34. from .interfaces import IsolationLevel
  35. from .url import URL
  36. from ..log import _EchoFlagType
  37. from ..pool import _CreatorFnType
  38. from ..pool import _CreatorWRecFnType
  39. from ..pool import _ResetStyleArgType
  40. from ..pool import Pool
  41. from ..util.typing import Literal
  42. @overload
  43. def create_engine(
  44. url: Union[str, URL],
  45. *,
  46. connect_args: Dict[Any, Any] = ...,
  47. convert_unicode: bool = ...,
  48. creator: Union[_CreatorFnType, _CreatorWRecFnType] = ...,
  49. echo: _EchoFlagType = ...,
  50. echo_pool: _EchoFlagType = ...,
  51. enable_from_linting: bool = ...,
  52. execution_options: _ExecuteOptions = ...,
  53. future: Literal[True],
  54. hide_parameters: bool = ...,
  55. implicit_returning: Literal[True] = ...,
  56. insertmanyvalues_page_size: int = ...,
  57. isolation_level: IsolationLevel = ...,
  58. json_deserializer: Callable[..., Any] = ...,
  59. json_serializer: Callable[..., Any] = ...,
  60. label_length: Optional[int] = ...,
  61. logging_name: str = ...,
  62. max_identifier_length: Optional[int] = ...,
  63. max_overflow: int = ...,
  64. module: Optional[Any] = ...,
  65. paramstyle: Optional[_ParamStyle] = ...,
  66. pool: Optional[Pool] = ...,
  67. poolclass: Optional[Type[Pool]] = ...,
  68. pool_logging_name: str = ...,
  69. pool_pre_ping: bool = ...,
  70. pool_size: int = ...,
  71. pool_recycle: int = ...,
  72. pool_reset_on_return: Optional[_ResetStyleArgType] = ...,
  73. pool_timeout: float = ...,
  74. pool_use_lifo: bool = ...,
  75. plugins: List[str] = ...,
  76. query_cache_size: int = ...,
  77. use_insertmanyvalues: bool = ...,
  78. **kwargs: Any,
  79. ) -> Engine:
  80. ...
  81. @overload
  82. def create_engine(url: Union[str, URL], **kwargs: Any) -> Engine:
  83. ...
  84. @util.deprecated_params(
  85. strategy=(
  86. "1.4",
  87. "The :paramref:`_sa.create_engine.strategy` keyword is deprecated, "
  88. "and the only argument accepted is 'mock'; please use "
  89. ":func:`.create_mock_engine` going forward. For general "
  90. "customization of create_engine which may have been accomplished "
  91. "using strategies, see :class:`.CreateEnginePlugin`.",
  92. ),
  93. empty_in_strategy=(
  94. "1.4",
  95. "The :paramref:`_sa.create_engine.empty_in_strategy` keyword is "
  96. "deprecated, and no longer has any effect. All IN expressions "
  97. "are now rendered using "
  98. 'the "expanding parameter" strategy which renders a set of bound'
  99. 'expressions, or an "empty set" SELECT, at statement execution'
  100. "time.",
  101. ),
  102. implicit_returning=(
  103. "2.0",
  104. "The :paramref:`_sa.create_engine.implicit_returning` parameter "
  105. "is deprecated and will be removed in a future release. ",
  106. ),
  107. )
  108. def create_engine(url: Union[str, _url.URL], **kwargs: Any) -> Engine:
  109. """Create a new :class:`_engine.Engine` instance.
  110. The standard calling form is to send the :ref:`URL <database_urls>` as the
  111. first positional argument, usually a string
  112. that indicates database dialect and connection arguments::
  113. engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
  114. .. note::
  115. Please review :ref:`database_urls` for general guidelines in composing
  116. URL strings. In particular, special characters, such as those often
  117. part of passwords, must be URL encoded to be properly parsed.
  118. Additional keyword arguments may then follow it which
  119. establish various options on the resulting :class:`_engine.Engine`
  120. and its underlying :class:`.Dialect` and :class:`_pool.Pool`
  121. constructs::
  122. engine = create_engine("mysql+mysqldb://scott:tiger@hostname/dbname",
  123. pool_recycle=3600, echo=True)
  124. The string form of the URL is
  125. ``dialect[+driver]://user:password@host/dbname[?key=value..]``, where
  126. ``dialect`` is a database name such as ``mysql``, ``oracle``,
  127. ``postgresql``, etc., and ``driver`` the name of a DBAPI, such as
  128. ``psycopg2``, ``pyodbc``, ``cx_oracle``, etc. Alternatively,
  129. the URL can be an instance of :class:`~sqlalchemy.engine.url.URL`.
  130. ``**kwargs`` takes a wide variety of options which are routed
  131. towards their appropriate components. Arguments may be specific to
  132. the :class:`_engine.Engine`, the underlying :class:`.Dialect`,
  133. as well as the
  134. :class:`_pool.Pool`. Specific dialects also accept keyword arguments that
  135. are unique to that dialect. Here, we describe the parameters
  136. that are common to most :func:`_sa.create_engine()` usage.
  137. Once established, the newly resulting :class:`_engine.Engine` will
  138. request a connection from the underlying :class:`_pool.Pool` once
  139. :meth:`_engine.Engine.connect` is called, or a method which depends on it
  140. such as :meth:`_engine.Engine.execute` is invoked. The
  141. :class:`_pool.Pool` in turn
  142. will establish the first actual DBAPI connection when this request
  143. is received. The :func:`_sa.create_engine` call itself does **not**
  144. establish any actual DBAPI connections directly.
  145. .. seealso::
  146. :doc:`/core/engines`
  147. :doc:`/dialects/index`
  148. :ref:`connections_toplevel`
  149. :param connect_args: a dictionary of options which will be
  150. passed directly to the DBAPI's ``connect()`` method as
  151. additional keyword arguments. See the example
  152. at :ref:`custom_dbapi_args`.
  153. :param creator: a callable which returns a DBAPI connection.
  154. This creation function will be passed to the underlying
  155. connection pool and will be used to create all new database
  156. connections. Usage of this function causes connection
  157. parameters specified in the URL argument to be bypassed.
  158. This hook is not as flexible as the newer
  159. :meth:`_events.DialectEvents.do_connect` hook which allows complete
  160. control over how a connection is made to the database, given the full
  161. set of URL arguments and state beforehand.
  162. .. seealso::
  163. :meth:`_events.DialectEvents.do_connect` - event hook that allows
  164. full control over DBAPI connection mechanics.
  165. :ref:`custom_dbapi_args`
  166. :param echo=False: if True, the Engine will log all statements
  167. as well as a ``repr()`` of their parameter lists to the default log
  168. handler, which defaults to ``sys.stdout`` for output. If set to the
  169. string ``"debug"``, result rows will be printed to the standard output
  170. as well. The ``echo`` attribute of ``Engine`` can be modified at any
  171. time to turn logging on and off; direct control of logging is also
  172. available using the standard Python ``logging`` module.
  173. .. seealso::
  174. :ref:`dbengine_logging` - further detail on how to configure
  175. logging.
  176. :param echo_pool=False: if True, the connection pool will log
  177. informational output such as when connections are invalidated
  178. as well as when connections are recycled to the default log handler,
  179. which defaults to ``sys.stdout`` for output. If set to the string
  180. ``"debug"``, the logging will include pool checkouts and checkins.
  181. Direct control of logging is also available using the standard Python
  182. ``logging`` module.
  183. .. seealso::
  184. :ref:`dbengine_logging` - further detail on how to configure
  185. logging.
  186. :param empty_in_strategy: No longer used; SQLAlchemy now uses
  187. "empty set" behavior for IN in all cases.
  188. :param enable_from_linting: defaults to True. Will emit a warning
  189. if a given SELECT statement is found to have un-linked FROM elements
  190. which would cause a cartesian product.
  191. .. versionadded:: 1.4
  192. .. seealso::
  193. :ref:`change_4737`
  194. :param execution_options: Dictionary execution options which will
  195. be applied to all connections. See
  196. :meth:`~sqlalchemy.engine.Connection.execution_options`
  197. :param future: Use the 2.0 style :class:`_engine.Engine` and
  198. :class:`_engine.Connection` API.
  199. As of SQLAlchemy 2.0, this parameter is present for backwards
  200. compatibility only and must remain at its default value of ``True``.
  201. The :paramref:`_sa.create_engine.future` parameter will be
  202. deprecated in a subsequent 2.x release and eventually removed.
  203. .. versionadded:: 1.4
  204. .. versionchanged:: 2.0 All :class:`_engine.Engine` objects are
  205. "future" style engines and there is no longer a ``future=False``
  206. mode of operation.
  207. .. seealso::
  208. :ref:`migration_20_toplevel`
  209. :param hide_parameters: Boolean, when set to True, SQL statement parameters
  210. will not be displayed in INFO logging nor will they be formatted into
  211. the string representation of :class:`.StatementError` objects.
  212. .. versionadded:: 1.3.8
  213. .. seealso::
  214. :ref:`dbengine_logging` - further detail on how to configure
  215. logging.
  216. :param implicit_returning=True: Legacy parameter that may only be set
  217. to True. In SQLAlchemy 2.0, this parameter does nothing. In order to
  218. disable "implicit returning" for statements invoked by the ORM,
  219. configure this on a per-table basis using the
  220. :paramref:`.Table.implicit_returning` parameter.
  221. :param insertmanyvalues_page_size: number of rows to format into an
  222. INSERT statement when the statement uses "insertmanyvalues" mode, which is
  223. a paged form of bulk insert that is used for many backends when using
  224. :term:`executemany` execution typically in conjunction with RETURNING.
  225. Defaults to 1000, but may also be subject to dialect-specific limiting
  226. factors which may override this value on a per-statement basis.
  227. .. versionadded:: 2.0
  228. .. seealso::
  229. :ref:`engine_insertmanyvalues`
  230. :ref:`engine_insertmanyvalues_page_size`
  231. :paramref:`_engine.Connection.execution_options.insertmanyvalues_page_size`
  232. :param isolation_level: optional string name of an isolation level
  233. which will be set on all new connections unconditionally.
  234. Isolation levels are typically some subset of the string names
  235. ``"SERIALIZABLE"``, ``"REPEATABLE READ"``,
  236. ``"READ COMMITTED"``, ``"READ UNCOMMITTED"`` and ``"AUTOCOMMIT"``
  237. based on backend.
  238. The :paramref:`_sa.create_engine.isolation_level` parameter is
  239. in contrast to the
  240. :paramref:`.Connection.execution_options.isolation_level`
  241. execution option, which may be set on an individual
  242. :class:`.Connection`, as well as the same parameter passed to
  243. :meth:`.Engine.execution_options`, where it may be used to create
  244. multiple engines with different isolation levels that share a common
  245. connection pool and dialect.
  246. .. versionchanged:: 2.0 The
  247. :paramref:`_sa.create_engine.isolation_level`
  248. parameter has been generalized to work on all dialects which support
  249. the concept of isolation level, and is provided as a more succinct,
  250. up front configuration switch in contrast to the execution option
  251. which is more of an ad-hoc programmatic option.
  252. .. seealso::
  253. :ref:`dbapi_autocommit`
  254. :param json_deserializer: for dialects that support the
  255. :class:`_types.JSON`
  256. datatype, this is a Python callable that will convert a JSON string
  257. to a Python object. By default, the Python ``json.loads`` function is
  258. used.
  259. .. versionchanged:: 1.3.7 The SQLite dialect renamed this from
  260. ``_json_deserializer``.
  261. :param json_serializer: for dialects that support the :class:`_types.JSON`
  262. datatype, this is a Python callable that will render a given object
  263. as JSON. By default, the Python ``json.dumps`` function is used.
  264. .. versionchanged:: 1.3.7 The SQLite dialect renamed this from
  265. ``_json_serializer``.
  266. :param label_length=None: optional integer value which limits
  267. the size of dynamically generated column labels to that many
  268. characters. If less than 6, labels are generated as
  269. "_(counter)". If ``None``, the value of
  270. ``dialect.max_identifier_length``, which may be affected via the
  271. :paramref:`_sa.create_engine.max_identifier_length` parameter,
  272. is used instead. The value of
  273. :paramref:`_sa.create_engine.label_length`
  274. may not be larger than that of
  275. :paramref:`_sa.create_engine.max_identfier_length`.
  276. .. seealso::
  277. :paramref:`_sa.create_engine.max_identifier_length`
  278. :param logging_name: String identifier which will be used within
  279. the "name" field of logging records generated within the
  280. "sqlalchemy.engine" logger. Defaults to a hexstring of the
  281. object's id.
  282. .. seealso::
  283. :ref:`dbengine_logging` - further detail on how to configure
  284. logging.
  285. :paramref:`_engine.Connection.execution_options.logging_token`
  286. :param max_identifier_length: integer; override the max_identifier_length
  287. determined by the dialect. if ``None`` or zero, has no effect. This
  288. is the database's configured maximum number of characters that may be
  289. used in a SQL identifier such as a table name, column name, or label
  290. name. All dialects determine this value automatically, however in the
  291. case of a new database version for which this value has changed but
  292. SQLAlchemy's dialect has not been adjusted, the value may be passed
  293. here.
  294. .. versionadded:: 1.3.9
  295. .. seealso::
  296. :paramref:`_sa.create_engine.label_length`
  297. :param max_overflow=10: the number of connections to allow in
  298. connection pool "overflow", that is connections that can be
  299. opened above and beyond the pool_size setting, which defaults
  300. to five. this is only used with :class:`~sqlalchemy.pool.QueuePool`.
  301. :param module=None: reference to a Python module object (the module
  302. itself, not its string name). Specifies an alternate DBAPI module to
  303. be used by the engine's dialect. Each sub-dialect references a
  304. specific DBAPI which will be imported before first connect. This
  305. parameter causes the import to be bypassed, and the given module to
  306. be used instead. Can be used for testing of DBAPIs as well as to
  307. inject "mock" DBAPI implementations into the :class:`_engine.Engine`.
  308. :param paramstyle=None: The `paramstyle <https://legacy.python.org/dev/peps/pep-0249/#paramstyle>`_
  309. to use when rendering bound parameters. This style defaults to the
  310. one recommended by the DBAPI itself, which is retrieved from the
  311. ``.paramstyle`` attribute of the DBAPI. However, most DBAPIs accept
  312. more than one paramstyle, and in particular it may be desirable
  313. to change a "named" paramstyle into a "positional" one, or vice versa.
  314. When this attribute is passed, it should be one of the values
  315. ``"qmark"``, ``"numeric"``, ``"named"``, ``"format"`` or
  316. ``"pyformat"``, and should correspond to a parameter style known
  317. to be supported by the DBAPI in use.
  318. :param pool=None: an already-constructed instance of
  319. :class:`~sqlalchemy.pool.Pool`, such as a
  320. :class:`~sqlalchemy.pool.QueuePool` instance. If non-None, this
  321. pool will be used directly as the underlying connection pool
  322. for the engine, bypassing whatever connection parameters are
  323. present in the URL argument. For information on constructing
  324. connection pools manually, see :ref:`pooling_toplevel`.
  325. :param poolclass=None: a :class:`~sqlalchemy.pool.Pool`
  326. subclass, which will be used to create a connection pool
  327. instance using the connection parameters given in the URL. Note
  328. this differs from ``pool`` in that you don't actually
  329. instantiate the pool in this case, you just indicate what type
  330. of pool to be used.
  331. :param pool_logging_name: String identifier which will be used within
  332. the "name" field of logging records generated within the
  333. "sqlalchemy.pool" logger. Defaults to a hexstring of the object's
  334. id.
  335. .. seealso::
  336. :ref:`dbengine_logging` - further detail on how to configure
  337. logging.
  338. :param pool_pre_ping: boolean, if True will enable the connection pool
  339. "pre-ping" feature that tests connections for liveness upon
  340. each checkout.
  341. .. versionadded:: 1.2
  342. .. seealso::
  343. :ref:`pool_disconnects_pessimistic`
  344. :param pool_size=5: the number of connections to keep open
  345. inside the connection pool. This used with
  346. :class:`~sqlalchemy.pool.QueuePool` as
  347. well as :class:`~sqlalchemy.pool.SingletonThreadPool`. With
  348. :class:`~sqlalchemy.pool.QueuePool`, a ``pool_size`` setting
  349. of 0 indicates no limit; to disable pooling, set ``poolclass`` to
  350. :class:`~sqlalchemy.pool.NullPool` instead.
  351. :param pool_recycle=-1: this setting causes the pool to recycle
  352. connections after the given number of seconds has passed. It
  353. defaults to -1, or no timeout. For example, setting to 3600
  354. means connections will be recycled after one hour. Note that
  355. MySQL in particular will disconnect automatically if no
  356. activity is detected on a connection for eight hours (although
  357. this is configurable with the MySQLDB connection itself and the
  358. server configuration as well).
  359. .. seealso::
  360. :ref:`pool_setting_recycle`
  361. :param pool_reset_on_return='rollback': set the
  362. :paramref:`_pool.Pool.reset_on_return` parameter of the underlying
  363. :class:`_pool.Pool` object, which can be set to the values
  364. ``"rollback"``, ``"commit"``, or ``None``.
  365. .. seealso::
  366. :ref:`pool_reset_on_return`
  367. :param pool_timeout=30: number of seconds to wait before giving
  368. up on getting a connection from the pool. This is only used
  369. with :class:`~sqlalchemy.pool.QueuePool`. This can be a float but is
  370. subject to the limitations of Python time functions which may not be
  371. reliable in the tens of milliseconds.
  372. .. note: don't use 30.0 above, it seems to break with the :param tag
  373. :param pool_use_lifo=False: use LIFO (last-in-first-out) when retrieving
  374. connections from :class:`.QueuePool` instead of FIFO
  375. (first-in-first-out). Using LIFO, a server-side timeout scheme can
  376. reduce the number of connections used during non- peak periods of
  377. use. When planning for server-side timeouts, ensure that a recycle or
  378. pre-ping strategy is in use to gracefully handle stale connections.
  379. .. versionadded:: 1.3
  380. .. seealso::
  381. :ref:`pool_use_lifo`
  382. :ref:`pool_disconnects`
  383. :param plugins: string list of plugin names to load. See
  384. :class:`.CreateEnginePlugin` for background.
  385. .. versionadded:: 1.2.3
  386. :param query_cache_size: size of the cache used to cache the SQL string
  387. form of queries. Set to zero to disable caching.
  388. The cache is pruned of its least recently used items when its size reaches
  389. N * 1.5. Defaults to 500, meaning the cache will always store at least
  390. 500 SQL statements when filled, and will grow up to 750 items at which
  391. point it is pruned back down to 500 by removing the 250 least recently
  392. used items.
  393. Caching is accomplished on a per-statement basis by generating a
  394. cache key that represents the statement's structure, then generating
  395. string SQL for the current dialect only if that key is not present
  396. in the cache. All statements support caching, however some features
  397. such as an INSERT with a large set of parameters will intentionally
  398. bypass the cache. SQL logging will indicate statistics for each
  399. statement whether or not it were pull from the cache.
  400. .. note:: some ORM functions related to unit-of-work persistence as well
  401. as some attribute loading strategies will make use of individual
  402. per-mapper caches outside of the main cache.
  403. .. seealso::
  404. :ref:`sql_caching`
  405. .. versionadded:: 1.4
  406. :param use_insertmanyvalues: True by default, use the "insertmanyvalues"
  407. execution style for INSERT..RETURNING statements by default.
  408. .. versionadded:: 2.0
  409. .. seealso::
  410. :ref:`engine_insertmanyvalues`
  411. """ # noqa
  412. if "strategy" in kwargs:
  413. strat = kwargs.pop("strategy")
  414. if strat == "mock":
  415. # this case is deprecated
  416. return create_mock_engine(url, **kwargs) # type: ignore
  417. else:
  418. raise exc.ArgumentError("unknown strategy: %r" % strat)
  419. kwargs.pop("empty_in_strategy", None)
  420. # create url.URL object
  421. u = _url.make_url(url)
  422. u, plugins, kwargs = u._instantiate_plugins(kwargs)
  423. entrypoint = u._get_entrypoint()
  424. _is_async = kwargs.pop("_is_async", False)
  425. if _is_async:
  426. dialect_cls = entrypoint.get_async_dialect_cls(u)
  427. else:
  428. dialect_cls = entrypoint.get_dialect_cls(u)
  429. if kwargs.pop("_coerce_config", False):
  430. def pop_kwarg(key: str, default: Optional[Any] = None) -> Any:
  431. value = kwargs.pop(key, default)
  432. if key in dialect_cls.engine_config_types:
  433. value = dialect_cls.engine_config_types[key](value)
  434. return value
  435. else:
  436. pop_kwarg = kwargs.pop # type: ignore
  437. dialect_args = {}
  438. # consume dialect arguments from kwargs
  439. for k in util.get_cls_kwargs(dialect_cls):
  440. if k in kwargs:
  441. dialect_args[k] = pop_kwarg(k)
  442. dbapi = kwargs.pop("module", None)
  443. if dbapi is None:
  444. dbapi_args = {}
  445. if "import_dbapi" in dialect_cls.__dict__:
  446. dbapi_meth = dialect_cls.import_dbapi
  447. elif hasattr(dialect_cls, "dbapi") and inspect.ismethod(
  448. dialect_cls.dbapi
  449. ):
  450. util.warn_deprecated(
  451. "The dbapi() classmethod on dialect classes has been "
  452. "renamed to import_dbapi(). Implement an import_dbapi() "
  453. f"classmethod directly on class {dialect_cls} to remove this "
  454. "warning; the old .dbapi() classmethod may be maintained for "
  455. "backwards compatibility.",
  456. "2.0",
  457. )
  458. dbapi_meth = dialect_cls.dbapi
  459. else:
  460. dbapi_meth = dialect_cls.import_dbapi
  461. for k in util.get_func_kwargs(dbapi_meth):
  462. if k in kwargs:
  463. dbapi_args[k] = pop_kwarg(k)
  464. dbapi = dbapi_meth(**dbapi_args)
  465. dialect_args["dbapi"] = dbapi
  466. dialect_args.setdefault("compiler_linting", compiler.NO_LINTING)
  467. enable_from_linting = kwargs.pop("enable_from_linting", True)
  468. if enable_from_linting:
  469. dialect_args["compiler_linting"] ^= compiler.COLLECT_CARTESIAN_PRODUCTS
  470. for plugin in plugins:
  471. plugin.handle_dialect_kwargs(dialect_cls, dialect_args)
  472. # create dialect
  473. dialect = dialect_cls(**dialect_args)
  474. # assemble connection arguments
  475. (cargs_tup, cparams) = dialect.create_connect_args(u)
  476. cparams.update(pop_kwarg("connect_args", {}))
  477. if "async_fallback" in cparams and util.asbool(cparams["async_fallback"]):
  478. util.warn_deprecated(
  479. "The async_fallback dialect argument is deprecated and will be "
  480. "removed in SQLAlchemy 2.1.",
  481. "2.0",
  482. )
  483. cargs = list(cargs_tup) # allow mutability
  484. # look for existing pool or create
  485. pool = pop_kwarg("pool", None)
  486. if pool is None:
  487. def connect(
  488. connection_record: Optional[ConnectionPoolEntry] = None,
  489. ) -> DBAPIConnection:
  490. if dialect._has_events:
  491. for fn in dialect.dispatch.do_connect:
  492. connection = cast(
  493. DBAPIConnection,
  494. fn(dialect, connection_record, cargs, cparams),
  495. )
  496. if connection is not None:
  497. return connection
  498. return dialect.connect(*cargs, **cparams)
  499. creator = pop_kwarg("creator", connect)
  500. poolclass = pop_kwarg("poolclass", None)
  501. if poolclass is None:
  502. poolclass = dialect.get_dialect_pool_class(u)
  503. pool_args = {"dialect": dialect}
  504. # consume pool arguments from kwargs, translating a few of
  505. # the arguments
  506. for k in util.get_cls_kwargs(poolclass):
  507. tk = _pool_translate_kwargs.get(k, k)
  508. if tk in kwargs:
  509. pool_args[k] = pop_kwarg(tk)
  510. for plugin in plugins:
  511. plugin.handle_pool_kwargs(poolclass, pool_args)
  512. pool = poolclass(creator, **pool_args)
  513. else:
  514. pool._dialect = dialect
  515. # create engine.
  516. if not pop_kwarg("future", True):
  517. raise exc.ArgumentError(
  518. "The 'future' parameter passed to "
  519. "create_engine() may only be set to True."
  520. )
  521. engineclass = base.Engine
  522. engine_args = {}
  523. for k in util.get_cls_kwargs(engineclass):
  524. if k in kwargs:
  525. engine_args[k] = pop_kwarg(k)
  526. # internal flags used by the test suite for instrumenting / proxying
  527. # engines with mocks etc.
  528. _initialize = kwargs.pop("_initialize", True)
  529. # all kwargs should be consumed
  530. if kwargs:
  531. raise TypeError(
  532. "Invalid argument(s) %s sent to create_engine(), "
  533. "using configuration %s/%s/%s. Please check that the "
  534. "keyword arguments are appropriate for this combination "
  535. "of components."
  536. % (
  537. ",".join("'%s'" % k for k in kwargs),
  538. dialect.__class__.__name__,
  539. pool.__class__.__name__,
  540. engineclass.__name__,
  541. )
  542. )
  543. engine = engineclass(pool, dialect, u, **engine_args)
  544. if _initialize:
  545. do_on_connect = dialect.on_connect_url(u)
  546. if do_on_connect:
  547. def on_connect(
  548. dbapi_connection: DBAPIConnection,
  549. connection_record: ConnectionPoolEntry,
  550. ) -> None:
  551. assert do_on_connect is not None
  552. do_on_connect(dbapi_connection)
  553. event.listen(pool, "connect", on_connect)
  554. builtin_on_connect = dialect._builtin_onconnect()
  555. if builtin_on_connect:
  556. event.listen(pool, "connect", builtin_on_connect)
  557. def first_connect(
  558. dbapi_connection: DBAPIConnection,
  559. connection_record: ConnectionPoolEntry,
  560. ) -> None:
  561. c = base.Connection(
  562. engine,
  563. connection=_AdhocProxiedConnection(
  564. dbapi_connection, connection_record
  565. ),
  566. _has_events=False,
  567. # reconnecting will be a reentrant condition, so if the
  568. # connection goes away, Connection is then closed
  569. _allow_revalidate=False,
  570. # dont trigger the autobegin sequence
  571. # within the up front dialect checks
  572. _allow_autobegin=False,
  573. )
  574. c._execution_options = util.EMPTY_DICT
  575. try:
  576. dialect.initialize(c)
  577. finally:
  578. # note that "invalidated" and "closed" are mutually
  579. # exclusive in 1.4 Connection.
  580. if not c.invalidated and not c.closed:
  581. # transaction is rolled back otherwise, tested by
  582. # test/dialect/postgresql/test_dialect.py
  583. # ::MiscBackendTest::test_initial_transaction_state
  584. dialect.do_rollback(c.connection)
  585. # previously, the "first_connect" event was used here, which was then
  586. # scaled back if the "on_connect" handler were present. now,
  587. # since "on_connect" is virtually always present, just use
  588. # "connect" event with once_unless_exception in all cases so that
  589. # the connection event flow is consistent in all cases.
  590. event.listen(
  591. pool, "connect", first_connect, _once_unless_exception=True
  592. )
  593. dialect_cls.engine_created(engine)
  594. if entrypoint is not dialect_cls:
  595. entrypoint.engine_created(engine)
  596. for plugin in plugins:
  597. plugin.engine_created(engine)
  598. return engine
  599. def engine_from_config(
  600. configuration: Dict[str, Any], prefix: str = "sqlalchemy.", **kwargs: Any
  601. ) -> Engine:
  602. """Create a new Engine instance using a configuration dictionary.
  603. The dictionary is typically produced from a config file.
  604. The keys of interest to ``engine_from_config()`` should be prefixed, e.g.
  605. ``sqlalchemy.url``, ``sqlalchemy.echo``, etc. The 'prefix' argument
  606. indicates the prefix to be searched for. Each matching key (after the
  607. prefix is stripped) is treated as though it were the corresponding keyword
  608. argument to a :func:`_sa.create_engine` call.
  609. The only required key is (assuming the default prefix) ``sqlalchemy.url``,
  610. which provides the :ref:`database URL <database_urls>`.
  611. A select set of keyword arguments will be "coerced" to their
  612. expected type based on string values. The set of arguments
  613. is extensible per-dialect using the ``engine_config_types`` accessor.
  614. :param configuration: A dictionary (typically produced from a config file,
  615. but this is not a requirement). Items whose keys start with the value
  616. of 'prefix' will have that prefix stripped, and will then be passed to
  617. :func:`_sa.create_engine`.
  618. :param prefix: Prefix to match and then strip from keys
  619. in 'configuration'.
  620. :param kwargs: Each keyword argument to ``engine_from_config()`` itself
  621. overrides the corresponding item taken from the 'configuration'
  622. dictionary. Keyword arguments should *not* be prefixed.
  623. """
  624. options = {
  625. key[len(prefix) :]: configuration[key]
  626. for key in configuration
  627. if key.startswith(prefix)
  628. }
  629. options["_coerce_config"] = True
  630. options.update(kwargs)
  631. url = options.pop("url")
  632. return create_engine(url, **options)
  633. @overload
  634. def create_pool_from_url(
  635. url: Union[str, URL],
  636. *,
  637. poolclass: Optional[Type[Pool]] = ...,
  638. logging_name: str = ...,
  639. pre_ping: bool = ...,
  640. size: int = ...,
  641. recycle: int = ...,
  642. reset_on_return: Optional[_ResetStyleArgType] = ...,
  643. timeout: float = ...,
  644. use_lifo: bool = ...,
  645. **kwargs: Any,
  646. ) -> Pool:
  647. ...
  648. @overload
  649. def create_pool_from_url(url: Union[str, URL], **kwargs: Any) -> Pool:
  650. ...
  651. def create_pool_from_url(url: Union[str, URL], **kwargs: Any) -> Pool:
  652. """Create a pool instance from the given url.
  653. If ``poolclass`` is not provided the pool class used
  654. is selected using the dialect specified in the URL.
  655. The arguments passed to :func:`_sa.create_pool_from_url` are
  656. identical to the pool argument passed to the :func:`_sa.create_engine`
  657. function.
  658. .. versionadded:: 2.0.10
  659. """
  660. for key in _pool_translate_kwargs:
  661. if key in kwargs:
  662. kwargs[_pool_translate_kwargs[key]] = kwargs.pop(key)
  663. engine = create_engine(url, **kwargs, _initialize=False)
  664. return engine.pool
  665. _pool_translate_kwargs = immutabledict(
  666. {
  667. "logging_name": "pool_logging_name",
  668. "echo": "echo_pool",
  669. "timeout": "pool_timeout",
  670. "recycle": "pool_recycle",
  671. "events": "pool_events", # deprecated
  672. "reset_on_return": "pool_reset_on_return",
  673. "pre_ping": "pool_pre_ping",
  674. "use_lifo": "pool_use_lifo",
  675. }
  676. )