def __getattr__(self, attr: str):
    """Fallback to get a missing method from an HandledEffectRef."""
    eff_proto = self.effect_protocol()
    if hasattr(eff_proto, attr) and callable(getattr(eff_proto, attr)):
      # This attribute is a protocol method of the effect. This probably means
      # that some layer is trying to access an effect that we haven't yet
      # actually replaced with an implementation.
      def unhandled_effect_stub(*args, **kwargs):
        del args, kwargs
        raise UnhandledEffectError(
            f"Effect method {repr(attr)} was called on an unbound effect"
            f" reference {self}! Layers with side"
            " effects should only be called using the handler that handles"
            " those effects. This error usually means that an effectful node"
            " was removed from its handler without actually handling the"
            " effect first."
        )

      return unhandled_effect_stub
    else:
      raise AttributeError(
          f"'{type(self).__name__}' object has no attribute '{attr}'",
          name=attr,
          obj=self,
      )
Fallback to get a missing method from an HandledEffectRef.
penzai/deprecated/v1/data_effects/effect_base.py