Example #1
0
def includeme(config: Configurator) -> None:
    """Configure Jinja2 template renderer."""
    settings = config.get_settings()

    settings['jinja2.lstrip_blocks'] = True
    settings['jinja2.trim_blocks'] = True
    settings['jinja2.undefined'] = 'strict'

    # add custom jinja filters
    settings['jinja2.filters'] = {
        'ago': descriptive_timedelta,
    }

    # add custom jinja tests
    settings['jinja2.tests'] = {
        'comment': is_comment,
        'group': is_group,
        'topic': is_topic,
    }

    config.include('pyramid_jinja2')

    config.add_jinja2_search_path('tildes:templates/')

    config.add_jinja2_extension('jinja2.ext.do')
    config.add_jinja2_extension('webassets.ext.jinja2.AssetsExtension')

    # attach webassets to jinja2 environment (via scheduled action)
    def attach_webassets_to_jinja2() -> None:
        jinja2_env = config.get_jinja2_environment()
        jinja2_env.assets_environment = config.get_webassets_env()

    config.action(None, attach_webassets_to_jinja2, order=999)
Example #2
0
def includeme(config: Configurator) -> None:
    """Configure Jinja2 template renderer."""
    settings = config.get_settings()

    settings["jinja2.lstrip_blocks"] = True
    settings["jinja2.trim_blocks"] = True

    # add custom jinja filters
    settings["jinja2.filters"] = {
        "adaptive_date": adaptive_date,
        "ago": descriptive_timedelta,
        "quote_plus": do_quote_plus,
    }

    # add custom jinja tests
    settings["jinja2.tests"] = {
        "comment": is_comment,
        "group": is_group,
        "topic": is_topic,
    }

    config.include("pyramid_jinja2")

    config.add_jinja2_search_path("tildes:templates/")

    config.add_jinja2_extension("jinja2.ext.do")
    config.add_jinja2_extension("webassets.ext.jinja2.AssetsExtension")

    # attach webassets to jinja2 environment (via scheduled action)
    def attach_webassets_to_jinja2() -> None:
        jinja2_env = config.get_jinja2_environment()
        jinja2_env.assets_environment = config.get_webassets_env()

    config.action(None, attach_webassets_to_jinja2, order=999)
Example #3
0
def config_process_struct(config: Configurator, process):
    for mapper in process.mappers:
        # code smell, EP-19
        wrapper = MapperWrapper(mapper)
        logger.debug("Registering mapper_wrapper %s", mapper)
        # code smell - registry use. EP-20.
        config.registry.registerUtility(wrapper, IMapperInfo, wrapper.key)
        node_name = mapper.local_table.key
        # EP-19
        manager = ResourceManager(mapper_key=wrapper.key,
                                  node_name=node_name,
                                  mapper_wrapper=wrapper)
        # fixme code smell
        # EP-19
        entry_point = EntryPoint(wrapper.key, manager)

        # more code smell
        # ??
        manager.operation(name='form',
                          view=EntityFormView,
                          args=[
                              OperationArgument.SubpathArgument(
                                  'action', String, default='create')
                          ])

        intr = config.introspectable(
            'resource manager', manager.mapper_key,
            'resource manager %s' % manager.mapper_key, 'resource manager')
        config.action(('resource manager', manager.mapper_key),
                      _add_resmgr_action,
                      introspectables=(intr, ),
                      args=(config, manager),
                      order=PHASE3_CONFIG)
Example #4
0
def register_routes(
    config: Configurator,
    route_name_ext: str = "x-pyramid-route-name",
    root_factory_ext: str = "x-pyramid-root-factory",
    apiname: str = "pyramid_openapi3",
) -> None:
    """Register routes to app from OpenApi 3.0 specification.

    :param route_name_ext: Extension's key for using a ``route_name`` argument
    :param root_factory_ext: Extension's key for using a ``factory`` argument
    """

    def action() -> None:
        spec = config.registry.settings[apiname]["spec"]
        for pattern, path_item in spec.paths.items():
            route_name = path_item.extensions.get(route_name_ext)
            if route_name:
                root_factory = path_item.extensions.get(root_factory_ext)
                config.add_route(
                    route_name.value,
                    pattern=pattern,
                    factory=root_factory.value if root_factory else None,
                )

    config.action(("pyramid_openapi3_register_routes",), action, order=PHASE1_CONFIG)
Example #5
0
def add_resource_admin(config: Configurator, fabric: Union[Type[ResourceAdmin],
                                                           str], name: str):
    dotted = config.maybe_dotted
    fabric = dotted(fabric)
    #verifyObject(interfaces.IExternalLinkFabric, fabric, tentative=True)

    # if not isinstance(resource_type, (tuple, list)):
    #     resource_type = (resource_type,)

    intr = config.introspectable(
        category_name='restfw_resource_admin',
        discriminator=id(fabric),
        title=config.object_description(fabric),
        type_name='restfw_resource_admin',
    )
    intr['fabric'] = fabric

    def register():
        config.registry.registerUtility(
            fabric,
            provided=interfaces.IResourceAdminFabric,
            name=name,
        )

    config.action(None, register, introspectables=(intr, ))
    return fabric
