Ejemplo n.º 1
0
def init(confdict, ctx=None):
    """
    Initializes this module acoording to the :ref:`SCORE module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`backend` :confdefault:`python`
        The shell backend to use. You can use either of the shells prvided by
        this module ("python", "ipython" and "bpython") or a string, that will
        be resolved using :func:`score.init.parse_dotted_path`.

    :confkey:`backend.autoinstall` :confdefault:`True`
        Whether the given *backend* should be installed automatically, if it was
        not found.

    :confkey:`callbacks`
        A :func:`list <score.init.parse_list>` of :func:`dotted python paths
        <score.init.parse_dotted_path>` to functions that will be called before
        the shell is spawned. Every callback will receive a `dict` representing
        the variables that will be available in the shell. The callbacks are
        free to add further variables to this list.

    """
    conf = defaults.copy()
    conf.update(confdict)
    shell_cls = Shell.get(conf['backend'])
    if not shell_cls:
        shell_cls = parse_dotted_path(conf['backend'])
    backend = shell_cls(conf['backend.autoinstall'])
    callbacks = []
    for path in parse_list(conf['callbacks']):
        callback = parse_dotted_path(path)
        if not callable(callback):
            raise ConfigurationError('Given callback not callable: %s' % path)
        callbacks.append(callback)
    return ConfiguredShellModule(ctx, backend, callbacks)
Ejemplo n.º 2
0
def _postprocess(data, objects=None):
    relationships = {}
    proxies = {}
    columns = {}
    if not objects:
        objects = {}
        classes = {}
    else:
        classes = dict((cls, parse_dotted_path(cls))
                       for cls in objects)
    for classname in data:
        classes[classname] = parse_dotted_path(classname)
        cls = classes[classname]
        relationships[classname] = {}
        proxies[classname] = {}
        for relationship in sa.inspect(cls).relationships:
            relationships[classname][relationship.key] = relationship
        columns[classname] = {}
        for column in sa.inspect(cls).columns:
            columns[classname][column.description] = column
        if classname not in objects:
            objects[classname] = {}
        objects[classname].update(dict((id, cls()) for id in data[classname]))
        for member in dir(cls):
            if member.startswith('__'):
                continue
            value = getattr(cls, member)
            if isinstance(value, AssociationProxy):
                proxies[classname][member] = value
    for classname in data:
        cls = classes[classname]
        for id in data[classname]:
            obj = objects[classname][id]
            if not data[classname][id]:
                continue
            for member in data[classname][id]:
                value = data[classname][id][member]
                if member in relationships[classname]:
                    relcls = relationships[classname][member].argument
                    if isinstance(relcls, sa.orm.Mapper):
                        relcls = relcls.class_
                    else:
                        relcls = relcls()
                    if not isinstance(relcls, type):
                        relcls = relcls.__class__
                    value = _replace_object(classes, objects, relcls, value)
                elif member in proxies[classname]:
                    proxy = proxies[classname][member]
                    col = proxy.attr[1].property.columns[0]
                    if isinstance(col.type, type(cls)):
                        value = _replace_object(
                            classes, objects, relcls, value)
                    else:
                        value = map(lambda v: _convert_value(v, col), value)
                elif member in columns[classname]:
                    value = _convert_value(value, columns[classname][member])
                setattr(obj, member, value)
    return objects
