Traitlets#

Traitlets is a tool that allows to make python objects that, automatically check types, autamatically change values of attributes and implement “on change” callbacks.

import traitlets

Observation#

“Observing” is one of the main features of the HasTraits objects. You can set a method to be called when something changes in the instance with the observe method. If you don’t need this callback anymore just use the unobserve method.


The following cell creates a has_traits object that has the my_trait trait and attaches something function to be called when any attribute in the has_traits changes.

class ItHasTratis(traitlets.HasTraits):
    my_trait = traitlets.Int()

has_traits = ItHasTratis()

def something(change):
    print("Trait value changed!")

has_traits.observe(something)

So in case to has_tratis.my_trait got a new value - code of the something is executed.

has_traits.my_trait = 1
Trait value changed!

The following cell unobserve callback from the has_trats object.

has_traits.unobserve(something)
has_traits.my_trait = 2

As a result, there is no output assumed by something in the output.

Change#

Any function that you assign to be a callback must have a to have one parameter - this is an for argument that describes the change that triggered the callback.


The next cell defines HasTraits, which stores the change it received in the global variable test - so it’s possible to study this object from the global environment.

test: object

class ItHasTratis(traitlets.HasTraits):
    my_trait = traitlets.Int()

    @traitlets.observe(traitlets.All)
    def method(self, change):
        global test
        test = change

has_traits = ItHasTratis()
has_traits.my_trait = 1

The next cell shows the type of the object.

type(test)
traitlets.utils.bunch.Bunch

Actually, it’s a relatively simple dictionary that describes change.

test
{'name': 'my_trait',
 'old': 0,
 'new': 1,
 'owner': <__main__.ItHasTratis at 0x7ddb005f7b30>,
 'type': 'change'}

Configurable#

Configurable is a special object that allows objects to be created from a configuration file defined elsewhere. In particular, it could be a simple python file that has traitlets.config.Config defined in it.


The following cell defines Configurable, which we’ll use as an example.

class MyConfigurable(traitlets.config.Configurable):
    name = traitlets.Unicode("DefaultName", config=True)
    count = traitlets.Int(5, config=True)

The following cell defines config - so it contains default values for attributes of the MyConfigurable instance.

config = traitlets.config.Config()
config.MyConfigurable.name = "Alice"
config.MyConfigurable.count = 42

The following code creates MyConfigurable with the previously defined config - the corresponding attributes take the values as defined in the config.

my_configurable = MyConfigurable(config=config)
print(my_configurable.name, my_configurable.count)
Alice 42

Application#

Application is a class that implements functionality that needs to be shared by the entire application - more specificaly, it manages global parameters that are loaded from command line arguments.

The IPKernel backend itself uses this class - so it is autamatically created for each IPython notebook.


The Application.instance method returns the current instance of the Application or creates a new one if it’s needed. The following cell shows that Application.instance executed from IPython kernel returns application that implements IPython backend.

from traitlets.config import Application
Application.instance()
<ipykernel.kernelapp.IPKernelApp at 0x7e6f93bf98e0>

To actually create a new instance for experiments, it must be run in the separate python object. The next cell shows an option to run it.

%%writefile /tmp/application.py
from traitlets.config import Application
print(Application.instance())
Writing /tmp/application.py
!python3 /tmp/application.py
<traitlets.config.application.Application object at 0x748f6a9f7560>

Note there is a hack - set Applicaiton._instance = None it will make Applicaiton to think it isn’t initialized. Obviously never use it in any production level solutions, but for experimenting purposes it’s ok.

The following cell resets Application and shows that from that point Applicaiton.instance() returns the Application instance.

Application._instance = None
Application.instance()
<traitlets.config.application.Application at 0x7e6f8c44a5d0>