magpie.app ========== .. py:module:: magpie.app .. autoapi-nested-parse:: Magpie is a service for AuthN and AuthZ based on Ziggurat-Foundations. Attributes ---------- .. autoapisummary:: magpie.app.LOGGER Classes ------- .. autoapisummary:: magpie.app.RemoveSlashNotFoundViewFactory Functions --------- .. autoapisummary:: magpie.app.apply_response_format_tween magpie.app.internal_server_error magpie.app.not_found_or_method_not_allowed magpie.app.unauthorized_or_forbidden magpie.app.validate_accept_header_tween magpie.app.setup_webhooks_config magpie.app.register_defaults magpie.app.get_constant magpie.app.get_db_session_from_config_ini magpie.app.run_database_migration_when_ready magpie.app.set_sqlalchemy_log_level magpie.app.magpie_register_permissions_from_config magpie.app.magpie_register_services_from_config magpie.app.get_auth_config magpie.app.fully_qualified_name magpie.app.get_logger magpie.app.log_exception_tween magpie.app.log_request magpie.app.patch_magpie_url magpie.app.print_log magpie.app.setup_cache_settings magpie.app.setup_pyramid_config magpie.app.setup_session_config magpie.app.setup_ziggurat_config magpie.app.setup_magpie_configs magpie.app.main Module Contents --------------- .. py:class:: RemoveSlashNotFoundViewFactory(notfound_view=None) Bases: :py:obj:`object` Utility that will try to resolve a path without appended slash if one was provided. .. py:method:: __call__(request) .. py:function:: apply_response_format_tween(handler: Callable[[pyramid.request.Request], pyramid.httpexceptions.HTTPException], registry: pyramid.registry.Registry) -> Callable[[pyramid.request.Request], pyramid.response.Response] Tween that applies the response ``Content-Type`` according to the requested ``Accept`` header or ``format`` query. The target ``Content-Type`` is expected to have been validated by :func:`validate_accept_header_tween` beforehand to handle not-acceptable errors. If an invalid format is detected at this stage, JSON is used by default. This can be the case for example for :func:`validate_accept_header_tween` itself that raises the error about the invalid ``Accept`` header or ``format`` query, but detects these inadequate parameters from incoming request. The tween also ensures that additional request metadata extracted from :func:`get_request_info` is applied to the response body if not already provided by a previous operation. .. py:function:: internal_server_error(request: pyramid.request.Request) -> pyramid.httpexceptions.HTTPException Overrides default HTTP. .. py:function:: not_found_or_method_not_allowed(request: pyramid.request.Request) -> pyramid.httpexceptions.HTTPException Overrides the default ``HTTPNotFound`` [404] by appropriate ``HTTPMethodNotAllowed`` [405] when applicable. Not found response can correspond to underlying process operation not finding a required item, or a completely unknown route (path did not match any existing API definition). Method not allowed is more specific to the case where the path matches an existing API route, but the specific request method (GET, POST, etc.) is not allowed on this path. Without this fix, both situations return [404] regardless. .. py:function:: unauthorized_or_forbidden(request: pyramid.request.Request) -> pyramid.httpexceptions.HTTPException Overrides the default HTTP ``Forbidden [403]`` by appropriate ``Unauthorized [401]`` when applicable. Unauthorized response is for restricted user access according to missing credentials and/or authorization headers. Forbidden response is for operation refused by the underlying process operations or due to insufficient permissions. Without this fix, both situations return ``Forbidden [403]`` regardless. .. seealso:: - http://www.restapitutorial.com/httpstatuscodes.html In case the request references to `Magpie UI` route, it is redirected to :meth:`magpie.ui.home.HomeViews.error_view` for it to handle and display the error accordingly. .. py:function:: validate_accept_header_tween(handler: Callable[[pyramid.request.Request], pyramid.response.Response], registry: pyramid.registry.Registry) -> Callable[[pyramid.request.Request], pyramid.response.Response] Tween that validates that the specified request ``Accept`` header or ``format`` query (if any) is supported. Supported values are defined by :py:data:`SUPPORTED_ACCEPT_TYPES` and for the given context of API or UI. :raises HTTPNotAcceptable: if desired ``Accept`` or ``format`` specifier of content-type is not supported. .. py:function:: setup_webhooks_config(config_path: Optional[magpie.typedefs.Str], settings: magpie.typedefs.SettingsType) -> None Prepares and validates :term:`Webhook` settings for the application based on definitions in configuration file(s). Following execution, all validated :term:`Webhook` configurations will have every parameters defined in :py:data:`WEBHOOK_KEYS`, whether optional or mandatory. Required parameters in :py:data:`WEBHOOK_KEYS_REQUIRED` are explicitly validated for defined value and raise if missing. Parameters from :py:data:`WEBHOOK_KEYS_OPTIONAL` are defaulted to ``None`` if missing. Any :term:`Webhook` failing validation will raise the whole configuration and not apply any changes to the :paramref:`settings`. Format validation is applied to some specific parameters to anticipate and raise definitions guaranteed to be erroneous to avoid waiting until runtime for them to fail upon their trigger event. .. seealso:: Documentation in :ref:`config_webhook`. :param config_path: a single file or directory path where configuration file(s) with ``webhook`` section. :param settings: modified settings in-place with added valid webhooks. .. py:function:: register_defaults(db_session: Optional[sqlalchemy.orm.session.Session] = None, settings: Optional[magpie.typedefs.AnySettingsContainer] = None, ini_file_path: Optional[magpie.typedefs.Str] = None) -> None Registers into database every undefined default users and groups matching following variables: - :py:data:`magpie.constants.MAGPIE_ANONYMOUS_USER` - :py:data:`magpie.constants.MAGPIE_USERS_GROUP` - :py:data:`magpie.constants.MAGPIE_ADMIN_GROUP` - :py:data:`magpie.constants.MAGPIE_ADMIN_USER` .. py:function:: get_constant(constant_name: magpie.typedefs.Str, settings_container: Optional[magpie.typedefs.AnySettingsContainer] = None, settings_name: Optional[magpie.typedefs.Str] = None, default_value: Optional[magpie.typedefs.SettingValue] = None, raise_not_set: bool = True, raise_missing: bool = True, print_missing: bool = False, empty_missing: bool = False) -> magpie.typedefs.SettingValue Search in order for matched value of :paramref:`constant_name`: 1. search in :py:data:`MAGPIE_CONSTANTS` 2. search in settings if specified 3. search alternative setting names (see below) 4. search in :mod:`magpie.constants` definitions 5. search in environment variables Parameter :paramref:`constant_name` is expected to have the format ``MAGPIE_[VARIABLE_NAME]`` although any value can be passed to retrieve generic settings from all above-mentioned search locations. If :paramref:`settings_name` is provided as alternative name, it is used as is to search for results if :paramref:`constant_name` was not found. Otherwise, ``magpie.[variable_name]`` is used for additional search when the format ``MAGPIE_[VARIABLE_NAME]`` was used for :paramref:`constant_name` (i.e.: ``MAGPIE_ADMIN_USER`` will also search for ``magpie.admin_user`` and so on for corresponding constants). :param constant_name: key to search for a value :param settings_container: WSGI application settings container (if not provided, uses found one in current thread) :param settings_name: alternative name for `settings` if specified :param default_value: default value to be returned if not found anywhere, and exception raises are disabled. :param raise_not_set: raise an exception if the found key is ``None``, search until last case if others are ``None`` :param raise_missing: raise exception if key is not found anywhere :param print_missing: print message if key is not found anywhere, return ``None`` :param empty_missing: consider an empty value for an existing key as if it was missing (i.e.: as if not set). :returns: found value or `default_value` :raises ValueError: if resulting value is invalid based on options (by default raise missing/empty/``None`` value) :raises LookupError: if no appropriate value could be found from all search locations (according to options) .. py:function:: get_db_session_from_config_ini(config_ini_path, ini_main_section_name='app:magpie_app', settings_override=None) .. py:function:: run_database_migration_when_ready(settings: magpie.typedefs.SettingsType, db_session: Optional[sqlalchemy.orm.session.Session] = None) -> None Runs db migration if requested by config and need from revisions. .. py:function:: set_sqlalchemy_log_level(magpie_log_level: Union[magpie.typedefs.Str, int]) -> magpie.typedefs.SettingsType Suppresses :py:mod:`sqlalchemy` verbose logging if not in ``logging.DEBUG`` for Magpie. .. py:function:: magpie_register_permissions_from_config(permissions_config: Union[magpie.typedefs.Str, magpie.typedefs.PermissionsConfig], settings: Optional[magpie.typedefs.AnySettingsContainer] = None, db_session: Optional[sqlalchemy.orm.session.Session] = None, raise_errors: bool = False) -> None Applies `permissions` specified in configuration(s) defined as file, directory with files or literal configuration. :param permissions_config: file/dir path to `permissions` config or JSON/YAML equivalent pre-loaded. :param settings: Magpie settings to resolve an instance session when using requests instead of DB session. Will look for ``magpie.url``, ``magpie.admin_user`` and ``magpie.admin_password`` by default, or any corresponding environment variable resolution if omitted in the settings. :param db_session: db session to use instead of requests to directly create/remove permissions with config. :param raise_errors: raises errors related to permissions, instead of just logging the info. .. seealso:: `magpie/config/permissions.cfg` for specific parameters and operational details. .. py:function:: magpie_register_services_from_config(service_config_path: magpie.typedefs.Str, push_to_phoenix: bool = False, skip_registration: bool = False, force_update: bool = False, disable_getcapabilities: bool = False, db_session: Optional[sqlalchemy.orm.session.Session] = None) -> magpie.typedefs.ServicesSettings Registers Magpie services from one or many `providers.cfg` file. Uses the provided DB session to directly update service definitions, or uses API request routes as admin. Optionally pushes updates to Phoenix. :param service_config_path: where to look for `providers` configuration(s). Directory or file path. :param push_to_phoenix: whether to push loaded service definitions to remote `Phoenix` service. :param skip_registration: Load, validate and combine :term:`Service` configurations, but don't register them. :param force_update: override service definitions that conflict by name with registered ones. :param disable_getcapabilities: Skip `GetCapabilities` request validation and permission update. By default, any service with `type` that allows `GetCapabilities` permissions will be tested to ensure it can be reached on the provided `url`. Once validated, this permission is applied to `anonymous` group to make its entrypoint accessible by anyone. Services that cannot have `GetCapabilities` permission are ignored regardless. :param db_session: Use a pre-established database connection for registration. Otherwise, API requests are employed. :returns: loaded service configurations. .. py:function:: get_auth_config(container: magpie.typedefs.AnySettingsContainer) -> pyramid.config.Configurator Generates Magpie application configuration with all utilities required for security and access control. .. py:function:: fully_qualified_name(obj: Union[Any, Type[Any]]) -> str Obtains the ``'.'`` full path definition of the object to allow finding and importing it. .. py:function:: get_logger(name: magpie.typedefs.Str, level: Optional[int] = None, force_stdout: bool = None, message_format: Optional[magpie.typedefs.Str] = None, datetime_format: Optional[magpie.typedefs.Str] = None) -> logging.Logger Immediately sets the logger level to avoid duplicate log outputs from the `root logger` and `this logger` when `level` is ``logging.NOTSET``. .. py:function:: log_exception_tween(handler: Callable[[pyramid.request.Request], pyramid.response.Response], registry: pyramid.registry.Registry) -> Callable[[pyramid.request.Request], pyramid.response.Response] Tween factory that logs any exception before re-raising it. Application errors are marked as ``ERROR`` while non-critical HTTP errors are marked as ``WARNING``. .. py:function:: log_request(event: pyramid.events.NewRequest) -> None Subscriber event that logs basic details about the incoming requests. .. py:function:: patch_magpie_url(container: magpie.typedefs.AnySettingsContainer) -> magpie.typedefs.SettingsType Updates potentially missing configuration settings for normal application execution. .. py:function:: print_log(msg: magpie.typedefs.Str, logger: Optional[logging.Logger] = None, level: int = logging.INFO, **kwargs: Any) -> None Logs the requested message to the logger and optionally enforce printing to the console according to configuration value defined by ``MAGPIE_LOG_PRINT``. .. py:function:: setup_cache_settings(settings: magpie.typedefs.SettingsType, force: bool = False, enabled: bool = False, expire: int = 0) -> None Setup caching settings if not defined in configuration and enforce values if requested. Required caching regions that were missing from configuration are initiated with disabled caching by default. This ensures that any decorators or region references will not cause unknown key or region errors. :param settings: reference to application settings that will be updated in place. :param force: enforce following parameters, otherwise only ensure that caching regions exist. :param enabled: enable caching when enforced settings is requested. :param expire: cache expiration delay if setting values are enforced and enabled. .. py:function:: setup_pyramid_config(config: pyramid.config.Configurator) -> None Setup :mod:`Pyramid` utilities in the application configuration to define expected object references. .. py:function:: setup_session_config(config: pyramid.config.Configurator) -> None Setup database :class:`Session` transaction handlers and :class:`Request` properties for active :term:`User`. .. py:function:: setup_ziggurat_config(config: pyramid.config.Configurator) -> None Setup :mod:`ziggurat_foundations` configuration settings and extensions that are required by `Magpie`. Ensures that all needed extensions and parameter configuration values are defined as intended. Resolves any erroneous configuration or conflicts from the INI (backward compatible to when it was required to provide them explicitly) to guarantee that references are defined as needed for the application to behave correctly. :param config: configurator reference when loading the web application. .. py:data:: LOGGER .. py:function:: setup_magpie_configs(settings: magpie.typedefs.SettingsType, db_session: Optional[sqlalchemy.orm.session.Session] = None, setup_providers: bool = True, setup_permissions: bool = True, setup_webhooks: bool = True, skip_registration: bool = False) -> None Resolve known configuration file paths from settings or environment variables and process them for the application. .. seealso:: - https://pavics-magpie.readthedocs.io/en/latest/configuration.html#file-providers-cfg - https://pavics-magpie.readthedocs.io/en/latest/configuration.html#file-permissions-cfg - https://pavics-magpie.readthedocs.io/en/latest/configuration.html#configuration-file-formats - https://pavics-magpie.readthedocs.io/en/latest/configuration.html#combined-configuration-file .. py:function:: main(global_config: Optional[magpie.typedefs.SettingsType] = None, **settings: magpie.typedefs.SettingsType) -> pyramid.router.Router This function returns a Pyramid WSGI application.