def add_spec_view(
    config: Configurator,
    filepath: str,
    route: str = "/openapi.yaml",
    route_name: str = "pyramid_openapi3.spec",
    permission: str = NO_PERMISSION_REQUIRED,
    apiname: str = "pyramid_openapi3",
) -> None:
    """Serve and register OpenApi 3.0 specification file.

    :param filepath: absolute/relative path to the specification file
    :param route: URL path where to serve specification file
    :param route_name: Route name under which specification file will be served
    :param permission: Permission for the spec view
    """
    def register() -> None:
        settings = config.registry.settings.get(apiname)
        if settings and settings.get("spec") is not None:
            raise ConfigurationError(
                "Spec has already been configured. You may only call "
                "pyramid_openapi3_spec or pyramid_openapi3_spec_directory once"
            )

        if hupper.is_active():  # pragma: no cover
            hupper.get_reloader().watch_files([filepath])
        spec_dict = read_yaml_file(filepath)

        validate_spec(spec_dict)
        spec = create_spec(spec_dict)

        def spec_view(request: Request) -> FileResponse:
            return FileResponse(filepath,
                                request=request,
                                content_type="text/yaml")

        config.add_route(route_name, route)
        config.add_view(route_name=route_name,
                        permission=permission,
                        view=spec_view)

        custom_formatters = config.registry.settings.get(
            "pyramid_openapi3_formatters")

        config.registry.settings[apiname] = {
            "filepath":
            filepath,
            "spec_route_name":
            route_name,
            "spec":
            spec,
            "request_validator":
            RequestValidator(spec, custom_formatters=custom_formatters),
            "response_validator":
            ResponseValidator(spec, custom_formatters=custom_formatters),
        }
        APIS.append(apiname)

    config.action((f"{apiname}_spec", ), register, order=PHASE0_CONFIG)
Example #7
0
def add_validation_error_view(config: Configurator, view_name: str) -> None:
    """Use this to register a view for rendering validation errors."""

    def register() -> None:
        config.registry._pyramid_openapi3_validation_view_name = view_name  # noqa: SF01

    config.action(
        ("pyramid_openapi3_validation_error_view",), register, order=PHASE0_CONFIG
    )
Example #8
0
def add_spec_view_directory(
    config: Configurator,
    filepath: str,
    route: str = "/spec",
    route_name: str = "pyramid_openapi3.spec",
) -> None:
    """Serve and register OpenApi 3.0 specification directory.

    :param filepath: absolute/relative path to the root specification file
    :param route: URL path where to serve specification file
    :param route_name: Route name under which specification file will be served
    """
    def register() -> None:
        settings = config.registry.settings.get("pyramid_openapi3")
        if settings and settings.get("spec") is not None:
            raise ConfigurationError(
                "Spec has already been configured. You may only call "
                "pyramid_openapi3_spec or pyramid_openapi3_spec_directory once"
            )
        if route.endswith((".yaml", ".yml", ".json")):
            raise ConfigurationError(
                "Having route be a filename is not allowed when using a spec directory"
            )

        path = Path(filepath).resolve()
        if hupper.is_active():  # pragma: no cover
            hupper.get_reloader().watch_files(list(path.parent.iterdir()))

        spec_dict = read_yaml_file(path)
        spec_url = path.as_uri()
        validate_spec(spec_dict, spec_url=spec_url)
        spec = create_spec(spec_dict, spec_url=spec_url)

        config.add_static_view(route, str(path.parent))
        config.add_route(route_name, f"{route}/{path.name}")

        custom_formatters = config.registry.settings.get(
            "pyramid_openapi3_formatters")

        config.registry.settings["pyramid_openapi3"] = {
            "filepath":
            filepath,
            "spec_route_name":
            route_name,
            "spec":
            spec,
            "request_validator":
            RequestValidator(spec, custom_formatters=custom_formatters),
            "response_validator":
            ResponseValidator(spec, custom_formatters=custom_formatters),
        }

    config.action(("pyramid_openapi3_spec", ), register, order=PHASE0_CONFIG)
Example #9
0
def setup_sqlalchemy(config: Configurator,
                     *,
                     settings: Optional[dict] =_NOT_SET,
                     prefix: str ='sqlalchemy.',
                     engine: Optional['sqlalchemy.Engine'] =_NOT_SET,
                     name: str='') -> None:

    """
    Sets up SQLAlchemy, creating a request scoped service for the ORM session.
    Include all models before calling this configurator.

    :param config: the configurator
    :param base: The declarative base class. Required
    :param settings: Optional settings dictionary for the engine creation
    :param prefix: Optional settings prefix for the engine settings
    :param engine: The engine to use - if specified, settings must not be
                given, or vice versa
    :param name: the alternate name for which to bind the session service
    """

    from sqlalchemy import engine_from_config
    from sqlalchemy.orm import sessionmaker, Session, configure_mappers, scoped_session

    if settings is not _NOT_SET:
        if engine is not _NOT_SET:
            raise ValueError('Only one of settings, '
                             'engine may be specified')
    else:
        settings = config.registry.settings

    if engine is _NOT_SET:
        engine = engine_from_config(settings, prefix)

    session_factory = sessionmaker()
    session_factory.configure(bind=engine)

    if 'tet.sqlalchemy.simple.factories' not in config.registry:
        config.registry['tet.sqlalchemy.simple.factories' ] = {}

    config.registry['tet.sqlalchemy.simple.factories'][name] = session_factory

    def _session_service(context: Any, request: Request):
        return get_tm_session(session_factory, request.tm)

    config.register_service_factory(
        _session_service, Session, Interface, name=name)

    config.register_service(
        scoped_session(session_factory),
        name='scoped_session' + (':' + name if name else '')
    )

    config.action('tet.sqlalchemy.simple.configure_mappers', configure_mappers)