Ejemplo n.º 3
0
def engine_from_config(config):
    """
    A wrapper around :func:`sqlalchemy.engine_from_config`, that converts
    certain configuration values. Currently, the following configurations are
    processed:

    - ``sqlalchemy.echo`` (using :func:`score.init.parse_bool`)
    - ``sqlalchemy.echo_pool`` (using :func:`score.init.parse_bool`)
    - ``sqlalchemy.case_sensitive`` (using :func:`score.init.parse_bool`)
    - ``sqlalchemy.module`` (using :func:`score.init.parse_dotted_path`)
    - ``sqlalchemy.poolclass`` (using :func:`score.init.parse_dotted_path`)
    - ``sqlalchemy.pool`` (using :func:`score.init.parse_call`)
    - ``sqlalchemy.pool_size`` (converted to `int`)
    - ``sqlalchemy.pool_recycle`` (converted to `int`)
    """
    global _registered_utf8mb4
    conf = dict()
    for key in config:
        if key in ('sqlalchemy.echo', 'sqlalchemy.echo_pool',
                   'sqlalchemy.case_sensitive'):
            conf[key] = parse_bool(config[key])
        elif key in ('sqlalchemy.module', 'sqlalchemy.poolclass'):
            conf[key] = parse_dotted_path(config[key])
        elif key == 'sqlalchemy.pool':
            conf[key] = parse_call(config[key])
        elif key in ('sqlalchemy.pool_size', 'sqlalchemy.pool_recycle'):
            conf[key] = int(config[key])
        else:
            conf[key] = config[key]
    if not _registered_utf8mb4 and 'utf8mb4' in conf.get('sqlalchemy.url', ''):
        import codecs
        codecs.register(lambda name: codecs.lookup('utf8')
                        if name == 'utf8mb4' else None)
        _registered_utf8mb4 = True
    return sa.engine_from_config(conf)
