Member customization: advanced techniques

In the basics, we covered how to customize the behavior of a member by using prefixed method in a class definition. However this is not the only way to customize members. The following section will first describe how a member determine the action to take at each step of the getting, setting process, before giving more details about the behaviors taht can be used to build custom members.

Members inner working

For each step of the process described of Introducing the members, Members check the mode identifying the action it should take. Based on this flag, it will either call a builtin function or the appropriate user provided function or method.

One can inspect the mode set on the member by accesing the matching attribute as described in the table below. This attribute is a tuple containing two items. The first item is the flag value matching the member behavior, the second item depend on the value of the flag.

The behavior of the member can be modified by calling the matching set_ method, to set the flag to a new and provide the additional item matching the flag value.

For all steps of the getattr, setattr process, you can invoke them separatly by calling the mathcing do_ method. Among them, do_full_validate() is special in that it will run both the validate and post_validate steps on the provided value.

The following table summarizes the different steps along with the flags and the aforementionned attributes and methods:

Steps

Mode

Mode (getter/setter)

Manual running

getattr

GetAttr

getattr_mode() / set_getattr_mode()

do_getattr()

post_getattr

PostGetAttr

post_getattr_mode() / set_post_getattr_mode()

do_post_getattr()

setattr

SetAttr

setattr_mode() / set_setattr_mode()

do_setattr()

post_setattr

PostSetAttr

post_setattr_mode() / set_post_setattr_mode()

do_post_setattr()

validate

Validate

validate_mode() / set_validate_mode()

do_validate()

post_validate

PostValidate

post_validate_mode() / set_post_validate_mode()

do_post_validate()

default_value

DefaultValue

default_value_mode() / set_default_value_mode()

do_default_value()

Note

Delattr works on the same model but the flag is not exposed as part of the public API. You can still access the mode using delattr_mode()

Behaviors for custom members

In order to create custom members, you can either subclass Member and set the modes in the __init__ method, or set the modes after instantiating the member. The modes that can be used in conjunction with custom callable or methods are listed below and expected signature of the callable or the method can be directly inferred from the mode. When specifying a method, the second item of the mode should be the name of the method. In the following, Object always refers to an Atom subclass instance and Name to the member name.

  • GetAttr:
    • CallObject_Object

    • CallObject_ObjectName

    • ObjectMethod

    • ObjectMethod_Name

    • MemberMethod_Object

  • PostGetAttr:
    • ObjectMethod_Value

    • ObjectMethod_NameValue

    • MemberMethod_ObjectValue

  • SetAttr:
    • CallObject_ObjectValue

    • CallObject_ObjectNameValue

    • ObjectMethod_Value

    • ObjectMethod_NameValue

    • MemberMethod_ObjectValue

  • PostSetAttr:
    • ObjectMethod_OldNew

    • ObjectMethod_NameOldNew

    • MemberMethod_ObjectOldNew

  • DefaultValue:
    • CallObject

    • CallObject_Object

    • CallObject_ObjectName

    • ObjectMethod

    • ObjectMethod_Name

    • MemberMethod_Object

  • Validate:
    • ObjectMethod_OldNew

    • ObjectMethod_NameOldNew

    • MemberMethod_ObjectOldNew

  • PostValidate:
    • ObjectMethod_OldNew

    • ObjectMethod_NameOldNew

    • MemberMethod_ObjectOldNew

  • GetState:
    • ObjectMethod_Name

    • MemberMethod_Object

Note

It is recommended to avoid customizing specialized members that may make some assumptions regarding the values of the other modes.

Using __init_subclass__

Starting with atom 0.10.0, __init_subclass__ can be meaningfully used to customize members as illustrated in Pickling Example.

When accessing members in __init_subclass__ one should however be careful to only modify members that belong to the class being customized. Otherwise a parent class could see its behavior change which is definitively undesirable. To avoid this issue clone_if_needed() can be used to clone a member if it does not belong to a class and update the class to use the clone. It returns the original member or its clone.