Example #10
0
def add_sdi_add_view_directive(config: Configurator,
                               iresource: IInterface,
                               view_name: str,
                               ):
    """Create `add_sdi_add_view` pyramid config directive.

    Example usage::

        config.add_sdi_add_view(IResource, 'add_iresource')
    """
    config.action(('add_sdi_add_view', iresource, view_name),
                  add_sdi_add_view,
                  args=(config, iresource, view_name))
Example #11
0
def add_sdi_add_view_directive(
    config: Configurator,
    iresource: IInterface,
    view_name: str,
):
    """Create `add_sdi_add_view` pyramid config directive.

    Example usage::

        config.add_sdi_add_view(IResource, 'add_iresource')
    """
    config.action(('add_sdi_add_view', iresource, view_name),
                  add_sdi_add_view,
                  args=(config, iresource, view_name))
Example #12
0
    def test_multiple(self):
        from pyramid_services_sqlalchemy import (
            IDBSessionCreated,
            create_unmanaged_session,
            get_engine,
            get_tm_session,
        )

        config = Configurator(
            settings={
                'sqlalchemy.names': 'a b',
                'sqlalchemy.a.url': 'sqlite://',
                'sqlalchemy.b.url': 'sqlite://',
            })
        config.include('pyramid_services_sqlalchemy')

        def aview(request):
            db_a = get_tm_session(request, name='a')
            db_b = get_tm_session(request, name='b')
            self.assertIsInstance(db_a, Session)
            self.assertIsInstance(db_b, Session)
            self.assertIsNot(db_a, db_b)
            return 'OK'

        def handle_db_session_created(event):
            verifyObject(IDBSessionCreated, event)
            self.assertIsInstance(event.session, Session)
            self.assertIn(event.name, {'a', 'b'})

        def touch_engine():
            engine_a = get_engine(config, 'a')
            engine_b = get_engine(config, 'b')
            self.assertIsInstance(engine_a, Engine)
            self.assertIsInstance(engine_b, Engine)
            self.assertIsNot(engine_a, engine_b)

        config.add_route('root', pattern='/')
        config.add_view(aview, route_name='root', renderer='json')
        config.add_subscriber(handle_db_session_created, IDBSessionCreated)
        config.action(None, touch_engine)
        app = config.make_wsgi_app()

        c_db_a = create_unmanaged_session(config, name='a')
        c_db_b = create_unmanaged_session(config, name='b')
        self.assertIsInstance(c_db_a, Session)
        self.assertIsInstance(c_db_b, Session)

        resp = Request.blank('/').get_response(app)
        self.assertEqual(resp.status_code, 200)
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    config = Configurator(settings=settings)
    config.include('pyramid_jinja2')

    def pre_commit():
        jinja_env = config.get_jinja2_environment()
        jinja_env.filters['markdown'] = md_factory()

    config.action(None, pre_commit, order=PHASE3_CONFIG + 999)

    config.include('.routes')
    config.scan()
    return config.make_wsgi_app()
Example #14
0
def includeme(config: Configurator):
    def action():
        logger.info("Executing config action [exception views].")
        config.app_exception_view(Exception, ExceptionView,
                                  "templates/exception/exception.jinja2")
        config.app_exception_view(OperationArgumentException,
                                  OperationArgumentExceptionView,
                                  "templates/exception/exception.jinja2")
        config.app_exception_view(HTTPNotFound, ExceptionView,
                                  "templates/exception/exception.jinja2")

    intr = config.introspectable('app modules', __name__,
                                 "App module %r" % __name__, 'app modules')
    config.add_directive("app_exception_view", app_exception_view)
    disc = ('exception views', )
    config.action(None, action, introspectables=(intr, ))
Example #15
0
    def test_declarative(self):
        import sqlalchemy as sa
        from pyramid_services_sqlalchemy import (
            base_factory,
            get_engine,
            get_tm_session,
        )
        Base = base_factory()

        def default_value(execution_context):
            return execution_context.engine.my_value

        class Some(Base):
            __tablename__ = 'some'
            id = sa.Column(sa.INTEGER, primary_key=True)
            s = sa.Column(sa.VARCHAR(255),
                          nullable=False,
                          default=default_value,
                          onupdate=default_value)

        config = Configurator(settings={
            'sqlalchemy.url': 'sqlite://',
        })
        config.include('pyramid_services_sqlalchemy')

        def aview(request):
            db = get_tm_session(request)
            db.add(Some())
            db.flush()
            v = db.query(Some).first()
            self.assertEqual(v.s, '__my_value__')
            return 'OK'

        def touch_engine():
            engine = get_engine(config)
            engine.my_value = '__my_value__'

        config.add_route('root', pattern='/')
        config.add_view(aview, route_name='root', renderer='json')
        config.action(None, touch_engine)
        app = config.make_wsgi_app()

        Base.metadata.create_all(bind=get_engine(config))

        resp = Request.blank('/').get_response(app)
        self.assertEqual(resp.status_code, 200)
