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)
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)
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)
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)
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)
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 )
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)
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)
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))
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))
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()
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, ))
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)
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)
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)
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
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
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)
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)
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)
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()
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
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)
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)
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()
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
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()