Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Allow partial instantiation with factories #2981

Open
hobbeshunter opened this issue Nov 13, 2024 · 0 comments
Open

[Feature Request] Allow partial instantiation with factories #2981

hobbeshunter opened this issue Nov 13, 2024 · 0 comments
Labels
enhancement Enhanvement request

Comments

@hobbeshunter
Copy link

🚀 Feature Request

Add some way to not instantiate the whole config tree but stop when parameters are missing and create a factory (that needs to receive the missing parameters) instead.

Motivation

I have a config tree with many target objects that I instantiate with hydra. However, sometimes it happens that a class has both: parameters that are config params and parameters that are just known at runtime. So it would be nice if hydra would detect when parameters are missing and return a factory instead.

Pitch

I came up with a hacky solution that requires changes to omegaconf (see hobbeshunter/omegaconf@master...hobbeshunter:omegaconf:non-strict-resolve) and hydra (see hobbeshunter/hydra@main...hobbeshunter:hydra:instantiate-factory).

With a little helper class

class Factory:

    def __init__(self, cfg: DictConfig):
        self._cfg = cfg
        self._cfg._set_flag(flags=["allow_objects", "struct", "readonly"],
                            values=[True, False, False])

    def __call__(self, _name_: str, **kwargs):
        cfg = OmegaConf.merge(self._cfg, kwargs)
        return instantiate(cfg.__getattr__(_name_), _convert_="object")

a config could look like:

_target_: my_package.FactoryReceiver
  factory:
    _target_: hydra.utils.Factory
      _recursive_: false
      cfg:
        a: ???
        instance:
          _target_: my_package.BClass
            a: ${..a}
            b: 5

A FactoryReceiver could e.g. look like

class FactoryReceiver:

    def __init__(self, factory: Factory):
        self._factory = factory

    def do_something(self):
        my_instance = self._factory(_name_="instance", a=7)

As can be seen above FactoryReceiver only has to know that it can instantiate an object named instance by providing an a. Instance can be arbitrarily complex.

IMHO that allows for nice parametrizable object composition.

@hobbeshunter hobbeshunter added the enhancement Enhanvement request label Nov 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Enhanvement request
Projects
None yet
Development

No branches or pull requests

1 participant