Example #16
0
def add_spec_view(
    config: Configurator,
    filepath: str,
    route: str = "/openapi.yaml",
    route_name: str = "pyramid_openapi3.spec",
) -> None:
    """Serve and register OpenApi 3.0 specification file.

    :param filepath: absolute/relative path to the specification file
    :param route: URL path where to serve specification file
    :param route_name: Route name under which specification file will be served
    """
    def register() -> None:
        if hupper.is_active():  # pragma: no cover
            hupper.get_reloader().watch_files([filepath])
        spec_dict = read_yaml_file(filepath)

        validate_spec(spec_dict)
        spec = create_spec(spec_dict)

        def spec_view(request: Request) -> FileResponse:
            return FileResponse(filepath,
                                request=request,
                                content_type="text/yaml")

        config.add_route(route_name, route)
        config.add_view(route_name=route_name, view=spec_view)

        custom_formatters = config.registry.settings.get(
            "pyramid_openapi3_formatters")

        config.registry.settings["pyramid_openapi3"] = {
            "filepath":
            filepath,
            "spec_route_name":
            route_name,
            "spec":
            spec,
            "request_validator":
            RequestValidator(spec, custom_formatters=custom_formatters),
            "response_validator":
            ResponseValidator(spec, custom_formatters=custom_formatters),
        }

    config.action(("pyramid_openapi3_spec", ), register, order=PHASE0_CONFIG)
Example #17
0
def add_explorer_view(
    config: Configurator,
    route: str = "/docs/",
    route_name: str = "pyramid_openapi3.explorer",
    template: str = "static/index.html",
    ui_version: str = "3.17.1",
    permission: str = NO_PERMISSION_REQUIRED,
    apiname: str = "pyramid_openapi3",
) -> None:
    """Serve Swagger UI at `route` url path.

    :param route: URL path where to serve
    :param route_name: Route name that's being added
    :param template: Dotted path to the html template that renders Swagger UI response
    :param ui_version: Swagger UI version string
    :param permission: Permission for the explorer view
    """

    def register() -> None:
        resolved_template = AssetResolver().resolve(template)

        def explorer_view(request: Request) -> Response:
            settings = config.registry.settings
            if settings.get(apiname) is None:
                raise ConfigurationError(
                    "You need to call config.pyramid_openapi3_spec for the 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[apiname]["spec_route_name"]),
                )
            return Response(html)

        config.add_route(route_name, route)
        config.add_view(
            route_name=route_name, permission=permission, view=explorer_view
        )

    config.action((f"{apiname}_add_explorer",), register, order=PHASE0_CONFIG)
Example #18
0
def add_validator_converter(
        config: Configurator,
        validator_type: Type[ColanderValidator],
        converter: ValidatorConverter,
):
    dotted = config.maybe_dotted
    validator_type = dotted(validator_type)
    converter = dotted(converter)

    if isfunction(validator_type):
        adapter_name = f'{validator_type.__module__}.{validator_type.__qualname__}'
        required = [interfaces.IColanderValidator]
    else:
        adapter_name = ''
        required = [validator_type]

    discriminator = f'restfw_admin_validator:{id(validator_type)}'
    intr = config.introspectable(
        category_name='restfw_admin_validator_converter',
        discriminator=discriminator,
        title=config.object_description(converter),
        type_name='restfw_admin_validator_converter',
    )
    intr['validator_type'] = validator_type
    intr['converter'] = converter

    def register():
        def adapter(_):
            return converter

        config.registry.registerAdapter(
            adapter,
            required,
            provided=interfaces.IValidatorConverter,
            name=adapter_name,
        )

    config.action(discriminator, register, introspectables=(intr,))
    return converter
Example #19
0
def add_field_converter(
    config: Configurator,
    node_type: Type[colander.SchemaType],
    converter: FieldConverter,
    is_input=False,
):
    dotted = config.maybe_dotted
    node_type = dotted(node_type)
    converter = dotted(converter)

    if is_input:
        field_type = 'input'
        provided = interfaces.ISchemaNodeToInputWidget
    else:
        field_type = 'view'
        provided = interfaces.ISchemaNodeToFieldWidget

    discriminator = f'restfw_{field_type}_field:{id(node_type)}'
    intr = config.introspectable(
        category_name='restfw_admin_field_converter',
        discriminator=discriminator,
        title=config.object_description(converter),
        type_name=f'restfw_admin_{field_type}_field_converter',
    )
    intr['node_type'] = node_type
    intr['converter'] = converter

    def register():
        def adapter(_):
            return converter

        config.registry.registerAdapter(
            adapter,
            [node_type],
            provided=provided,
        )

    config.action(discriminator, register, introspectables=(intr, ))
    return converter
Example #20
0
def add_explorer_view(
    config: Configurator,
    route: str = "/docs/",
    route_name: str = "pyramid_openapi3.explorer",
    template: str = "static/index.html",
    ui_version: str = "3.17.1",
) -> None:
    """Serve Swagger UI at `route` url path.

    :param route: URL path where to serve
    :param route_name: Route name that's being added
    :param template: Dotted path to the html template that renders Swagger UI response
    :param ui_version: Swagger UI version string
    """

    def register():
        resolved_template = AssetResolver().resolve(template)

        def explorer_view(request):
            settings = config.registry.settings
            if settings.get("pyramid_openapi3") is None:
                raise 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)

        config.add_route(route_name, route)
        config.add_view(route_name=route_name, view=explorer_view)

    config.action(("pyramid_openapi3_add_explorer",), register, order=PHASE0_CONFIG)
