A node in a tree of Modules.
| 770 | kwargs_types = {k: type(v) for k, v in kwargs.items()} |
| 771 | new_exc = TypeError( |
| 772 | f"Type error when calling {self}.{method_fn} " |
| 773 | f"with args={args_types} and kwargs={kwargs_types}" |
| 774 | ) |
| 775 | setattr(new_exc, "_handled", True) |
| 776 | raise new_exc from e |
| 777 | |
| 778 | return wrap_method_fn |
| 779 | |
| 780 | |
| 781 | class Module(Configurable, metaclass=_PostInitMeta): |
| 782 | """A node in a tree of Modules.""" |
| 783 | |
| 784 | @config_class |
| 785 | class Config(Configurable.Config): |
| 786 | """Module config. |
| 787 | |
| 788 | Attributes: |
| 789 | name: Name of this module. |
| 790 | vlog: The maximum vlog level. If None, vlog is disabled. |
| 791 | """ |
| 792 | |
| 793 | name: Required[str] = REQUIRED |
| 794 | vlog: Optional[int] = None |
| 795 | |
| 796 | def __init__(self, cfg: Config, *, parent: Optional["Module"]): |
| 797 | super().__init__(cfg) |
| 798 | cfg = self.config |
| 799 | self._name = cfg.name |
| 800 | self._parent = parent # Avoid adding parent to self._modules. |
| 801 | self._children: dict[str, "Module"] = {} |
| 802 | # Mapping from descendant module name to relative path from current module. |
| 803 | self._paths_to_shared_modules: dict[str, list[str]] = {} |
| 804 | # Mapping from modules being shared by the current module, to the shared module name. |
| 805 | self._shared_module_names: dict["Module", str] = {} |
| 806 | self._vlog_level = cfg.vlog |
| 807 | |
| 808 | def __post_init__(self): |
| 809 | # Wrap methods after `__init__`, allowing access to child modules. |
| 810 | for method_name, method_fn in self._wrapped_methods_for_auto_child_context().items(): |
| 811 | setattr(self, method_name, method_fn) |
| 812 | |
| 813 | def _wrapped_methods_for_auto_child_context(self) -> dict[str, Callable]: |
| 814 | """Returns methods that have been wrapped and bound to `self`. |
| 815 | |
| 816 | This ensures that module methods are bound to the instance that defined the method, rather |
| 817 | than the instance that the method is assigned to in `__post_init__`. |
| 818 | |
| 819 | For example, `self.child._wrapped_methods_for_auto_child_context()` returns methods bound to |
| 820 | `self.child` rather than `self`, which affects what `self.config` points to within the |
| 821 | wrapped method. |
| 822 | |
| 823 | On the other hand, `self.child._methods_to_wrap_for_auto_child_context()` returns un-bound |
| 824 | methods of `self.child`. Subclasses will typically override this method to control which |
| 825 | methods of the subclass to wrap. |
| 826 | """ |
| 827 | methods = self._methods_to_wrap_for_auto_child_context() |
| 828 | return self._wrap_methods_with_auto_child_context(methods) |
| 829 |
nothing calls this directly
no outgoing calls
no test coverage detected