Example #1
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)
Example #2
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
Example #3
0
def init(confdict):
    """
    Initializes this module acoording to the :ref:`SCORE module initialization
    guidelines <module_initialization>` with the following configuration keys:
    """
    conf = defaults.copy()
    conf.update(confdict)
    servers = []
    loop = asyncio.new_event_loop()
    server_names = [c.split('.')[0] for c in extract_conf(conf, 'server.')]
    for name in server_names:
        server_conf = extract_conf(conf, 'server.%s.' % name)
        name = server_conf.get('name', name)
        host, port = parse_host_port(server_conf['monitor'])
        servers.append(
            SocketConnector(name, loop, host, port))
    return ConfiguredCruiseModule(loop, servers)
Example #4
0
def init(confdict, webassets=None):
    """
    Initializes this module acoording to :ref:`our module initialization
    guidelines <module_initialization>` with the following configuration keys:

    :confkey:`rootdir` :faint:`[default=None]`
        Denotes the root folder containing all templates. When a new format is
        created via :meth:`.Renderer.register_format`, it will have a
        sub-folder of this folder as its default root (unless, of course, the
        `rootdir` parameter of that function is provided). If this value is
        omitted, all calls to :meth:`.Renderer.register_format` must provide a
        format-specific root folder.

    :confkey:`cachedir` :faint:`[default=None]`
        A cache folder that will be used to cache rendered templates. Will
        fall back to a sub-folder (called ``tpl``) of the cachedir in the
        *webassets*, if one was provided.

        Although this module will work without a cache folder, it is highly
        recommended that it is either initialized with a ``cachedir`` or a
        *webassets* with a valid ``cachedir``, even if the value points
        to the system's temporary folder.

    :confkey:`default_format` :faint:`[default=None]`
        The default format of files where the :term:`template format` could
        not be determined automatically. This must be the name of another,
        registered format.

    :confkey:`engine.*`
        All keys starting with ``engine.`` will be registered as engines. For
        example, if the key ``engine.php`` is provided, the engine will be
        instantiated via :func:`score.init.init_object` and registered for the
        extension ``php``.
    """
    conf = dict(defaults.items())
    conf.update(confdict)
    if not conf['cachedir'] and webassets and webassets.cachedir:
        conf['cachedir'] = os.path.join(webassets.cachedir, 'tpl')
    if conf['cachedir']:
        init_cache_folder(conf, 'cachedir', autopurge=True)
    if conf['rootdir']:
        if not os.path.isdir(conf['rootdir']):
            import score.tpl
            raise ConfigurationError(score.tpl, 'Given rootdir is not a folder')
    renderer = Renderer(conf['rootdir'], conf['cachedir'],
                        conf['default_format'])
    extensions = set()
    for key in extract_conf(conf, 'engine.'):
        extensions.add(key.split('.', 1)[0])
    for ext in extensions:
        engine = init_object(conf, 'engine.' + ext)
        renderer.register_engine(ext, engine)
    return ConfiguredTplModule(renderer, conf['rootdir'],
                               conf['cachedir'], conf['default_format'])
Example #5
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
Example #6
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)
Example #7
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
Example #8
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
Example #9
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:`ctx.member.url` :confdefault:`fs`
        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 configured file systems within a
        :class:`score.ctx.Context` like the following:

        >>> ctx.fs['my_configured_fs']

    :confkey:`path.*`
        Configuration keys like `path.foo` are file system definitions that must
        contain a valid :ref:`pyfilesystem URL <pyfilesystem:fs-urls>`. These
        values automatically :meth:`register
        <ConfiguredPyfilesystemModule.register_path>` paths during
        initialization. The following example is for registering a memory file
        system called `foo`:

        .. code-block:: ini

            path.foo = mem://

        The only customization is a *scope* parameter, which can also define the
        :term:`scope <pyfilesystem scope>` of a file system. Valid values for
        this parameter are ``global`` (the default) and ``ctx``. The same
        filesystem as above with a scope bound to a context would look like
        this:

        .. code-block:: ini

            path.foo = mem://?scope=ctx

    """
    conf = defaults.copy()
    conf.update(confdict)
    fsconf = ConfiguredPyfilesystemModule()
    for name, url in extract_conf(conf, 'path.').items():
        scope = 'global'
        if '://' in url:
            url = urllib.parse.urlsplit(url)
            query = []
            for key, value in urllib.parse.parse_qsl(url.query):
                if key == 'scope':
                    scope = Scope(value)
                else:
                    query.append((key, value))
            url = [*url]
            url[3] = query
            url = urllib.parse.urlunsplit(url)
            if '://' not in url:
                # the URL probably does not contain a netloc part and urlunsplit
                # generates something like 'mem:', which is actually valid.
                # pyfilesystem, on the other hand, interprets this as a path on
                # the local filesystem and tries to open it with OSFS.
                # the fix is simple: append two slashes to the first colon
                url = url.replace(':', '://', 1)
        if scope == Scope.CONTEXT and not ctx:
            import score.pyfilesystem
            raise InitializationError(
                score.pyfilesystem,
                'Cannot register object with scope=ctx '
                'without a configured ctx module')
        try:
            fsconf.register_path(name, url, scope=scope)
        except Exception as e:
            import score.pyfilesystem
            raise InitializationError(score.pyfilesystem, str(e)) from e
    if ctx and conf['ctx.member'].lower() != 'none':
        ctx.register(conf['ctx.member'], fsconf._ctx_constructor)
    return fsconf
Example #10
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