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
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
def parse_cookie_kwargs(conf): if not conf['cookie'] or conf['cookie'] == 'None': return None cookie_kwargs = { 'name': conf['cookie'], 'path': conf['cookie.path'], 'domain': conf['cookie.domain'], 'secure': parse_bool(conf['cookie.secure']), 'httponly': parse_bool(conf['cookie.httponly']), } if conf['cookie.max_age']: cookie_kwargs['max_age'] = \ parse_time_interval(conf['cookie.max_age']) return cookie_kwargs
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:`destroyable` :confdefault:`False` Whether destructive operations may be performed on the database. This value prevents accidental deletion of important data on live servers. Note that any application feature destroying data must consult this flag before proceeding! :confkey:`ctx.member` :confdefault:`db` The name of the :term:`context member` providing an :class:`sqlalchemy.engine.Connection`. Can be the string `None` to indicate, that no context member should be registered. This value is only relevant, if the optional :mod:`score.ctx` dependency was configured. :confkey:`ctx.transaction` :confdefault:`True` Whether the context member providing the context-scoped database connection should wrap the connection in a transaction. The transaction will be committed at the end of the context object's lifecycle (or rolled back, if the context was terminated with an uncaught exception). This value is only relevant if *ctx.member* is not `None`. """ conf = defaults.copy() conf.update(confdict) engine = engine_from_config(conf) ctx_member = None if conf['ctx.member'] and conf['ctx.member'] != 'None': ctx_member = conf['ctx.member'] if conf['ctx.transaction']: ctx_transaction = parse_bool(conf['ctx.transaction']) return ConfiguredSaDbModule( ctx, engine, parse_bool(conf['destroyable']), ctx_member, ctx_transaction)
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)
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)
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)
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)
def rename(self, project, newname): """ Changes the name of a given *project* to *newname*. The *project* can be anything accepted by :meth:`get`. .. note:: Since the folder path of a project's virtual environment depends on its name, the function will also delete the project's old virtualenv and create a new one. """ project = self.get(project) oldname = project.name try: shutil.rmtree(project.venvdir) except FileNotFoundError: pass project.name = newname settings = self._read_conf() try: site_packages = parse_bool(settings[oldname]['site_packages']) except: site_packages = False project.recreate_venv(site_packages=site_packages) del settings[oldname] settings[newname] = {'folder': project.folder} self._write_conf(settings)
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
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
def _init_kvcache_backend(conf, session, kvcache): if not kvcache: return None from ._kvcache import KvcacheSession return type('ConfiguredKvcacheSession', (KvcacheSession,), { '_conf': session, '_livedata': parse_bool(conf['kvcache.livedata']), '_container': kvcache[conf['kvcache.container']], })
def _init_kvcache_backend(conf, session, kvcache): if not kvcache: return None from ._kvcache import KvcacheSession return type( 'ConfiguredKvcacheSession', (KvcacheSession, ), { '_conf': session, '_livedata': parse_bool(conf['kvcache.livedata']), '_container': kvcache[conf['kvcache.container']], })
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
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)
def parse_cookie_kwargs(conf): if not conf['cookie'] or conf['cookie'] == 'None': return None samesite = conf['cookie.samesite'] if samesite and samesite.strip().lower() != 'none': samesite = samesite.strip() samesite = samesite[0].upper() + samesite[1:].lower() if samesite not in ('Strict', 'Lax'): raise ValueError('cookie.samesite must be "Strict" or "Lax"') else: samesite = None cookie_kwargs = { 'name': conf['cookie'], 'path': conf['cookie.path'], 'domain': conf['cookie.domain'], 'secure': parse_bool(conf['cookie.secure']), 'httponly': parse_bool(conf['cookie.httponly']), 'samesite': samesite, } if conf['cookie.max_age']: cookie_kwargs['max_age'] = \ parse_time_interval(conf['cookie.max_age']) return cookie_kwargs
def init(confdict, ctx=None): """ Initializes this module acoording to :ref:`our module initialization guidelines <module_initialization>` with the following configuration keys: :confkey:`server` :faint:`[default=localhost:14000]` The server to connect to for all remote operations. Read using the generic :func:`score.init.parse_host_port`. The special value ``None`` indicates that all remote operations will immediately raise an exception. It is still possible to use higher level functions like :meth:`put <.ConfiguredNetfsModule.put>` and :meth:`get <.ConfiguredNetfsModule.get>` (although :meth:`get <.ConfiguredNetfsModule.get>` will raise an exception if the requested file is not present in the local folder.) :confkey:`cachedir` :faint:`[default=None]` A local folder that will hold downloaded files. If this value is omitted, the module will create a new temporary folder on demand, that will be used as the local folder for this session. :confkey:`deltmpcache` :faint:`[default=True]` This option is only relevant if the configuration did not contain a ``cachedir``. If this value is `True`, any temporary folder that was created for this session—as described for the configuration value ``cachedir``, above—will be removed when the :class:`.ConfiguredNetfsModule` is freed. The only use case where you might need this configuration is when you want to operate on a temporary folder, but still keep its contents when you are done with this module. """ conf = dict(defaults.items()) conf.update(confdict) if conf['server'] in (None, 'None'): host, port = None, None else: host, port = parse_host_port(conf['server'], defaults['server']) cachedir = None delcache = False if conf['cachedir']: cachedir = init_cache_folder(conf, 'cachedir') else: delcache = parse_bool(conf['deltmpcache']) c = ConfiguredNetfsModule(host, port, cachedir, delcache) c.ctx_conf = ctx if ctx and conf['ctx.member'] not in ('None', None): ctx.register(conf['ctx.member'], lambda _: c.connect()) return c
def _readconf(self, file): if not file: if not self.file: raise ValueError('No zergling configuration provided') file = self.file result = {} defaults = {'pause': True} confdict = parse_config_file(self.file) for section in confdict: if section in ['DEFAULT', 'score.init']: continue result[section] = defaults.copy() result[section].update(confdict[section]) result[section]['name'] = section result[section]['pause'] = parse_bool(result[section]['pause']) return result
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
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)
def init(confdict, ctx): """ Initializes this module acoording to :ref:`our module initialization guidelines <module_initialization>` with the following configuration keys: :confkey:`host` :confdefault:`0.0.0.0` The hostname to listen for connnections on. :confkey:`port` :confdefault:`8081` The port to listen for connnections on. :confkey:`stop_timeout` :confdefault:`None` Defines how long the module will wait for connections to close when pausing the worker. The value will be interpreted through a call to :func:`score.init.parse_time_interval`. The default value `None` indicates that the module will wait indefinitely. If you want to the server to terminate immediately, without waiting for open connections at all, you must pass "0". :confkey:`reuse_port` :confdefault:`False` Whether the ``reuse_port`` keyword argument should be passed to the underlying event loop's :meth:`create_server() <asyncio.AbstractEventLoop.create_server>` method. """ conf = dict(defaults.items()) conf.update(confdict) host = conf['host'] port = int(conf['port']) stop_timeout = conf['stop_timeout'] if stop_timeout == 'None': stop_timeout = None if stop_timeout is not None: stop_timeout = parse_time_interval(stop_timeout) reuse_port = parse_bool(conf['reuse_port']) return ConfiguredWebsocketsModule(ctx, host, port, stop_timeout, reuse_port)
def init(confdict, http=None, netfs=None): """ Initializes this module acoording to :ref:`our module initialization guidelines <module_initialization>` with the following configuration keys: :confkey:`cachedir` :default:`None` A writable folder that will be used to cache intermediate values. This value is mostly unused in this module, but the initialized value can be used by other modules. The :mod:`css module <score.css>`, for example, will create a sub-folder beneath this folder, if it was initialized without an explicit `cachedir` of its own. :confkey:`versionmanager` :default:`score.webassets.versioning.Dummy` The :class:`VersionManager <score.webassets.versioning.VersionManager>` to use. This value will be converted to an object using :func:`score.init.parse_object`. See the :mod:`package description <score.webassets.versioning>` for available implementations. :confkey:`netfs` :default:`True` The initializer will upload all webassets to a :mod:`score.netfs` server, if one was configured. You can disable this feature by passing a `False` value here """ conf = dict(defaults.items()) conf.update(confdict) if conf['cachedir']: init_cache_folder(conf, 'cachedir', autopurge=True) versionmanager = parse_object(conf, 'versionmanager') if netfs and parse_bool(conf['netfs']): versionmanager = NetfsVersionManager(versionmanager, netfs) def assetnotfound(ctx, exception): raise HTTPNotFound() if http: http.exception_handlers[AssetNotFound] = assetnotfound return ConfiguredWebassetsModule(conf['cachedir'], versionmanager)
def init(confdict, webassets, http, tpl, html=None): """ 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 javascript 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:`minifier` :confdefault:`None` The minifier to use for minification. Will be initialized using :func:`score.init.init_object`. See :mod:`score.tpl.minifier` for available minifiers. :confkey:`combine` :confdefault:`False` Whether javascript 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 javascript file. """ conf = dict(defaults.items()) conf.update(confdict) if conf['minifier']: conf['minifier'] = init_object(conf, 'minifier') if not conf['cachedir'] and webassets.cachedir: conf['cachedir'] = os.path.join(webassets.cachedir, 'js') if conf['cachedir']: init_cache_folder(conf, 'cachedir', autopurge=True) conf['combine'] = parse_bool(conf['combine']) return ConfiguredJsModule( http, tpl, webassets, conf['rootdir'], conf['cachedir'], conf['combine'], conf['minifier'])
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
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
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