You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					813 lines
				
				26 KiB
			
		
		
			
		
	
	
					813 lines
				
				26 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								# engine/url.py
							 | 
						||
| 
								 | 
							
								# Copyright (C) 2005-2022 the SQLAlchemy authors and contributors
							 | 
						||
| 
								 | 
							
								# <see AUTHORS file>
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# This module is part of SQLAlchemy and is released under
							 | 
						||
| 
								 | 
							
								# the MIT License: https://www.opensource.org/licenses/mit-license.php
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""Provides the :class:`~sqlalchemy.engine.url.URL` class which encapsulates
							 | 
						||
| 
								 | 
							
								information about a database connection specification.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The URL object is created automatically when
							 | 
						||
| 
								 | 
							
								:func:`~sqlalchemy.engine.create_engine` is called with a string
							 | 
						||
| 
								 | 
							
								argument; alternatively, the URL is a public-facing construct which can
							 | 
						||
| 
								 | 
							
								be used directly and is also accepted directly by ``create_engine()``.
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import re
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from .interfaces import Dialect
							 | 
						||
| 
								 | 
							
								from .. import exc
							 | 
						||
| 
								 | 
							
								from .. import util
							 | 
						||
| 
								 | 
							
								from ..dialects import plugins
							 | 
						||
| 
								 | 
							
								from ..dialects import registry
							 | 
						||
| 
								 | 
							
								from ..util import collections_abc
							 | 
						||
