xotl.tools.objects - Functions for dealing with objects¶
Several utilities for objects in general.
-
xotl.tools.objects.validate_attrs(source, target, force_equals=(), force_differents=())[source]¶ Makes a ‘comparison’ of
sourceandtargetby its attributes (or keys).This function returns True if and only if both of these tests pass:
- All attributes in
force_equalsare equal insourceandtarget - All attributes in
force_differentsare different insourceandtarget
For instance:
>>> class Person: ... def __init__(self, **kwargs): ... for which in kwargs: ... setattr(self, which, kwargs[which]) >>> source = Person(name='Manuel', age=33, sex='male') >>> target = {'name': 'Manuel', 'age': 4, 'sex': 'male'} >>> validate_attrs(source, target, force_equals=('sex',), ... force_differents=('age',)) True >>> validate_attrs(source, target, force_equals=('age',)) False
If both
force_equalsandforce_differentsare empty it will return True:>>> validate_attrs(source, target) True
- All attributes in
-
xotl.tools.objects.iterate_over(source, *keys)[source]¶ Yields pairs of (key, value) for of all
keysinsource.If any
keyis missing fromsourceis ignored (not yielded).If
sourceis acollection, iterate over each of the items searching for any of keys. This is not recursive.If no
keysare provided, return an “empty” iterator – i.e will raise StopIteration upon callingnext.New in version 1.5.2.
-
xotl.tools.objects.smart_getter(obj, strict=False)[source]¶ Returns a smart getter for
obj.If
objis a mapping, it returns the.get()method bound to the objectobj, otherwise it returns a partial ofgetattronobj.Parameters: strict – Set this to True so that the returned getter checks that keys/attrs exists. If strictis True the getter may raise a KeyError or an AttributeError.Changed in version 1.5.3: Added the parameter
strict.
-
xotl.tools.objects.smart_getter_and_deleter(obj)[source]¶ Returns a function that get and deletes either a key or an attribute of obj depending on the type of
obj.If
objis acollections.Mappingit must be acollections.MutableMapping.
-
xotl.tools.objects.popattr(obj, name, default=None)[source]¶ Looks for an attribute in the
objand returns its value and removes the attribute. If the attribute is not found,defaultis returned instead.Examples:
>>> class Foo: ... a = 1 >>> foo = Foo() >>> foo.a = 2 >>> popattr(foo, 'a') 2 >>> popattr(foo, 'a') 1 >>> popattr(foo, 'a') is None True
-
xotl.tools.objects.setdefaultattr(obj, name, value)[source]¶ Sets the attribute name to value if it is not set:
>>> class Someclass: pass >>> inst = Someclass() >>> setdefaultattr(inst, 'foo', 'bar') 'bar' >>> inst.foo 'bar' >>> inst.spam = 'egg' >>> setdefaultattr(inst, 'spam', 'with ham') 'egg'
-
xotl.tools.objects.copy_class(cls, meta=None, ignores=None, new_attrs=None, new_name=None)[source]¶ Copies a class definition to a new class.
The returned class will have the same name, bases and module of
cls.Parameters: - meta – If None, the
type(cls)of the class is used to build the new class, otherwise this must be a proper metaclass. - ignores –
A sequence of attributes names that should not be copied to the new class.
An item may be callable accepting a single argument
attrthat must return a non-null value if the theattrshould be ignored. - new_attrs (dict) – New attributes the class must have. These will take precedence over the attributes in the original class.
- new_name – The name for the copy. If not provided the name will copied.
New in version 1.4.0.
Changed in version 1.7.1: The
ignoresargument must an iterable of strings or callables. Removed the glob-pattern and regular expressions as possible values. They are all possible via the callable variant.New in version 1.7.1: The
new_nameargument.- meta – If None, the
-
class
xotl.tools.objects.classproperty[source]¶ A descriptor that behaves like property for instances but for classes.
Example of its use:
class Foobar: @classproperty def getx(cls): return cls._x
A writable
classpropertyis difficult to define, and it’s not intended for that case because ‘setter’, and ‘deleter’ decorators can’t be used for obvious reasons. For example:class Foobar: x = 1 def __init__(self, x=2): self.x = x def _get_name(cls): return str(cls.x) def _set_name(cls, x): cls.x = int(x) name = classproperty(_get_name, _set_name)
In Python 3.9+ this is actually the composition of
classmethodtoproperty(i.e same aslambda *a, **kw: classmethod(property(*a, **kw))).New in version 1.4.1.
Changed in version 1.8.0: Inherits from
propertyChanged in version 2.11.0: Changed to be
compose(classmethod, property)in Python 3.9+.
-
xotl.tools.objects.import_object(name, package=None, sep='.', default=None, **kwargs)[source]¶ Get symbol by qualified name.
The name should be the full dot-separated path to the class:
modulename.ClassName
Example:
celery.concurrency.processes.TaskPool ^- class name
or using ‘:’ to separate module and symbol:
celery.concurrency.processes:TaskPool
Examples:
>>> import_object('celery.concurrency.processes.TaskPool') <class 'celery.concurrency.processes.TaskPool'> # Does not try to look up non-string names. >>> from celery.concurrency.processes import TaskPool >>> import_object(TaskPool) is TaskPool True
-
xotl.tools.objects.get_first_of(sources, *keys, default=None, pred=None)[source]¶ Return the value of the first occurrence of any of the specified
keysinsourcethat matchespred(if given).Both
sourceandkeyshas the same meaning as initerate_over().Parameters: - default – A value to be returned if no key is found in
source. - pred – A function that should receive a single value and return
False if the value is not acceptable, and thus
get_first_ofshould look for another.
Changed in version 1.5.2: Added the
predoption.- default – A value to be returned if no key is found in
-
xotl.tools.objects.xdir(obj, filter=None, attr_filter=None, value_filter=None, getattr=None)[source]¶ Return all
(attr, value)pairs fromobjmakefilter(attr, value)True.Parameters: - obj – The object to be instrospected.
- filter –
A filter that will be passed both the attribute name and it’s value as two positional arguments. It should return True for attrs that should be yielded.
If None, all pairs will match.
- getter – A function with the same signature that
getattrto be used to get the values fromobj. If None, usegetattr().
Changed in version 1.8.1: Removed deprecated
attr_filterandvalue_filterarguments.
-
xotl.tools.objects.fdir(obj, filter=None, attr_filter=None, value_filter=None, getattr=None)[source]¶ Similar to
xdir()but yields only the attributes names.
-
xotl.tools.objects.smart_copy(*sources, target, *, defaults=False)[source]¶ Copies the first apparition of attributes (or keys) from
sourcestotarget.Parameters: - sources – The objects from which to extract keys or attributes.
- target – The object to fill.
- defaults (Either a bool, a dictionary, an iterable or a callable.) – Default values for the attributes to be copied as explained below. Defaults to False.
Every
sourcesandtargetare always positional arguments. There should be at least one source.targetwill always be the last positional argument.If
defaultsis a dictionary or an iterable then only the names provided by itering overdefaultswill be copied. Ifdefaultsis a dictionary, and one of its key is not found in any of thesources, then the value of the key in the dictionary is copied totargetunless:- It’s the value
Undefined. - An exception object
- A sequence with is first value being a subclass of Exception. In which
case
adapt_exceptionis used.
In these cases a KeyError is raised if the key is not found in the sources.
If
defaultsis an iterable and a key is not found in any of the sources, None is copied totarget.If
defaultsis a callable then it should receive one positional arguments for the currentattribute nameand several keyword arguments (we passsource) and return either True or False if the attribute should be copied.If
defaultsis False (or None) only the attributes that do not start with a “_” are copied, if it’s True all attributes are copied.When
targetis not a mapping only valid Python identifiers will be copied.Each
sourceis considered a mapping if it’s an instance ofcollections.Mappingor aMappingProxyType.The
targetis considered a mapping if it’s an instance ofcollections.MutableMapping.Returns: target.Changed in version 1.7.0:
defaultsis now keyword only.
-
xotl.tools.objects.extract_attrs(obj, *names, default=Unset)[source]¶ Extracts all
namesfrom an object.If
objis a Mapping, the names will be search in the keys of theobj; otherwise the names are considered regular attribute names.If
defaultis Unset and any name is not found, an AttributeError is raised, otherwise thedefaultis used instead.Returns a tuple if there are more that one name, otherwise returns a single value.
New in version 1.4.0.
Changed in version 1.5.3: Each
namemay be a path like inget_traverser(), but only “.” is allowed as separator.
-
xotl.tools.objects.traverse(obj, path, default=Unset, sep='.', getter=None)[source]¶ Traverses an object’s hierarchy by performing an attribute get at each level.
This helps getting an attribute that is buried down several levels deep. For example:
traverse(request, 'session.somevalue')
If
defaultis not provided (i.e isUnset) and any component in the path is not found an AttributeError exceptions is raised.You may provide
septo change the default separator.You may provide a custom
getter. By default, does ansmart_getter()over the objects. If providedgettershould have the signature ofgetattr().See
get_traverser()if you need to apply the same path(s) to several objects. Actually this is equivalent to:get_traverser(path, default=default, sep=sep, getter=getter)(obj)
-
xotl.tools.objects.get_traverser(*paths, default=Unset, sep='.', getter=None)[source]¶ Combines the power of
traverse()with the expectations from bothoperator.itemgetter()andoperator.attrgetter().Parameters: paths – Several paths to extract. Keyword arguments has the same meaning as in
traverse().Returns: A function the when invoked with an objecttraverse the object finding eachpath.New in version 1.5.3.
-
xotl.tools.objects.dict_merge(*dicts, **other)[source]¶ Merges several dicts into a single one.
Merging is similar to updating a dict, but if values are non-scalars they are also merged is this way:
- Any two
sequencesorsetsare joined together. - Any two mappings are recursively merged.
- Other types are just replaced like in
update().
If for a single key two values of incompatible types are found, raise a TypeError. If the values for a single key are compatible but different (i.e a list an a tuple) the resultant type will be the type of the first apparition of the key, unless for mappings which are always cast to dicts.
No matter the types of
dictsthe result is always a dict.Without arguments, return the empty dict.
- Any two
-
xotl.tools.objects.pop_first_of(source, *keys, default=None)[source]¶ Similar to
get_first_of()using assourceeither an object or a mapping and deleting the first attribute or key.Examples:
>>> somedict = dict(bar='bar-dict', eggs='eggs-dict') >>> class Foo: pass >>> foo = Foo() >>> foo.bar = 'bar-obj' >>> foo.eggs = 'eggs-obj' >>> pop_first_of((somedict, foo), 'eggs') 'eggs-dict' >>> pop_first_of((somedict, foo), 'eggs') 'eggs-obj' >>> pop_first_of((somedict, foo), 'eggs') is None True >>> pop_first_of((foo, somedict), 'bar') 'bar-obj' >>> pop_first_of((foo, somedict), 'bar') 'bar-dict' >>> pop_first_of((foo, somedict), 'bar') is None True
-
xotl.tools.objects.fix_method_documentation(cls, method_name, ignore=None, min_length=10, deep=1, default=None)[source]¶ Fix the documentation for the given class using its super-classes.
This function may be useful for shells or Python Command Line Interfaces (CLI).
If
clshas an invalid documentation, super-classes are recursed in MRO until a documentation definition was made at any level.Parameters: - ignore – could be used to specify which classes to ignore by specifying its name in this list.
- min_length – specify that documentations with less that a number of characters, also are ignored.
-
xotl.tools.objects.multi_getter(source, *ids)[source]¶ Get values from
sourceof all givenids.Parameters: - source – Any object but dealing with differences between mappings and other object types.
- ids –
Identifiers to get values from
source.An ID item could be:
- a string: is considered a key, if
sourceis a mapping, or an attribute name ifsourceis an instance of any other type. - a collection of strings: find the first valid value in
sourceevaluating each item in this collection using the above logic.
- a string: is considered a key, if
Example:
>>> d = {'x': 1, 'y': 2, 'z': 3} >>> list(multi_getter(d, 'a', ('y', 'x'), ('x', 'y'), ('a', 'z', 'x'))) [None, 2, 1, 3] >>> next(multi_getter(d, ('y', 'x'), ('x', 'y')), '---') 2 >>> next(multi_getter(d, 'a', ('b', 'c'), ('e', 'f')), '---') is None True
New in version 1.7.1.
-
xotl.tools.objects.get_branch_subclasses(cls, *, include_this=False, without_duplicates=False)[source]¶ Similar to
type.__subclasses__()but recursive.Only return sub-classes in branches (those with no sub-classes). Return a list of all classes reachable from
cls.The same class can be included more than once if there are two different paths from
clsto that class:>>> class Foo: pass >>> class Bar(Foo): pass >>> class Baz(Foo): pass >>> class Final(Bar, Baz): pass >>> get_branch_subclasses(Foo) == [Final, Final] True
You can set
without_duplicatesto True to avoid this:>>> get_branch_subclasses(Foo, without_duplicates=True) == [Final] True
New in version 1.7.0.
Changed in version 2.1.5: Add keyword-only argument
include_this.Changed in version 2.2.5: Add keyword-only argument
without_duplicates.
-
xotl.tools.objects.iter_branch_subclasses(cls, include_this=True, without_duplicates=False)[source]¶ Internal function, see
get_branch_subclasses().
-
xotl.tools.objects.FinalSubclassEnumeration(superclass, *, dynamic=True)[source]¶ A final sub-class enumeration.
Return a enumeration-like class (i.e has
__members__and each attribute) that enumerates the final subclasses of a given superclass (not includingsuperclass).If
dynamicis True, don’t cache the subclasses; i.e if a new subclass is created after the enumeration, the __members__ dictionary will change.The resulting enumeration class has a method
invalidate_cache()which allows non-dynamic classes to update its underlying cache.New in version 2.1.0.
-
xotl.tools.objects.save_attributes(obj, *attributes, getter=None, setter=None)[source]¶ A context manager that restores
objattributes at exit.We deal with
obj’s attributes withsmart_getter()andsmart_setter(). You can override passing keywordgetterandsetter. They must take the object and return a callable to get/set the its attributes.Basic example:
>>> from xotl.tools.future.types import SimpleNamespace as new >>> obj = new(a=1, b=2) >>> with save_attributes(obj, 'a'): ... obj.a = 2 ... obj.b = 3 >>> obj.a 1 >>> obj.b 3
Depending on the behavior of
getterand or the object itself, it may be an error to get an attribute or key that does not exists.>>> getter = lambda o: lambda a: getattr(o, a) >>> with save_attributes(obj, 'c', getter=getter): ... pass Traceback (...) ... AttributeError: ...
Beware, however, that
smart_getter()is non-strict by default and it returns None for a non-existing key or attribute. In this case, we attempt to set that attribute or key at exit:>>> with save_attributes(obj, 'x'): ... pass >>> obj.x is None True
But, then, setting the value may fail:
>>> obj = object() >>> with save_attribute(obj, 'x'): ... pass Traceback (...) ... AttributeError: ...
New in version 1.8.2.
-
xotl.tools.objects.temp_attributes(obj, attrs, getter=None, setter=None)[source]¶ A context manager that temporarily sets attributes.
attrsis a dictionary containing the attributes to set.Keyword arguments
getterandsetterhave the same meaning as insave_attributes(). We also use thesetterto set the values provided inattrs.New in version 1.8.5.
-
class
xotl.tools.objects.memoized_property[source]¶ A read-only property that is only evaluated once.
In Python 3.8+ this is based on
functools.cached_property.In Python version before 3.8, this code is extracted from the SQLAlchemy project’s codebase, merit and copyright goes to SQLAlchemy authors:
Copyright (C) 2005-2011 the SQLAlchemy authors and contributors This module is part of SQLAlchemy and is released under the MIT License: http://www.opensource.org/licenses/mit-license.php
New in version 1.8.1: Ported from
xoutil.decorator.memoized_property.New in version 2.11.0: Subclass of
functools.cached_propertyin Python 3.8+.
-
xotl.tools.objects.delegator(attribute, attrs_map, metaclass=<class 'type'>)[source]¶ Create a base class that delegates attributes to another object.
The returned base class contains a
delegated attribute descriptorfor each key inattrs_map.Parameters: - attribute – The attribute of the delegating object that holds the delegated attributes.
- attrs_map – A map of attributes to delegate. The keys are the attribute names the delegating object attributes, and the values the attribute names of the delegated object.
Example:
>>> class Bar: ... x = 'bar'
>>> class Foo(delegator('egg', {'x1': 'x'})): ... def __init__(self): ... self.egg = Bar()
>>> foo = Foo() >>> foo.x1 'bar'
New in version 1.9.3.
-
class
xotl.tools.objects.DelegatedAttribute(target_name, delegated_attr, default=Unset)[source]¶ A delegator data descriptor.
When accessed the descriptor finds the
delegated_attrin the instance’s value given by attributetarget_name.If the instance has no attribute with name
target_name, raise an AttributeError.If the target object does not have an attribute with name
delegate_attranddefaultisUnset, raise an AttributeError. Ifdefaultis not Unset, returndefault.New in version 1.9.3.