From fc72bf8edcf24c38945cfb27cb095ea2eeb68ccf Mon Sep 17 00:00:00 2001 From: Gord Thompson Date: Thu, 24 Nov 2022 10:38:20 -0700 Subject: [PATCH] Add recommendation for URL.create() re: escaping Let users know that URL.create() can build the whole connection URL instead of making them escape things like passwords ad-hoc. includes some general cleanup of URL docstring by mike Change-Id: Ic71bb0201fecf30e1db11e006c269f2d041b5439 (cherry picked from commit 14c73685ba909838fb90d762d465e7ae8d067c15) --- doc/build/core/engines.rst | 50 +++++++++++++++++++++++++++++++++++- lib/sqlalchemy/engine/url.py | 24 ++++++++++------- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/doc/build/core/engines.rst b/doc/build/core/engines.rst index f27caa2d4f..ba800d6983 100644 --- a/doc/build/core/engines.rst +++ b/doc/build/core/engines.rst @@ -79,7 +79,8 @@ known driver available for that backend. Escaping Special Characters such as @ signs in Passwords ---------------------------------------------------------- -As the URL is like any other URL, **special characters such as those that may +When constructing a fully formed URL string to pass to +:func:`_sa.create_engine`, **special characters such as those that may be used in the user and password need to be URL encoded to be parsed correctly.**. **This includes the @ sign**. @@ -99,12 +100,59 @@ The encoding for the above password can be generated using >>> urllib.parse.quote_plus("kx@jj5/g") 'kx%40jj5%2Fg' +The URL may then be passed as a string to :func:`_sa.create_engine`:: + + from sqlalchemy import create_engine + + engine = create_engine("postgresql+pg8000://dbuser:kx%40jj5%2Fg@pghost10/appdb") + +As an alternative to escaping special characters in order to create a complete +URL string, the object passed to :func:`_sa.create_engine` may instead be an +instance of the :class:`.URL` object, which bypasses the parsing +phase and can accommodate for unescaped strings directly. See the next +section for an example. + .. versionchanged:: 1.4 Support for ``@`` signs in hostnames and database names has been fixed. As a side effect of this fix, ``@`` signs in passwords must be escaped. +Creating URLs Programmatically +------------------------------- + +The value passed to :func:`_sa.create_engine` may be an instance of +:class:`.URL`, instead of a plain string, which bypasses the need for string +parsing to be used, and therefore does not need an escaped URL string to be +provided. + +The :class:`.URL` object is created using the :meth:`_engine.URL.create()` +constructor method, passing all fields individually. Special characters +such as those within passwords may be passed without any modification:: + + from sqlalchemy import URL + + url_object = URL.create( + "postgresql+pg8000", + username="dbuser", + password="kx@jj5/g", # plain (unescaped) text + host="pghost10", + database="appdb", + ) + +The constructed :class:`.URL` object may then be passed directly to +:func:`_sa.create_engine` in place of a string argument:: + + from sqlalchemy import create_engine + + engine = create_engine(url_object) + +.. seealso:: + + :class:`.URL` + + :meth:`.URL.create` + Backend-Specific URLs ---------------------- diff --git a/lib/sqlalchemy/engine/url.py b/lib/sqlalchemy/engine/url.py index a8138c1b48..5b54d40d0a 100644 --- a/lib/sqlalchemy/engine/url.py +++ b/lib/sqlalchemy/engine/url.py @@ -42,15 +42,21 @@ class URL( """ Represent the components of a URL used to connect to a database. - This object is suitable to be passed directly to a - :func:`_sa.create_engine` call. The fields of the URL are parsed from a - string by the :func:`.make_url` function. The string format of the URL - generally follows `RFC-1738 `_, with - some exceptions. - - To create a new :class:`_engine.URL` object, use the - :func:`_engine.url.make_url` function. To construct a :class:`_engine.URL` - programmatically, use the :meth:`_engine.URL.create` constructor. + URLs are typically constructed from a fully formatted URL string, where the + :func:`.make_url` function is used internally by the + :func:`_sa.create_engine` function in order to parse the URL string into + its individual components, which are then used to construct a new + :class:`.URL` object. When parsing from a formatted URL string, the parsing + format generally follows + `RFC-1738 `_, with some exceptions. + + A :class:`_engine.URL` object may also be produced directly, either by + using the :func:`.make_url` function with a fully formed URL string, or + by using the :meth:`_engine.URL.create` constructor in order + to construct a :class:`_engine.URL` programmatically given individual + fields. The resulting :class:`.URL` object may be passed directly to + :func:`_sa.create_engine` in place of a string argument, which will bypass + the usage of :func:`.make_url` within the engine's creation process. .. versionchanged:: 1.4 -- 2.47.2