docstr: Dependency injection.
  
  This will inject values from settings if available and not passed
  directly::
  
      @settings._inject("foo")
      def fn(foo=1):
          return foo
  
      # Since foo is not available in settings, the functions default
      # value is taken.
      assert fn() == 1
  
      with settings._let(foo=2):
          # Since foo is declared in the settings, it is used.
          assert fn() == 2
  
          # Directly passed values always take precedence.
          assert fn(3) == 3
code: def _inject(self, *keys, **kwargs):
      """
      Dependency injection.
  
      This will inject values from settings if available and not passed
      directly::
  
          @settings._inject("foo")
          def fn(foo=1):
              return foo
  
          # Since foo is not available in settings, the functions default
          # value is taken.
          assert fn() == 1
  
          with settings._let(foo=2):
              # Since foo is declared in the settings, it is used.
              assert fn() == 2
  
              # Directly passed values always take precedence.
              assert fn(3) == 3
      """
  
      def dec(fn):
          # We need the signature to be able to assemble the args later.
          sig = inspect.signature(fn)
  
          getters = {}
  
          for key in keys:
              assert (
                  key in sig.parameters
              ), f"Key {key} not in arguments."
              getters[key] = attrgetter(key)
  
          for key, path in kwargs.items():
              assert (
                  key in sig.parameters
              ), f"Key {key} not in arguments."
              assert key not in getters, f"Key {key} defined twice."
              getters[key] = attrgetter(path)
  
          @functools.wraps(fn)
          def wrapper(*args, **kwargs):
              # arguments are always keyword params
              arguments = sig.bind_partial(*args, **kwargs).arguments
  
              setting_kwargs = {}
  
              for key, getter in getters.items():
                  if key not in arguments:
                      try:
                          setting_kwargs[key] = getter(self)
                      except (KeyError, AttributeError):
                          continue
  
              return fn(**arguments, **setting_kwargs)
  
          return wrapper
  
      return dec
  
imports: import functools
  import inspect
  import itertools
  from operator import attrgetter
  from typing import Any
  from gluonts.pydantic import pydantic, deep_update
label_desc: Use image node_id 17 for calling the Settings obj's underlying member method code with example usage: obj._inject() and returns: dec, wrapper, fn