Ejemplo n.º 4
0
def init(confdict, ctx=None):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`sqlalchemy.*`
        All configuration values under this key will be passed to
        :func:`engine_from_config`, which in turn calls
        :func:`sqlalchemy.create_engine` with these configuration values as
        keyword arguments. Usually the following is sufficient::

            sqlalchemy.url = postgresql://dbuser@localhost/projname

    :confkey:`base` :faint:`[default=None]`
        The dotted python path to the :ref:`base class <db_base>` to
        configure. See :func:`parse_dotted_path` for the syntax.

    :confkey:`destroyable` :faint:`[default=False]`
        Whether destructive operations may be performed on the database. This
        value prevents accidental deletion of important data on live servers.

    :confkey:`ctx.member` :faint:`[default=db]`
        The name of the :term:`context member`, that should be registered with
        the configured :mod:`score.ctx` module (if there is one). The default
        value allows you to always access a valid session within a
        :class:`score.ctx.Context` like this:

        >>> ctx.db.query(User).first()

        Providing the special value 'None' will disable registration of the
        context member, even if a configured :mod:`ctx module <score.ctx>` was
        provided.

    This function will initialize an sqlalchemy
    :ref:`Engine <sqlalchemy:engines_toplevel>` and the provided
    :ref:`base class <db_base>`.

    """
    conf = defaults.copy()
    conf.update(confdict)
    engine = engine_from_config(conf)
    Base = None
    if 'base' in conf:
        Base = parse_dotted_path(conf['base'])
        Base.metadata.bind = engine
    ctx_member = None
    if ctx and conf['ctx.member'] not in (None, 'None'):
        ctx_member = conf['ctx.member']
    db_conf = ConfiguredDbModule(
        engine, Base, parse_bool(conf['destroyable']), ctx_member)
    if ctx_member:

        def constructor(ctx):
            zope_tx = ZopeTransactionExtension(
                transaction_manager=ctx.tx_manager)
            return db_conf.Session(extension=zope_tx)

        ctx.register(ctx_member, constructor)
    return db_conf
Ejemplo n.º 5
0
def engine_from_config(config):
    """
    A wrapper around :func:`sqlalchemy.engine_from_config`, that converts
    certain configuration values. Currently, the following configurations are
    processed:

    - ``sqlalchemy.case_sensitive`` (using :func:`score.init.parse_bool`)
    - ``sqlalchemy.connect_args.cursorclass`` (using
      :func:`score.init.parse_dotted_path`)
    - ``sqlalchemy.echo`` (using :func:`score.init.parse_bool`)
    - ``sqlalchemy.echo_pool`` (using :func:`score.init.parse_bool`)
    - ``sqlalchemy.module`` (using :func:`score.init.parse_dotted_path`)
    - ``sqlalchemy.poolclass`` (using :func:`score.init.parse_dotted_path`)
    - ``sqlalchemy.pool`` (using :func:`score.init.parse_call`)
    - ``sqlalchemy.pool_size`` (converted to `int`)
    - ``sqlalchemy.pool_recycle`` (converted to `int`)

    Any other keys are used without conversion.
    """
    conf = dict()
    for key in config:
        if key in ('sqlalchemy.echo', 'sqlalchemy.echo_pool',
                   'sqlalchemy.case_sensitive'):
            conf[key] = parse_bool(config[key])
        elif key in ('sqlalchemy.module', 'sqlalchemy.poolclass'):
            conf[key] = parse_dotted_path(config[key])
        elif key.startswith('sqlalchemy.connect_args.'):
            if 'sqlalchemy.connect_args' not in conf:
                conf['sqlalchemy.connect_args'] = {}
            value = config[key]
            key = key[len('sqlalchemy.connect_args.'):]
            if key == 'cursorclass':
                value = parse_dotted_path(value)
            conf['sqlalchemy.connect_args'][key] = value
        elif key == 'sqlalchemy.pool':
            conf[key] = parse_call(config[key])
        elif key in ('sqlalchemy.pool_size', 'sqlalchemy.pool_recycle'):
            conf[key] = int(config[key])
        else:
            conf[key] = config[key]
    return sa.engine_from_config(conf)
Ejemplo n.º 6
0
def init(confdict, ctx=None):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`args.hosts`
        A list of hosts (as read by :func:`score.init.parse_list`) to pass to
        the :class:`Elasticsearch <elasticsearch.Elasticsearch>` constructor.

    :confkey:`args.*`
        Any other arguments to be passed to the :class:`Elasticsearch
        <elasticsearch.Elasticsearch>` constructor.

    :confkey:`index` :confdefault:`score`
        The index to use in all operations.

    :confkey:`keep_source` :confdefault:`False`
        Whether the `_source` field should be enabled. The default is `False`,
        since the canonical representation of objects should be in a
        database.

    :confkey:`ctx.member` :confdefault:`es`
        The name of the :term:`context member`, that should be registered with
        the configured :mod:`score.ctx` module (if there is one). The default
        value allows one to conveniently query the index:

        >>> response = ctx.es.client.search(body={"query": {"match_all": {}}})
        >>> for hit in response['hits']['hits']:
        ...     print(hit['_source']['title'])

    :confkey:`ctx.extensions`
        Additional extension classes for the context proxy.

    """
    conf = defaults.copy()
    conf.update(confdict)
    connect_kwargs = parse_connect_conf(extract_conf(conf, 'args.'))
    if 'index' not in conf:
        conf['index'] = 'score'
    keep_source = parse_bool(conf['keep_source'])
    ctx_extensions = [DslExtension]
    for path in parse_list(conf['ctx.extensions']):
        class_ = parse_dotted_path(path)
        if not issubclass(class_, CtxProxy):
            raise InitializationError(
                'score.es7',
                'Ctx extensions classes must be sub-classes of CtxProxy')
        ctx_extensions.append(class_)
    es_conf = ConfiguredEs7Module(connect_kwargs, conf['index'], keep_source,
                                  ctx_extensions)
    if ctx and conf['ctx.member'] not in (None, 'None'):
        ctx.register(conf['ctx.member'], es_conf.get_ctx_proxy)
    return es_conf
