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 |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The instantiated object with the given parameters. |
Raises:
| Type | Description |
|---|---|
ImportError
|
if the target cannot be found. |
TypeError
|
if |
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 |
ImportError
|
if |
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 |
'__init__'
|
**kwargs
|
Any
|
Keyword arguments to pass to the class constructor or callable. |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The instantiated object if |
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
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
|
|
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 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 |
required |
cls
|
type[T]
|
The expected type. Used to validate the resolved object,
whether |
object
|
Returns:
| Type | Description |
|---|---|
T
|
A configured instance of |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
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
... )