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 init(confdict):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`autoreload` :confdefault:`False`
        When set to :func:`true <score.init.parse_bool>`, the server will
        automatically reload whenever it detects a change in one of the python
        files, that are in use.

    :confkey:`modules`
        The :func:`list <score.init.parse_list>` of modules to serve. This need
        to be a list of module aliases, i.e. the same name, with which you
        configured the module with ("score.http" becomes "http" if not specified
        otherwise.)

    """
    conf = defaults.copy()
    conf.update(confdict)
    modules = parse_list(conf['modules'])
    if not modules:
        import score.serve
        raise InitializationError(score.serve, 'No modules configured')
    autoreload = parse_bool(conf['autoreload'])
    return ConfiguredServeModule(conf['conf'], modules, autoreload)
Ejemplo n.º 3
0
def init(confdict):
    """
    Initializes this module according to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`hosts`
        A list of Varnish hosts passed to :func:`parse_host_port
        <score.init.parse_host_port>` and :func:`parse_list
        <score.init.parse_list>`.

    :confkey:`soft` :faint:`[default=true]`
        Whether to purge :term:`soft <soft purge>` or :term:`hard <hard purge>`.

    :confkey:`timeout` :faint:`[default=5s]`
        The timeout for sending requests to a Varnish host passed to
        :func:`parse_time_interval <score.init.parse_time_interval>`.

    :confkey:`header.domain` :faint:`[default=X-Purge-Domain]`
        The name of the header used for purging a domain.

    :confkey:`header.path` :faint:`[default=X-Purge-Path]`
        The name of the header used for purging a path.

    :confkey:`header.soft` :faint:`[default=X-Purge-Soft]`
        The name of the header used for triggering a :term:`soft purge`.
    """
    conf = dict(defaults.items())
    conf.update(confdict)
    hosts = [parse_host_port(host) for host in parse_list(conf['hosts'])]
    soft = parse_bool(conf['soft'])
    timeout = parse_time_interval(conf['timeout'])
    header_mapping = extract_conf(conf, 'header.')
    return ConfiguredVarnishModule(hosts, soft, timeout, header_mapping)
Ejemplo n.º 4
0
def init(confdict):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`autoreload` :confdefault:`False`
        When set to :func:`true <score.init.parse_bool>`, the server will
        automatically reload whenever it detects a change in one of the python
        files, that are in use.

    :confkey:`modules`
        The :func:`list <score.init.parse_list>` of modules to serve. This need
        to be a list of module aliases, i.e. the same name, with which you
        configured the module with ("score.http" becomes "http" if not
        specified otherwise.)

    """
    conf = defaults.copy()
    conf.update(confdict)
    modules = parse_list(conf['modules'])
    if not modules:
        import score.serve
        raise InitializationError(score.serve, 'No modules configured')
    autoreload = parse_bool(conf['autoreload'])
    monitor_host_port = None
    if conf['monitor']:
        monitor_host_port = parse_host_port(conf['monitor'])
    return ConfiguredServeModule(conf['conf'], modules, autoreload,
                                 monitor_host_port)