Ejemplo n.º 7
0
def engine_from_config(config):
    """
    A wrapper around :func:`sqlalchemy.engine_from_config`, that converts
    certain configuration values. Currently, the following configurations are
    processed:

    - ``sqlalchemy.echo`` (using :func:`score.init.parse_bool`)
    - ``sqlalchemy.echo_pool`` (using :func:`score.init.parse_bool`)
    - ``sqlalchemy.case_sensitive`` (using :func:`score.init.parse_bool`)
    - ``sqlalchemy.module`` (using :func:`score.init.parse_dotted_path`)
    - ``sqlalchemy.poolclass`` (using :func:`score.init.parse_dotted_path`)
    - ``sqlalchemy.pool`` (using :func:`score.init.parse_call`)
    - ``sqlalchemy.pool_size`` (converted to `int`)
    - ``sqlalchemy.pool_recycle`` (converted to `int`)
    """
    if 'sqlalchemy.echo' in config:
        config['sqlalchemy.echo'] = parse_bool(config['sqlalchemy.echo'])
    if 'sqlalchemy.echo_pool' in config:
        config['sqlalchemy.echo_pool'] = \
            parse_bool(config['sqlalchemy.echo_pool'])
    if 'sqlalchemy.case_sensitive' in config:
        config['sqlalchemy.case_sensitive'] = \
            parse_bool(config['sqlalchemy.case_sensitive'])
    if 'sqlalchemy.module' in config:
        config['sqlalchemy.module'] = \
            parse_dotted_path(config['sqlalchemy.module'])
    if 'sqlalchemy.poolclass' in config:
        config['sqlalchemy.poolclass'] = \
            parse_dotted_path(config['sqlalchemy.poolclass'])
    if 'sqlalchemy.pool' in config:
        config['sqlalchemy.pool'] = parse_call(config['sqlalchemy.pool'])
    if 'sqlalchemy.pool_size' in config:
        config['sqlalchemy.pool_size'] = \
            int(config['sqlalchemy.pool_size'])
    if 'sqlalchemy.pool_recycle' in config:
        config['sqlalchemy.pool_recycle'] = \
            int(config['sqlalchemy.pool_recycle'])
    return sa.engine_from_config(config)
Ejemplo n.º 8
0
def init(confdict, ctx_conf, js_conf=None):
    conf = dict(defaults.items())
    conf.update(confdict)
    server = parse_dotted_path(conf['server'])
    server.host = conf['host']
    server.port = int(conf['port'])
    server.url = 'ws://%s:%d' % (server.host, server.port)
    if js_conf and conf['virtjs.path']:

        @js_conf.virtjs(conf['virtjs.path'])
        def ws():
            # TODO: next two lines should be outside of function for increased
            # performance
            tpl = open(os.path.join(os.path.dirname(__file__), 'ws.js')).read()
            virtjs = tpl % conf['virtjs.name']
            return virtjs
    ws_conf = ConfiguredWsModule(ctx_conf, server, parse_bool(conf['expose']))
    server.conf = ws_conf
    return ws_conf
Ejemplo n.º 9
0
def init(confdict, ctx):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`ruleset` :faint:`[default=RuleSet()]`
        A dotted path to an instance of :class:`RuleSet` in your project. This
        module will be initialized without any rules, if this configuration key
        is omitted, resulting in denial of every operation.

    :confkey:`authenticators` :faint:`[default=list()]`
        List of :class:`Authenticators` capable of determining the current
        actor.

    :confkey:`ctx.member` :faint:`[default=actor]`
        The :term:`context member` under which the current actor should be made
        available. Leaving this at its default will allow you to access the
        current actor as the following:

        >>> ctx.actor
    """
    conf = defaults.copy()
    conf.update(confdict)
    if conf['ruleset'] in (None, 'None'):
        ruleset = RuleSet()
    else:
        ruleset = parse_dotted_path(conf['ruleset'])
    if 'authenticator' in conf:
        assert not conf['authenticators']
        conf['authenticators'] = [conf['authenticator']]
        del conf['authenticator']
    auth = ConfiguredAuthModule(ruleset, conf['ctx.member'])
    authenticator = NullAuthenticator()
    for line in reversed(parse_list(conf['authenticators'])):
        authenticator = parse_call(line, (auth, authenticator))
    auth.authenticator = authenticator
    _register_ctx_actor(conf, ctx, auth)
    _register_ctx_permits(conf, ctx, auth)
    return auth
Ejemplo n.º 10
0
def init(confdict, ctx):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`ruleset` :confdefault:`RuleSet()`
        A dotted path to an instance of :class:`RuleSet` in your project. This
        module will be initialized without any rules, if this configuration key
        is omitted, resulting in denial of every operation.

    :confkey:`authenticators` :confdefault:`list()`
        List of :class:`Authenticators` capable of determining the current
        actor.

    :confkey:`ctx.member` :confdefault:`actor`
        The :term:`context member` under which the current actor should be made
        available. Leaving this at its default will allow you to access the
        current actor as the following:

        >>> ctx.actor
    """
    conf = defaults.copy()
    conf.update(confdict)
    if conf['ruleset'] in (None, 'None'):
        ruleset = RuleSet()
    else:
        ruleset = parse_dotted_path(conf['ruleset'])
    if 'authenticator' in conf:
        assert not conf['authenticators']
        conf['authenticators'] = [conf['authenticator']]
        del conf['authenticator']
    auth = ConfiguredAuthModule(ruleset, conf['ctx.member'])
    authenticator = NullAuthenticator()
    for line in reversed(parse_list(conf['authenticators'])):
        authenticator = parse_call(line, (auth, authenticator))
    auth.authenticator = authenticator
    _register_ctx_actor(conf, ctx, auth)
    _register_ctx_permits(conf, ctx, auth)
    return auth