Example #21
0
def includeme(config: Configurator) -> None:
    """Configure Jinja2 template renderer."""
    settings = config.get_settings()

    settings["jinja2.lstrip_blocks"] = True
    settings["jinja2.trim_blocks"] = True

    # add custom jinja filters
    settings["jinja2.filters"] = {
        "adaptive_date": adaptive_date,
        "ago": descriptive_timedelta,
        "quote_plus": quote_plus,
        "vague_timedelta_description": vague_timedelta_description,
    }

    # add custom jinja tests
    settings["jinja2.tests"] = {
        "comment": lambda obj: isinstance(obj, Comment),
        "group": lambda obj: isinstance(obj, Group),
        "topic": lambda obj: isinstance(obj, Topic),
    }

    config.include("pyramid_jinja2")

    config.add_jinja2_search_path("tildes:templates/")

    config.add_jinja2_extension("jinja2.ext.do")
    config.add_jinja2_extension("webassets.ext.jinja2.AssetsExtension")

    # attach webassets to jinja2 and set SITE_NAME global (via scheduled action)
    def setup_jinja_env() -> None:
        jinja2_env = config.get_jinja2_environment()
        jinja2_env.assets_environment = config.get_webassets_env()
        jinja2_env.globals["SITE_NAME"] = settings["tildes.site_name"]

    config.action(None, setup_jinja_env, order=999)
Example #22
0
def add_spec_view(
    config: Configurator,
    filepath: str,
    route: str = "/openapi.yaml",
    route_name: str = "pyramid_openapi3.spec",
) -> None:
    """Serve and register OpenApi 3.0 specification file.

    :param filepath: absolute/relative path to the specification file
    :param route: URL path where to serve specification file
    :param route_name: Route name under which specification file will be served
    """

    def register() -> None:
        spec_dict = read_yaml_file(filepath)

        validate_spec(spec_dict)
        spec = create_spec(spec_dict)

        def spec_view(request: Request) -> FileResponse:
            return FileResponse(filepath, request=request, content_type="text/yaml")

        config.add_route(route_name, route)
        config.add_view(route_name=route_name, view=spec_view)

        custom_formatters = config.registry.settings.get("pyramid_openapi3_formatters")

        config.registry.settings["pyramid_openapi3"] = {
            "filepath": filepath,
            "spec_route_name": route_name,
            "spec": spec,
            "request_validator": RequestValidator(spec, custom_formatters),
            "response_validator": ResponseValidator(spec, custom_formatters),
        }

    config.action(("pyramid_openapi3_spec",), register, order=PHASE0_CONFIG)
