Skip to content

Factory

coola.factory

Contain factory utilities.

coola.factory.factory

factory(_target_: str, *args: Any, **kwargs: Any) -> Any

Instantiate dynamically an object given its configuration.

This function provides a universal factory that can instantiate any class or call any function by its fully qualified name. Unlike the AbstractFactory or Registry approaches, this function does not require prior registration of classes.

Parameters:

Name Type Description Default
_target_ str

The fully qualified name of the object (class or function) to instantiate, e.g., "collections.Counter" or "math.isclose".

required
*args Any

Positional arguments to pass to the class constructor or function.

()
**kwargs Any

Keyword arguments to pass to the class constructor or function. The special OBJECT_INIT ("_init_") key controls the function or method used to create the object. If "__init__" (default), the object is created by calling the constructor. Can also be "__new__" or the name of a class method.

{}

Returns:

Type Description
Any

The instantiated object with the given parameters.

Raises:

Type Description
ImportError

if the target cannot be found.

TypeError

if _target_ is not a string.

Security

_target_ is imported and called with no allowlist or restriction on which module or class it may reference: this function will import arbitrary module code and instantiate or call arbitrary objects from a dotted path string. Only pass a _target_ that comes from a trusted source (e.g. code you wrote, or a configuration file you control). Never resolve a _target_ derived from untrusted input, such as a third-party-uploaded config file or a network payload, as this is a remote-code-execution vector.

Example
>>> from coola.factory import factory
>>> factory("collections.Counter", [1, 2, 1, 3])
Counter({1: 2, 2: 1, 3: 1})

coola.factory.import_object

import_object(object_path: str) -> Any

Import an object given its path.

This function dynamically imports a class, function, or other Python object using its fully qualified name. The object path should have the structure module_path.object_name (e.g., "collections.Counter" or "math.isclose").

Parameters:

Name Type Description Default
object_path str

The fully qualified path of the object to import. Must be a string in the format "module.path.ObjectName".

required

Returns:

Type Description
Any

The imported object.

Raises:

Type Description
TypeError

if object_path is not a string.

ImportError

if object_path cannot be imported.

Security

This function imports arbitrary module code with no allowlist or restriction on which module or attribute it may reference: importing a module executes its top-level code. Only pass an object_path that comes from a trusted source. Never resolve an object_path derived from untrusted input, such as a third-party-uploaded config file or a network payload, as this is a remote-code-execution vector.

Example
>>> from coola.factory import import_object
>>> cls = import_object("collections.Counter")
>>> cls()
Counter()
>>> fn = import_object("math.isclose")
>>> fn(1, 1)
True
>>> pi = import_object("math.pi")
>>> pi
3.141592653589793
>>> pkg = import_object("math")
>>> pkg
<module 'math' (built-in)>

coola.factory.instantiate_object

instantiate_object(
    obj: Callable | type,
    *args: Any,
    _init_: str = "__init__",
    **kwargs: Any,
) -> Any

Instantiate dynamically an object from its configuration.

This function creates an instance of a class or calls a callable with the provided arguments. For classes, it supports different instantiation methods (constructor, new, or class methods). For any other callable (function, builtin, functools.partial, or an object implementing __call__), it simply calls it with the given arguments.

Parameters:

Name Type Description Default
obj Callable | type

The class to instantiate or the callable to call. Must be a class or a callable object.

required
*args Any

Positional arguments to pass to the class constructor or callable.

()
_init_ str

The function or method to use to create the object. This parameter is ignored if obj is not a class. For classes, if "__init__" (default), the object is created by calling the constructor. Can also be "__new__" or the name of a class method.

'__init__'
**kwargs Any

Keyword arguments to pass to the class constructor or callable.

{}

Returns:

Type Description
Any

The instantiated object if obj is a class, otherwise the returned value of the callable.

Raises:

Type Description
TypeError

if obj is not a class or a callable.

Warning

"__new__" bypasses cls.__init__ entirely: it calls cls.__new__(cls, *args, **kwargs) and returns the result as-is, so the object's __init__ is never invoked. Unlike cls(*args, **kwargs), which always runs __new__ then __init__, this can silently produce a partially-initialized object if the caller expected the usual two-step semantics.

Security

obj is instantiated or called with the given arguments with no allowlist or restriction on what it may do: an arbitrary class or callable will be invoked as-is. Only pass an obj (and _init_) that come from a trusted source. Never instantiate an object whose class/callable or arguments are derived from untrusted input, as this is a remote-code-execution vector.

Example
>>> from collections import Counter
>>> from coola.factory import instantiate_object
>>> instantiate_object(Counter, [1, 2, 1])
Counter({1: 2, 2: 1})
>>> instantiate_object(list, [1, 2, 1])
[1, 2, 1]

coola.factory.is_object_config

is_object_config(config: dict[str, Any], cls: type) -> bool

Indicate if the input configuration is a configuration for a given class.

This function only checks if the value of the key _target_ is valid. It does not check the other values. If _target_ indicates a function, the returned type hint is used to check the class.

Parameters:

Name Type Description Default
config dict[str, Any]

The configuration to check.

required
cls type

The object class.

required

Returns:

Type Description
bool

True if the input configuration is a configuration for the given class.

Example
>>> from coola.factory import is_object_config
>>> from collections import Counter
>>> is_object_config({"_target_": "collections.Counter", "iterable": [1, 2, 1, 3]}, Counter)
True

coola.factory.resolve_object

resolve_object(
    obj: T | dict[str, Any], cls: type[T] = object
) -> T

Resolve an instance of cls from an existing object or a configuration dictionary.

If obj is already an instance of cls it is returned as-is. Otherwise, if it is a :class:dict, it is treated as a factory configuration and instantiated via :func:coola.factory.factory.

Note

If cls is itself a :class:dict subclass (e.g. Counter or OrderedDict), a dict (or dict subclass) instance that is already a valid instance of cls is returned as-is rather than being treated as a factory configuration. Any other :class:dict is treated as a factory configuration, including a plain :class:dict used to describe how to build a dict-subclass instance, and a dict subclass instance that is not itself a valid cls instance (e.g. a Counter when cls is OrderedDict).

Parameters:

Name Type Description Default
obj T | dict[str, Any]

Either a fully configured instance of cls, or a :class:dict containing a factory specification (must include a "_target_" key pointing to the fully-qualified class name).

required
cls type[T]

The expected type. Used to validate the resolved object, whether obj was already an instance or was built from a configuration dictionary. Defaults to :class:object, which accepts any resolved value without validation.

object

Returns:

Type Description
T

A configured instance of cls.

Raises:

Type Description
TypeError

If obj is a :class:dict missing the "_target_" key, or if the resolved object is not an instance of cls.

Security

When obj is a :class:dict, its "_target_" value is passed to :func:coola.factory.factory, which imports and instantiates arbitrary objects from a dotted path string with no allowlist. Only call this function with a configuration dictionary that comes from a trusted source; never resolve a _target_ derived from untrusted input, as this is a remote-code-execution vector.

Example
>>> from datetime import date
>>> from coola.factory import resolve_object
>>> # From an existing instance:
>>> d = resolve_object(date(2020, 1, 1), cls=date)
>>> # From a configuration dictionary:
>>> d = resolve_object(
...     {"_target_": "datetime.date", "year": 2020, "month": 1, "day": 1}, cls=date
... )