Ejemplo n.º 11
0
def _init_orm_backend(conf, session, orm, ctx):
    if 'orm.class' not in conf:
        return None
    if not conf['orm.class'] or conf['orm.class'] == 'None':
        return None
    if not orm:
        import score.session
        raise ConfigurationError(
            score.session, 'Need score.sa.orm in order to use `orm.class`')
    if not ctx:
        import score.session
        raise ConfigurationError(score.session,
                                 'Need score.ctx in order to use `orm.class`')
    from .orm import OrmSessionMixin, OrmSession
    class_ = parse_dotted_path(conf['orm.class'])
    if not issubclass(class_, OrmSessionMixin):
        import score.session
        raise ConfigurationError(
            score.session,
            'Configured `orm.class` must inherit OrmSessionMixin')
    if not hasattr(orm, 'ctx'):
        import score.session
        raise ConfigurationError(
            score.session,
            'Configured score.sa.orm has not score.ctx configuration')
    if ctx != orm.ctx:
        import score.session
        raise ConfigurationError(
            score.session,
            'Configured score.sa.orm uses different score.ctx dependency')
    return type(
        'ConfiguredOrmSession', (OrmSession, ), {
            '_has_ctx': ctx is not None,
            '_conf': session,
            '_orm_conf': orm,
            '_orm_class': class_,
            '_orm': property(lambda self: orm.get_session(self._ctx)),
        })
Ejemplo n.º 12
0
def _init_db_backend(conf, session, db, ctx):
    if not db:
        return None
    if 'db.class' not in conf:
        return None
    if not conf['db.class'] or conf['db.class'] == 'None':
        return None
    from .db import DbSessionMixin, DbSession
    from zope.sqlalchemy import ZopeTransactionExtension
    class_ = parse_dotted_path(conf['db.class'])
    if not issubclass(class_, DbSessionMixin):
        import score.session
        raise ConfigurationError(
            score.session, 'Configured `db.class` must inherit DbSessionMixin')
    if ctx and db.ctx_member:
        def session(self):
            return getattr(self._ctx, db.ctx_member)
    elif ctx:
        def session(self):
            if not hasattr(self, '_db_session'):
                zope_tx = ZopeTransactionExtension(
                    transaction_manager=self._ctx.tx_manager)
                self._db_session = db.Session(extension=zope_tx)
            return self._db_session
    else:
        def session(self):
            if not hasattr(self, '_db_session'):
                self._db_session = db.Session(extension=[])
            return self._db_session
    return type('ConfiguredDbSession', (DbSession,), {
        '_has_ctx': ctx is not None,
        '_conf': session,
        '_db_conf': db,
        '_db_class': class_,
        '_db': property(session),
    })