Example #23
0
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """

    settings.setdefault('jinja2.i18n.domain', 'testscaffold')

    stacked_policy = AuthenticationStackPolicy()
    auth_tkt = AuthTktAuthenticationPolicy(settings['auth_tkt.seed'],
                                           callback=groupfinder)
    auth_token_policy = AuthTokenAuthenticationPolicy(callback=groupfinder)

    stacked_policy.add_policy('auth_tkt', auth_tkt)
    stacked_policy.add_policy('auth_token', auth_token_policy)
    authorization_policy = ACLAuthorizationPolicy()

    settings['jinja2.undefined'] = 'strict'
    config = Configurator(settings=settings,
                          authentication_policy=stacked_policy,
                          authorization_policy=authorization_policy,
                          root_factory='testscaffold.security.RootFactory',
                          default_permission='view')
    config.add_translation_dirs(
        'testscaffold:locale/',
        'wtforms:locale/',
    )

    # modify json renderer
    json_renderer = JSON(indent=4)

    def datetime_adapter(obj, request):
        return obj.isoformat()

    json_renderer.add_adapter(datetime.datetime, datetime_adapter)
    json_renderer.add_adapter(datetime.date, datetime_adapter)
    config.add_renderer('json', json_renderer)

    # set crypto key used to store sensitive data like auth tokens
    encryption.ENCRYPTION_SECRET = settings['encryption_secret']
    # CSRF is enabled by defualt
    # use X-XSRF-TOKEN for angular
    config.set_default_csrf_options(require_csrf=True, header='X-XSRF-TOKEN')
    config.add_view_deriver(
        'testscaffold.predicates.auth_token_aware_csrf_view', name='csrf_view')

    config.include('pyramid_mailer')
    config.include('pyramid_jinja2')
    config.include('pyramid_redis_sessions')
    config.include('ziggurat_foundations.ext.pyramid.sign_in')

    # make request.user available
    config.add_request_method('testscaffold.util.request:get_user',
                              'user',
                              reify=True)
    config.add_request_method('testscaffold.util.request:safe_json_body',
                              'safe_json_body',
                              reify=True)
    config.add_request_method('testscaffold.util.request:unsafe_json_body',
                              'unsafe_json_body',
                              reify=True)
    config.add_request_method('testscaffold.util.request:get_authomatic',
                              'authomatic',
                              reify=True)

    config.add_view_predicate('context_type_class',
                              'testscaffold.predicates.ContextTypeClass')

    config.scan('testscaffold.events')
    config.scan('testscaffold.subscribers')
    config.include('testscaffold.models')
    config.include('testscaffold.routes')
    config.include('testscaffold.views')

    # configure celery in later phase
    def wrap_config_celery():
        configure_celery(config.registry)

    config.action(None, wrap_config_celery, order=PHASE3_CONFIG + 999)

    # setup dogpile cache
    cache_regions.regions = cache_regions.CacheRegions(settings)
    config.registry.cache_regions = cache_regions.regions

    if not config.registry.settings.get('testscaffold.ignore_warnings', True):
        warnings.filterwarnings('default')

    return config.make_wsgi_app()
Example #24
0
def add_sub_resource_fabric(
    config: Configurator,
    fabric,
    name: str,
    parent=interfaces.IResource,
    add_link_into_embedded=False,
    **predicates,
):
    """A configurator command for register sub-resource fabric.
    :param fabric: Object that provides interfaces.ISubResourceFabric
    :param parent: type or zope.interface.Interface

    Using the default ``parent`` value, ``IResource`` will cause the sub resource
    fabric to be registered for all resource types.

    Any number of predicate keyword arguments may be passed in
    ``**predicates``.  Each predicate named will narrow the set of
    circumstances in which the sub resource fabric will be invoked. Each named
    predicate must have been registered via
    :meth:`restfw.config.add_sub_resource_fabric_predicate` before it
    can be used.
    """

    dotted = config.maybe_dotted
    fabric, parent = dotted(fabric), dotted(parent)
    verifyObject(interfaces.ISubResourceFabric, fabric, tentative=True)

    if not isinstance(parent, (tuple, list)):
        parent = (parent, )

    intr = config.introspectable(
        category_name='Sub-resource fabrics',
        discriminator=id(fabric),
        title=config.object_description(fabric),
        type_name='sub-resource fabric',
    )
    intr['fabric'] = fabric
    intr['parent'] = parent
    intr['add_link_into_embedded'] = add_link_into_embedded

    def register():
        pred_list = config.get_predlist('sub_resource_fabric')
        order, preds, phash = pred_list.make(config, **predicates)
        derived_fabric = derive_fabric(fabric, preds)

        intr.update({
            'phash': phash,
            'order': order,
            'predicates': preds,
            'derived_fabric': derived_fabric,
        })

        config.registry.registerAdapter(
            derived_fabric,
            required=parent,
            provided=interfaces.IResource,
            name=name,
        )
        if add_link_into_embedded:
            add_into_embedded_fabric = derive_fabric(_add_into_embedded_fabric,
                                                     preds)
            config.registry.registerAdapter(
                add_into_embedded_fabric,
                required=parent,
                provided=interfaces.IAddSubresourceLinkIntoEmbedded,
                name=name,
            )

    config.action(None, register, introspectables=(intr, ))
    return fabric
Example #25
0
def setup_sqlalchemy(
    config: Configurator,
    *,
    settings: Optional[dict] = _NOT_SET,
    prefix: str = 'sqlalchemy.',
    engine: Optional['sqlalchemy.Engine'] = _NOT_SET,
    name: str = '',
    post_init_session: Optional[Callable[['sqlalchemy.orm.Session', Request],
                                         None]] = None
) -> None:
    """
    Sets up SQLAlchemy, creating a request scoped service for the ORM session.
    Include all models before calling this configurator.

    :param config: the configurator
    :param base: The declarative base class. Required
    :param settings: Optional settings dictionary for the engine creation
    :param prefix: Optional settings prefix for the engine settings
    :param engine: The engine to use - if specified, settings must not be
                given, or vice versa
    :param name: the alternate name for which to bind the session service
    :param post_init_session: optional callback to run after an SQLAlchemy
                session is initialized
    """

    from sqlalchemy import engine_from_config
    from sqlalchemy.orm import sessionmaker, Session, configure_mappers, scoped_session

    if settings is not _NOT_SET:
        if engine is not _NOT_SET:
            raise ValueError('Only one of settings, '
                             'engine may be specified')
    else:
        settings = config.registry.settings

    if engine is _NOT_SET:
        engine = engine_from_config(settings, prefix)

    session_factory = sessionmaker()
    session_factory.configure(bind=engine)

    if 'tet.sqlalchemy.simple.factories' not in config.registry:
        config.registry['tet.sqlalchemy.simple.factories'] = {}

    config.registry['tet.sqlalchemy.simple.factories'][name] = session_factory

    def _session_service(context: Any, request: Request):
        session = get_tm_session(session_factory, request.tm)
        if post_init_session:
            post_init_session(session, request)
        return session

    config.register_service_factory(_session_service,
                                    Session,
                                    Interface,
                                    name=name)

    config.register_service(scoped_session(session_factory),
                            name='scoped_session' +
                            (':' + name if name else ''))

    config.action('tet.sqlalchemy.simple.configure_mappers', configure_mappers)
Example #26
0
def _register_resource_view(config: Configurator,
                            view_class: Type[IResourceView],
                            resource_class: Type[IResource],
                            request_type=None,
                            containment=None,
                            name='',
                            **view_options):
    view_class = config.maybe_dotted(view_class)
    resource_class = config.maybe_dotted(resource_class)
    containment = config.maybe_dotted(containment)

    if not view_class:
        raise ConfigurationError('"view_class" was not specified')

    if request_type is not None:
        request_type = config.maybe_dotted(request_type)
        if not IInterface.providedBy(request_type):
            raise ConfigurationError(
                'request_type must be an interface, not %s' % request_type)

    introspectables = []
    ovals = view_options.copy()
    ovals.update(dict(
        containment=containment,
        request_type=request_type,
    ))

    r_resource_class = resource_class
    if r_resource_class is None:
        r_resource_class = Interface
    if not IInterface.providedBy(r_resource_class):
        r_resource_class = implementedBy(r_resource_class)

    def discrim_func():
        # We need to defer the discriminator until we know what the phash
        # is. It can't be computed any sooner because third-party
        # predicates/view derivers may not yet exist when add_view is
        # called.
        predlist = config.get_predlist('view')
        valid_predicates = predlist.names()
        pvals = {}

        for (k, v) in ovals.items():
            if k in valid_predicates:
                pvals[k] = v

        order, preds, phash = predlist.make(config, **pvals)

        view_intr.update({'phash': phash, 'order': order, 'predicates': preds})
        return 'serializer', resource_class, phash

    discriminator = Deferred(discrim_func)

    view_intr = config.introspectable(
        category_name='Resource views',
        discriminator=discriminator,
        title=config.object_description(view_class),
        type_name='resource view',
    )
    view_intr.update(
        dict(
            name=name,
            context=resource_class,
            containment=containment,
            callable=view_class,
        ))
    view_intr.update(view_options)
    introspectables.append(view_intr)

    def register():
        # __discriminator__ is used by super-dynamic systems
        # that require it for introspection after manual view lookup;
        # see also MultiResourceView.__discriminator__
        view_class.__discriminator__ = lambda *arg: discriminator

        # A resource_views is a set of views which are registered for
        # exactly the same resource type/request type/name triad. Each
        # constituent view in a resource_views differs only by the
        # predicates which it possesses.

        # To find a previously registered view for a resource
        # type/request type/name triad, we need to use the
        # ``registered`` method of the adapter registry rather than
        # ``lookup``. ``registered`` ignores interface inheritance
        # for the required and provided arguments, returning only a
        # view registered previously with the *exact* triad we pass
        # in.

        request_iface = IRequest
        registered = config.registry.adapters.registered
        multi_resource_views = registered((request_iface, r_resource_class),
                                          IResourceView, name)

        if not multi_resource_views:
            multi_resource_views = MultiResourceView(name)
            config.registry.registerAdapter(
                multi_resource_views,
                (request_iface, resource_class),
                IResourceView,
                name,
            )

        multi_resource_views.add(
            view_class,
            view_intr['order'],
            view_intr['phash'],
            view_intr['predicates'],
        )

    config.action(discriminator, register, introspectables=introspectables)
Example #27
0
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """

    settings.setdefault("jinja2.i18n.domain", "testscaffold")

    auth_tkt = AuthTktAuthenticationPolicy(
        settings["auth_tkt.seed"], callback=groupfinder
    )
    auth_token_policy = AuthTokenAuthenticationPolicy(callback=groupfinder)

    authorization_policy = ACLAuthorizationPolicy()

    def policy_selector(request):
        # default policy
        policy = "auth_tkt"
        # return API token policy if header is present
        if request.headers.get("x-testscaffold-auth-token"):
            policy = "auth_token_policy"
        log.info("Policy used: {}".format(policy))
        return policy

    auth_policy = PyramidSelectorPolicy(
        policy_selector=policy_selector,
        policies={
            "auth_tkt": auth_tkt,
            "auth_token_policy": auth_token_policy
        }
    )

    settings["jinja2.undefined"] = "strict"
    config = Configurator(
        settings=settings,
        authentication_policy=auth_policy,
        authorization_policy=authorization_policy,
        root_factory="testscaffold.security.RootFactory",
    )
    config.include("pyramid_apispec.views")
    config.pyramid_apispec_add_explorer(
        spec_route_name="openapi_spec")
    config.add_translation_dirs("testscaffold:locale/", "wtforms:locale/")

    # modify json renderer
    json_renderer = JSON(indent=4)

    def datetime_adapter(obj, request):
        return obj.isoformat()

    json_renderer.add_adapter(datetime.datetime, datetime_adapter)
    json_renderer.add_adapter(datetime.date, datetime_adapter)
    config.add_renderer("json", json_renderer)

    # set crypto key used to store sensitive data like auth tokens
    encryption.ENCRYPTION_SECRET = settings["encryption_secret"]
    # CSRF is enabled by defualt
    # use X-XSRF-TOKEN for angular
    # config.set_default_csrf_options(require_csrf=True, header='X-XSRF-TOKEN')
    config.add_view_deriver(
        "testscaffold.predicates.auth_token_aware_csrf_view", name="csrf_view"
    )

    config.include("pyramid_mailer")
    config.include("pyramid_jinja2")
    config.include("pyramid_redis_sessions")
    config.include("ziggurat_foundations.ext.pyramid.sign_in")

    # make request.user available
    config.add_request_method("testscaffold.util.request:get_user", "user", reify=True)
    config.add_request_method(
        "testscaffold.util.request:safe_json_body", "safe_json_body", reify=True
    )
    config.add_request_method(
        "testscaffold.util.request:unsafe_json_body", "unsafe_json_body", reify=True
    )
    config.add_request_method(
        "testscaffold.util.request:get_authomatic", "authomatic", reify=True
    )

    config.add_view_predicate(
        "context_type_class", "testscaffold.predicates.ContextTypeClass"
    )

    config.scan("testscaffold.events")
    config.scan("testscaffold.subscribers")
    config.include("testscaffold.models")
    config.include("testscaffold.routes")
    config.include("testscaffold.views")

    # configure celery in later phase
    def wrap_config_celery():
        configure_celery(config.registry)

    config.action(None, wrap_config_celery, order=PHASE3_CONFIG + 999)

    # setup dogpile cache
    cache_regions.regions = cache_regions.CacheRegions(settings)
    config.registry.cache_regions = cache_regions.regions

    if not config.registry.settings.get("testscaffold.ignore_warnings", True):
        warnings.filterwarnings("default")

    return config.make_wsgi_app()