Ejemplo n.º 5
0
def init(confdict, webassets, tpl, http):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`rootdir` :confdefault:`None`
        Denotes the root folder containing all css files. Will fall
        back to a sub-folder of the folder in :mod:`score.tpl`'s
        configuration, as described in :func:`score.tpl.init`.

    :confkey:`cachedir` :confdefault:`None`
        A dedicated cache folder for this module. It is generally sufficient
        to provide a ``cachedir`` for :mod:`score.tpl`, as this module will
        use a sub-folder of that by default.

    :confkey:`combine` :confdefault:`False`
        Whether css files should be delivered as a single file. If this
        value is `true` (as defined by :func:`score.init.parse_bool`), the
        default url will point to the combined css file.

    :confkey:`minify` :confdefault:`False`
        Whether css assets should be minified.

    :confkey:`group.*`
        Keys starting with ``group.*`` will register :term:`asset groups
        <asset group>`. The following configuration will create a
        :term:`virtual asset` called ``meal`` which has the combined content
        of the assets 'bacon.css' and 'spam.css'::

            group.meal =
                bacon.css
                spam.css

        Note that groups defined this way *must* reference real assets, i.e.
        at the point this value is interpreted, there are no virtual assets
        yet! If you need to add virtual assets to a group, you will need to
        create the asset group after all required virtual assets have been
        registered.

    """
    conf = dict(defaults.items())
    conf.update(confdict)
    if not conf['rootdir']:
        conf['rootdir'] = os.path.join(tpl.rootdir, 'css')
    conf['minify'] = parse_bool(conf['minify'])
    conf['combine'] = parse_bool(conf['combine'])
    if not conf['cachedir'] and tpl.cachedir:
        conf['cachedir'] = os.path.join(tpl.cachedir, 'css')
    if conf['cachedir']:
        init_cache_folder(conf, 'cachedir', autopurge=True)
    else:
        warnings.warn('No cachedir configured, SCSS rendering will not work.')
    cssconf = ConfiguredCssModule(
        webassets, tpl, http, conf['rootdir'], conf['cachedir'],
        conf['combine'], conf['minify'])
    for name, pathlist in extract_conf(conf, 'group.').items():
        paths = parse_list(pathlist)
        _create_group(cssconf, webassets, name + '.css', paths)
    return cssconf
Ejemplo n.º 6
0
def init(confdict, ctx, http, jslib=None):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`endpoints` :confdefault:`list()`
        A :func:`list <score.init.parse_list>` of :func:`dotted paths
        <score.init.parse_dotted_path>` pointing to any amount of
        :class:`Endpoints <.Endpoint>`. The registered functions of these
        Endpoints will be available in javascript.

    :confkey:`expose` :confdefault:`False`
        Whether security critical data may be exposed through the API. This
        value should be left at its default value in production, but may be
        switched to `True` during development to receive Exceptions and
        stacktraces in the browser console.

    :confkey:`jslib.require` :confdefault:`score.jsapi`
        The name of the require.js module to create the virtual javascript with.
        When left at its default value, the resulting javascript can be included
        like the following:

        .. code-block:: javascript

            require(['score.jsapi'], function(Api) {
                var api = new Api();
                // ... use api here ...
            });
    """
    conf = dict(defaults.items())
    conf.update(confdict)
    endpoints = list(map(parse_dotted_path, parse_list(conf['endpoints'])))
    expose = parse_bool(conf['expose'])
    jsapi = ConfiguredJsapiModule(ctx, http, jslib, expose,
                                  conf['jslib.require'])
    for endpoint in endpoints:
        jsapi.add_endpoint(endpoint)

    if jslib:
        import score.jsapi

        version = score.jsapi.__version__
        dependencies = {
            conf['jslib.require'] + '/excformat': version,
            'bluebird': '3.X.X',
            'score.init': '0.X.X',
            'score.oop': '0.4.X'
        }

        @jslib.virtlib(conf['jslib.require'] + '/excformat', version, {})
        def exc2json(ctx):
            return gen_excformat_js(ctx)

        @jslib.virtlib(conf['jslib.require'], version, dependencies)
        def api(ctx):
            return jsapi.generate_js()

    return jsapi
Ejemplo n.º 7
0
 def _collect_services(self):
     self._services = OrderedDict()
     score = init_from_file(self.conf.conf)
     if self._changedetector:
         for file in parse_list(score.conf['score.init']['_files']):
             self._changedetector.observe(file)
     for desc in self.conf.modules:
         for name, worker in self._iter_workers(score, desc):
             self._services[name] = Service(name, worker)
Ejemplo n.º 8
0
def parse_connect_conf(conf):
    conf = conf.copy()
    if 'hosts' in conf:
        conf['hosts'] = parse_list(conf['hosts'])
    if 'verify_certs' in conf:
        conf['verify_certs'] = parse_bool(conf['verify_certs'])
    if 'use_ssl' in conf:
        conf['use_ssl'] = parse_bool(conf['use_ssl'])
    if 'timeout' in conf:
        conf['timeout'] = parse_time_interval(conf['timeout'])
    return conf
Ejemplo n.º 9
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.º 10
0
def init(confdict, tpl):
    """
    Initializes this module acoording to the :ref:`SCORE module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`cachedir` :confdefault:`None`
        A cache folder to use for storing parsed templates. Highly recommended.
    """
    conf = defaults.copy()
    conf.update(confdict)
    return ConfiguredJinja2Module(tpl, conf['extension'], conf['cachedir'],
                                  parse_list(conf['filters']))
