Decorate a function or a class's __init__ method so that it can be called with a :class:`CfgNode` object using a :func:`from_config` function that translates :class:`CfgNode` to arguments. Examples: :: # Usage 1: Decorator on __init__: class A: @conf
(init_func=None, *, from_config=None)
| 5 | import inspect |
| 6 | |
| 7 | def configurable(init_func=None, *, from_config=None): |
| 8 | """ |
| 9 | Decorate a function or a class's __init__ method so that it can be called |
| 10 | with a :class:`CfgNode` object using a :func:`from_config` function that translates |
| 11 | :class:`CfgNode` to arguments. |
| 12 | |
| 13 | Examples: |
| 14 | :: |
| 15 | # Usage 1: Decorator on __init__: |
| 16 | class A: |
| 17 | @configurable |
| 18 | def __init__(self, a, b=2, c=3): |
| 19 | pass |
| 20 | |
| 21 | @classmethod |
| 22 | def from_config(cls, cfg): # 'cfg' must be the first argument |
| 23 | # Returns kwargs to be passed to __init__ |
| 24 | return {"a": cfg.A, "b": cfg.B} |
| 25 | |
| 26 | a1 = A(a=1, b=2) # regular construction |
| 27 | a2 = A(cfg) # construct with a cfg |
| 28 | a3 = A(cfg, b=3, c=4) # construct with extra overwrite |
| 29 | |
| 30 | # Usage 2: Decorator on any function. Needs an extra from_config argument: |
| 31 | @configurable(from_config=lambda cfg: {"a: cfg.A, "b": cfg.B}) |
| 32 | def a_func(a, b=2, c=3): |
| 33 | pass |
| 34 | |
| 35 | a1 = a_func(a=1, b=2) # regular call |
| 36 | a2 = a_func(cfg) # call with a cfg |
| 37 | a3 = a_func(cfg, b=3, c=4) # call with extra overwrite |
| 38 | |
| 39 | Args: |
| 40 | init_func (callable): a class's ``__init__`` method in usage 1. The |
| 41 | class must have a ``from_config`` classmethod which takes `cfg` as |
| 42 | the first argument. |
| 43 | from_config (callable): the from_config function in usage 2. It must take `cfg` |
| 44 | as its first argument. |
| 45 | """ |
| 46 | |
| 47 | if init_func is not None: |
| 48 | assert ( |
| 49 | inspect.isfunction(init_func) |
| 50 | and from_config is None |
| 51 | and init_func.__name__ == "__init__" |
| 52 | ), "Incorrect use of @configurable. Check API documentation for examples." |
| 53 | |
| 54 | @functools.wraps(init_func) |
| 55 | def wrapped(self, *args, **kwargs): |
| 56 | try: |
| 57 | from_config_func = type(self).from_config |
| 58 | except AttributeError as e: |
| 59 | raise AttributeError( |
| 60 | "Class with @configurable must have a 'from_config' classmethod." |
| 61 | ) from e |
| 62 | if not inspect.ismethod(from_config_func): |
| 63 | raise TypeError("Class with @configurable must have a 'from_config' classmethod.") |
| 64 |
nothing calls this directly
no outgoing calls
no test coverage detected