:py:mod:`magpie.utils` ====================== .. py:module:: magpie.utils Module Contents --------------- Classes ~~~~~~~ .. autoapisummary:: magpie.utils.ExtendedEnum magpie.utils.FlexibleNameEnum magpie.utils.SingletonMeta magpie.utils.classproperty Functions ~~~~~~~~~ .. autoapisummary:: magpie.utils.get_logger magpie.utils.set_logger_config magpie.utils.print_log magpie.utils.raise_log magpie.utils.bool2str magpie.utils.islambda magpie.utils.isclass magpie.utils.ismethod magpie.utils.signature_with_args magpie.utils.get_settings_from_config_ini magpie.utils.setup_cache_settings magpie.utils.setup_pyramid_config magpie.utils.cleanup_session magpie.utils.setup_session_config magpie.utils.setup_ziggurat_config magpie.utils.debug_cookie_identify magpie.utils.get_request_user magpie.utils.get_json magpie.utils.get_header magpie.utils.convert_response magpie.utils.get_authenticate_headers magpie.utils.get_cookies magpie.utils.get_admin_cookies magpie.utils.get_registry magpie.utils.get_settings magpie.utils.import_target magpie.utils.normalize_field_pattern magpie.utils.patch_magpie_url magpie.utils.get_magpie_url magpie.utils.get_phoenix_url magpie.utils.get_twitcher_url magpie.utils.get_twitcher_protected_service_url magpie.utils.is_magpie_ui_path magpie.utils.fully_qualified_name magpie.utils.log_request_format magpie.utils.log_request magpie.utils.log_exception_tween magpie.utils.is_json_body magpie.utils.decompose_enum_flags Attributes ~~~~~~~~~~ .. autoapisummary:: magpie.utils.CONTENT_TYPE_ANY magpie.utils.CONTENT_TYPE_JSON magpie.utils.CONTENT_TYPE_FORM magpie.utils.CONTENT_TYPE_HTML magpie.utils.CONTENT_TYPE_PLAIN magpie.utils.CONTENT_TYPE_APP_XML magpie.utils.CONTENT_TYPE_TXT_XML magpie.utils.FORMAT_TYPE_MAPPING magpie.utils.SUPPORTED_ACCEPT_TYPES magpie.utils.SUPPORTED_FORMAT_TYPES magpie.utils.KNOWN_CONTENT_TYPES magpie.utils.LOGGER .. py:data:: CONTENT_TYPE_ANY :value: '*/*' .. py:data:: CONTENT_TYPE_JSON :value: 'application/json' .. py:data:: CONTENT_TYPE_FORM :value: 'application/x-www-form-urlencoded' .. py:data:: CONTENT_TYPE_HTML :value: 'text/html' .. py:data:: CONTENT_TYPE_PLAIN :value: 'text/plain' .. py:data:: CONTENT_TYPE_APP_XML :value: 'application/xml' .. py:data:: CONTENT_TYPE_TXT_XML :value: 'text/xml' .. py:data:: FORMAT_TYPE_MAPPING .. py:data:: SUPPORTED_ACCEPT_TYPES .. py:data:: SUPPORTED_FORMAT_TYPES .. py:data:: KNOWN_CONTENT_TYPES .. 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:data:: LOGGER .. py:function:: set_logger_config(logger: logging.Logger, force_stdout: bool = False, message_format: Optional[magpie.typedefs.Str] = None, datetime_format: Optional[magpie.typedefs.Str] = None, log_file: Optional[magpie.typedefs.Str] = None) -> logging.Logger Applies the provided logging configuration settings to the logger. .. 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:: raise_log(msg: magpie.typedefs.Str, exception: Type[Exception] = Exception, logger: Optional[logging.Logger] = None, level: int = logging.ERROR) -> NoReturn Logs the provided message to the logger and raises the corresponding exception afterwards. :raises exception: whichever exception provided is raised systematically after logging. .. py:function:: bool2str(value: Any) -> magpie.typedefs.Str Converts :paramref:`value` to explicit ``"true"`` or ``"false"`` :class:`str` with permissive variants comparison that can represent common falsy or truthy values. .. py:function:: islambda(func: Any) -> bool Evaluate if argument is a callable :class:`lambda` expression. .. py:function:: isclass(obj: Any) -> bool Evaluate an object for :class:`class` type (ie: class definition, not an instance nor any other type). .. py:function:: ismethod(obj: Any) -> bool Evaluate an object for :class:`method` type (i.e.: class method reference. .. py:function:: signature_with_args(func: Callable[[Ellipsis], Any], *args: Any, **kwargs: Any) -> magpie.typedefs.Str Returns a visual representation of a function signature with is arguments. .. code-block:: python def function(a, b, c=1): ... signature_with_args(function, 1, 2, c=3) # returns: .. py:function:: get_settings_from_config_ini(config_ini_path: magpie.typedefs.Str, ini_main_section_name: magpie.typedefs.Str = 'app:magpie_app') -> magpie.typedefs.SettingsType .. 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:: cleanup_session(handler: Callable[[pyramid.request.Request], pyramid.response.Response], _: pyramid.registry.Registry) -> Callable[[pyramid.request.Request], pyramid.response.Response] Tween that forces the database connection to be closed once the response is obtained from the request. .. 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:function:: debug_cookie_identify(request) Logs debug information about request cookie. .. WARNING:: This function is intended for debugging purposes only. It reveals sensible configuration information. Re-implements basic functionality of :func:`pyramid.AuthTktAuthenticationPolicy.cookie.identify` called via :func:`request.unauthenticated_userid` within :func:`get_request_user` to provide additional logging. .. seealso:: - :class:`pyramid.authentication.AuthTktCookieHelper` - :class:`pyramid.authentication.AuthTktAuthenticationPolicy` .. py:function:: get_request_user(request: pyramid.request.Request) -> Optional[magpie.models.User] Obtains the user that corresponds to the authentication details found in the request. Prior to resolving the user matching the authenticated user ID, reattaches the detached session or closed transaction if commit occurred beforehand. This can happen for example when creating a user from a pending-user where the user must be committed to allow webhooks to refer to it immediately, although the request has not completed processing. Operations using the ``request.user`` reference following that user creation could have a detached object state from the session. Ensure that any resolved user is also attached to the reestablished database session reference in the request. After reattaching to the session, following step is the original configuration setup similarly to typical methodology:: config.include("ziggurat_foundations.ext.pyramid.get_user") :param request: request to look for authenticated user. :return: authenticated user or none if unauthenticated. .. py:function:: get_json(request_or_response: Union[magpie.typedefs.AnyRequestType, magpie.typedefs.AnyResponseType]) -> magpie.typedefs.JSON Retrieves the 'JSON' body of a response using the property/callable according to the response's implementation. .. py:function:: get_header(header_name: magpie.typedefs.Str, header_container: magpie.typedefs.AnyHeadersType, default: (Optional[magpie.typedefs.Str], Optional[Union[magpie.typedefs.Str, List[magpie.typedefs.Str]]], bool) = None, split: Optional[Union[magpie.typedefs.Str, List[magpie.typedefs.Str]]] = None, multi: bool = False, pop: bool = False) -> Optional[Union[magpie.typedefs.Str, List[magpie.typedefs.Str]]] Retrieves ``header_name`` by fuzzy match (independently of upper/lower-case and underscore/dash) from various framework implementations of ``Headers``. If ``split`` is specified, the matched ``header_name`` is first split with it and the first item is returned. This allows to parse complex headers (e.g.: ``text/plain; charset=UTF-8`` to ``text/plain`` with ``split=';'``). :param header_name: Header to find. :param header_container: Where to look for `header_name`. :param default: Value to returned if `header_container` is invalid or `header_name` could not be found. :param split: Character(s) to use to split the *found* `header_name`. :param multi: Return extracted header as array of multiple values or return a single value on fist match. :param pop: Remove the header from the container if found. :returns: Found header value(s) if applicable. .. py:function:: convert_response(response: magpie.typedefs.AnyResponseType) -> pyramid.response.Response Converts a :class:`requests.Response` object to an equivalent :class:`pyramid.response.Response` object. Content of the :paramref:`response` is expected to be JSON. :param response: Response to be converted. :returns: Converted response. .. py:function:: get_authenticate_headers(request: pyramid.request.Request, error_type: magpie.typedefs.Str = 'invalid_token') -> Optional[magpie.typedefs.HeadersType] Obtains all required headers by 401 responses based on executed :paramref:`request`. :param request: request that was sent to attempt authentication or access which must respond with Unauthorized. :param error_type: Additional detail of the cause of error. Must be one of (invalid_request, invalid_token, insufficient_scope). .. py:function:: get_cookies(request_or_response: Union[magpie.typedefs.AnyRequestType, magpie.typedefs.AnyResponseType]) -> magpie.typedefs.CookiesType Retrieves a dictionary of cookie names and values from distinct implementations and container types. :param request_or_response: Object that potentially contains cookies, by literal property or corresponding headers. :return: Found cookies. .. py:function:: get_admin_cookies(container: magpie.typedefs.AnySettingsContainer, verify: bool = True, raise_message: Optional[magpie.typedefs.Str] = None) -> magpie.typedefs.CookiesType .. py:function:: get_registry(container: Optional[magpie.typedefs.AnyRegistryContainer] = None, nothrow: bool = False) -> Optional[pyramid.registry.Registry] Retrieves the application ``registry`` from various containers referencing to it. .. py:function:: get_settings(container: Optional[magpie.typedefs.AnySettingsContainer], app: bool = False) -> magpie.typedefs.SettingsType Retrieve application settings from a supported container. :param container: supported container with a handle to application settings. :param app: allow retrieving from current thread registry if no container was defined. :return: found application settings dictionary. :raise TypeError: when no application settings could be found or unsupported container. .. py:function:: import_target(target: magpie.typedefs.Str, default_root: Optional[magpie.typedefs.Str] = None) -> Optional[Any] Imports a target resource from a Python script as module. The Python script does not need to be defined within a module directory (i.e.: with ``__init__.py``). Files can be imported from virtually anywhere. To avoid name conflicts in generated module references, each imported target employs its full escaped file path as module name. Format expected as follows: .. code-block:: python "path/to/script.py:function" :param target: Resource to be imported. :param default_root: Root directory to employ if target is relative (default :data:`magpie.constants.MAGPIE_ROOT`). :return: Found and imported resource or None. .. py:function:: normalize_field_pattern(pattern: magpie.typedefs.Str, escape: bool = True) -> magpie.typedefs.Str Escapes necessary regex pattern characters and applies start/end-of-line control characters. .. py:function:: patch_magpie_url(container: magpie.typedefs.AnySettingsContainer) -> magpie.typedefs.SettingsType Updates potentially missing configuration settings for normal application execution. .. py:function:: get_magpie_url(container: Optional[magpie.typedefs.AnySettingsContainer] = None) -> magpie.typedefs.Str Obtains the configured Magpie URL entrypoint based on the various combinations of supported configuration settings. .. seealso:: Documentation section :ref:`config_app_settings` for available setting combinations. :param container: container that provides access to application settings. :return: resolved Magpie URL .. py:function:: get_phoenix_url(container: Optional[magpie.typedefs.AnySettingsContainer] = None) -> magpie.typedefs.Str Obtains the configured Phoenix URL entrypoint based on the various combinations of supported configuration settings. .. seealso:: Documentation section :ref:`config_phoenix` for available setting combinations. :param container: container that provides access to application settings. :return: resolved Phoenix URL .. py:function:: get_twitcher_url(container: Optional[magpie.typedefs.AnySettingsContainer] = None, hostname: Optional[magpie.typedefs.Str] = None) -> magpie.typedefs.Str Obtains the configured Twitcher URL entrypoint based on various combinations of supported configuration settings. .. seealso:: Documentation section :ref:`config_twitcher` for available setting combinations. :param container: container that provides access to application settings. :param hostname: override literal hostname to generate the URL instead of resolving using settings. :return: resolved Twitcher URL .. py:function:: get_twitcher_protected_service_url(magpie_service_name: magpie.typedefs.Str, container: Optional[magpie.typedefs.AnySettingsContainer] = None, hostname: Optional[magpie.typedefs.Str] = None) -> magpie.typedefs.Str Obtains the protected service URL behind Twitcher Proxy based on combination of supported configuration settings. .. seealso:: Documentation section :ref:`config_twitcher` for available setting combinations. :param magpie_service_name: name of the service to employ in order to form the URL path behind the proxy. :param container: container that provides access to application settings. :param hostname: override literal hostname to generate the URL instead of resolving using settings. :return: resolved Twitcher Proxy protected service URL .. py:function:: is_magpie_ui_path(request: pyramid.request.Request) -> bool Determines if the request path corresponds to any Magpie UI location. .. 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:: log_request_format(request: pyramid.request.Request) -> magpie.typedefs.Str .. py:function:: log_request(event: pyramid.events.NewRequest) -> None Subscriber event that logs basic details about the incoming requests. .. 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:: is_json_body(body: Any, return_body: bool = False) -> bool .. py:class:: ExtendedEnum Bases: :py:obj:`enum.Enum` Utility :class:`enum.Enum` methods. Create an extended enum with these utilities as follows:: class CustomEnum(ExtendedEnum): ItemA = "A" ItemB = "B" .. py:property:: title :type: magpie.typedefs.Str Returns the title representation of the enum element. Title use the original enum element name with capitalization considering underscores for separate words. .. py:method:: names() -> List[magpie.typedefs.Str] :classmethod: Returns the member names assigned to corresponding enum elements. .. py:method:: values() -> List[magpie.typedefs.AnyKey] :classmethod: Returns the literal values assigned to corresponding enum elements. .. py:method:: get(key_or_value: magpie.typedefs.AnyKey, default: Optional[Any] = None) -> Optional[_TC] :classmethod: Finds an enum entry by defined name or its value. Returns the entry directly if it is already a valid enum. .. py:method:: titles() -> List[magpie.typedefs.Str] :classmethod: Returns the title representation of all enum elements. .. py:class:: FlexibleNameEnum Bases: :py:obj:`ExtendedEnum` Enum that allows more permissive name cases for lookup. .. py:method:: _missing_(value) :classmethod: .. py:method:: __missing_flexible(value) :classmethod: .. py:method:: get(key_or_value, default=None) :classmethod: Finds an enum entry by defined name or its value. Returns the entry directly if it is already a valid enum. .. py:function:: decompose_enum_flags(enum_flags: enum.Enum) -> List[enum.Enum] Decompose a ``Flag``-enabled ``Enum`` into its individual parts. The operation is agnostic of the ``Enum`` implementation, whether from stdlib :mod:`enum` or :mod:`aenum`. .. py:class:: SingletonMeta Bases: :py:obj:`type` A metaclass that creates a Singleton base class when called. Create a class such that:: @six.add_metaclass(SingletonMeta) class A(object): pass @six.add_metaclass(SingletonMeta) class B(object): pass a1 = A() a2 = A() b1 = B() b2 = B() a1 is a2 # True b1 is b2 # True a1 is b1 # False .. py:attribute:: _instances .. py:method:: __call__(*args, **kwargs) Call self as a function. .. py:class:: classproperty Bases: :py:obj:`property` Mimics :class:`property` decorator, but applied onto ``classmethod`` in backward compatible way. .. note:: This decorator purposely only supports getter attribute to define unmodifiable class properties. .. seealso:: https://stackoverflow.com/a/5191224 Initialize self. See help(type(self)) for accurate signature. .. py:method:: __get__(cls, owner) Return an attribute of instance, which is of type owner.