def _get_object_path(current_path, current_object, path, default, required): if len(path) == 0: result = dict(default) result.update(current_object) for key in required: if key not in result: raise ConfigurationError( 'Missing configuration value for {}.{}.'.format( '.'.join(current_path), key)) return result k = path[0] if k not in current_object: raise ConfigurationError( 'Missing configuration object for {}.{}.'.format( '.'.join(current_path), k)) current_path.append(k) if type(current_object[k]) != dict: raise ConfigurationError( 'The configuration {} is not an object.'.format( '.'.join(current_path))) return Config._get_object_path(current_path, current_object[k], path[1:], default, required)
def get_logo_config(): """ Returns a dictionary of the configured file path's to the logos. Returns: dict: The configured paths to the logos wrapped in a dictionary. """ assert Config._config is not None confederation_key = 'confederation' oereb_key = 'oereb' canton_key = 'canton' msg = 'The definition for "{key}" must be set. Got: {found_config}' logo_dict = Config._config.get('logo') if not logo_dict.get(confederation_key): raise ConfigurationError( msg.format(key=confederation_key, found_config=logo_dict)) if not logo_dict.get(oereb_key): raise ConfigurationError( msg.format(key=oereb_key, found_config=logo_dict)) if not logo_dict.get(canton_key): raise ConfigurationError( msg.format(key=canton_key, found_config=logo_dict)) file_adapter = FileAdapter() confederation_logo = ImageRecord( file_adapter.read(logo_dict.get(confederation_key))) oereb_logo = ImageRecord(file_adapter.read(logo_dict.get(oereb_key))) canton_logo = ImageRecord(file_adapter.read(logo_dict.get(canton_key))) return { confederation_key: confederation_logo, oereb_key: oereb_logo, canton_key: canton_logo }
def __init__(self, **kwargs): """ Keyword Args: db_connection (str): A rfc1738 conform database connection string in the form of: ``<driver_name>://<username>:<password>@<database_host>:<port>/<database_name>`` model (str): A valid dotted name string which leads to an importable representation of sqlalchemy.ext.declarative.DeclarativeMeta or the real class itself. """ from pyramid_oereb import database_adapter if database_adapter: self._adapter_ = database_adapter else: raise ConfigurationError( 'Adapter for database must be defined if you use database sources.' ) if kwargs.get('db_connection'): self._key_ = kwargs.get('db_connection') else: raise ConfigurationError( '"db_connection" for source has to be defined in used yaml ' 'configuration file') if kwargs.get('model'): self._model_ = DottedNameResolver().maybe_resolve( kwargs.get('model')) else: raise ConfigurationError( '"model" for source has to be defined in used yaml configuration file' )
def parse(cfg_file, cfg_section, c2ctemplate_style=False): """ Parses the defined YAML file and returns the defined section as dictionary. Args: cfg_file (str): The YAML file to be parsed. cfg_section (str): The section to be returned. Returns: dict: The parsed section as dictionary. """ if cfg_file is None: raise ConfigurationError( 'Missing configuration parameter "pyramid_oereb.cfg.file" or ' '"pyramid_oereb.cfg.c2ctemplate.file".') if cfg_section is None: raise ConfigurationError( 'Missing configuration parameter "pyramid_oereb.cfg.section".') try: if c2ctemplate_style: import c2c.template content = c2c.template.get_config(cfg_file) else: with open(cfg_file) as f: content = yaml.safe_load(f.read()) except IOError as e: e.strerror = '{0}{1} \'{2}\', Current working directory is {3}'.format( e.strerror, e.args[1], e.filename, os.getcwd()) raise cfg = content.get(cfg_section) if cfg is None: raise ConfigurationError( 'YAML file contains no section "{0}"'.format(cfg_section)) return cfg
def get_layer_config(theme_code): """ Obtaining the layer configuration of a theme from config. Args: theme_code (str): The theme code. Returns: list: Layer index (int) and layer opacity (float). """ assert Config._config is not None themes = Config._config.get('plrs') if themes and isinstance(themes, list): for theme in themes: if theme.get('code') == theme_code: view_service = theme.get('view_service') if view_service and isinstance(view_service, dict): layer_index = view_service.get('layer_index') layer_opacity = view_service.get('layer_opacity') if layer_opacity is None: raise ConfigurationError( 'For {} the "layer_opacity" was not found!'.format(theme_code) ) if layer_index is None: raise ConfigurationError( 'For {} the "layer_index" was not found!'.format(theme_code) ) return layer_index, layer_opacity return None, None
def check_database_config(config): from papaye.models import get_manager manager = get_manager(config) if manager.get_db_version() < manager.get_sw_version(): raise ConfigurationError('Your database need to be updated! Run ' '"papaye_evolve path_to_your_config_file.ini" command first') conn = config.registry._zodb_databases[''].open() if user_root_factory(conn) is None or repository_root_factory(conn) is None: raise ConfigurationError('Database does not exist! Run "papaye_init ' 'path_to_your_config_file.ini command first') return True
def __init__(self, **kwargs): """ Keyword Args: db_connection (str): A rfc1738 conform database connection string in the form of: ``<driver_name>://<username>:<password>@<database_host>:<port>/<database_name>`` model (str): A valid dotted name string which leads to an importable representation of sqlalchemy.ext.declarative.DeclarativeMeta or the real class itself. """ from pyramid_oereb import database_adapter if database_adapter: self._adapter_ = database_adapter else: raise ConfigurationError( 'Adapter for database must be defined if you use database sources.' ) if kwargs.get('db_connection'): self._key_ = kwargs.get('db_connection') else: raise ConfigurationError( '"db_connection" for source has to be defined in used yaml ' 'configuration file') if kwargs.get('model'): self._model_ = DottedNameResolver().maybe_resolve( kwargs.get('model')) else: raise ConfigurationError( '"model" for source has to be defined in used yaml configuration file' ) # check if database is available and wait until it might be or raise error timeout_target = time.time() + self.TIMEOUT db_healthy = False current_wait_position = 0 sleep_period = 1.0 while time.time() < timeout_target: db_healthy = self.health_check() if not db_healthy: current_wait_position += int(sleep_period) # 1.0 sets it to a second log.info( 'Waiting for the database {} more seconds ({})'.format( self.TIMEOUT - current_wait_position, self._key_)) time.sleep(sleep_period) else: break if not db_healthy: raise ConfigurationError( 'Database was not reached until timeout of {} seconds ({})'. format(self.TIMEOUT, self._key_))
def register_widget_template(template, widget, settings, provides, registry=None): """Register new widget template""" if not os.path.isfile(template): raise ConfigurationError("No such file", template) content_type = settings.get('content_type', 'text/html') macro = settings.get('macro') factory = WidgetTemplateFactory(template, content_type, macro) provides = settings.get('provides', provides) directlyProvides(factory, provides) # check context required = (settings.get('context', Interface), settings.get('layer', IFormLayer), settings.get('form', None), settings.get('field', None), widget) # update registry if registry is None: registry = settings.get('registry') if registry is None: registry = get_pyramid_registry() registry.registerAdapter(factory, required, provides, settings.get('mode', INPUT_MODE))
def get_magpie_url(container=None): # type: (Optional[AnySettingsContainer]) -> Str if container is None: LOGGER.warning( "Registry not specified, trying to find Magpie URL from environment" ) url = get_constant("MAGPIE_URL", raise_missing=False, raise_not_set=False, print_missing=False) if url: return url hostname = ( get_constant("HOSTNAME", raise_not_set=False, raise_missing=False) or get_constant( "MAGPIE_HOST", raise_not_set=False, raise_missing=False)) if not hostname: raise ConfigurationError( "Missing or unset MAGPIE_HOST or HOSTNAME value.") magpie_port = get_constant("MAGPIE_PORT", raise_not_set=False) magpie_scheme = get_constant("MAGPIE_SCHEME", raise_not_set=False, raise_missing=False, default_value="http") return "{}://{}{}".format( magpie_scheme, hostname, ":{}".format(magpie_port) if magpie_port else "") try: # add "http" scheme to url if omitted from config since further 'requests' calls fail without it # mostly for testing when only "localhost" is specified # otherwise config should explicitly define it with 'MAGPIE_URL' env or 'magpie.url' config settings = get_settings(container) url_parsed = urlparse( get_constant("MAGPIE_URL", settings, "magpie.url").strip("/")) if url_parsed.scheme in ["http", "https"]: return url_parsed.geturl() magpie_url = "http://{}".format(url_parsed.geturl()) print_log( "Missing scheme from settings URL, new value: '{}'".format( magpie_url), LOGGER, logging.WARNING) return magpie_url except AttributeError: # If magpie.url does not exist, calling strip fct over None will raise this issue raise ConfigurationError( "MAGPIE_URL or magpie.url config cannot be found")
def validate_config(config, prefix): settings = config.get_settings() if prefix + 'api_key' not in settings: raise ConfigurationError( "Megaphone API key must be provided for {}".format(prefix)) api_key = settings[prefix + 'api_key'] if prefix + 'url' not in settings: raise ConfigurationError( "Megaphone URL must be provided for {}".format(prefix)) url = settings[prefix + 'url'] if prefix + 'broadcaster_id' not in settings: raise ConfigurationError( "Megaphone broadcaster_id must be provided for {}".format(prefix)) broadcaster_id = settings[prefix + 'broadcaster_id'] return MegaphoneConfig(api_key, url, broadcaster_id)
def register_workflow(config, workflow, type_, content_type=None): if content_type is None: content_type = IDefaultWorkflow reg = config.registry if not reg.content.exists(content_type): raise ConfigurationError('Workflow %s registered for content_type %s ' 'which does not exist.' % (workflow, content_type)) reg.workflow.add(workflow, content_type)
def get_phoenix_url(container=None): # type: (Optional[AnySettingsContainer]) -> Str hostname = (get_constant( "PHOENIX_HOST", container, raise_missing=False, raise_not_set=False) or get_constant( "HOSTNAME", raise_missing=False, raise_not_set=False)) if not hostname: raise ConfigurationError( "Missing or unset PHOENIX_HOST or HOSTNAME value.") phoenix_port = get_constant("PHOENIX_PORT", raise_not_set=False) return "https://{0}{1}".format( hostname, ":{}".format(phoenix_port) if phoenix_port else "")
def includeme(config): config.scan(__name__) settings = config.registry.settings if not 'persona.audiences' in settings: raise ConfigurationError(AUDIENCES_MESSAGE) # Construct a browserid Verifier using the configured audience. # This will pre-compile some regexes to reduce per-request overhead. verifier_factory = config.maybe_dotted(settings.get('persona.verifier', 'browserid.RemoteVerifier')) audiences = aslist(settings['persona.audiences']) config.registry['persona.verifier'] = verifier_factory(audiences)
def find_megaphone_prefix(registry): # FIXME: this assumes only one Megaphone server per config listeners = aslist(registry.settings['event_listeners']) for listener in listeners: prefix = 'event_listeners.{}.'.format(listener) listener_modpath = registry.settings['{}use'.format(prefix)] # FIXME: maybe be smarter about the current module's path? if listener_modpath.startswith('kinto_megaphone.'): return prefix raise ConfigurationError( "No megaphone listeners configured. Listeners are {}".format( listeners))
def callback(context, name, widget): # pylint: disable=unused-argument template = os.path.join( os.path.dirname(inspect.getfile(inspect.getmodule(widget))), settings.get('template')) if not os.path.isfile(template): raise ConfigurationError("No such file", template) # check registry registry = settings.get('registry') if registry is None: config = context.config.with_package(info.module) # pylint: disable=no-member registry = config.registry register_widget_template(template, widget, settings, self.interface, registry)
def override_widget_layout(widget, **settings): """Override layout template for a given class This function can be used to override a class layout template without using ZCML. Settings are the same as for @layout_config decorator. """ template = settings.get('template', '') if not template: raise ConfigurationError("No template specified") if not template.startswith('/'): stack = inspect.stack()[1] template = os.path.join( os.path.dirname(inspect.getfile(inspect.getmodule(stack[0]))), template) register_widget_template(template, widget, settings, IWidgetLayoutTemplate)
def __init__(self, **settings): # pylint: disable=too-many-branches if 'name' not in settings: raise ConfigurationError( "Missing 'name' argument for form definition") if 'for_' in settings: if settings.get('context') is None: settings['context'] = settings.pop('for_') if 'layer' in settings: settings['request_type'] = settings.pop('layer') # get AJAX settings settings['ajax'] = ajax_settings = {} if 'context' in settings: ajax_settings['context'] = settings.get('context') if 'ajax_name' in settings: ajax_settings['name'] = settings.pop('ajax_name') else: ajax_settings['name'] = settings['name'].replace('.html', '.json') if 'ajax_base' in settings: ajax_settings['base'] = settings.pop('ajax_base') if 'ajax_implements' in settings: ajax_settings['implements'] = settings.pop('ajax_implements') if 'ajax_method' in settings: method = settings.pop('ajax_method') if method is not None: ajax_settings['request_method'] = method else: ajax_settings['request_method'] = 'POST' if 'ajax_permission' in settings: ajax_settings['permission'] = settings.pop('ajax_permission') if 'ajax_renderer' in settings: renderer = settings.pop('ajax_renderer') if renderer is not None: ajax_settings['renderer'] = renderer else: ajax_settings['renderer'] = 'json' if 'ajax_xhr' in settings: xhr = settings.pop('ajax_xhr') if xhr is not None: ajax_settings['xhr'] = xhr else: ajax_settings['xhr'] = True if 'ajax_require_csrf' in settings: csrf = settings.pop('ajax_require_csrf') if csrf is not None: ajax_settings['require_csrf'] = csrf self.__dict__.update(settings)
def load_from_config(config, prefix): mp_config = validate_config(config, prefix) settings = config.get_settings() if prefix + "match_kinto_changes" not in settings: ERROR_MSG = ("Resources to filter must be provided to kinto_changes " "using match_kinto_changes") raise ConfigurationError(ERROR_MSG) included_resources = aslist(settings[prefix + "match_kinto_changes"]) excluded_resources = aslist(settings.get(prefix + "except_kinto_changes", "")) client = megaphone.Megaphone(mp_config.url, mp_config.api_key) listener = KintoChangesListener( client, mp_config.broadcaster_id, included_resources, excluded_resources) config.add_subscriber(listener._convert_resources, pyramid.events.ApplicationCreated) return listener
def add_workflow(config, workflow, content_types=(None,)): """Configurator method for adding a workflow. If no **content_types** is given, workflow is registered globally. :param config: Pyramid configurator :param workflow: :class:`Workflow` instance :param content_types: Register workflow for given content_types :type content_types: iterable :raises: :exc:`ConfigurationError` if :meth:`Workflow.check` fails :raises: :exc:`ConfigurationError` if **content_type** does not exist :raises: :exc:`DoesNotImplement` if **workflow** does not implement IWorkflow """ if not IWorkflow.providedBy(workflow): raise ValueError('Not a workflow') try: workflow.check() except WorkflowError as why: raise ConfigurationError(str(why)) intr = config.introspectable( 'pyramid workflows', (IWorkflow, content_types, workflow.type), content_types, 'pyramid workflow', ) intr['workflow'] = workflow intr['type'] = workflow.type intr['content_types'] = content_types for content_type in content_types: config.action((IWorkflow, content_type, workflow.type), callable=register_workflow, introspectables=(intr,), order=9999, args=(config, workflow, workflow.type, content_type))
def get_twitcher_protected_service_url(magpie_service_name, hostname=None): twitcher_proxy_url = get_constant("TWITCHER_PROTECTED_URL", raise_not_set=False) if not twitcher_proxy_url: twitcher_proxy = get_constant("TWITCHER_PROTECTED_PATH", raise_not_set=False) if not twitcher_proxy.endswith("/"): twitcher_proxy = twitcher_proxy + "/" if not twitcher_proxy.startswith("/"): twitcher_proxy = "/" + twitcher_proxy if not twitcher_proxy.startswith("/twitcher"): twitcher_proxy = "/twitcher" + twitcher_proxy hostname = (hostname or get_constant( "TWITCHER_HOST", raise_not_set=False, raise_missing=False) or get_constant( "HOSTNAME", raise_not_set=False, raise_missing=False)) if not hostname: raise ConfigurationError( "Missing or unset TWITCHER_PROTECTED_URL, TWITCHER_HOST or HOSTNAME value." ) twitcher_proxy_url = "https://{0}{1}".format(hostname, twitcher_proxy) twitcher_proxy_url = twitcher_proxy_url.rstrip("/") return "{0}/{1}".format(twitcher_proxy_url, magpie_service_name)
def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ # inject the url from the environment settings['sqlalchemy.url'] = os.environ.get( 'DATABASE_URL', 'postgresql://cewing:@localhost:5432/lj2') engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) Base.metadata.bind = engine # authn/authz configuration auth_secret = os.environ.get('LJ_AUTH_SECRET', 'itsaseekrit') authentication_policy = AuthTktAuthenticationPolicy( secret=auth_secret, hashalg='sha512', callback=groupfinder, ) authorization_policy = ACLAuthorizationPolicy() config = Configurator( settings=settings, authentication_policy=authentication_policy, authorization_policy=authorization_policy, root_factory=DefaultRoot, ) # add a view predicate to validate api keys: config.add_view_predicate('valid_api_key', APIKeyPredicate) # github authentication configuration: config.include('velruse.providers.github') github_key = os.environ.get('LJ_GITHUB_KEY', None) github_secret = os.environ.get('LJ_GITHUB_SECRET', None) if not github_key and not github_secret: raise ConfigurationError( 'Github Login requires LJ_GITHUB_SECRET and LJ_GITHUB_KEY set in the environment' ) config.add_github_login( consumer_key=github_key, consumer_secret=github_secret, scope=settings.get('velruse.providers.github.scope', 'user, public_repo'), ) # provide constructing the login url as a request method config.add_request_method(lambda req, svc='github': login_url(req, svc), name='login_url') # session configuration session_secret = os.environ.get('LJ_SESSION_SECRET', 'itsaseekrit') session_factory = SignedCookieSessionFactory(session_secret) config.set_session_factory(session_factory) # templating configuration config.include('pyramid_jinja2') # view configuration config.add_static_view('static', 'static', cache_max_age=3600) config.add_route('home', '/') config.add_route('mine', '/mine') config.add_route('about', '/about') config.add_route('create', '/entry/create') config.add_route('entry', '/entry/{id:\d+}', factory=EntryRoot, traverse='/{id:\d+}') config.add_route('edit', '/entry/{id:\d+}/edit', factory=EntryRoot, traverse='/{id:\d+}') config.add_route('delete', '/entry/{id:\d+}/delete', factory=EntryRoot, traverse='/{id:\d+}') config.add_route('apikey', '/api/key') config.add_route('export', '/api/export') config.add_route('logout', '/logout') # add user to the request config.add_request_method(get_user, 'user', reify=True) # approved and admin usernames, too config.add_request_method(get_approved_users, 'approved', reify=True) config.add_request_method(get_admin_users, 'admins', reify=True) config.add_request_method(get_active_courses, 'courses', reify=True) config.scan() return config.make_wsgi_app()
def add_panel(config, panel=None, name="", context=None, renderer=None, attr=None): """ Add a panel configuration to the current configuration state. Arguments panel A panel callable or a dotted Python name which refers to a panel callable. This argument is required unless a ``renderer`` argument also exists. If a ``renderer`` argument is passed, and a ``panel`` argument is not provided, the panel callable defaults to a callable that returns an empty dictionary. attr The panel machinery defaults to using the ``__call__`` method of the panel callable (or the function itself, if the panel callable is a function) to obtain a response. The ``attr`` value allows you to vary the method attribute used to obtain the response. For example, if your panel was a class, and the class has a method named ``index`` and you wanted to use this method instead of the class' ``__call__`` method to return the response, you'd say ``attr="index"`` in the panel configuration for the panel. This is most useful when the panel definition is a class. renderer This is either a single string term (e.g. ``json``) or a string implying a path or asset specification (e.g. ``templates/panels.pt``) naming a renderer implementation. If the ``renderer`` value does not contain a dot ``.``, the specified string will be used to look up a renderer implementation, and that renderer implementation will be used to construct a response from the panel return value. If the ``renderer`` value contains a dot (``.``), the specified term will be treated as a path, and the filename extension of the last element in the path will be used to look up the renderer implementation, which will be passed the full path. The renderer implementation will be used to construct a response from the panel return value. Note that if the panel itself returns an instance of `basestring` (or just `str` in Python 3), the specified renderer implementation is never called. When the renderer is a path, although a path is usually just a simple relative pathname (e.g. ``templates/foo.pt``, implying that a template named "foo.pt" is in the "templates" directory relative to the directory of the current package of the Configurator), a path can be absolute, starting with a slash on UNIX or a drive letter prefix on Windows. The path can alternately be an asset specification in the form ``some.dotted.package_name:relative/path``, making it possible to address template assets which live in a separate package. The ``renderer`` attribute is optional. If it is not defined, the "null" renderer is assumed (no rendering is performed and the value is passed back to the upstream Pyramid machinery unmodified). name The optional panel name, which defaults to an empty string. context An object or a dotted Python name referring to an interface or class object that the context must be an instance of, *or* the interface that the context must provide in order for this panel to be found and called. This predicate is true when the context is an instance of the represented class or if the context provides the represented interface; it is otherwise false. """ panel = config.maybe_dotted(panel) context = config.maybe_dotted(context) if not panel: if renderer: def panel(context, request): return {} else: raise ConfigurationError('"panel" was not specified and ' 'no "renderer" specified') introspectables = [] discriminator = ['panel', context, name, IPanel, attr] discriminator = tuple(discriminator) if inspect.isclass(panel) and attr: panel_desc = 'method %r of %s' % (attr, config.object_description(panel)) else: panel_desc = config.object_description(panel) panel_intr = config.introspectable('panels', discriminator, panel_desc, 'panel') panel_intr.update( dict( name=name, context=context, attr=attr, callable=panel, )) introspectables.append(panel_intr) def register(renderer=renderer): if renderer is None: # use default renderer if one exists (reg'd in phase 1) if config.registry.queryUtility(IRendererFactory) is not None: renderer = renderers.RendererHelper(name=None, package=config.package, registry=config.registry) elif isinstance(renderer, basestring): renderer = renderers.RendererHelper(name=renderer, package=config.package, registry=config.registry) def derive_rendered(wrapped, renderer): if renderer is None: return wrapped def derived(context, request, *args, **kw): result = wrapped(context, request, *args, **kw) if isinstance(result, basestring): return result system = { 'panel': panel, 'renderer_info': renderer, 'context': context, 'request': request } rendered = renderer.render(result, system, request=request) return rendered return derived def derive_unicode(wrapped): def derived(context, request, *args, **kw): result = wrapped(context, request, *args, **kw) if not isinstance(result, unicode): result = unicode(result, 'UTF-8') return result return derived derived_panel = derive_unicode( derive_rendered(_PanelMapper(attr)(panel), renderer)) config.registry.registerAdapter(derived_panel, (context, ), IPanel, name) if renderer is not None and renderer.name and '.' in renderer.name: # it's a template tmpl_intr = config.introspectable('templates', discriminator, renderer.name, 'template') tmpl_intr.relate('panels', discriminator) tmpl_intr['name'] = renderer.name tmpl_intr['type'] = renderer.type tmpl_intr['renderer'] = renderer tmpl_intr.relate('renderer factories', renderer.type) introspectables.append(tmpl_intr) config.action(('panel', context, name), register, introspectables=introspectables)
def includeme(config): """Include persona settings into a pyramid config. This function does the following: * Setup default authentication and authorization policies, and a default session factory. Keep in mind that the sessions are not encrypted, if you need to store secret information in it, please override the session factory. * Add two request attributes : * persona_js, the javascript code to inclue on a page to make persona work. * persona_button, the html for a default login/logout button. * Set login and logout views for use with persona. * Set a forbidden view with a loggin button """ settings = config.get_settings() if 'persona.audience' in settings: settings['persona.audiences'] = settings['persona.audience'] warnings.warn('persona.audience has been changed to persona.audiences, and may accept more than one value. ' 'Please update you config file accordingly.', stacklevel=3) if not 'persona.audiences' in settings: raise ConfigurationError('Missing persona.audience settings. This is needed for security reasons. ' 'See https://developer.mozilla.org/en-US/docs/Persona/Security_Considerations for details.') # Default authentication and authorization policies. Those are needed to remember the userid. authz_policy = ACLAuthorizationPolicy() config.set_authorization_policy(authz_policy) secret = settings.get('persona.secret', '') authn_policy = AuthTktAuthenticationPolicy(secret, hashalg='sha512') config.set_authentication_policy(authn_policy) # A default session factory, needed for the csrf check. session_factory = SignedCookieSessionFactory(secret) config.set_session_factory(session_factory) # Either a secret must be provided or the session factory must be overriden. def check(): if config.registry.queryUtility(ISessionFactory) == session_factory and not secret: raise ConfigurationError('If you do not override the session factory, you have to provide a persona.secret settings.') config.action(None, check, order=PHASE2_CONFIG) # Construct a browserid Verifier using the configured audience. # This will pre-compile some regexes to reduce per-request overhead. verifier_factory = config.maybe_dotted(settings.get('persona.verifier', 'browserid.RemoteVerifier')) audiences = aslist(settings['persona.audiences']) config.registry['persona.verifier'] = verifier_factory(audiences) # Parameters for the request API call request_params = {} for option in ('privacyPolicy', 'siteLogo', 'siteName', 'termsOfService', 'backgroundColor'): setting_name = 'persona.%s'%option if setting_name in settings: request_params[option] = settings[setting_name] config.registry['persona.request_params'] = json.dumps(request_params) # Login and logout views. login_route = settings.get('persona.login_route', 'login') config.registry['persona.login_route'] = login_route login_path = settings.get('persona.login_path', '/login') config.add_route(login_route, login_path) config.add_view(login, route_name=login_route, check_csrf=True, renderer='json', permission=NO_PERMISSION_REQUIRED) logout_route = settings.get('persona.logout_route', 'logout') config.registry['persona.logout_route'] = logout_route logout_path = settings.get('persona.logout_path', '/logout') config.add_route(logout_route, logout_path) config.add_view(logout, route_name=logout_route, check_csrf=True, renderer='json', permission=NO_PERMISSION_REQUIRED) # A simple 403 view, with a login button. config.add_forbidden_view(forbidden) # A quick access to the login button config.add_request_method(button, 'persona_button', reify=True) # The javascript needed by persona config.add_request_method(js, 'persona_js', reify=True) config.registry['persona.redirect_url_parameter'] = settings.get('persona.redirect_url_parameter', 'came_from')
def check(): if config.registry.queryUtility(ISessionFactory) == session_factory and not secret: raise ConfigurationError('If you do not override the session factory, you have to provide a persona.secret settings.')
def _create_theme_tables(configuration_yaml_path, theme, section='pyramid_oereb', tables_only=False): """ Create all tables defined in the specified module. Args: configuration_yaml_path (str): Path to the configuration file. theme (str): Code of the theme to create the tables for. section (str): Section within the specified configuration file used for pyramid_oereb. Default is 'pyramid_oereb'. tables_only (bool): True to skip creation of schema. Default is False. """ # Parse themes from configuration config = parse(configuration_yaml_path, section) themes = config.get('plrs') if not isinstance(themes, list): raise ConfigurationError('No list of themes found.') # Find the specified theme found = False for t in themes: if t.get('code') == theme: # Check required configuration parameters params = t.get('source').get('params') if not isinstance(params, dict): raise ConfigurationError( 'Missing params property in source definition.') if not ('db_connection' in params and 'models' in params): raise ConfigurationError( 'Params has to contain "db_connection" and "models" properties.' ) # Create sqlalchemy engine for configured connection and load module containing models engine = create_engine(params.get('db_connection'), echo=True) models = DottedNameResolver().resolve(params.get('models')) if not tables_only: # Iterate over contained classes to collect needed schemas classes = inspect.getmembers(models, inspect.isclass) schemas = [] create_schema_sql = 'CREATE SCHEMA IF NOT EXISTS {schema};' for c in classes: class_ = c[1] if hasattr(class_, '__table__' ) and class_.__table__.schema not in schemas: schemas.append(class_.__table__.schema) # Try to create missing schemas connection = engine.connect() try: for schema in schemas: connection.execute( create_schema_sql.format(schema=schema)) finally: connection.close() # Create tables models.Base.metadata.create_all(engine) found = True break if not found: raise ValueError( 'Specified theme "{theme}" not found in configuration.'.format( theme=theme))
def get_bbox(geometry): """ Return a bbox adapted for the map size specified in the print configuration and based on the geometry and a buffer (margin to add between the geometry and the border of the map). Args: geometry (list): The geometry (bbox) of the feature to center the map on. Returns: list: The bbox (meters) for the print. """ print_conf = Config.get_object_path( 'print', required=['basic_map_size', 'buffer']) print_buffer = print_conf['buffer'] map_size = print_conf['basic_map_size'] map_width = float(map_size[0]) map_height = float(map_size[1]) if print_buffer * 2 >= min(map_width, map_height): error_msg_txt = 'Your print buffer ({}px)'.format(print_buffer) error_msg_txt += ' applied on each side of the feature exceed the smaller' error_msg_txt += ' side of your map {}px.'.format( min(map_width, map_height)) raise ConfigurationError(error_msg_txt) geom_bounds = geometry.bounds geom_width = float(geom_bounds[2] - geom_bounds[0]) geom_height = float(geom_bounds[3] - geom_bounds[1]) geom_ration = geom_width / geom_height map_ration = map_width / map_height # If the format of the map is naturally adapted to the format of the geometry is_format_adapted = geom_ration > map_ration if is_format_adapted: # Part (percent) of the margin compared to the map width. margin_in_percent = 2 * print_buffer / map_width # Size of the margin in geom units. geom_margin = geom_width * margin_in_percent # Geom width with the margins (right and left). adapted_geom_width = geom_width + (2 * geom_margin) # Adapted geom height to the map height adapted_geom_height = (adapted_geom_width / map_width) * map_height else: # Part (percent) of the margin compared to the map height. margin_in_percent = 2 * print_buffer / map_height # Size of the margin in geom units. geom_margin = geom_height * margin_in_percent # Geom height with the buffer (top and bottom). adapted_geom_height = geom_height + (2 * geom_margin) # Adapted geom width to the map width adapted_geom_width = (adapted_geom_height / map_height) * map_width height_to_add = (adapted_geom_height - geom_height) / 2 width_to_add = (adapted_geom_width - geom_width) / 2 return [ geom_bounds[0] - width_to_add, geom_bounds[1] - height_to_add, geom_bounds[2] + width_to_add, geom_bounds[3] + height_to_add, ]
def add_layout(config, layout=None, template=None, name='', context=None, containment=None): """ Add a layout configuration to the current configuration state. Arguments layout A layout class or dotted Python name which refers to a layout class. This argument is not required. If the layout argument is not provided, a default layout class is used which merely has ``context`` and ``request`` as instance attributes. template A string implying a path or an asset specification for a template file. The file referred to by this argument must have a suffix that maps to a known renderer. This template will be available to other templates as the renderer global ``main_template``. This argument is required. name The layout name. context An object or a dotted Python name referring to an interface or class object that the context must be an instance of, *or* the interface that the context must provide in order for this layout to be found and used. This predicate is true when the context is an instance of the represented class or if the context provides the represented interface; it is otherwise false. containment This value should be a Python class or interface (or a dotted Python name) that an object in the lineage of the context must provide in order for this view to be found and called. The nodes in your object graph must be "location-aware" to use this feature. """ layout = config.maybe_dotted(layout) context = config.maybe_dotted(context) containment = config.maybe_dotted(containment) if layout is None: class layout(object): def __init__(self, context, request): self.context = context self.request = request if template is None: raise ConfigurationError('"template" is required') introspectables = [] discriminator = ['layout', context, name, ILayout] discriminator = tuple(discriminator) layout_desc = 'Layout %s' % (config.object_description(layout)) layout_intr = config.introspectable('layouts', discriminator, layout_desc, 'layout') def register(template=template): if isinstance(template, basestring): template = renderers.RendererHelper(name=template, package=config.package, registry=config.registry) layout_intr.update( dict( name=name, filename=template.name, context=context, callable=layout, )) introspectables.append(layout_intr) def derived_layout(context, request): wrapped = layout(context, request) wrapped.__layout__ = name wrapped.__template__ = template wrapped.__config_package__ = config.package return wrapped r_context = context if r_context is None: r_context = Interface if not IInterface.providedBy(r_context): r_context = implementedBy(r_context) reg_layout = config.registry.adapters.lookup((r_context, ), ILayout, name=name) if isinstance(reg_layout, _MultiLayout): reg_layout[containment] = derived_layout return elif containment: reg_layout = _MultiLayout(reg_layout) reg_layout[containment] = derived_layout else: reg_layout = derived_layout config.registry.registerAdapter(reg_layout, (context, ), ILayout, name=name) config.action(('layout', context, name, containment), register, introspectables=introspectables)
def add_resource(self, handler, member_name, collection_name, **kwargs): """ Add some RESTful routes for a resource handler. This function should never be called directly; instead the ``pyramid_routehelper.includeme`` function should be used to include this function into an application; the function will thereafter be available as a method of the resulting configurator. The concept of a web resource maps somewhat directly to 'CRUD' operations. The overlying things to keep in mind is that adding a resource handler is about handling creating, viewing, and editing that resource. ``handler`` is a dotted name of (or direct reference to) a Python handler class, e.g. ``'my.package.handlers.MyHandler'``. ``member_name`` should be the appropriate singular version of the resource given your locale and used with members of the collection. ``collection_name`` will be used to refer to the resource collection methods and should be a plural version of the member_name argument. All keyword arguments are optional. ``collection`` Additional action mappings used to manipulate/view the entire set of resources provided by the handler. Example:: config.add_resource('myproject.handlers:MessageHandler', 'message', 'messages', collection={'rss':'GET'}) # GET /messages/rss (maps to the rss action) # also adds named route "rss_message" ``member`` Additional action mappings used to access an individual 'member' of this handler's resources. Example:: config.add_resource('myproject.handlers:MessageHandler', 'message', 'messages', member={'mark':'POST'}) # POST /messages/1/mark (maps to the mark action) # also adds named route "mark_message" ``new`` Action mappings that involve dealing with a new member in the controller resources. Example:: config.add_resource('myproject.handlers:MessageHandler', 'message', 'messages', new={'preview':'POST'}) # POST /messages/new/preview (maps to the preview action) # also adds a url named "preview_new_message" ``path_prefix`` Prepends the URL path for the Route with the path_prefix given. This is most useful for cases where you want to mix resources or relations between resources. ``name_prefix`` Perpends the route names that are generated with the name_prefix given. Combined with the path_prefix option, it's easy to generate route names and paths that represent resources that are in relations. Example:: config.add_resource('myproject.handlers:CategoryHandler', 'message', 'messages', path_prefix='/category/:category_id', name_prefix="category_") # GET /category/7/messages/1 # has named route "category_message" ``parent_resource`` A ``dict`` containing information about the parent resource, for creating a nested resource. It should contain the ``member_name`` and ``collection_name`` of the parent resource. If ``parent_resource`` is supplied and ``path_prefix`` isn't, ``path_prefix`` will be generated from ``parent_resource`` as "<parent collection name>/:<parent member name>_id". If ``parent_resource`` is supplied and ``name_prefix`` isn't, ``name_prefix`` will be generated from ``parent_resource`` as "<parent member name>_". Example:: >>> from pyramid.url import route_path >>> config.add_resource('myproject.handlers:LocationHandler', 'location', 'locations', ... parent_resource=dict(member_name='region', ... collection_name='regions')) >>> # path_prefix is "regions/:region_id" >>> # name prefix is "region_" >>> route_path('region_locations', region_id=13) '/regions/13/locations' >>> route_path('region_new_location', region_id=13) '/regions/13/locations/new' >>> route_path('region_location', region_id=13, id=60) '/regions/13/locations/60' >>> route_path('region_edit_location', region_id=13, id=60) '/regions/13/locations/60/edit' Overriding generated ``path_prefix``:: >>> config.add_resource('myproject.handlers:LocationHandler', 'location', 'locations', ... parent_resource=dict(member_name='region', ... collection_name='regions'), ... path_prefix='areas/:area_id') >>> # name prefix is "region_" >>> route_path('region_locations', area_id=51) '/areas/51/locations' Overriding generated ``name_prefix``:: >>> config.add_resource('myproject.handlers:LocationHandler', 'location', 'locations', ... parent_resource=dict(member_name='region', ... collection_name='regions'), ... name_prefix='') >>> # path_prefix is "regions/:region_id" >>> route_path('locations', region_id=51) '/regions/51/locations' """ handler = self.maybe_dotted(handler) action_kwargs = {} for name,meth in inspect.getmembers(handler, inspect.ismethod): if hasattr(meth, '__exposed__'): for settings in meth.__exposed__: config_settings = settings.copy() action_name = config_settings.pop('alt_for', name) # If format is not set, use the route that doesn't specify a format if 'format' not in config_settings: if 'default' in action_kwargs.get(action_name,{}): raise ConfigurationError("Two methods have been decorated without specifying a format.") else: action_kwargs.setdefault(action_name, {})['default'] = config_settings # Otherwise, append to the list of view config settings for formatted views else: config_settings['attr'] = name action_kwargs.setdefault(action_name, {}).setdefault('formatted',[]).append(config_settings) collection = kwargs.pop('collection', {}) member = kwargs.pop('member', {}) new = kwargs.pop('new', {}) path_prefix = kwargs.pop('path_prefix', None) name_prefix = kwargs.pop('name_prefix', None) parent_resource = kwargs.pop('parent_resource', None) if parent_resource is not None: if path_prefix is None: path_prefix = '%s/:%s_id' % (parent_resource['collection_name'], parent_resource['member_name']) if name_prefix is None: name_prefix = '%s_' % parent_resource['member_name'] else: if path_prefix is None: path_prefix = '' if name_prefix is None: name_prefix = '' member['edit'] = 'GET' new['new'] = 'GET' def swap(dct, newdct): map(lambda (key,value): newdct.setdefault(value.upper(), []).append(key), dct.items()) return newdct collection_methods = swap(collection, {}) member_methods = swap(member, {}) new_methods = swap(new, {}) collection_methods.setdefault('POST', []).insert(0, 'create') member_methods.setdefault('PUT', []).insert(0, 'update') member_methods.setdefault('DELETE', []).insert(0, 'delete') # Continue porting code controller = strip_slashes(collection_name) path_prefix = strip_slashes(path_prefix) path_prefix = '/' + path_prefix if path_prefix and path_prefix != '/': path = path_prefix + '/' + controller else: path = '/' + controller collection_path = path new_path = path + '/new' member_path = path + '/:id' added_route_names = {} def add_route_if_new(self, route_name, path, **kwargs): if route_name not in added_route_names: self.add_route(route_name, path, **kwargs) added_route_names[route_name] = path def add_route_and_view(self, action, route_name, path, request_method='any'): if request_method != 'any': request_method = request_method.upper() else: request_method = None add_route_if_new(self, route_name, path, **kwargs) self.add_view(view=handler, attr=action, route_name=route_name, request_method=request_method, **action_kwargs.get(action, {}).get('default', {})) for format_kwargs in action_kwargs.get(action, {}).get('formatted', []): format = format_kwargs.pop('format') formatted_route_name = "%s_formatted_%s" % (format, route_name) add_route_if_new(self, formatted_route_name, "%s.%s" % (path, format), **kwargs) self.add_view(view=handler, attr=format_kwargs.pop('attr'), request_method=request_method, route_name = "%s_formatted_%s" % (format, route_name), **format_kwargs) for method, lst in collection_methods.iteritems(): primary = (method != 'GET' and lst.pop(0)) or None for action in lst: add_route_and_view(self, action, "%s%s_%s" % (name_prefix, action, collection_name), "%s/%s" % (collection_path,action)) if primary: add_route_and_view(self, primary, name_prefix + collection_name, collection_path, method) # Add route and view for collection add_route_and_view(self, 'index', name_prefix + collection_name, collection_path, 'GET') for method, lst in new_methods.iteritems(): for action in lst: path = (action == 'new' and new_path) or "%s/%s" % (new_path, action) name = "new_" + member_name if action != 'new': name = action + "_" + name formatted_path = (action == 'new' and new_path + '.:format') or "%s/%s.:format" % (new_path, action) add_route_and_view(self, action, name_prefix + name, path, method) for method, lst in member_methods.iteritems(): if method not in ['POST', 'GET', 'any']: primary = lst.pop(0) else: primary = None for action in lst: add_route_and_view(self, action, '%s%s_%s' % (name_prefix, action, member_name), '%s/%s' % (member_path, action)) if primary: add_route_and_view(self, primary, name_prefix + member_name, member_path, method) add_route_and_view(self, 'show', name_prefix + member_name, member_path, method) # Submapper support # Sub_domain option # Converters??