Ejemplo n.º 11
0
def init(confdict, tpl, webassets):
    """
    Initializes this module acoording to the :ref:`SCORE module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`config_file` :confdefault:`None`
        An optional javascript file containing the `requirejs configuration`_.
        This file should only contain the configuration object itself, but the
        object does not have to adhere to a strict JSON syntax and may contain
        javascript functions. The following is a perfectly valid example for the
        referenced file's content:

        .. code-block:: javascript

            {
                map: {
                    'some/newmodule': {
                        'foo': 'foo1.2'
                    },
                },
                shim: {
                    'foo': {
                        deps: ['bar'],
                        exports: 'Foo',
                        init: function (bar) {
                            return this.Foo.noConflict();
                        }
                    }
                }
            }

        .. _requirejs configuration: http://requirejs.org/docs/api.html#config

    :confkey:`passthrough_extensions` :confdefault:`[]`
        A list of additional file extensions that this module is allowed to pass
        to browsers. If you want to pass mustache_ templates to the browser, for
        example, you must provide the ``mustache`` extension in this list.

        .. _mustache: http://mustache.github.io/

    :confkey:`path.nodejs` :confdefault:`nodejs`
        The path to the nodejs_ executable. This value is only relevant if
        :term:`asset bundling <asset bundle>` is enabled in
        :mod:`score.webassets`.

        .. _nodejs: https://nodejs.org/en/
    """
    conf = defaults.copy()
    conf.update(confdict)
    return ConfiguredRequirejsModule(
        tpl, webassets, conf['config_file'], conf['path.nodejs'],
        parse_list(conf['passthrough_extensions']))
Ejemplo n.º 12
0
def init(confdict, webassets=None):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`backends`
        List of score module aliases that should be used as backends to the
        templating.
    """
    conf = dict(defaults.items())
    conf.update(confdict)
    backends = parse_list(conf['backends'])
    assert backends, 'No backends configured'
    return ConfiguredTplFallbackModule(backends)
Ejemplo n.º 13
0
def init_score(clickctx):
    conf = parse_config_file(clickctx.obj['conf'].path)
    try:
        modules = parse_list(conf['score.init']['modules'])
    except KeyError:
        modules = []
    modules.append('score.serve')
    if 'score.init' not in conf:
        conf['score.init'] = {}
    conf['score.init']['modules'] = modules
    if 'serve' not in conf:
        conf['serve'] = {}
    if 'conf' not in conf['serve']:
        conf['serve']['conf'] = clickctx.obj['conf'].path
    return score_init(conf)
Ejemplo n.º 14
0
 def _collect_services(self):
     self._services = OrderedDict()
     score = init_from_file(self.conf.conf)
     if self._changedetector:
         for file in parse_list(score.conf['score.init']['_files']):
             self._changedetector.observe(file)
     for mod in self.conf.modules:
         workers = score._modules[mod].score_serve_workers()
         if isinstance(workers, list):
             for i, worker in enumerate(workers):
                 name = '%s/%d' % (mod, i)
                 self._services[name] = Service(name, worker)
         elif isinstance(workers, dict):
             for name, worker in workers.items():
                 name = '%s/%s' % (mod, name)
                 self._services[name] = Service(name, worker)
Ejemplo n.º 15
0
def init(confdict, jsapi):
    """
    Initializes this module according to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    """
    conf = dict(defaults.items())
    conf.update(confdict)
    sources = list(map(parse_dotted_path, parse_list(conf['sources'])))
    dynq = ConfiguredDynqModule(jsapi, sources, conf['jsapi.name'])

    if jsapi.jslib:
        import score.dynq

        @jsapi.jslib.virtlib(conf['jslib.require'], score.dynq.__version__,
                             ['score.init', 'score.oop', 'score.dynq'])
        def api(ctx):
            return dynq.generate_js()

    return dynq
Ejemplo n.º 16
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.º 17
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.º 18
0
def init(confdict, db, 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:`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:

        >>> for knight in ctx.es.query(User, 'name:sir*')
        ...     print(knight.name)
    """
    conf = defaults.copy()
    conf.update(confdict)
    kwargs = extract_conf(confdict, 'args.')
    if 'hosts' in kwargs:
        kwargs['hosts'] = parse_list(kwargs['hosts'])
    if 'verify_certs' in kwargs:
        kwargs['verify_certs'] = parse_bool(kwargs['verify_certs'])
    if 'use_ssl' in kwargs:
        kwargs['use_ssl'] = parse_bool(kwargs['use_ssl'])
    es = Elasticsearch(**kwargs)
    if 'index' not in confdict:
        confdict['index'] = 'score'
    es_conf = ConfiguredEsModule(db, es, confdict['index'])
    to_insert = []
    to_delete = []

    @event.listens_for(db.Session, 'before_flush')
    def before_flush(session, flush_context, instances):
        """
        Stores the list of new and altered objects in ``to_insert``, and
        deleted objects in ``to_delete``. The actual storing can only be done
        *after* the flush operation (in ``after_flush``, below), since new
        objects don't have an id at this point. But we cannot move the whole
        logic into the ``after_flush``, since we might miss the optional
        *instances* argument to this function.
        """
        nonlocal to_insert, to_delete
        to_insert = []
        to_delete = []
        for obj in session.new:
            if not instances or obj in instances:
                if es_conf.get_es_class(obj) is not None:
                    to_insert.append(obj)
        for obj in session.dirty:
            if not session.is_modified(obj):
                # might actually be unaltered, see docs of Session.dirty:
                # http://docs.sqlalchemy.org/en/latest/orm/session_api.html#sqlalchemy.orm.session.Session.dirty
                continue
            if not instances or obj in instances:
                if es_conf.get_es_class(obj) is not None:
                    to_insert.append(obj)
        for obj in session.deleted:
            if not instances or obj in instances:
                if es_conf.get_es_class(obj) is not None:
                    to_delete.append(obj)

    @event.listens_for(db.Session, 'after_flush')
    def after_flush(session, flush_context):
        for obj in to_insert:
            es_conf.insert(obj)
        for obj in to_delete:
            es_conf.delete(obj)

    if ctx and conf['ctx.member'] not in (None, 'None'):
        ctx.register(conf['ctx.member'], lambda ctx: CtxProxy(es_conf, ctx))
    return es_conf
