PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Windows/Python3.8/WPy64-3830/WPy64-3830/python-3.8.3.amd64/Lib/site-packages/sqlalchemy/engine/url.py

https://gitlab.com/abhi1tb/build
Python | 310 lines | 249 code | 19 blank | 42 comment | 29 complexity | 2f46ded94c228c84b803b490cf8c1d16 MD5 | raw file
  1. # engine/url.py
  2. # Copyright (C) 2005-2020 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: http://www.opensource.org/licenses/mit-license.php
  7. """Provides the :class:`~sqlalchemy.engine.url.URL` class which encapsulates
  8. information about a database connection specification.
  9. The URL object is created automatically when
  10. :func:`~sqlalchemy.engine.create_engine` is called with a string
  11. argument; alternatively, the URL is a public-facing construct which can
  12. be used directly and is also accepted directly by ``create_engine()``.
  13. """
  14. import re
  15. from .interfaces import Dialect
  16. from .. import exc
  17. from .. import util
  18. from ..dialects import plugins
  19. from ..dialects import registry
  20. class URL(object):
  21. """
  22. Represent the components of a URL used to connect to a database.
  23. This object is suitable to be passed directly to a
  24. :func:`~sqlalchemy.create_engine` call. The fields of the URL are parsed
  25. from a string by the :func:`.make_url` function. the string
  26. format of the URL is an RFC-1738-style string.
  27. All initialization parameters are available as public attributes.
  28. :param drivername: the name of the database backend.
  29. This name will correspond to a module in sqlalchemy/databases
  30. or a third party plug-in.
  31. :param username: The user name.
  32. :param password: database password.
  33. :param host: The name of the host.
  34. :param port: The port number.
  35. :param database: The database name.
  36. :param query: A dictionary of options to be passed to the
  37. dialect and/or the DBAPI upon connect.
  38. """
  39. def __init__(
  40. self,
  41. drivername,
  42. username=None,
  43. password=None,
  44. host=None,
  45. port=None,
  46. database=None,
  47. query=None,
  48. ):
  49. self.drivername = drivername
  50. self.username = username
  51. self.password_original = password
  52. self.host = host
  53. if port is not None:
  54. self.port = int(port)
  55. else:
  56. self.port = None
  57. self.database = database
  58. self.query = query or {}
  59. def __to_string__(self, hide_password=True):
  60. s = self.drivername + "://"
  61. if self.username is not None:
  62. s += _rfc_1738_quote(self.username)
  63. if self.password is not None:
  64. s += ":" + (
  65. "***" if hide_password else _rfc_1738_quote(self.password)
  66. )
  67. s += "@"
  68. if self.host is not None:
  69. if ":" in self.host:
  70. s += "[%s]" % self.host
  71. else:
  72. s += self.host
  73. if self.port is not None:
  74. s += ":" + str(self.port)
  75. if self.database is not None:
  76. s += "/" + self.database
  77. if self.query:
  78. keys = list(self.query)
  79. keys.sort()
  80. s += "?" + "&".join(
  81. "%s=%s" % (util.quote_plus(k), util.quote_plus(element))
  82. for k in keys
  83. for element in util.to_list(self.query[k])
  84. )
  85. return s
  86. def __str__(self):
  87. return self.__to_string__(hide_password=False)
  88. def __repr__(self):
  89. return self.__to_string__()
  90. def __hash__(self):
  91. return hash(str(self))
  92. def __eq__(self, other):
  93. return (
  94. isinstance(other, URL)
  95. and self.drivername == other.drivername
  96. and self.username == other.username
  97. and self.password == other.password
  98. and self.host == other.host
  99. and self.database == other.database
  100. and self.query == other.query
  101. and self.port == other.port
  102. )
  103. def __ne__(self, other):
  104. return not self == other
  105. @property
  106. def password(self):
  107. if self.password_original is None:
  108. return None
  109. else:
  110. return util.text_type(self.password_original)
  111. @password.setter
  112. def password(self, password):
  113. self.password_original = password
  114. def get_backend_name(self):
  115. if "+" not in self.drivername:
  116. return self.drivername
  117. else:
  118. return self.drivername.split("+")[0]
  119. def get_driver_name(self):
  120. if "+" not in self.drivername:
  121. return self.get_dialect().driver
  122. else:
  123. return self.drivername.split("+")[1]
  124. def _instantiate_plugins(self, kwargs):
  125. plugin_names = util.to_list(self.query.get("plugin", ()))
  126. plugin_names += kwargs.get("plugins", [])
  127. return [
  128. plugins.load(plugin_name)(self, kwargs)
  129. for plugin_name in plugin_names
  130. ]
  131. def _get_entrypoint(self):
  132. """Return the "entry point" dialect class.
  133. This is normally the dialect itself except in the case when the
  134. returned class implements the get_dialect_cls() method.
  135. """
  136. if "+" not in self.drivername:
  137. name = self.drivername
  138. else:
  139. name = self.drivername.replace("+", ".")
  140. cls = registry.load(name)
  141. # check for legacy dialects that
  142. # would return a module with 'dialect' as the
  143. # actual class
  144. if (
  145. hasattr(cls, "dialect")
  146. and isinstance(cls.dialect, type)
  147. and issubclass(cls.dialect, Dialect)
  148. ):
  149. return cls.dialect
  150. else:
  151. return cls
  152. def get_dialect(self):
  153. """Return the SQLAlchemy database dialect class corresponding
  154. to this URL's driver name.
  155. """
  156. entrypoint = self._get_entrypoint()
  157. dialect_cls = entrypoint.get_dialect_cls(self)
  158. return dialect_cls
  159. def translate_connect_args(self, names=[], **kw):
  160. r"""Translate url attributes into a dictionary of connection arguments.
  161. Returns attributes of this url (`host`, `database`, `username`,
  162. `password`, `port`) as a plain dictionary. The attribute names are
  163. used as the keys by default. Unset or false attributes are omitted
  164. from the final dictionary.
  165. :param \**kw: Optional, alternate key names for url attributes.
  166. :param names: Deprecated. Same purpose as the keyword-based alternate
  167. names, but correlates the name to the original positionally.
  168. """
  169. translated = {}
  170. attribute_names = ["host", "database", "username", "password", "port"]
  171. for sname in attribute_names:
  172. if names:
  173. name = names.pop(0)
  174. elif sname in kw:
  175. name = kw[sname]
  176. else:
  177. name = sname
  178. if name is not None and getattr(self, sname, False):
  179. translated[name] = getattr(self, sname)
  180. return translated
  181. def make_url(name_or_url):
  182. """Given a string or unicode instance, produce a new URL instance.
  183. The given string is parsed according to the RFC 1738 spec. If an
  184. existing URL object is passed, just returns the object.
  185. """
  186. if isinstance(name_or_url, util.string_types):
  187. return _parse_rfc1738_args(name_or_url)
  188. else:
  189. return name_or_url
  190. def _parse_rfc1738_args(name):
  191. pattern = re.compile(
  192. r"""
  193. (?P<name>[\w\+]+)://
  194. (?:
  195. (?P<username>[^:/]*)
  196. (?::(?P<password>.*))?
  197. @)?
  198. (?:
  199. (?:
  200. \[(?P<ipv6host>[^/]+)\] |
  201. (?P<ipv4host>[^/:]+)
  202. )?
  203. (?::(?P<port>[^/]*))?
  204. )?
  205. (?:/(?P<database>.*))?
  206. """,
  207. re.X,
  208. )
  209. m = pattern.match(name)
  210. if m is not None:
  211. components = m.groupdict()
  212. if components["database"] is not None:
  213. tokens = components["database"].split("?", 2)
  214. components["database"] = tokens[0]
  215. if len(tokens) > 1:
  216. query = {}
  217. for key, value in util.parse_qsl(tokens[1]):
  218. if util.py2k:
  219. key = key.encode("ascii")
  220. if key in query:
  221. query[key] = util.to_list(query[key])
  222. query[key].append(value)
  223. else:
  224. query[key] = value
  225. else:
  226. query = None
  227. else:
  228. query = None
  229. components["query"] = query
  230. if components["username"] is not None:
  231. components["username"] = _rfc_1738_unquote(components["username"])
  232. if components["password"] is not None:
  233. components["password"] = _rfc_1738_unquote(components["password"])
  234. ipv4host = components.pop("ipv4host")
  235. ipv6host = components.pop("ipv6host")
  236. components["host"] = ipv4host or ipv6host
  237. name = components.pop("name")
  238. return URL(name, **components)
  239. else:
  240. raise exc.ArgumentError(
  241. "Could not parse rfc1738 URL from string '%s'" % name
  242. )
  243. def _rfc_1738_quote(text):
  244. return re.sub(r"[:@/]", lambda m: "%%%X" % ord(m.group(0)), text)
  245. def _rfc_1738_unquote(text):
  246. return util.unquote(text)
  247. def _parse_keyvalue_args(name):
  248. m = re.match(r"(\w+)://(.*)", name)
  249. if m is not None:
  250. (name, args) = m.group(1, 2)
  251. opts = dict(util.parse_qsl(args))
  252. return URL(name, *opts)
  253. else:
  254. return None