Ejemplo n.º 13
0
def init(confdict):
    """
    Initializes this module according to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`container`
        The cache container configuration. A container defines a name,
        a backend and optionally a generator and an expire. The configuration
        key for a container starts with ``container`` followed by the name
        and the configuration keys for the container.

        For example, the following configuration::

            container.greeter.backend = score.kvcache.backend.FileCache
            container.greeter.backend.path = /tmp/greeter.sqlite3
            container.greeter.generator = dotted.path.to.greeting_generator
            container.greeter.expire = 1m

        The Backend config will be passed to
        :func:`score.init.init_object`. Have a look at the configurable
        backend's constructor parameters for further information about
        the backend's configurable keys.

        To make life easier for a huge set of container configurations, we serve
        the possibility to configure backend aliases that will replace the
        container's backend config if the name matches.

        For example::

            backend.example_filecache = score.kvcache.backend.FileCache
            backend.example_filecache.path = /tmp/filecache.sqlite3
            container.greeter.backend = example_filecache
            container.greeter.generator = dotted.path.to.greeting_generator
            container.greeter.expire = 1m
            container.counter.backend = example_filecache
            container.counter.generator = dotted.path.to.counting_generator
            container.counter.expire = 30 seconds

    """
    containers = {}
    for container_conf in extract_conf(confdict, 'container.'):
        if not container_conf.endswith('.backend'):
            continue
        backend_key = 'container.%s' % container_conf
        backend_val = confdict[backend_key]
        if backend_val in extract_conf(confdict, 'backend.'):
            alias_conf = extract_conf(confdict, 'backend.%s' % backend_val)
            for k, v in alias_conf.items():
                confdict.update({'%s%s' % (backend_key, k): v})
        container_name = container_conf[:-len('.backend')]
        backend = parse_object(confdict, backend_key)
        generator_key = 'container.%s.generator' % container_name
        generator = None
        if generator_key in confdict:
            generator = parse_dotted_path(confdict[generator_key])
        expire_key = 'container.%s.expire' % container_name
        expire = None
        if expire_key in confdict:
            expire = parse_time_interval(confdict[expire_key])
        containers[container_name] = CacheContainer(container_name, backend,
                                                    generator=generator,
                                                    expire=expire)
    return ConfiguredKvCacheModule(containers)
Ejemplo n.º 14
0
 def __init__(self, conf, next, actor_class=None, session_key='actor'):
     super().__init__(conf, next)
     self.session_key = session_key
     if isinstance(actor_class, str):
         actor_class = parse_dotted_path(actor_class)
     self.dbcls = actor_class