Ejemplo n.º 19
0
def init(confdict, db, 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:`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:

        >>> for knight in ctx.es.query(User, 'name:sir*')
        ...     print(knight.name)
    """
    conf = defaults.copy()
    conf.update(confdict)
    kwargs = extract_conf(confdict, 'args.')
    if 'hosts' in kwargs:
        kwargs['hosts'] = parse_list(kwargs['hosts'])
    if 'verify_certs' in kwargs:
        kwargs['verify_certs'] = parse_bool(kwargs['verify_certs'])
    if 'use_ssl' in kwargs:
        kwargs['use_ssl'] = parse_bool(kwargs['use_ssl'])
    es = Elasticsearch(**kwargs)
    if 'index' not in confdict:
        confdict['index'] = 'score'
    es_conf = ConfiguredEsModule(db, es, confdict['index'])
    to_insert = []
    to_delete = []

    @event.listens_for(db.Session, 'before_flush')
    def before_flush(session, flush_context, instances):
        """
        Stores the list of new and altered objects in ``to_insert``, and
        deleted objects in ``to_delete``. The actual storing can only be done
        *after* the flush operation (in ``after_flush``, below), since new
        objects don't have an id at this point. But we cannot move the whole
        logic into the ``after_flush``, since we might miss the optional
        *instances* argument to this function.
        """
        nonlocal to_insert, to_delete
        to_insert = []
        to_delete = []
        for obj in session.new:
            if not instances or obj in instances:
                if es_conf.get_es_class(obj) is not None:
                    to_insert.append(obj)
        for obj in session.dirty:
            if not session.is_modified(obj):
                # might actually be unaltered, see docs of Session.dirty:
                # http://docs.sqlalchemy.org/en/latest/orm/session_api.html#sqlalchemy.orm.session.Session.dirty
                continue
            if not instances or obj in instances:
                if es_conf.get_es_class(obj) is not None:
                    to_insert.append(obj)
        for obj in session.deleted:
            if not instances or obj in instances:
                if es_conf.get_es_class(obj) is not None:
                    to_delete.append(obj)

    @event.listens_for(db.Session, 'after_flush')
    def after_flush(session, flush_context):
        for obj in to_insert:
            es_conf.insert(obj)
        for obj in to_delete:
            es_conf.delete(obj)
    if ctx and conf['ctx.member'] not in (None, 'None'):
        ctx.register(conf['ctx.member'], lambda ctx: CtxProxy(es_conf, ctx))
    return es_conf
Ejemplo n.º 20
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