changeset dd0bb6655e6d in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset&node=dd0bb6655e6d
description:
Add support for database connection parameters to configuration URI
issue10101
review339891002
diffstat:
CHANGELOG | 1 +
doc/topics/configuration.rst | 21 ++++++++++++++++--
trytond/backend/postgresql/database.py | 14 +++---------
trytond/backend/sqlite/database.py | 37 +++++++++++++++++++++++++--------
4 files changed, 51 insertions(+), 22 deletions(-)
diffs (159 lines):
diff -r 36ce819e336a -r dd0bb6655e6d CHANGELOG
--- a/CHANGELOG Mon Apr 12 20:16:41 2021 +0200
+++ b/CHANGELOG Mon Apr 12 20:39:23 2021 +0200
@@ -1,3 +1,4 @@
+* Add support for database connection parameters to configuration URI
* Use immutable datastructures for Dict and MultiSelection fields
* Skip warnings for non-interactive operations
* Check rule only if _check_access is set
diff -r 36ce819e336a -r dd0bb6655e6d doc/topics/configuration.rst
--- a/doc/topics/configuration.rst Mon Apr 12 20:16:41 2021 +0200
+++ b/doc/topics/configuration.rst Mon Apr 12 20:39:23 2021 +0200
@@ -106,7 +106,10 @@
Contains the URI to connect to the SQL database. The URI follows the RFC-3986_.
The typical form is:
- database://username:password@host:port/
+ database://username:password@host:port/?param1=value1¶m2=value2
+
+The parameters are database dependent, check the database documentation for a
+list of valid parameters.
Default: The value of the environment variable ``TRYTOND_DATABASE_URI`` or
``sqlite://`` if not set.
@@ -116,15 +119,27 @@
PostgreSQL
**********
-``pyscopg2`` supports two type of connections:
+``psycopg2`` supports two type of connections:
- TCP/IP connection: ``postgresql://user:password@localhost:5432/``
- Unix domain connection: ``postgresql://username:password@/``
+Please refer to `psycopg2 for the complete specification of the URI
+<https://www.psycopg.org/docs/module.html#psycopg2.connect>`_.
+
+A list of parameters supported by PostgreSQL can be found in the
+`documentation
<https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS>`_.
+
SQLite
******
-The only possible URI is: ``sqlite://``
+The URI is defined as ``sqlite://``
+
+If the name of the database is ``:memory:``, the parameter ``mode`` will be set
+to ``memory`` thus using a pure in-memory database.
+
+The recognized query parameters can be found in SQLite's
+`documentation <https://www.sqlite.org/uri.html#recognized_query_parameters>`_.
path
~~~~
diff -r 36ce819e336a -r dd0bb6655e6d trytond/backend/postgresql/database.py
--- a/trytond/backend/postgresql/database.py Mon Apr 12 20:16:41 2021 +0200
+++ b/trytond/backend/postgresql/database.py Mon Apr 12 20:39:23 2021 +0200
@@ -4,8 +4,8 @@
import time
import logging
import os
-import urllib.parse
import json
+import warnings
from datetime import datetime
from decimal import Decimal
from itertools import chain, repeat
@@ -243,17 +243,11 @@
@classmethod
def _connection_params(cls, name):
uri = parse_uri(config.get('database', 'uri'))
+ if uri.path:
+ warnings.warn("The path specified in the URI will be overridden")
params = {
- 'dbname': name,
+ 'dsn': uri._replace(path=name).geturl(),
}
- if uri.username:
- params['user'] = uri.username
- if uri.password:
- params['password'] = urllib.parse.unquote_plus(uri.password)
- if uri.hostname:
- params['host'] = uri.hostname
- if uri.port:
- params['port'] = uri.port
return params
def connect(self):
diff -r 36ce819e336a -r dd0bb6655e6d trytond/backend/sqlite/database.py
--- a/trytond/backend/sqlite/database.py Mon Apr 12 20:16:41 2021 +0200
+++ b/trytond/backend/sqlite/database.py Mon Apr 12 20:39:23 2021 +0200
@@ -7,8 +7,11 @@
import random
import threading
import time
+import urllib.parse
+import warnings
from decimal import Decimal
from weakref import WeakKeyDictionary
+from werkzeug.security import safe_join
try:
from pysqlite2 import dbapi2 as sqlite
@@ -24,7 +27,7 @@
Overlay, CharLength, CurrentTimestamp, Trim)
from trytond.backend.database import DatabaseInterface, SQLType
-from trytond.config import config
+from trytond.config import config, parse_uri
from trytond.transaction import Transaction
__all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError']
@@ -336,16 +339,10 @@
Database._local.memory_database = self
def connect(self):
- if self.name == ':memory:':
- path = ':memory:'
- else:
- db_filename = self.name + '.sqlite'
- path = os.path.join(config.get('database', 'path'), db_filename)
- if not os.path.isfile(path):
- raise IOError('Database "%s" doesn\'t exist!' % path)
if self._conn is not None:
return self
- self._conn = sqlite.connect(path,
+ self._conn = sqlite.connect(
+ self._make_uri(), uri=True,
detect_types=sqlite.PARSE_DECLTYPES | sqlite.PARSE_COLNAMES,
factory=SQLiteConnection)
self._conn.create_function('extract', 2, SQLiteExtract.extract)
@@ -402,6 +399,28 @@
self._conn.execute('PRAGMA foreign_keys = ON')
return self
+ def _make_uri(self):
+ uri = config.get('database', 'uri')
+ base_uri = parse_uri(uri)
+ if base_uri.path:
+ warnings.warn("The path specified in the URI will be overridden")
+
+ if self.name == ':memory:':
+ query_string = urllib.parse.parse_qs(base_uri.query)
+ query_string['mode'] = 'memory'
+ query = urllib.parse.urlencode(query_string, doseq=True)
+ db_uri = base_uri._replace(netloc='', path='/', query=query)
+ else:
+ db_path = safe_join(
+ config.get('database', 'path'), self.name + '.sqlite')
+ db_uri = base_uri._replace(path=db_path)
+
+ # Use unparse before replacing sqlite with file because SQLite accepts
+ # a relative path URI like file:db/test.sqlite which doesn't conform to
+ # RFC8089 which urllib follows and enforces when the scheme is 'file'
+ db_uri = urllib.parse.urlunparse(db_uri)
+ return db_uri.replace('sqlite', 'file', 1)
+
def get_connection(self, autocommit=False, readonly=False):
if self._conn is None:
self.connect()