Example #28
0
def _add_resmgr_action(config: Configurator, manager: ResourceManager):
    """

    :type config: Configurator
    :type manager: ResourceManager
    :param manager: ResourceManager instance
    :param config: Configurator instance
    :return:
    """
    op: ResourceOperation

    # sanity checks
    # # MANAGER.MAPPER_KEY
    key = manager.mapper_key
    assert key, "No mapper key (%s)" % key

    reg_view = False
    # # MANAGER.NODE_NAME
    node_name = manager.node_name

    # alter interface to this?
    presource = config.get_resource_context()

    # assert root_resource is not None and isinstance(root_resource, RootResource), root_resource
    my_parent = presource
    assert my_parent is not None

    #
    # Populate the root resource dictionary with our
    # { node_name, ContainerResource } pair.
    #
    # ContainerResource is the result of the default factory method
    #
    # Our parent is the "heptet_app.resources" in our
    # app registry. That's the root resource!!

    # can we encapsulate this somehow?
    # MANAGER.MAPPER_WRAPPERS

    # code smell
    mapper_wrapper = manager.mapper_wrappers[key]
    assert mapper_wrapper, "no mapper wrapper %s in %s" % (
        key, manager.mapper_wrappers)

    # code smell
    container_entry_point = EntryPoint(key,
                                       manager,
                                       mapper=manager.mapper_wrapper)
    m = config.registry.getAdapter(container_entry_point,
                                   IEntryPointMapperAdapter)
    m.mapper = mapper_wrapper

    resource = presource.create_resource(node_name, container_entry_point,
                                         manager.title)

    # this makes a direct mapping between operations, entry points, and views.
    extra = {}

    # MANAGER.OPERATIONS
    for op in manager.operations:
        resource.add_name(op.name)

        d = extra.copy()
        d['operation'] = op
        if op.renderer is not None:
            d['renderer'] = op.renderer

        entry_point_key = '%s_%s' % (node_name, op.name)
        d['view'] = op.view
        entry_point = EntryPoint(entry_point_key,
                                 manager,
                                 mapper=mapper_wrapper)
        logger.debug("spawning sub resource for op %s, %s", op.name, node_name)
        op_resource = resource.sub_resource(op.name, entry_point)
        d['context'] = type(op_resource)

        config.register_entry_point(entry_point)

        d['entry_point'] = entry_point

        # d['decorator'] = view_decorator

        logger.debug("Adding view: %s", d)

        def _action():
            logger.info("adding view %r", d)
            config.add_view(**d)

        intr = config.introspectable('app view',
                                     '%s.%s' % (node_name, op.name),
                                     'app view %s.%s' % (node_name, op.name),
                                     'app view')
        config.action(None,
                      config.add_view,
                      args=(),
                      kw=d,
                      introspectables=(intr, ))

        reg_view = True

    if not reg_view:
        logger.warning("No view registered!")
    manager._resource = resource
