Source code for relstorage.zodburi_resolver

# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function

import ZConfig.datatypes
from ZODB.DemoStorage import DemoStorage

from relstorage.options import Options
from relstorage.storage import RelStorage

try:
    from urllib import parse as urlparse
    from urllib.parse import parse_qsl
except ImportError:
    # Py2
    import urlparse
    from urlparse import parse_qsl


datatypes = ZConfig.datatypes.stock_datatypes.copy()
datatypes['string-list'] = lambda s: tuple(s.split(','))

def asBoolean(s):
    if s == '0':
        return False
    if s == '1':
        return True
    return ZConfig.datatypes.stock_datatypes['boolean'](s)

datatypes['boolean'] = asBoolean

class Resolver(object):
    _bool_args = ()
    _int_args = ()
    _string_args = ()
    _bytesize_args = ()
    _float_args = ()
    _tuple_args = ()

    def interpret_kwargs(self, kw):
        unused = kw.copy()
        new = {}

        converters = [
            (datatypes['boolean'], self._bool_args),
            (datatypes['integer'], self._int_args),
            (datatypes['string'], self._string_args),
            (datatypes['byte-size'], self._bytesize_args),
            (datatypes['float'], self._float_args),
            (datatypes['string-list'], self._tuple_args),
        ]
        for convert, arg_names in converters:
            for arg_name in arg_names:
                value = unused.pop(arg_name, None)
                if value is not None:
                    value = convert(value)
                    new[arg_name] = value

        return new, unused


# Not a real resolver, but we use interpret_kwargs
class PostgreSQLAdapterHelper(Resolver):
    _int_args = ('connect_timeout', )
    _string_args = ('ssl_mode', )

    def __call__(self, parsed_uri, kw):
        dsn_args = [
            ('dbname', parsed_uri.path[1:]),
            ('user', parsed_uri.username),
            ('password', parsed_uri.password),
            ('host', parsed_uri.hostname),
            ('port', parsed_uri.port)
        ]

        kw, unused = self.interpret_kwargs(kw)
        dsn_args.extend(kw.items())

        dsn = ' '.join("%s='%s'" % arg for arg in dsn_args)

        def factory(options):
            from relstorage.adapters.postgresql import PostgreSQLAdapter
            return PostgreSQLAdapter(dsn=dsn, options=options)
        return factory, unused


class MySQLAdapterHelper(Resolver):
    _int_args = ('connect_timeout', 'client_flag', 'load_infile', 'compress',
                 'named_pipe')
    _string_args = ('unix_socket', 'init_command', 'read_default_file',
                    'read_default_group')

    def __call__(self, parsed_uri, kw):
        settings = {
            'db': parsed_uri.path[1:],
            'user': parsed_uri.username,
            'passwd': parsed_uri.password,
            'host': parsed_uri.hostname,
            'port': parsed_uri.port
        }

        kw, unused = self.interpret_kwargs(kw)
        settings.update(kw)

        def factory(options):
            from relstorage.adapters.mysql import MySQLAdapter
            return MySQLAdapter(options=options, **settings)
        return factory, unused


class OracleAdapterHelper(Resolver):
    _int_args = ('twophase', )
    _string_args = ('user', 'password', 'dsn')

    def __call__(self, parsed_uri, kw):
        kw, unused = self.interpret_kwargs(kw)

        def factory(options):
            from relstorage.adapters.oracle import OracleAdapter
            return OracleAdapter(options=options, **kw)
        return factory, unused

[docs] class SqliteAdapterHelper(Resolver): """ .. versionchanged:: 4.0.0a1 The ``data_dir`` argument replaces the ``path`` argument. """ _string_args = ('data_dir',) def __call__(self, parsed_uri, kw): kw, unused = self.interpret_kwargs(kw) def factory(options): from relstorage.adapters.sqlite.adapter import Sqlite3Adapter return Sqlite3Adapter(options=options, pragmas={}, **kw) return factory, unused
# The relstorage support is inspired by django-zodb. class RelStorageURIResolver(Resolver): _bool_args = ( 'read_only', 'keep_history', 'pack_gc', 'pack_dry_run', 'shared_blob_dir', 'demostorage', ) _int_args = ( 'cache_local_mb', 'commit_lock_timeout', 'commit_lock_id', ) _string_args = ( 'name', 'blob_dir', 'replica_conf', 'cache_module_name', 'cache_prefix', 'cache_delta_size_limit', 'cache_local_compression', 'driver', ) _bytesize_args = ( 'blob_cache_size', 'blob_cache_size_check', 'blob_cache_chunk_size', 'cache_local_object_max', ) _float_args = ('replica_timeout', 'pack_batch_timeout', 'pack_duty_cycle', 'pack_max_delay') _tuple_args = ('cache_servers',) def __init__(self, adapter_helper): self.adapter_helper = adapter_helper def __call__(self, uri): uri = uri.replace('postgres://', 'http://', 1) uri = uri.replace('mysql://', 'http://', 1) uri = uri.replace('oracle://', 'http://', 1) uri = uri.replace('sqlite://', 'http://', 1) parsed_uri = urlparse.urlsplit(uri) kw = dict(parse_qsl(parsed_uri.query)) adapter_factory, kw = self.adapter_helper(parsed_uri, kw) kw, unused = self.interpret_kwargs(kw) demostorage = kw.pop('demostorage', False) options = Options(**kw) def factory(): adapter = adapter_factory(options) storage = RelStorage(adapter=adapter, options=options) return storage if not demostorage else DemoStorage(base=storage) return factory, unused postgresql_resolver = RelStorageURIResolver(PostgreSQLAdapterHelper()) mysql_resolver = RelStorageURIResolver(MySQLAdapterHelper()) oracle_resolver = RelStorageURIResolver(OracleAdapterHelper()) sqlite_resolver = RelStorageURIResolver(SqliteAdapterHelper())