Skip to content

Module lockattrs.decorators

Provides the decorator protect. It is used to annotate the

class method __setattr__ in order to prevent attribute modificaton.

Should be used in meta-classes and classes that are not instantiated often since the nested decorator is called every time an attribute is set.

View Source
""" Provides the decorator `protect`. It is used to annotate the

    class method `__setattr__` in order to prevent attribute

    modificaton.

    Should be used in meta-classes and classes that are not instantiated often

    since the nested decorator is called every time an attribute is set.

"""

from functools import wraps

from inspect import signature

from typing import Iterable

class ProtectedAttributeError(AttributeError):

    """Error indicating an attempted modification of a protected attribute."""

def protect(

    attr_names: Iterable[str] = (),

    error_type: Exception = ProtectedAttributeError,

):

    """

    Function used to decorate `__setattr__`.

    It raises an exception during an attempt to

    modify any class attributes specified by `attr_names` after the

    attributes have been initially set.

    - `attr_names`: A tuple containing the names of

      all class attributes that must not be modified.

      The default value of `attr_names` is an empty tuple

      indicating that all

      attributes should be protected.

    - `error_type`: Optional parameter used to

       specify the type of error raised.

    """

    if isinstance(attr_names, str):

        attr_names = (attr_names,)

    def _protect(func):

        @wraps(func)

        def inner(*args, **kwargs):

            # Map args onto kwargs:

            all_argument_names = tuple(signature(func).parameters.keys())

            mapped_kwargs = kwargs.copy()

            for index, arg_value in enumerate(args):

                mapped_kwargs[all_argument_names[index]] = arg_value

            # Check attempted modification of protected attributes.

            if (

                not attr_names or mapped_kwargs["name"] in attr_names

            ) and hasattr(mapped_kwargs["self"], mapped_kwargs["name"]):

                # mapped_kwargs['name'] in mapped_kwargs['self'].__dict__:

                raise error_type(

                    f"Class attribute '{mapped_kwargs['name']}' "

                    "must not be modified."

                )

            return func(*args, **kwargs)

        return inner

    return _protect

Functions

protect

def protect(
    attr_names: Iterable[str] = (),
    error_type: Exception = <class 'lockattrs.decorators.ProtectedAttributeError'>
)

Function used to decorate __setattr__.

It raises an exception during an attempt to modify any class attributes specified by attr_names after the attributes have been initially set.

  • attr_names: A tuple containing the names of all class attributes that must not be modified. The default value of attr_names is an empty tuple indicating that all attributes should be protected.
  • error_type: Optional parameter used to specify the type of error raised.
View Source
def protect(

    attr_names: Iterable[str] = (),

    error_type: Exception = ProtectedAttributeError,

):

    """

    Function used to decorate `__setattr__`.

    It raises an exception during an attempt to

    modify any class attributes specified by `attr_names` after the

    attributes have been initially set.

    - `attr_names`: A tuple containing the names of

      all class attributes that must not be modified.

      The default value of `attr_names` is an empty tuple

      indicating that all

      attributes should be protected.

    - `error_type`: Optional parameter used to

       specify the type of error raised.

    """

    if isinstance(attr_names, str):

        attr_names = (attr_names,)

    def _protect(func):

        @wraps(func)

        def inner(*args, **kwargs):

            # Map args onto kwargs:

            all_argument_names = tuple(signature(func).parameters.keys())

            mapped_kwargs = kwargs.copy()

            for index, arg_value in enumerate(args):

                mapped_kwargs[all_argument_names[index]] = arg_value

            # Check attempted modification of protected attributes.

            if (

                not attr_names or mapped_kwargs["name"] in attr_names

            ) and hasattr(mapped_kwargs["self"], mapped_kwargs["name"]):

                # mapped_kwargs['name'] in mapped_kwargs['self'].__dict__:

                raise error_type(

                    f"Class attribute '{mapped_kwargs['name']}' "

                    "must not be modified."

                )

            return func(*args, **kwargs)

        return inner

    return _protect

Classes

ProtectedAttributeError

class ProtectedAttributeError(
    /,
    *args,
    **kwargs
)
View Source
class ProtectedAttributeError(AttributeError):

    """Error indicating an attempted modification of a protected attribute."""

Ancestors (in MRO)

  • builtins.AttributeError
  • builtins.Exception
  • builtins.BaseException

Class variables

args

Methods

with_traceback

def with_traceback(
    ...
)

Exception.with_traceback(tb) --

set self.traceback to tb and return self.