Example #29
0
def main(global_config, test_settings=None, **settings):
	if test_settings is None:
		engine = engine_from_config(settings, 'sqlalchemy.')
		dbsession.configure(bind=engine)
		Base.metadata.bind = engine
		config = Configurator(settings=settings)
		session_factory = SignedCookieSessionFactory(
			secret=settings['session.secret'],
			domain=settings['hostname'],
			secure=True,
			httponly=True,
			samesite='strict',
			reissue_time=900,
			max_age=900,
			serializer=JSONSerializer()
		)
	else:
		engine = engine_from_config(test_settings, 'sqlalchemy.')
		dbsession.configure(bind=engine)
		Base.metadata.bind = engine
		config = Configurator(settings=test_settings)
		session_factory = SignedCookieSessionFactory(
			secret=test_settings['session.secret'],
			domain=test_settings['hostname'],
			secure=True,
			httponly=True,
			samesite='strict',
			reissue_time=900,
			max_age=900,
			serializer=JSONSerializer()
		)

	config.add_renderer('json', JSON(indent=4))

	config.set_session_factory(session_factory)
	config.add_forbidden_view(forbidden)
	config.include('pyramid_jinja2')

	def page_controller(page):
		if page == 'adminpage':
			return True
		if page == 'login':
			return False
		return False

	def check_sort(unsorted):
		return unsorted
	
	def img(imgtype):
		if imgtype == 'img':
			return True
		return False

	def pdf(imgtype):
		if imgtype == 'pdf':
			return True
		return False
	
	def setup_jinja2_env():
		jinja_environment = config.get_jinja2_environment()
		tests = {
			'page_controller': page_controller,
			'check_sort': check_sort,
			'img': img,
			'pdf': pdf
		}
		for key,val in tests.items():
			jinja_environment.tests[key] = val

	config.action(None, setup_jinja2_env, order=999)

	config.include('.models')
	config.include('.routes')
	config.include('.security')
	config.scan('bigwebsite')

	return config.make_wsgi_app()