Ejemplo n.º 15
0
def init(confdict, ctx, db=None):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`router`
        Path to the :class:`RouteConfiguration` containing the list of routes to
        compile.

    :confkey:`preroutes` :confdefault:`list()`
        List of :term:`preroute` functions to call before invoking the actual
        route.  See :ref:`http_routing` for details.

    :confkey:`handler.*`
        Keys starting with "``handler.``" are interpreted as :ref:`error
        handlers <http_error_handler>`.

    :confkey:`debug` :confdefault:`False`
        Setting this to `True` will enable the `werkzeug debugger`_ for your
        application.

    :confkey:`urlbase` :confdefault:`None`
        This will be the prefix for all URLs generated by the module. The module
        will create relative URLs by default (i.e. `/Sir%20Lancelot`), but you
        can make it create absolute URLs by default by paassing this
        configuration value.

        If you configure this to be 'http://example.net/', your URL would be
        'http://example.net/Sir%20Lancelot'.

        Note that you can always decide, whether a *certain* URL should be
        absolute or relative, by passing the appropriate argument to
        :meth:`ConfiguredHttpModule.url`.

    :confkey:`ctx.member.url` :confdefault:`url`
        The name of the :term:`context member` function for generating URLs.

    :confkey:`serve.ip` :confdefault:`0.0.0.0`
        This will be the ip address your HTTP server will bind_ to, when using
        :mod:`score.serve` to serve your application.

    :confkey:`serve.port` :confdefault:`8080`
        This will be the port of your HTTP server, when using
        :mod:`score.serve` to serve your application.

    :confkey:`serve.threaded` :confdefault:`False`
        Setting this to `True` will make your HTTP server threaded, which should
        increase its performance. Note that your application will need to be
        thread-safe_, if you want to enable this feature.

    .. _werkzeug debugger: http://werkzeug.pocoo.org/docs/0.11/debug/#using-the-debugger
    .. _bind: http://www.xeams.com/bindtoaddress.htm
    .. _thread-safe: https://en.wikipedia.org/wiki/Thread_safety
    """
    conf = dict(defaults.items())
    conf.update(confdict)
    if 'router' not in conf:
        import score.http
        raise ConfigurationError(score.http, 'No router provided')
    router = parse_dotted_path(conf['router'])
    preroutes = list(map(parse_dotted_path, parse_list(conf['preroutes'])))
    error_handlers = {}
    exception_handlers = {}
    for error, handler in extract_conf(conf, 'handler.').items():
        if re.match('\d(\d\d|XX)', error):
            error_handlers[error] = parse_dotted_path(handler)
        else:
            error = parse_dotted_path(error)
            exception_handlers[error] = handler
    debug = parse_bool(conf['debug'])
    if not conf['urlbase']:
        conf['urlbase'] = ''
    http = ConfiguredHttpModule(
        ctx, db, router, preroutes, error_handlers, exception_handlers, debug,
        conf['urlbase'], conf['serve.ip'], int(conf['serve.port']),
        parse_bool(conf['serve.threaded']))

    def constructor(ctx):
        def url(*args, **kwargs):
            return http.url(ctx, *args, **kwargs)
        return url

    ctx.register(conf['ctx.member.url'], constructor)
    return http
Ejemplo n.º 16
0
def init(confdict, ctx=None):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`sqlalchemy.*`
        All configuration values under this key will be passed to
        :func:`engine_from_config`, which in turn calls
        :func:`sqlalchemy.create_engine` with these configuration values as
        keyword arguments. Usually the following is sufficient::

            sqlalchemy.url = postgresql://dbuser@localhost/projname

    :confkey:`base` :faint:`[default=None]`
        The dotted python path to the :ref:`base class <db_base_class>` to
        configure, as interpreted by func:`score.init.parse_dotted_path`.

    :confkey:`destroyable` :faint:`[default=False]`
        Whether destructive operations may be performed on the database. This
        value prevents accidental deletion of important data on live servers.

    :confkey:`ctx.member` :faint:`[default=db]`
        The name of the :term:`context member`, that should be registered with
        the configured :mod:`score.ctx` module (if there is one). The default
        value allows you to always access a valid session within a
        :class:`score.ctx.Context` like this:

        >>> ctx.db.query(User).first()

    This function will initialize an sqlalchemy
    :ref:`Engine <sqlalchemy:engines_toplevel>` and the provided
    :ref:`base class <db_base_class>`.

    """
    conf = defaults.copy()
    conf.update(confdict)
    engine = engine_from_config(conf)
    if not conf['base']:
        import score.db
        raise ConfigurationError(score.db, 'No base class configured')
    Base = parse_dotted_path(conf['base'])
    Base.metadata.bind = engine
    ctx_member = None
    if ctx and conf['ctx.member']:
        ctx_member = conf['ctx.member']
    if engine.dialect.name == 'sqlite':
        @sa.event.listens_for(engine, "connect")
        def set_sqlite_pragma(dbapi_connection, connection_record):
            cursor = dbapi_connection.cursor()
            cursor.execute("PRAGMA foreign_keys=ON")
            cursor.close()
    db_conf = ConfiguredDbModule(
        engine, Base, parse_bool(conf['destroyable']), ctx_member)
    if ctx_member:

        def constructor(ctx):
            zope_tx = ZopeTransactionExtension(
                transaction_manager=ctx.tx_manager)
            return db_conf.Session(extension=zope_tx)

        ctx.register(ctx_member, constructor)
    return db_conf
Ejemplo n.º 17
0
 def __init__(self, conf, next, actor_class=None, session_key='actor'):
     super().__init__(conf, next)
     self.session_key = session_key
     if isinstance(actor_class, str):
         actor_class = parse_dotted_path(actor_class)
     self.dbcls = actor_class