Spaces:
Sleeping
Sleeping
# Copyright 2015 gRPC authors. | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
"""Utilities for working with callables.""" | |
from abc import ABC | |
import collections | |
import enum | |
import functools | |
import logging | |
_LOGGER = logging.getLogger(__name__) | |
class Outcome(ABC): | |
"""A sum type describing the outcome of some call. | |
Attributes: | |
kind: One of Kind.RETURNED or Kind.RAISED respectively indicating that the | |
call returned a value or raised an exception. | |
return_value: The value returned by the call. Must be present if kind is | |
Kind.RETURNED. | |
exception: The exception raised by the call. Must be present if kind is | |
Kind.RAISED. | |
""" | |
class Kind(enum.Enum): | |
"""Identifies the general kind of the outcome of some call.""" | |
RETURNED = object() | |
RAISED = object() | |
class _EasyOutcome( | |
collections.namedtuple( | |
"_EasyOutcome", ["kind", "return_value", "exception"] | |
), | |
Outcome, | |
): | |
"""A trivial implementation of Outcome.""" | |
def _call_logging_exceptions(behavior, message, *args, **kwargs): | |
try: | |
return _EasyOutcome( | |
Outcome.Kind.RETURNED, behavior(*args, **kwargs), None | |
) | |
except Exception as e: # pylint: disable=broad-except | |
_LOGGER.exception(message) | |
return _EasyOutcome(Outcome.Kind.RAISED, None, e) | |
def with_exceptions_logged(behavior, message): | |
"""Wraps a callable in a try-except that logs any exceptions it raises. | |
Args: | |
behavior: Any callable. | |
message: A string to log if the behavior raises an exception. | |
Returns: | |
A callable that when executed invokes the given behavior. The returned | |
callable takes the same arguments as the given behavior but returns a | |
future.Outcome describing whether the given behavior returned a value or | |
raised an exception. | |
""" | |
def wrapped_behavior(*args, **kwargs): | |
return _call_logging_exceptions(behavior, message, *args, **kwargs) | |
return wrapped_behavior | |
def call_logging_exceptions(behavior, message, *args, **kwargs): | |
"""Calls a behavior in a try-except that logs any exceptions it raises. | |
Args: | |
behavior: Any callable. | |
message: A string to log if the behavior raises an exception. | |
*args: Positional arguments to pass to the given behavior. | |
**kwargs: Keyword arguments to pass to the given behavior. | |
Returns: | |
An Outcome describing whether the given behavior returned a value or raised | |
an exception. | |
""" | |
return _call_logging_exceptions(behavior, message, *args, **kwargs) | |