pytraits

Copyright 2014-2015 Teppo Perä

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

class pytraits.Singleton[source]

Turn the class to immutable singleton.

>>> class Example(object, metaclass=Singleton):
...    pass
...
>>> a = Example()
>>> b = Example()
>>> id(a) == id(b)
True

Having your instance as a singleton is faster than creating from scratch

>>> import timeit
>>> class MySingleton(object, metaclass=Singleton):
...    def __init__(self):
...        self._store = dict(one=1, two=2, three=3, four=4)
...
>>> class NonSingleton:
...    def __init__(self):
...        self._store = dict(one=1, two=2, three=3, four=4)
...
>>> #timeit.timeit(NonSingleton) > timeit.timeit(MySingleton)

After creating a singleton, data it is holding should not be changed. There is a small enforcement done for these singletons to prevent modifying the contents. With little effort it is doable, but don’t do it. :)

>>> MySingleton().new_item = False
Traceback (most recent call last):
...
pytraits.support.errors.SingletonError: Singletons are immutable!
class pytraits.Factory(override_duplicates=False)[source]

Simple factory to register and create objects.

This class contains multiple ways to hold and create instances of classes. This class also works as a container for all those classes that are registered in and can those classes can be accessed from anywhere by simply importing that factory.

The main mechanism in python to create and initialize objects are __new__ and __init__ functions. It is also a good habit to avoid any conditional logic inside class constructor, thus writing own create classmethod is recommended and also supported by this factory. By using own class method for creating the object, it makes far more easier to setup and test classes you write since the __init__ method is left for simple assignments.

NOTE: This factory is abstract thus anyone using it must inherit own
version before instantiating it.
>>> class ExampleFactory(Factory):
...     pass
...
>>> @ExampleFactory.register
... class ExampleObject:
...     def __init__(self, name, **kwargs):
...         self.name = name
...
...     @classmethod
...     def create(cls, *args, **kwargs):
...         return cls(*args, **kwargs)
...
>>> example_instance = ExampleFactory["ExampleObject"]("MyObject")
>>> example_instance.name
'MyObject'
__getitem__(name)[source]

Returns factory method of registered object.

@see constructor

exists(clazz)[source]

Convenience function to check if class is already exists.

original_class(name)[source]

Retrieves the original registered class.

classmethod register(*classes, override=False, autoinit=True)[source]

Decorator function to register classes to this factory.

classmethod reset()[source]

Removes all registered classes.

pytraits.combine_class(class_name: str, *traits, **resolved_conflicts)[source]

This function composes new class out of any number of traits.

Parameters:
  • class_name – Name of the new class.
  • traits – Collection of traits, such as functions, classes or instances.
Keyword Arguments:
 

name of trait (str) – new name

Example of combining multiple classes to one:

>>> class One:
...     def first(self): return 1
...
>>> class Two:
...     def second(self): return 2
...
>>> class Three:
...     def third(self): return 3
...
>>> Combination = combine_class("Combination", One, Two, Three)
>>> instance = Combination()
>>> instance.first(), instance.second(), instance.third()
(1, 2, 3)
>>> instance.__class__.__name__
'Combination'
pytraits.extendable(target)[source]

Decorator that adds function for object to be extended using traits.

NOTE: The ‘add_traits’ function this extendable decorator adds contains

behavior that differs from usual function behavior. This method alters its behavior depending is the function called on a class or on an instance. If the function is invoked on class, then the class gets updated by the traits, affecting all new instances created from the class. On the other hand, if the function is invoked on an instance, only that instance gets the update, NOT whole class.

See complete example from: pytraits/examples/extendable_function_class_vs_instance.py

>>> @extendable
... class ExampleClass:
...     pass
...
>>> hasattr(ExampleClass, 'add_traits')
True
>>> class InstanceExample:
...     pass
...
>>> instance_example = InstanceExample()
>>> _ = extendable(instance_example)
>>> hasattr(instance_example, 'add_traits')
True
pytraits.add_traits[source]

Bind new traits to given object.

Parameters:
  • target – Object of any type that is going to be extended with traits
  • traits – Tuple of traits as object and strings or callables or functions.
  • resolutions – dictionary of conflict resolutions to solve situations where multiple methods or properties of same name are encountered in traits.
>>> class ExampleClass:
...    def example_method(self):
...        return None
...
>>> class ExampleTrait:
...    def other_method(self):
...        return 42
...
>>> add_traits(ExampleClass, ExampleTrait)
>>> ExampleClass().other_method()
42
class pytraits.type_safe(function)[source]

Decorator to enforce type safety. It certainly kills some ducks but allows us also to fail fast.

>>> @type_safe
... def check(value: int, answer: bool, anything):
...     return value, answer, anything
...
>>> check("12", "false", True)
Traceback (most recent call last):
...
TypeError: While calling check(value:int, answer:bool, anything):
   - parameter 'value' had value '12' of type 'str'
   - parameter 'answer' had value 'false' of type 'str'
>>> check(1000, True)
Traceback (most recent call last):
...
TypeError: check() missing 1 required positional argument: 'anything'
__call__(*args, **kwargs)[source]

Converts annotated types into proper type and calls original function.

__get__(instance, clazz)[source]

Stores calling instances and returns this decorator object as function.

iter_positional_args(args)[source]

Yields type, name, value combination of function arguments.

class pytraits.type_converted(function)[source]

Decorator to enforce types and do auto conversion to values.

>>> @type_converted
... def convert(value: int, answer: bool, anything):
...     return value, answer, anything
...
>>> convert("12", "false", None)
(12, False, None)
>>> class Example:
...     @type_converted
...     def convert(self, value: int, answer: bool, anything):
...       return value, answer, anything
...
>>> Example().convert("12", 0, "some value")
(12, False, 'some value')
>>> Example().convert(None, None, None)
Traceback (most recent call last):
...
pytraits.support.errors.TypeConversionError: While calling Example.convert(self, value:int, answer:bool, anything):
   - got arg 'value' as 'None' of type 'NoneType' which cannot be converted to 'int'
   - got arg 'answer' as 'None' of type 'NoneType' which cannot be converted to 'bool'
boolean_conversion(value)[source]

Convert given value to boolean.

>>> conv = type_converted(lambda self: None)
>>> conv.boolean_conversion("True"), conv.boolean_conversion("false")
(True, False)
>>> conv.boolean_conversion(1), conv.boolean_conversion(0)
(True, False)
convert(arg_type, arg_name, arg_value)[source]

Converts argument to given type.

pytraits.setproperty(target, fget=None, fset=None, fdel=None, source=None, name=None)[source]

Convinience function that dynamically creates property to an object. (If you have property created, just use ‘add_traits’)

This function has different behavior depending on the target object, whether it is an instance or a class. If target is an instance the property is being set only for that instance. In case the object is a class, the property will be added to it normally to class.

Parameters:
  • target (object or type) – Target object, which can be any instance or class.
  • fget (str or function) – Getter function or its name
  • fset (str or function) – Setter function or its name
  • fdel (str or function) – Deleter function or its name
  • source (object or type) – Source object in case fget, fset and fdel are strings.
Keyword Arguments:
 
  • name (str) – Name of the property
  • name of fget (str) – Name of the property

Example, where new property is added dynamically into instance:

>>> class Example:
...     def __init__(self):
...         self.__value = 42
...
...     def set_value(self, new_value):
...         self.__value = new_value
...
...     def value(self):
...         return self.__value
...
...     def del_value(self):
...         self.__value = 42
...
>>> instance = Example()
>>> setproperty(instance, "value", "set_value", "del_value", name="my_property")
>>> instance.my_property
42