| 
								 | 
							
								from ..util import compat
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class URL(
							 | 
						||
| 
								 | 
							
								    util.namedtuple(
							 | 
						||
| 
								 | 
							
								        "URL",
							 | 
						||
| 
								 | 
							
								        [
							 | 
						||
| 
								 | 
							
								            "drivername",
							 | 
						||
| 
								 | 
							
								            "username",
							 | 
						||
| 
								 | 
							
								            "password",
							 | 
						||
| 
								 | 
							
								            "host",
							 | 
						||
| 
								 | 
							
								            "port",
							 | 
						||
| 
								 | 
							
								            "database",
							 | 
						||
| 
								 | 
							
								            "query",
							 | 
						||
| 
								 | 
							
								        ],
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    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 is an RFC-1738-style string.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    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.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionchanged:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        The :class:`_engine.URL` object is now an immutable object.  To
							 | 
						||
| 
								 | 
							
								        create a URL, use the :func:`_engine.make_url` or
							 | 
						||
| 
								 | 
							
								        :meth:`_engine.URL.create` function / method.  To modify
							 | 
						||
| 
								 | 
							
								        a :class:`_engine.URL`, use methods like
							 | 
						||
| 
								 | 
							
								        :meth:`_engine.URL.set` and
							 | 
						||
| 
								 | 
							
								        :meth:`_engine.URL.update_query_dict` to return a new
							 | 
						||
| 
								 | 
							
								        :class:`_engine.URL` object with modifications.   See notes for this
							 | 
						||
| 
								 | 
							
								        change at :ref:`change_5526`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :class:`_engine.URL` contains the following attributes:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    * :attr:`_engine.URL.drivername`: database backend and driver name, such as
							 | 
						||
| 
								 | 
							
								      ``postgresql+psycopg2``
							 | 
						||
| 
								 | 
							
								    * :attr:`_engine.URL.username`: username string
							 | 
						||
| 
								 | 
							
								    * :attr:`_engine.URL.password`: password string, or object that includes
							 | 
						||
| 
								 | 
							
								      a ``__str__()`` method that produces a password.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      .. note::  A password-producing object will be stringified only
							 | 
						||
| 
								 | 
							
								         **once** per :class:`_engine.Engine` object.  For dynamic password
							 | 
						||
| 
								 | 
							
								         generation per connect, see :ref:`engines_dynamic_tokens`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    * :attr:`_engine.URL.host`: string hostname
							 | 
						||
| 
								 | 
							
								    * :attr:`_engine.URL.port`: integer port number
							 | 
						||
| 
								 | 
							
								    * :attr:`_engine.URL.database`: string database name
							 | 
						||
| 
								 | 
							
								    * :attr:`_engine.URL.query`: an immutable mapping representing the query
							 | 
						||
| 
								 | 
							
								      string.  contains strings for keys and either strings or tuples of
							 | 
						||
| 
								 | 
							
								      strings for values.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __new__(self, *arg, **kw):
							 | 
						||
| 
								 | 
							
								        if kw.pop("_new_ok", False):
							 | 
						||
| 
								 | 
							
								            return super(URL, self).__new__(self, *arg, **kw)
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            util.warn_deprecated(
							 | 
						||
| 
								 | 
							
								                "Calling URL() directly is deprecated and will be disabled "
							 | 
						||
| 
								 | 
							
								                "in a future release.  The public constructor for URL is "
							 | 
						||
| 
								 | 
							
								                "now the URL.create() method.",
							 | 
						||
| 
								 | 
							
								                "1.4",
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								            return URL.create(*arg, **kw)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def create(
							 | 
						||
| 
								 | 
							
								        cls,
							 | 
						||
| 
								 | 
							
								        drivername,
							 | 
						||
| 
								 | 
							
								        username=None,
							 | 
						||
| 
								 | 
							
								        password=None,
							 | 
						||
| 
								 | 
							
								        host=None,
							 | 
						||
| 
								 | 
							
								        port=None,
							 | 
						||
| 
								 | 
							
								        database=None,
							 | 
						||
| 
								 | 
							
								        query=util.EMPTY_DICT,
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        """Create a new :class:`_engine.URL` object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param drivername: the name of the database backend. This name will
							 | 
						||
| 
								 | 
							
								          correspond to a module in sqlalchemy/databases or a third party
							 | 
						||
| 
								 | 
							
								          plug-in.
							 | 
						||
| 
								 | 
							
								        :param username: The user name.
							 | 
						||
| 
								 | 
							
								        :param password: database password.  Is typically a string, but may
							 | 
						||
| 
								 | 
							
								          also be an object that can be stringified with ``str()``.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          .. note::  A password-producing object will be stringified only
							 | 
						||
| 
								 | 
							
								             **once** per :class:`_engine.Engine` object.  For dynamic password
							 | 
						||
| 
								 | 
							
								             generation per connect, see :ref:`engines_dynamic_tokens`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param host: The name of the host.
							 | 
						||
| 
								 | 
							
								        :param port: The port number.
							 | 
						||
| 
								 | 
							
								        :param database: The database name.
							 | 
						||
| 
								 | 
							
								        :param query: A dictionary of string keys to string values to be passed
							 | 
						||
| 
								 | 
							
								          to the dialect and/or the DBAPI upon connect.   To specify non-string
							 | 
						||
| 
								 | 
							
								          parameters to a Python DBAPI directly, use the
							 | 
						||
| 
								 | 
							
								          :paramref:`_sa.create_engine.connect_args` parameter to
							 | 
						||
| 
								 | 
							
								          :func:`_sa.create_engine`.   See also
							 | 
						||
| 
								 | 
							
								          :attr:`_engine.URL.normalized_query` for a dictionary that is
							 | 
						||
| 
								 | 
							
								          consistently string->list of string.
							 | 
						||
| 
								 | 
							
								        :return: new :class:`_engine.URL` object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            The :class:`_engine.URL` object is now an **immutable named
							 | 
						||
| 
								 | 
							
								            tuple**.  In addition, the ``query`` dictionary is also immutable.
							 | 
						||
| 
								 | 
							
								            To create a URL, use the :func:`_engine.url.make_url` or
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.create` function/ method.  To modify a
							 | 
						||
| 
								 | 
							
								            :class:`_engine.URL`, use the :meth:`_engine.URL.set` and
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.update_query` methods.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return cls(
							 | 
						||
| 
								 | 
							
								            cls._assert_str(drivername, "drivername"),
							 | 
						||
| 
								 | 
							
								            cls._assert_none_str(username, "username"),
							 | 
						||
| 
								 | 
							
								            password,
							 | 
						||
| 
								 | 
							
								            cls._assert_none_str(host, "host"),
							 | 
						||
| 
								 | 
							
								            cls._assert_port(port),
							 | 
						||
| 
								 | 
							
								            cls._assert_none_str(database, "database"),
							 | 
						||
| 
								 | 
							
								            cls._str_dict(query),
							 | 
						||
| 
								 | 
							
								            _new_ok=True,
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def _assert_port(cls, port):
							 | 
						||
| 
								 | 
							
								        if port is None:
							 | 
						||
| 
								 | 
							
								            return None
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            return int(port)
							 | 
						||
| 
								 | 
							
								        except TypeError:
							 | 
						||
| 
								 | 
							
								            raise TypeError("Port argument must be an integer or None")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def _assert_str(cls, v, paramname):
							 | 
						||
| 
								 | 
							
								        if not isinstance(v, compat.string_types):
							 | 
						||
| 
								 | 
							
								            raise TypeError("%s must be a string" % paramname)
							 | 
						||
| 
								 | 
							
								        return v
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def _assert_none_str(cls, v, paramname):
							 | 
						||
| 
								 | 
							
								        if v is None:
							 | 
						||
| 
								 | 
							
								            return v
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return cls._assert_str(v, paramname)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def _str_dict(cls, dict_):
							 | 
						||
| 
								 | 
							
								        if dict_ is None:
							 | 
						||
| 
								 | 
							
								            return util.EMPTY_DICT
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def _assert_value(val):
							 | 
						||
| 
								 | 
							
								            if isinstance(val, compat.string_types):
							 | 
						||
| 
								 | 
							
								                return val
							 | 
						||
| 
								 | 
							
								            elif isinstance(val, collections_abc.Sequence):
							 | 
						||
| 
								 | 
							
								                return tuple(_assert_value(elem) for elem in val)
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                raise TypeError(
							 | 
						||
| 
								 | 
							
								                    "Query dictionary values must be strings or "
							 | 
						||
| 
								 | 
							
								                    "sequences of strings"
							 | 
						||
| 
								 | 
							
								                )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def _assert_str(v):
							 | 
						||
| 
								 | 
							
								            if not isinstance(v, compat.string_types):
							 | 
						||
| 
								 | 
							
								                raise TypeError("Query dictionary keys must be strings")
							 | 
						||
| 
								 | 
							
								            return v
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if isinstance(dict_, collections_abc.Sequence):
							 | 
						||
| 
								 | 
							
								            dict_items = dict_
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            dict_items = dict_.items()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return util.immutabledict(
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _assert_str(key): _assert_value(
							 | 
						||
| 
								 | 
							
								                    value,
							 | 
						||
| 
								 | 
							
								                )
							 | 
						||
| 
								 | 
							
								                for key, value in dict_items
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def set(
							 | 
						||
| 
								 | 
							
								        self,
							 | 
						||
| 
								 | 
							
								        drivername=None,
							 | 
						||
| 
								 | 
							
								        username=None,
							 | 
						||
| 
								 | 
							
								        password=None,
							 | 
						||
| 
								 | 
							
								        host=None,
							 | 
						||
| 
								 | 
							
								        port=None,
							 | 
						||
| 
								 | 
							
								        database=None,
							 | 
						||
| 
								 | 
							
								        query=None,
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        """return a new :class:`_engine.URL` object with modifications.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Values are used if they are non-None.  To set a value to ``None``
							 | 
						||
| 
								 | 
							
								        explicitly, use the :meth:`_engine.URL._replace` method adapted
							 | 
						||
| 
								 | 
							
								        from ``namedtuple``.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param drivername: new drivername
							 | 
						||
| 
								 | 
							
								        :param username: new username
							 | 
						||
| 
								 | 
							
								        :param password: new password
							 | 
						||
| 
								 | 
							
								        :param host: new hostname
							 | 
						||
| 
								 | 
							
								        :param port: new port
							 | 
						||
| 
								 | 
							
								        :param query: new query parameters, passed a dict of string keys
							 | 
						||
| 
								 | 
							
								         referring to string or sequence of string values.  Fully
							 | 
						||
| 
								 | 
							
								         replaces the previous list of arguments.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :return: new :class:`_engine.URL` object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.update_query_dict`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        kw = {}
							 | 
						||
| 
								 | 
							
								        if drivername is not None:
							 | 
						||
| 
								 | 
							
								            kw["drivername"] = drivername
							 | 
						||
| 
								 | 
							
								        if username is not None:
							 | 
						||
| 
								 | 
							
								            kw["username"] = username
							 | 
						||
| 
								 | 
							
								        if password is not None:
							 | 
						||
| 
								 | 
							
								            kw["password"] = password
							 | 
						||
| 
								 | 
							
								        if host is not None:
							 | 
						||
| 
								 | 
							
								            kw["host"] = host
							 | 
						||
| 
								 | 
							
								        if port is not None:
							 | 
						||
| 
								 | 
							
								            kw["port"] = port
							 | 
						||
| 
								 | 
							
								        if database is not None:
							 | 
						||
| 
								 | 
							
								            kw["database"] = database
							 | 
						||
| 
								 | 
							
								        if query is not None:
							 | 
						||
| 
								 | 
							
								            kw["query"] = query
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return self._replace(**kw)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _replace(self, **kw):
							 | 
						||
| 
								 | 
							
								        """Override ``namedtuple._replace()`` to provide argument checking."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if "drivername" in kw:
							 | 
						||
| 
								 | 
							
								            self._assert_str(kw["drivername"], "drivername")
							 | 
						||
| 
								 | 
							
								        for name in "username", "host", "database":
							 | 
						||
| 
								 | 
							
								            if name in kw:
							 | 
						||
| 
								 | 
							
								                self._assert_none_str(kw[name], name)
							 | 
						||
| 
								 | 
							
								        if "port" in kw:
							 | 
						||
| 
								 | 
							
								            self._assert_port(kw["port"])
							 | 
						||
| 
								 | 
							
								        if "query" in kw:
							 | 
						||
| 
								 | 
							
								            kw["query"] = self._str_dict(kw["query"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return super(URL, self)._replace(**kw)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def update_query_string(self, query_string, append=False):
							 | 
						||
| 
								 | 
							
								        """Return a new :class:`_engine.URL` object with the :attr:`_engine.URL.query`
							 | 
						||
| 
								 | 
							
								        parameter dictionary updated by the given query string.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        E.g.::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            >>> from sqlalchemy.engine import make_url
							 | 
						||
| 
								 | 
							
								            >>> url = make_url("postgresql://user:pass@host/dbname")
							 | 
						||
| 
								 | 
							
								            >>> url = url.update_query_string("alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
							 | 
						||
| 
								 | 
							
								            >>> str(url)
							 | 
						||
| 
								 | 
							
								            'postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param query_string: a URL escaped query string, not including the
							 | 
						||
| 
								 | 
							
								         question mark.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param append: if True, parameters in the existing query string will
							 | 
						||
| 
								 | 
							
								         not be removed; new parameters will be in addition to those present.
							 | 
						||
| 
								 | 
							
								         If left at its default of False, keys present in the given query
							 | 
						||
| 
								 | 
							
								         parameters will replace those of the existing query string.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`_engine.URL.query`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.update_query_dict`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """  # noqa: E501
							 | 
						||
| 
								 | 
							
								        return self.update_query_pairs(
							 | 
						||
| 
								 | 
							
								            util.parse_qsl(query_string), append=append
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def update_query_pairs(self, key_value_pairs, append=False):
							 | 
						||
| 
								 | 
							
								        """Return a new :class:`_engine.URL` object with the
							 | 
						||
| 
								 | 
							
								        :attr:`_engine.URL.query`
							 | 
						||
| 
								 | 
							
								        parameter dictionary updated by the given sequence of key/value pairs
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        E.g.::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            >>> from sqlalchemy.engine import make_url
							 | 
						||
| 
								 | 
							
								            >>> url = make_url("postgresql://user:pass@host/dbname")
							 | 
						||
| 
								 | 
							
								            >>> url = url.update_query_pairs([("alt_host", "host1"), ("alt_host", "host2"), ("ssl_cipher", "/path/to/crt")])
							 | 
						||
| 
								 | 
							
								            >>> str(url)
							 | 
						||
| 
								 | 
							
								            'postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param key_value_pairs: A sequence of tuples containing two strings
							 | 
						||
| 
								 | 
							
								         each.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param append: if True, parameters in the existing query string will
							 | 
						||
| 
								 | 
							
								         not be removed; new parameters will be in addition to those present.
							 | 
						||
| 
								 | 
							
								         If left at its default of False, keys present in the given query
							 | 
						||
| 
								 | 
							
								         parameters will replace those of the existing query string.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`_engine.URL.query`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.difference_update_query`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.set`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """  # noqa: E501
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        existing_query = self.query
							 | 
						||
| 
								 | 
							
								        new_keys = {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for key, value in key_value_pairs:
							 | 
						||
| 
								 | 
							
								            if key in new_keys:
							 | 
						||
| 
								 | 
							
								                new_keys[key] = util.to_list(new_keys[key])
							 | 
						||
| 
								 | 
							
								                new_keys[key].append(value)
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                new_keys[key] = value
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if append:
							 | 
						||
| 
								 | 
							
								            new_query = {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for k in new_keys:
							 | 
						||
| 
								 | 
							
								                if k in existing_query:
							 | 
						||
| 
								 | 
							
								                    new_query[k] = util.to_list(
							 | 
						||
| 
								 | 
							
								                        existing_query[k]
							 | 
						||
| 
								 | 
							
								                    ) + util.to_list(new_keys[k])
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    new_query[k] = new_keys[k]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            new_query.update(
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    k: existing_query[k]
							 | 
						||
| 
								 | 
							
								                    for k in set(existing_query).difference(new_keys)
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            new_query = self.query.union(new_keys)
							 | 
						||
| 
								 | 
							
								        return self.set(query=new_query)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def update_query_dict(self, query_parameters, append=False):
							 | 
						||
| 
								 | 
							
								        """Return a new :class:`_engine.URL` object with the
							 | 
						||
| 
								 | 
							
								        :attr:`_engine.URL.query` parameter dictionary updated by the given
							 | 
						||
| 
								 | 
							
								        dictionary.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        The dictionary typically contains string keys and string values.
							 | 
						||
| 
								 | 
							
								        In order to represent a query parameter that is expressed multiple
							 | 
						||
| 
								 | 
							
								        times, pass a sequence of string values.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        E.g.::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            >>> from sqlalchemy.engine import make_url
							 | 
						||
| 
								 | 
							
								            >>> url = make_url("postgresql://user:pass@host/dbname")
							 | 
						||
| 
								 | 
							
								            >>> url = url.update_query_dict({"alt_host": ["host1", "host2"], "ssl_cipher": "/path/to/crt"})
							 | 
						||
| 
								 | 
							
								            >>> str(url)
							 | 
						||
| 
								 | 
							
								            'postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param query_parameters: A dictionary with string keys and values
							 | 
						||
| 
								 | 
							
								         that are either strings, or sequences of strings.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param append: if True, parameters in the existing query string will
							 | 
						||
| 
								 | 
							
								         not be removed; new parameters will be in addition to those present.
							 | 
						||
| 
								 | 
							
								         If left at its default of False, keys present in the given query
							 | 
						||
| 
								 | 
							
								         parameters will replace those of the existing query string.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`_engine.URL.query`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.update_query_string`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.update_query_pairs`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.difference_update_query`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.set`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """  # noqa: E501
							 | 
						||
| 
								 | 
							
								        return self.update_query_pairs(query_parameters.items(), append=append)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def difference_update_query(self, names):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Remove the given names from the :attr:`_engine.URL.query` dictionary,
							 | 
						||
| 
								 | 
							
								        returning the new :class:`_engine.URL`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        E.g.::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            url = url.difference_update_query(['foo', 'bar'])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Equivalent to using :meth:`_engine.URL.set` as follows::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            url = url.set(
							 | 
						||
| 
								 | 
							
								                query={
							 | 
						||
| 
								 | 
							
								                    key: url.query[key]
							 | 
						||
| 
								 | 
							
								                    for key in set(url.query).difference(['foo', 'bar'])
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`_engine.URL.query`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.update_query_dict`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :meth:`_engine.URL.set`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if not set(names).intersection(self.query):
							 | 
						||
| 
								 | 
							
								            return self
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return URL(
							 | 
						||
| 
								 | 
							
								            self.drivername,
							 | 
						||
| 
								 | 
							
								            self.username,
							 | 
						||
| 
								 | 
							
								            self.password,
							 | 
						||
| 
								 | 
							
								            self.host,
							 | 
						||
| 
								 | 
							
								            self.port,
							 | 
						||
| 
								 | 
							
								            self.database,
							 | 
						||
| 
								 | 
							
								            util.immutabledict(
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    key: self.query[key]
							 | 
						||
| 
								 | 
							
								                    for key in set(self.query).difference(names)
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								            _new_ok=True,
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @util.memoized_property
							 | 
						||
| 
								 | 
							
								    def normalized_query(self):
							 | 
						||
| 
								 | 
							
								        """Return the :attr:`_engine.URL.query` dictionary with values normalized
							 | 
						||
| 
								 | 
							
								        into sequences.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        As the :attr:`_engine.URL.query` dictionary may contain either
							 | 
						||
| 
								 | 
							
								        string values or sequences of string values to differentiate between
							 | 
						||
| 
								 | 
							
								        parameters that are specified multiple times in the query string,
							 | 
						||
| 
								 | 
							
								        code that needs to handle multiple parameters generically will wish
							 | 
						||
| 
								 | 
							
								        to use this attribute so that all parameters present are presented
							 | 
						||
| 
								 | 
							
								        as sequences.   Inspiration is from Python's ``urllib.parse.parse_qs``
							 | 
						||
| 
								 | 
							
								        function.  E.g.::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            >>> from sqlalchemy.engine import make_url
							 | 
						||
| 
								 | 
							
								            >>> url = make_url("postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
							 | 
						||
| 
								 | 
							
								            >>> url.query
							 | 
						||
| 
								 | 
							
								            immutabledict({'alt_host': ('host1', 'host2'), 'ssl_cipher': '/path/to/crt'})
							 | 
						||
| 
								 | 
							
								            >>> url.normalized_query
							 | 
						||
| 
								 | 
							
								            immutabledict({'alt_host': ('host1', 'host2'), 'ssl_cipher': ('/path/to/crt',)})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """  # noqa: E501
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return util.immutabledict(
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                k: (v,) if not isinstance(v, tuple) else v
							 | 
						||
| 
								 | 
							
								                for k, v in self.query.items()
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @util.deprecated(
							 | 
						||
| 
								 | 
							
								        "1.4",
							 | 
						||
| 
								 | 
							
								        "The :meth:`_engine.URL.__to_string__ method is deprecated and will "
							 | 
						||
| 
								 | 
							
								        "be removed in a future release.  Please use the "
							 | 
						||
| 
								 | 
							
								        ":meth:`_engine.URL.render_as_string` method.",
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    def __to_string__(self, hide_password=True):
							 | 
						||
| 
								 | 
							
								        """Render this :class:`_engine.URL` object as a string.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param hide_password: Defaults to True.   The password is not shown
							 | 
						||
| 
								 | 
							
								         in the string unless this is set to False.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return self.render_as_string(hide_password=hide_password)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def render_as_string(self, hide_password=True):
							 | 
						||
| 
								 | 
							
								        """Render this :class:`_engine.URL` object as a string.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method is used when the ``__str__()`` or ``__repr__()``
							 | 
						||
| 
								 | 
							
								        methods are used.   The method directly includes additional options.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param hide_password: Defaults to True.   The password is not shown
							 | 
						||
| 
								 | 
							
								         in the string unless this is set to False.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        s = self.drivername + "://"
							 | 
						||
| 
								 | 
							
								        if self.username is not None:
							 | 
						||
| 
								 | 
							
								            s += _rfc_1738_quote(self.username)
							 | 
						||
| 
								 | 
							
								            if self.password is not None:
							 | 
						||
| 
								 | 
							
								                s += ":" + (
							 | 
						||
| 
								 | 
							
								                    "***"
							 | 
						||
| 
								 | 
							
								                    if hide_password
							 | 
						||
| 
								 | 
							
								                    else _rfc_1738_quote(str(self.password))
							 | 
						||
| 
								 | 
							
								                )
							 | 
						||
| 
								 | 
							
								            s += "@"
							 | 
						||
| 
								 | 
							
								        if self.host is not None:
							 | 
						||
| 
								 | 
							
								            if ":" in self.host:
							 | 
						||
| 
								 | 
							
								                s += "[%s]" % self.host
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                s += self.host
							 | 
						||
| 
								 | 
							
								        if self.port is not None:
							 | 
						||
| 
								 | 
							
								            s += ":" + str(self.port)
							 | 
						||
| 
								 | 
							
								        if self.database is not None:
							 | 
						||
| 
								 | 
							
								            s += "/" + self.database
							 | 
						||
| 
								 | 
							
								        if self.query:
							 | 
						||
| 
								 | 
							
								            keys = list(self.query)
							 | 
						||
| 
								 | 
							
								            keys.sort()
							 | 
						||
| 
								 | 
							
								            s += "?" + "&".join(
							 | 
						||
| 
								 | 
							
								                "%s=%s" % (util.quote_plus(k), util.quote_plus(element))
							 | 
						||
| 
								 | 
							
								                for k in keys
							 | 
						||
| 
								 | 
							
								                for element in util.to_list(self.query[k])
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        return s
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __str__(self):
							 | 
						||
| 
								 | 
							
								        return self.render_as_string(hide_password=False)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __repr__(self):
							 | 
						||
| 
								 | 
							
								        return self.render_as_string()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __copy__(self):
							 | 
						||
| 
								 | 
							
								        return self.__class__.create(
							 | 
						||
| 
								 | 
							
								            self.drivername,
							 | 
						||
| 
								 | 
							
								            self.username,
							 | 
						||
| 
								 | 
							
								            self.password,
							 | 
						||
| 
								 | 
							
								            self.host,
							 | 
						||
| 
								 | 
							
								            self.port,
							 | 
						||
| 
								 | 
							
								            self.database,
							 | 
						||
| 
								 | 
							
								            # note this is an immutabledict of str-> str / tuple of str,
							 | 
						||
| 
								 | 
							
								            # also fully immutable.  does not require deepcopy
							 | 
						||
| 
								 | 
							
								            self.query,
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __deepcopy__(self, memo):
							 | 
						||
| 
								 | 
							
								        return self.__copy__()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __hash__(self):
							 | 
						||
| 
								 | 
							
								        return hash(str(self))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __eq__(self, other):
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            isinstance(other, URL)
							 | 
						||
| 
								 | 
							
								            and self.drivername == other.drivername
							 | 
						||
| 
								 | 
							
								            and self.username == other.username
							 | 
						||
| 
								 | 
							
								            and self.password == other.password
							 | 
						||
| 
								 | 
							
								            and self.host == other.host
							 | 
						||
| 
								 | 
							
								            and self.database == other.database
							 | 
						||
| 
								 | 
							
								            and self.query == other.query
							 | 
						||
| 
								 | 
							
								            and self.port == other.port
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __ne__(self, other):
							 | 
						||
| 
								 | 
							
								        return not self == other
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def get_backend_name(self):
							 | 
						||
| 
								 | 
							
								        """Return the backend name.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This is the name that corresponds to the database backend in
							 | 
						||
| 
								 | 
							
								        use, and is the portion of the :attr:`_engine.URL.drivername`
							 | 
						||
| 
								 | 
							
								        that is to the left of the plus sign.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if "+" not in self.drivername:
							 | 
						||
| 
								 | 
							
								            return self.drivername
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return self.drivername.split("+")[0]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def get_driver_name(self):
							 | 
						||
| 
								 | 
							
								        """Return the backend name.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This is the name that corresponds to the DBAPI driver in
							 | 
						||
| 
								 | 
							
								        use, and is the portion of the :attr:`_engine.URL.drivername`
							 | 
						||
| 
								 | 
							
								        that is to the right of the plus sign.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        If the :attr:`_engine.URL.drivername` does not include a plus sign,
							 | 
						||
| 
								 | 
							
								        then the default :class:`_engine.Dialect` for this :class:`_engine.URL`
							 | 
						||
| 
								 | 
							
								        is imported in order to get the driver name.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if "+" not in self.drivername:
							 | 
						||
| 
								 | 
							
								            return self.get_dialect().driver
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return self.drivername.split("+")[1]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _instantiate_plugins(self, kwargs):
							 | 
						||
| 
								 | 
							
								        plugin_names = util.to_list(self.query.get("plugin", ()))
							 | 
						||
| 
								 | 
							
								        plugin_names += kwargs.get("plugins", [])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        kwargs = dict(kwargs)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        loaded_plugins = [
							 | 
						||
| 
								 | 
							
								            plugins.load(plugin_name)(self, kwargs)
							 | 
						||
| 
								 | 
							
								            for plugin_name in plugin_names
							 | 
						||
| 
								 | 
							
								        ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        u = self.difference_update_query(["plugin", "plugins"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for plugin in loaded_plugins:
							 | 
						||
| 
								 | 
							
								            new_u = plugin.update_url(u)
							 | 
						||
| 
								 | 
							
								            if new_u is not None:
							 | 
						||
| 
								 | 
							
								                u = new_u
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        kwargs.pop("plugins", None)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return u, loaded_plugins, kwargs
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _get_entrypoint(self):
							 | 
						||
| 
								 | 
							
								        """Return the "entry point" dialect class.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This is normally the dialect itself except in the case when the
							 | 
						||
| 
								 | 
							
								        returned class implements the get_dialect_cls() method.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if "+" not in self.drivername:
							 | 
						||
| 
								 | 
							
								            name = self.drivername
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            name = self.drivername.replace("+", ".")
							 | 
						||
| 
								 | 
							
								        cls = registry.load(name)
							 | 
						||
| 
								 | 
							
								        # check for legacy dialects that
							 | 
						||
| 
								 | 
							
								        # would return a module with 'dialect' as the
							 | 
						||
| 
								 | 
							
								        # actual class
							 | 
						||
| 
								 | 
							
								        if (
							 | 
						||
| 
								 | 
							
								            hasattr(cls, "dialect")
							 | 
						||
| 
								 | 
							
								            and isinstance(cls.dialect, type)
							 | 
						||
| 
								 | 
							
								            and issubclass(cls.dialect, Dialect)
							 | 
						||
| 
								 | 
							
								        ):
							 | 
						||
| 
								 | 
							
								            return cls.dialect
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return cls
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def get_dialect(self):
							 | 
						||
| 
								 | 
							
								        """Return the SQLAlchemy :class:`_engine.Dialect` class corresponding
							 | 
						||
| 
								 | 
							
								        to this URL's driver name.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        entrypoint = self._get_entrypoint()
							 | 
						||
| 
								 | 
							
								        dialect_cls = entrypoint.get_dialect_cls(self)
							 | 
						||
| 
								 | 
							
								        return dialect_cls
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def translate_connect_args(self, names=None, **kw):
							 | 
						||
| 
								 | 
							
								        r"""Translate url attributes into a dictionary of connection arguments.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Returns attributes of this url (`host`, `database`, `username`,
							 | 
						||
| 
								 | 
							
								        `password`, `port`) as a plain dictionary.  The attribute names are
							 | 
						||
| 
								 | 
							
								        used as the keys by default.  Unset or false attributes are omitted
							 | 
						||
| 
								 | 
							
								        from the final dictionary.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param \**kw: Optional, alternate key names for url attributes.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param names: Deprecated.  Same purpose as the keyword-based alternate
							 | 
						||
| 
								 | 
							
								            names, but correlates the name to the original positionally.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if names is not None:
							 | 
						||
| 
								 | 
							
								            util.warn_deprecated(
							 | 
						||
| 
								 | 
							
								                "The `URL.translate_connect_args.name`s parameter is "
							 | 
						||
| 
								 | 
							
								                "deprecated. Please pass the "
							 | 
						||
| 
								 | 
							
								                "alternate names as kw arguments.",
							 | 
						||
| 
								 | 
							
								                "1.4",
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        translated = {}
							 | 
						||
| 
								 | 
							
								        attribute_names = ["host", "database", "username", "password", "port"]
							 | 
						||
| 
								 | 
							
								        for sname in attribute_names:
							 | 
						||
| 
								 | 
							
								            if names:
							 | 
						||
| 
								 | 
							
								                name = names.pop(0)
							 | 
						||
| 
								 | 
							
								            elif sname in kw:
							 | 
						||
| 
								 | 
							
								                name = kw[sname]
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                name = sname
							 | 
						||
| 
								 | 
							
								            if name is not None and getattr(self, sname, False):
							 | 
						||
| 
								 | 
							
								                if sname == "password":
							 | 
						||
| 
								 | 
							
								                    translated[name] = str(getattr(self, sname))
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    translated[name] = getattr(self, sname)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return translated
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def make_url(name_or_url):
							 | 
						||
| 
								 | 
							
								    """Given a string or unicode instance, produce a new URL instance.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The given string is parsed according to the RFC 1738 spec.  If an
							 | 
						||
| 
								 | 
							
								    existing URL object is passed, just returns the object.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if isinstance(name_or_url, util.string_types):
							 | 
						||
| 
								 | 
							
								        return _parse_rfc1738_args(name_or_url)
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return name_or_url
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _parse_rfc1738_args(name):
							 | 
						||
| 
								 | 
							
								    pattern = re.compile(
							 | 
						||
| 
								 | 
							
								        r"""
							 | 
						||
| 
								 | 
							
								            (?P<name>[\w\+]+)://
							 | 
						||
| 
								 | 
							
								            (?:
							 | 
						||
| 
								 | 
							
								                (?P<username>[^:/]*)
							 | 
						||
| 
								 | 
							
								                (?::(?P<password>[^@]*))?
							 | 
						||
| 
								 | 
							
								            @)?
							 | 
						||
| 
								 | 
							
								            (?:
							 | 
						||
| 
								 | 
							
								                (?:
							 | 
						||
| 
								 | 
							
								                    \[(?P<ipv6host>[^/\?]+)\] |
							 | 
						||
| 
								 | 
							
								                    (?P<ipv4host>[^/:\?]+)
							 | 
						||
| 
								 | 
							
								                )?
							 | 
						||
| 
								 | 
							
								                (?::(?P<port>[^/\?]*))?
							 | 
						||
| 
								 | 
							
								            )?
							 | 
						||
| 
								 | 
							
								            (?:/(?P<database>[^\?]*))?
							 | 
						||
| 
								 | 
							
								            (?:\?(?P<query>.*))?
							 | 
						||
| 
								 | 
							
								            """,
							 | 
						||
| 
								 | 
							
								        re.X,
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    m = pattern.match(name)
							 | 
						||
| 
								 | 
							
								    if m is not None:
							 | 
						||
| 
								 | 
							
								        components = m.groupdict()
							 | 
						||
| 
								 | 
							
								        if components["query"] is not None:
							 | 
						||
| 
								 | 
							
								            query = {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for key, value in util.parse_qsl(components["query"]):
							 | 
						||
| 
								 | 
							
								                if util.py2k:
							 | 
						||
| 
								 | 
							
								                    key = key.encode("ascii")
							 | 
						||
| 
								 | 
							
								                if key in query:
							 | 
						||
| 
								 | 
							
								                    query[key] = util.to_list(query[key])
							 | 
						||
| 
								 | 
							
								                    query[key].append(value)
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    query[key] = value
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            query = None
							 | 
						||
| 
								 | 
							
								        components["query"] = query
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if components["username"] is not None:
							 | 
						||
| 
								 | 
							
								            components["username"] = _rfc_1738_unquote(components["username"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if components["password"] is not None:
							 | 
						||
| 
								 | 
							
								            components["password"] = _rfc_1738_unquote(components["password"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ipv4host = components.pop("ipv4host")
							 | 
						||
| 
								 | 
							
								        ipv6host = components.pop("ipv6host")
							 | 
						||
| 
								 | 
							
								        components["host"] = ipv4host or ipv6host
							 | 
						||
| 
								 | 
							
								        name = components.pop("name")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if components["port"]:
							 | 
						||
| 
								 | 
							
								            components["port"] = int(components["port"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return URL.create(name, **components)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        raise exc.ArgumentError(
							 | 
						||
| 
								 | 
							
								            "Could not parse rfc1738 URL from string '%s'" % name
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _rfc_1738_quote(text):
							 | 
						||
| 
								 | 
							
								    return re.sub(r"[:@/]", lambda m: "%%%X" % ord(m.group(0)), text)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _rfc_1738_unquote(text):
							 | 
						||
| 
								 | 
							
								    return util.unquote(text)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _parse_keyvalue_args(name):
							 | 
						||
| 
								 | 
							
								    m = re.match(r"(\w+)://(.*)", name)
							 | 
						||
| 
								 | 
							
								    if m is not None:
							 | 
						||
| 
								 | 
							
								        (name, args) = m.group(1, 2)
							 | 
						||
| 
								 | 
							
								        opts = dict(util.parse_qsl(args))
							 | 
						||
| 
								 | 
							
								        return URL(name, *opts)
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return None
							 |