def get_uris(settings): named = [] for k, v in settings.items(): if k.startswith(NAMED): name = k[len(NAMED):] if not name: raise ConfigurationError( '%s is not a valid zodbconn identifier' % k) named.append((name, v)) primary = settings.get('zodbconn.uri') if primary is None and named: raise ConfigurationError( 'Must have primary zodbconn.uri in settings containing named uris') if primary: yield '', primary for name, uri in named: yield name, uri
def add_authn_plugin(self, config, plugin): plugin_id = plugin.get_id() if plugin_id in self._plugins.keys(): raise ConfigurationError( 'Cannot register authentication plugin twice: "%s"', plugin_id) else: log.debug('Register authentication plugin: "%s"', plugin_id) self._plugins[plugin_id] = plugin
def __call__(self, view): if (asyncio.iscoroutinefunction(view) or asyncio.iscoroutinefunction(getattr(view, '__call__', None)) or self.is_class_method_coroutine(view)): raise ConfigurationError( 'Coroutine {} mapped to executor.'.format(view)) view = super().__call__(view) return self.run_in_executor_view(view)
def ensure(): if self.autocommit: return if self.registry.queryUtility(IAuthenticationPolicy) is None: raise ConfigurationError( 'Cannot configure an authorization policy without ' 'also configuring an authentication policy ' '(use the set_authorization_policy method)')
def __init__(self, **settings): if not settings.get('name'): raise ConfigurationError( "You must provide a name for a content provider") if 'for_' in settings: if settings.get('context') is None: settings['context'] = settings['for_'] self.__dict__.update(settings)
def add_translation_dirs(self, *specs): """ Add one or more :term:`translation directory` paths to the current configuration state. The ``specs`` argument is a sequence that may contain absolute directory paths (e.g. ``/usr/share/locale``) or :term:`asset specification` names naming a directory path (e.g. ``some.package:locale``) or a combination of the two. Example: .. code-block:: python config.add_translation_dirs('/usr/share/locale', 'some.package:locale') Later calls to ``add_translation_dir`` insert directories into the beginning of the list of translation directories created by earlier calls. This means that the same translation found in a directory added later in the configuration process will be found before one added earlier in the configuration process. However, if multiple specs are provided in a single call to ``add_translation_dirs``, the directories will be inserted into the beginning of the directory list in the order they're provided in the ``*specs`` list argument (items earlier in the list trump ones later in the list). """ directories = [] introspectables = [] for spec in specs[::-1]: # reversed package_name, filename = self._split_spec(spec) if package_name is None: # absolute filename directory = filename else: __import__(package_name) package = sys.modules[package_name] directory = os.path.join(package_path(package), filename) if not os.path.isdir(os.path.realpath(directory)): raise ConfigurationError('"%s" is not a directory' % directory) intr = self.introspectable('translation directories', directory, spec, 'translation directory') intr['directory'] = directory intr['spec'] = spec introspectables.append(intr) directories.append(directory) def register(): for directory in directories: tdirs = self.registry.queryUtility(ITranslationDirectories) if tdirs is None: tdirs = [] self.registry.registerUtility(tdirs, ITranslationDirectories) tdirs.insert(0, directory) self.action(None, register, introspectables=introspectables)
def initialize(config, version=None, settings_prefix='', default_settings=None): """Initialize kinto.core with the given configuration, version and project name. This will basically include kinto.core in Pyramid and set route prefix based on the specified version. :param config: Pyramid configuration :type config: ~pyramid:pyramid.config.Configurator :param str version: Current project version (e.g. '0.0.1') if not defined in application settings. :param str settings_prefix: Project name if not defined in application settings. :param dict default_settings: Override kinto.core default settings values. """ from kinto.core import DEFAULT_SETTINGS settings = config.get_settings() settings_prefix = settings.pop( 'kinto.settings_prefix', settings.get('settings_prefix')) or settings_prefix settings['settings_prefix'] = settings_prefix if not settings_prefix: warnings.warn('No value specified for `settings_prefix`') kinto_core_defaults = {**DEFAULT_SETTINGS} if default_settings: kinto_core_defaults.update(default_settings) load_default_settings(config, kinto_core_defaults) http_scheme = settings['http_scheme'] if http_scheme != 'https': warnings.warn('HTTPS is not enabled') # Override project version from settings. project_version = settings.get('project_version') or version if not project_version: error_msg = 'Invalid project version: {}'.format(project_version) raise ConfigurationError(error_msg) settings['project_version'] = project_version = str(project_version) # HTTP API version. http_api_version = settings.get('http_api_version') if http_api_version is None: # The API version is derivated from the module version if not provided. http_api_version = '.'.join(project_version.split('.')[0:2]) settings['http_api_version'] = http_api_version = str(http_api_version) api_version = 'v{}'.format(http_api_version.split('.')[0]) # Include kinto.core views with the correct api version prefix. config.include('kinto.core', route_prefix=api_version) config.route_prefix = api_version
def initialize(config, version=None, settings_prefix="", default_settings=None): """Initialize kinto.core with the given configuration, version and project name. This will basically include kinto.core in Pyramid and set route prefix based on the specified version. :param config: Pyramid configuration :type config: ~pyramid:pyramid.config.Configurator :param str version: Current project version (e.g. '0.0.1') if not defined in application settings. :param str settings_prefix: Project name if not defined in application settings. :param dict default_settings: Override kinto.core default settings values. """ from kinto.core import DEFAULT_SETTINGS settings = config.get_settings() settings_prefix = (settings.pop("kinto.settings_prefix", settings.get("settings_prefix")) or settings_prefix) settings["settings_prefix"] = settings_prefix if not settings_prefix: warnings.warn("No value specified for `settings_prefix`") kinto_core_defaults = {**DEFAULT_SETTINGS} if default_settings: kinto_core_defaults.update(default_settings) load_default_settings(config, kinto_core_defaults) http_scheme = settings["http_scheme"] if http_scheme != "https": warnings.warn("HTTPS is not enabled") # Override project version from settings. project_version = settings.get("project_version") or version if not project_version: error_msg = f"Invalid project version: {project_version}" raise ConfigurationError(error_msg) settings["project_version"] = project_version = str(project_version) # HTTP API version. http_api_version = settings.get("http_api_version") if http_api_version is None: # The API version is derivated from the module version if not provided. http_api_version = ".".join(project_version.split(".")[0:2]) settings["http_api_version"] = http_api_version = str(http_api_version) api_version = f"v{http_api_version.split('.')[0]}" # Include kinto.core views with the correct api version prefix. config.include("kinto.core", route_prefix=api_version) config.route_prefix = api_version
def _add_view_from_route(self, route_name, view, context, permission, renderer, attr, ): if view: self.add_view( permission=permission, context=context, view=view, name='', route_name=route_name, renderer=renderer, attr=attr, ) else: # prevent mistakes due to misunderstanding of how hybrid calls to # add_route and add_view interact if attr: raise ConfigurationError( 'view_attr argument not permitted without view ' 'argument') if context: raise ConfigurationError( 'view_context argument not permitted without view ' 'argument') if permission: raise ConfigurationError( 'view_permission argument not permitted without view ' 'argument') if renderer: raise ConfigurationError( 'view_renderer argument not permitted without ' 'view argument') warnings.warn( 'Passing view-related arguments to add_route() is deprecated as of ' 'Pyramid 1.1. Use add_view() to associate a view with a route ' 'instead. See "Deprecations" in "What\'s New in Pyramid 1.1" ' 'within the general Pyramid documentation for further details.', DeprecationWarning, 4)
def includeme(config): config.add_api_capability( 'accounts', description='Manage user accounts.', url='https://kinto.readthedocs.io/en/latest/api/1.x/accounts.html') config.scan('kinto.plugins.accounts.views') PERMISSIONS_INHERITANCE_TREE['root'].update({ 'account:create': {} }) PERMISSIONS_INHERITANCE_TREE['account'] = { 'write': {'account': ['write']}, 'read': {'account': ['write', 'read']} } # Add some safety to avoid weird behaviour with basicauth default policy. settings = config.get_settings() auth_policies = settings['multiauth.policies'] if 'basicauth' in auth_policies and 'account' in auth_policies: if auth_policies.index('basicauth') < auth_policies.index('account'): error_msg = ("'basicauth' should not be mentioned before 'account' " "in 'multiauth.policies' setting.") raise ConfigurationError(error_msg) # We assume anyone in account_create_principals is to create # accounts for other people. # No one can create accounts for other people unless they are an # "admin", defined as someone matching account_write_principals. # Therefore any account that is in account_create_principals # should be in account_write_principals too. creators = set(settings.get('account_create_principals', '').split()) admins = set(settings.get('account_write_principals', '').split()) cant_create_anything = creators.difference(admins) # system.Everyone isn't an account. cant_create_anything.discard('system.Everyone') if cant_create_anything: message = ('Configuration has some principals in account_create_principals ' 'but not in account_write_principals. These principals will only be ' 'able to create their own accounts. This may not be what you want.\n' 'If you want these users to be able to create accounts for other users, ' 'add them to account_write_principals.\n' 'Affected users: {}'.format(list(cant_create_anything))) raise ConfigurationError(message)
def __init__(self, name, path=None, description=None, cors_policy=None, depth=1, pyramid_route=None, **kw): self.name = name self.path = path self.pyramid_route = pyramid_route if not self.path and not self.pyramid_route: raise TypeError('You need to pass path or pyramid_route arg') self.description = description self.cors_expose_all_headers = True self._cors_enabled = None if cors_policy: for key, value in cors_policy.items(): kw.setdefault('cors_' + key, value) for key in self.list_arguments: # default_{validators,filters} and {filters,validators} don't # have to be mutables, so we need to create a new list from them extra = to_list(kw.get(key, [])) kw[key] = [] kw[key].extend(getattr(self, 'default_%s' % key, [])) kw[key].extend(extra) self.arguments = self.get_arguments(kw) for key, value in self.arguments.items(): # avoid squashing Service.decorator if ``decorator`` # argument is used to specify a default pyramid view # decorator if key != 'decorator': setattr(self, key, value) if hasattr(self, 'acl'): raise ConfigurationError("'acl' is not supported") # instantiate some variables we use to keep track of what's defined for # this service. self.defined_methods = [] self.definitions = [] # add this service to the list of available services SERVICES.append(self) # this callback will be called when config.scan (from pyramid) will # be triggered. def callback(context, name, ob): config = context.config.with_package(info.module) config.add_cornice_service(self) info = venusian.attach(self, callback, category='pyramid', depth=depth)
def scan_handler(config, handler, route_name, action_decorator, **default_view_args): """Scan a handler for automatically exposed views to register""" autoexpose = getattr(handler, '__autoexpose__', r'[A-Za-z]+') if autoexpose: try: autoexpose = re.compile(autoexpose).match except (re.error, TypeError), why: raise ConfigurationError(why[0])
def __call__(self, view): if inspect.isclass(view): view = getattr(view, self.attr) if asyncio.iscoroutinefunction(view) or asyncio.iscoroutinefunction( getattr(view, '__call__', None)): raise ConfigurationError( 'Coroutine {} mapped to executor.'.format(view)) view = super().__call__(view) return self.run_in_executor_view(view)
def _parse_settings(settings): """ Convenience function to collect settings prefixed by 'mongoengine_session' and coerce settings to ``int``, ``float``, and ``bool`` as needed. """ keys = [s for s in settings if s.startswith('mongoengine_sessions.')] options = {} for k in keys: param = k.split('.')[-1] value = settings[k] options[param] = value # only required setting if 'secret' not in options: raise ConfigurationError( 'mongoengine_sessions.secret is a required setting') # coerce bools for b in ('cookie_secure', 'cookie_httponly', 'cookie_on_exception'): if b in options: options[b] = asbool(options[b]) # coerce ints for i in ('timeout', 'port', 'db', 'cookie_max_age'): if i in options: options[i] = int(options[i]) # coerce float if 'socket_timeout' in options: options['socket_timeout'] = float(options['socket_timeout']) # check for settings conflict if 'prefix' in options and 'id_generator' in options: err = 'cannot specify custom id_generator and a key prefix' raise ConfigurationError(err) # convenience setting for overriding key prefixes if 'prefix' in options: prefix = options.pop('prefix') options['id_generator'] = partial(prefixed_id, prefix=prefix) return options
def __init__(self, name, path, description=None, cors_policy=None, depth=1, **kw): self.name = name self.path = path self.description = description self.cors_expose_all_headers = True self._cors_enabled = None if cors_policy: for key, value in cors_policy.items(): kw.setdefault('cors_' + key, value) for key in self.list_arguments: # default_{validators,filters} and {filters,validators} don't # have to be mutables, so we need to create a new list from them extra = to_list(kw.get(key, [])) kw[key] = [] kw[key].extend(getattr(self, 'default_%s' % key, [])) kw[key].extend(extra) self.arguments = self.get_arguments(kw) for key, value in self.arguments.items(): # avoid squashing Service.decorator if ``decorator`` # argument is used to specify a default pyramid view # decorator if key != 'decorator': setattr(self, key, value) if hasattr(self, 'factory') and hasattr(self, 'acl'): raise ConfigurationError("Cannot specify both 'acl' and 'factory'") # instantiate some variables we use to keep track of what's defined for # this service. self.defined_methods = [] self.definitions = [] # add this service to the list of available services SERVICES.append(self) # register aliases for the decorators for verb in ('GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'): setattr(self, verb.lower(), functools.partial(self.decorator, verb)) # this callback will be called when config.scan (from pyramid) will # be triggered. def callback(context, name, ob): config = context.config.with_package(info.module) config.add_cornice_service(self) info = venusian.attach(self, callback, category='pyramid', depth=depth)
def prepare(request=None, registry=None): """ This function pushes data onto the Pyramid threadlocal stack (request and registry), making those objects 'current'. It returns a dictionary useful for bootstrapping a Pyramid application in a scripting environment. ``request`` is passed to the :app:`Pyramid` application root factory to compute the root. If ``request`` is None, a default will be constructed using the registry's :term:`Request Factory` via the :meth:`pyramid.interfaces.IRequestFactory.blank` method. If ``registry`` is not supplied, the last registry loaded from :attr:`pyramid.config.global_registries` will be used. If you have loaded more than one :app:`Pyramid` application in the current process, you may not want to use the last registry loaded, thus you can search the ``global_registries`` and supply the appropriate one based on your own criteria. The function returns a dictionary composed of ``root``, ``closer``, ``registry``, ``request`` and ``root_factory``. The ``root`` returned is the application's root resource object. The ``closer`` returned is a callable (accepting no arguments) that should be called when your scripting application is finished using the root. ``registry`` is the registry object passed or the last registry loaded into :attr:`pyramid.config.global_registries` if no registry is passed. ``request`` is the request object passed or the constructed request if no request is passed. ``root_factory`` is the root factory used to construct the root. """ if registry is None: registry = getattr(request, 'registry', global_registries.last) if registry is None: raise ConfigurationError('No valid Pyramid applications could be ' 'found, make sure one has been created ' 'before trying to activate it.') if request is None: request = _make_request('/', registry) # NB: even though _make_request might have already set registry on # request, we reset it in case someone has passed in their own # request. request.registry = registry threadlocals = {'registry':registry, 'request':request} threadlocal_manager.push(threadlocals) extensions = registry.queryUtility(IRequestExtensions) if extensions is not None: request._set_extensions(extensions) def closer(): threadlocal_manager.pop() root_factory = registry.queryUtility(IRootFactory, default=DefaultRootFactory) root = root_factory(request) if getattr(request, 'context', None) is None: request.context = root return {'root':root, 'closer':closer, 'registry':registry, 'request':request, 'root_factory':root_factory}
def safe_json(get, section, key): try: value = get(key) json_value = json.loads(value) except ValueError: msg = 'The %s=%s is not valid json in section %s' % (key, value, section) raise ConfigurationError(msg) return json_value
def get_ldap_connector(request): """ Return the LDAP connector attached to the request. If :meth:`pyramid.config.Configurator.ldap_setup` was not called, using this function will raise an :exc:`pyramid.exceptions.ConfigurationError`.""" connector = getattr(request, 'ldap_connector', None) if connector is None: raise ConfigurationError( 'You must call Configurator.ldap_setup during setup ' 'to use an ldap connector') return connector
def __call__(self, view): if not asyncio.iscoroutinefunction(view) and is_generator(view): view = asyncio.coroutine(view) else: raise ConfigurationError( 'Non-coroutine {} mapped to coroutine.'.format(view) ) view = super().__call__(view) return self.run_in_coroutine_view(view)
def includeme(config): settings = config.registry.settings servers = splitlines(settings.get('velruse.store.servers', '')) key_prefix = settings.get('velruse.store.key_prefix', 'velruse_ustore') if not servers: raise ConfigurationError('Missing "velruse.store.servers" setting') store = MemcachedStore(servers=servers, key_prefix=key_prefix) config.registry.velruse_store = store
def action(): storage = cfg.registry.get(ID_LAYER, {}) layers = storage.get(layer, []) for intr in layers: if intr['name'] == name: intr['filters'][template] = mapped_view return raise ConfigurationError("Can't find layer: %s%s" % (layer, '(%s)' % name if name else ''))
def add_translation_dirs(self, *specs): """ Add one or more :term:`translation directory` paths to the current configuration state. The ``specs`` argument is a sequence that may contain absolute directory paths (e.g. ``/usr/share/locale``) or :term:`asset specification` names naming a directory path (e.g. ``some.package:locale``) or a combination of the two. Example: .. code-block:: python config.add_translation_dirs('/usr/share/locale', 'some.package:locale') Later calls to ``add_translation_dir`` insert directories into the beginning of the list of translation directories created by earlier calls. This means that the same translation found in a directory added later in the configuration process will be found before one added earlier in the configuration process. However, if multiple specs are provided in a single call to ``add_translation_dirs``, the directories will be inserted into the beginning of the directory list in the order they're provided in the ``*specs`` list argument (items earlier in the list trump ones later in the list). """ for spec in specs[::-1]: # reversed package_name, filename = self._split_spec(spec) if package_name is None: # absolute filename directory = filename else: __import__(package_name) package = sys.modules[package_name] directory = os.path.join(package_path(package), filename) if not os.path.isdir(os.path.realpath(directory)): raise ConfigurationError('"%s" is not a directory' % directory) tdirs = self.registry.queryUtility(ITranslationDirectories) if tdirs is None: tdirs = [] self.registry.registerUtility(tdirs, ITranslationDirectories) tdirs.insert(0, directory) # XXX no action? if specs: # We actually only need an IChameleonTranslate function # utility to be registered zero or one times. We register the # same function once for each added translation directory, # which does too much work, but has the same effect. ctranslate = ChameleonTranslate(translator) self.registry.registerUtility(ctranslate, IChameleonTranslate)
def __init__(self, request): try: self.tempdir=request.registry.settings['substanced.uploads_tempdir'] except KeyError: raise ConfigurationError( 'To use FileUploadTempStore, you must set a ' '"substanced.uploads_tempdir" key in your .ini settings. It ' 'points to a directory which will temporarily ' 'hold uploaded files when form validation fails.') self.request = request self.session = request.session
def load_provider(config, provider): settings = config.registry.settings impl = settings.get('provider.%s.impl' % provider) or provider login_cfg = settings_adapter.get(impl) if login_cfg is None: raise ConfigurationError( 'could not find configuration method for provider %s' '' % provider) loader = getattr(config, login_cfg) loader(prefix='provider.%s.' % provider)
def includeme(config): config.add_directive('load_and_include', load_and_include) config.include('.models') if config.registry.settings.get('pyramid_settings.includes', None): raise ConfigurationError("'pyramid_settings.includes' was in the paster ini file. " "That setting is only ment for included config files. If you need to load something " "before this package, use the default 'pyramid.includes'") filenames = config.registry.settings.get('pyramid_settings.files', "").splitlines() for fn in filenames: if fn: config.load_and_include(fn)
def __call__(self, view): if is_unbound_method(view) and self.attr is None: raise ConfigurationError(( 'Unbound method calls are not supported, please set the class ' 'as your `view` and the method as your `attr`')) if inspect.isclass(view): view = self.map_class(view) else: view = self.map_nonclass(view) return view
def get_callable_name(name): """ Verifies that the ``name`` is ascii and will raise a ``ConfigurationError`` if it is not. """ try: return native_(name, 'ascii') except (UnicodeEncodeError, UnicodeDecodeError): msg = ('`name="%s"` is invalid. `name` must be ascii because it is ' 'used on __name__ of the method') raise ConfigurationError(msg % name)
def explorer_view(request): settings = config.registry.settings if settings.get('pyramid_openapi3') is None: ConfigurationError('You need to call config.pyramid_openapi3_spec for explorer to work.') with open(resolved_template.abspath()) as f: template = Template(f.read()) html = template.safe_substitute( ui_version=ui_version, spec_url=request.route_url(settings['pyramid_openapi3']["spec_route_name"]), ) return Response(html)
def authenticate(self, login, password, attributes=ALL_ATTRIBUTES): """ Given a login name and a password, return a tuple of ``(dn, attrdict)`` if the matching user if the user exists and his password is correct. Otherwise return ``None``. In a ``(dn, attrdict)`` return value, ``dn`` will be the distinguished name of the authenticated user. Attrdict will be a dictionary mapping LDAP user attributes to sequences of values. The keys and values in the dictionary values provided will be decoded from UTF-8, recursively, where possible. The dictionary returned is a case-insensitive dictionary implemenation. A zero length password will always be considered invalid since it results in a request for "unauthenticated authentication" which should not be used for LDAP based authentication. See `section 5.1.2 of RFC-4513 <http://tools.ietf.org/html/rfc4513#section-5.1.2>`_ for a description of this behavior. If :meth:`pyramid.config.Configurator.ldap_set_login_query` was not called, using this function will raise an :exc:`pyramid.exceptions.ConfiguratorError`.""" if password == '': return None #with self.manager.connection() as conn: #with self.connection as conn: conn = self.connection conn.open() search = getattr(self.registry, 'ldap_login_query', None) if search is None: raise ConfigurationError( 'ldap_set_login_query was not called during setup') result = search.execute(conn, login=login, password=password, attributes=attributes) if len(result) > 1: conn.result['description'] = 'invalidCredentials' conn.result['message'] = '' return None elif len(result) < 1: conn.result['description'] = 'invalidCredentials' conn.result['message'] = '' return None else: login_dn = result[0]['dn'] try: conn.user = login_dn conn.password = password conn.bind() # must invoke the __enter__ of this thing for it to connect return _ldap_decode(result[0]) except ldap3.LDAPException: logger.debug('Exception in authenticate with login %r' % login, exc_info=True) return None
def session(self): """ Obtain the :term:`session` object associated with this request. If a :term:`session factory` has not been registered during application configuration, a :class:`pyramid.exceptions.ConfigurationError` will be raised""" factory = self.registry.queryUtility(ISessionFactory) if factory is None: raise ConfigurationError( 'No session factory registered ' '(see the Sessions chapter of the Pyramid documentation)') return factory(self)