about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/grpc/framework
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/grpc/framework
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/grpc/framework')
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/__init__.py13
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/common/__init__.py13
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/common/cardinality.py26
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/common/style.py24
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/foundation/__init__.py13
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/foundation/abandonment.py22
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/foundation/callable_util.py98
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/foundation/future.py219
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/foundation/logging_pool.py72
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/foundation/stream.py43
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/foundation/stream_util.py148
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/interfaces/__init__.py13
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/__init__.py13
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/base.py328
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/utilities.py83
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/__init__.py13
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/face.py1084
-rw-r--r--.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/utilities.py245
18 files changed, 2470 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/__init__.py b/.venv/lib/python3.12/site-packages/grpc/framework/__init__.py
new file mode 100644
index 00000000..5fb4f3c3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/common/__init__.py b/.venv/lib/python3.12/site-packages/grpc/framework/common/__init__.py
new file mode 100644
index 00000000..5fb4f3c3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/common/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/common/cardinality.py b/.venv/lib/python3.12/site-packages/grpc/framework/common/cardinality.py
new file mode 100644
index 00000000..3d3d4d34
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/common/cardinality.py
@@ -0,0 +1,26 @@
+# 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.
+"""Defines an enum for classifying RPC methods by streaming semantics."""
+
+import enum
+
+
+@enum.unique
+class Cardinality(enum.Enum):
+    """Describes the streaming semantics of an RPC method."""
+
+    UNARY_UNARY = "request-unary/response-unary"
+    UNARY_STREAM = "request-unary/response-streaming"
+    STREAM_UNARY = "request-streaming/response-unary"
+    STREAM_STREAM = "request-streaming/response-streaming"
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/common/style.py b/.venv/lib/python3.12/site-packages/grpc/framework/common/style.py
new file mode 100644
index 00000000..10bf5f17
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/common/style.py
@@ -0,0 +1,24 @@
+# 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.
+"""Defines an enum for classifying RPC methods by control flow semantics."""
+
+import enum
+
+
+@enum.unique
+class Service(enum.Enum):
+    """Describes the control flow style of RPC method implementation."""
+
+    INLINE = "inline"
+    EVENT = "event"
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/foundation/__init__.py b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/__init__.py
new file mode 100644
index 00000000..5fb4f3c3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/foundation/abandonment.py b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/abandonment.py
new file mode 100644
index 00000000..c4cb7d5c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/abandonment.py
@@ -0,0 +1,22 @@
+# 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 indicating abandonment of computation."""
+
+
+class Abandoned(Exception):
+    """Indicates that some computation is being abandoned.
+
+    Abandoning a computation is different than returning a value or raising
+    an exception indicating some operational or programming defect.
+    """
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/foundation/callable_util.py b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/callable_util.py
new file mode 100644
index 00000000..b64131b4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/callable_util.py
@@ -0,0 +1,98 @@
+# 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.
+    """
+
+    @enum.unique
+    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.
+    """
+
+    @functools.wraps(behavior)
+    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)
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/foundation/future.py b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/future.py
new file mode 100644
index 00000000..73b0d0bd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/future.py
@@ -0,0 +1,219 @@
+# 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.
+"""A Future interface.
+
+Python doesn't have a Future interface in its standard library. In the absence
+of such a standard, three separate, incompatible implementations
+(concurrent.futures.Future, ndb.Future, and asyncio.Future) have appeared. This
+interface attempts to be as compatible as possible with
+concurrent.futures.Future. From ndb.Future it adopts a traceback-object accessor
+method.
+
+Unlike the concrete and implemented Future classes listed above, the Future
+class defined in this module is an entirely abstract interface that anyone may
+implement and use.
+
+The one known incompatibility between this interface and the interface of
+concurrent.futures.Future is that this interface defines its own CancelledError
+and TimeoutError exceptions rather than raising the implementation-private
+concurrent.futures._base.CancelledError and the
+built-in-but-only-in-3.3-and-later TimeoutError.
+"""
+
+import abc
+
+
+class TimeoutError(Exception):
+    """Indicates that a particular call timed out."""
+
+
+class CancelledError(Exception):
+    """Indicates that the computation underlying a Future was cancelled."""
+
+
+class Future(abc.ABC):
+    """A representation of a computation in another control flow.
+
+    Computations represented by a Future may be yet to be begun, may be ongoing,
+    or may have already completed.
+    """
+
+    # NOTE(nathaniel): This isn't the return type that I would want to have if it
+    # were up to me. Were this interface being written from scratch, the return
+    # type of this method would probably be a sum type like:
+    #
+    # NOT_COMMENCED
+    # COMMENCED_AND_NOT_COMPLETED
+    # PARTIAL_RESULT<Partial_Result_Type>
+    # COMPLETED<Result_Type>
+    # UNCANCELLABLE
+    # NOT_IMMEDIATELY_DETERMINABLE
+    @abc.abstractmethod
+    def cancel(self):
+        """Attempts to cancel the computation.
+
+        This method does not block.
+
+        Returns:
+          True if the computation has not yet begun, will not be allowed to take
+            place, and determination of both was possible without blocking. False
+            under all other circumstances including but not limited to the
+            computation's already having begun, the computation's already having
+            finished, and the computation's having been scheduled for execution on a
+            remote system for which a determination of whether or not it commenced
+            before being cancelled cannot be made without blocking.
+        """
+        raise NotImplementedError()
+
+    # NOTE(nathaniel): Here too this isn't the return type that I'd want this
+    # method to have if it were up to me. I think I'd go with another sum type
+    # like:
+    #
+    # NOT_CANCELLED (this object's cancel method hasn't been called)
+    # NOT_COMMENCED
+    # COMMENCED_AND_NOT_COMPLETED
+    # PARTIAL_RESULT<Partial_Result_Type>
+    # COMPLETED<Result_Type>
+    # UNCANCELLABLE
+    # NOT_IMMEDIATELY_DETERMINABLE
+    #
+    # Notice how giving the cancel method the right semantics obviates most
+    # reasons for this method to exist.
+    @abc.abstractmethod
+    def cancelled(self):
+        """Describes whether the computation was cancelled.
+
+        This method does not block.
+
+        Returns:
+          True if the computation was cancelled any time before its result became
+            immediately available. False under all other circumstances including but
+            not limited to this object's cancel method not having been called and
+            the computation's result having become immediately available.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def running(self):
+        """Describes whether the computation is taking place.
+
+        This method does not block.
+
+        Returns:
+          True if the computation is scheduled to take place in the future or is
+            taking place now, or False if the computation took place in the past or
+            was cancelled.
+        """
+        raise NotImplementedError()
+
+    # NOTE(nathaniel): These aren't quite the semantics I'd like here either. I
+    # would rather this only returned True in cases in which the underlying
+    # computation completed successfully. A computation's having been cancelled
+    # conflicts with considering that computation "done".
+    @abc.abstractmethod
+    def done(self):
+        """Describes whether the computation has taken place.
+
+        This method does not block.
+
+        Returns:
+          True if the computation is known to have either completed or have been
+            unscheduled or interrupted. False if the computation may possibly be
+            executing or scheduled to execute later.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def result(self, timeout=None):
+        """Accesses the outcome of the computation or raises its exception.
+
+        This method may return immediately or may block.
+
+        Args:
+          timeout: The length of time in seconds to wait for the computation to
+            finish or be cancelled, or None if this method should block until the
+            computation has finished or is cancelled no matter how long that takes.
+
+        Returns:
+          The return value of the computation.
+
+        Raises:
+          TimeoutError: If a timeout value is passed and the computation does not
+            terminate within the allotted time.
+          CancelledError: If the computation was cancelled.
+          Exception: If the computation raised an exception, this call will raise
+            the same exception.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def exception(self, timeout=None):
+        """Return the exception raised by the computation.
+
+        This method may return immediately or may block.
+
+        Args:
+          timeout: The length of time in seconds to wait for the computation to
+            terminate or be cancelled, or None if this method should block until
+            the computation is terminated or is cancelled no matter how long that
+            takes.
+
+        Returns:
+          The exception raised by the computation, or None if the computation did
+            not raise an exception.
+
+        Raises:
+          TimeoutError: If a timeout value is passed and the computation does not
+            terminate within the allotted time.
+          CancelledError: If the computation was cancelled.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def traceback(self, timeout=None):
+        """Access the traceback of the exception raised by the computation.
+
+        This method may return immediately or may block.
+
+        Args:
+          timeout: The length of time in seconds to wait for the computation to
+            terminate or be cancelled, or None if this method should block until
+            the computation is terminated or is cancelled no matter how long that
+            takes.
+
+        Returns:
+          The traceback of the exception raised by the computation, or None if the
+            computation did not raise an exception.
+
+        Raises:
+          TimeoutError: If a timeout value is passed and the computation does not
+            terminate within the allotted time.
+          CancelledError: If the computation was cancelled.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def add_done_callback(self, fn):
+        """Adds a function to be called at completion of the computation.
+
+        The callback will be passed this Future object describing the outcome of
+        the computation.
+
+        If the computation has already completed, the callback will be called
+        immediately.
+
+        Args:
+          fn: A callable taking this Future object as its single parameter.
+        """
+        raise NotImplementedError()
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/foundation/logging_pool.py b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/logging_pool.py
new file mode 100644
index 00000000..a4e140f1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/logging_pool.py
@@ -0,0 +1,72 @@
+# 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.
+"""A thread pool that logs exceptions raised by tasks executed within it."""
+
+from concurrent import futures
+import logging
+
+_LOGGER = logging.getLogger(__name__)
+
+
+def _wrap(behavior):
+    """Wraps an arbitrary callable behavior in exception-logging."""
+
+    def _wrapping(*args, **kwargs):
+        try:
+            return behavior(*args, **kwargs)
+        except Exception:
+            _LOGGER.exception(
+                "Unexpected exception from %s executed in logging pool!",
+                behavior,
+            )
+            raise
+
+    return _wrapping
+
+
+class _LoggingPool(object):
+    """An exception-logging futures.ThreadPoolExecutor-compatible thread pool."""
+
+    def __init__(self, backing_pool):
+        self._backing_pool = backing_pool
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self._backing_pool.shutdown(wait=True)
+
+    def submit(self, fn, *args, **kwargs):
+        return self._backing_pool.submit(_wrap(fn), *args, **kwargs)
+
+    def map(self, func, *iterables, **kwargs):
+        return self._backing_pool.map(
+            _wrap(func), *iterables, timeout=kwargs.get("timeout", None)
+        )
+
+    def shutdown(self, wait=True):
+        self._backing_pool.shutdown(wait=wait)
+
+
+def pool(max_workers):
+    """Creates a thread pool that logs exceptions raised by the tasks within it.
+
+    Args:
+      max_workers: The maximum number of worker threads to allow the pool.
+
+    Returns:
+      A futures.ThreadPoolExecutor-compatible thread pool that logs exceptions
+        raised by the tasks executed within it.
+    """
+    return _LoggingPool(futures.ThreadPoolExecutor(max_workers))
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/foundation/stream.py b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/stream.py
new file mode 100644
index 00000000..70ca1d91
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/stream.py
@@ -0,0 +1,43 @@
+# 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.
+"""Interfaces related to streams of values or objects."""
+
+import abc
+
+
+class Consumer(abc.ABC):
+    """Interface for consumers of finite streams of values or objects."""
+
+    @abc.abstractmethod
+    def consume(self, value):
+        """Accepts a value.
+
+        Args:
+          value: Any value accepted by this Consumer.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def terminate(self):
+        """Indicates to this Consumer that no more values will be supplied."""
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def consume_and_terminate(self, value):
+        """Supplies a value and signals that no more values will be supplied.
+
+        Args:
+          value: Any value accepted by this Consumer.
+        """
+        raise NotImplementedError()
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/foundation/stream_util.py b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/stream_util.py
new file mode 100644
index 00000000..1faaf29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/foundation/stream_util.py
@@ -0,0 +1,148 @@
+# 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.
+"""Helpful utilities related to the stream module."""
+
+import logging
+import threading
+
+from grpc.framework.foundation import stream
+
+_NO_VALUE = object()
+_LOGGER = logging.getLogger(__name__)
+
+
+class TransformingConsumer(stream.Consumer):
+    """A stream.Consumer that passes a transformation of its input to another."""
+
+    def __init__(self, transformation, downstream):
+        self._transformation = transformation
+        self._downstream = downstream
+
+    def consume(self, value):
+        self._downstream.consume(self._transformation(value))
+
+    def terminate(self):
+        self._downstream.terminate()
+
+    def consume_and_terminate(self, value):
+        self._downstream.consume_and_terminate(self._transformation(value))
+
+
+class IterableConsumer(stream.Consumer):
+    """A Consumer that when iterated over emits the values it has consumed."""
+
+    def __init__(self):
+        self._condition = threading.Condition()
+        self._values = []
+        self._active = True
+
+    def consume(self, value):
+        with self._condition:
+            if self._active:
+                self._values.append(value)
+                self._condition.notify()
+
+    def terminate(self):
+        with self._condition:
+            self._active = False
+            self._condition.notify()
+
+    def consume_and_terminate(self, value):
+        with self._condition:
+            if self._active:
+                self._values.append(value)
+                self._active = False
+                self._condition.notify()
+
+    def __iter__(self):
+        return self
+
+    def __next__(self):
+        return self.next()
+
+    def next(self):
+        with self._condition:
+            while self._active and not self._values:
+                self._condition.wait()
+            if self._values:
+                return self._values.pop(0)
+            else:
+                raise StopIteration()
+
+
+class ThreadSwitchingConsumer(stream.Consumer):
+    """A Consumer decorator that affords serialization and asynchrony."""
+
+    def __init__(self, sink, pool):
+        self._lock = threading.Lock()
+        self._sink = sink
+        self._pool = pool
+        # True if self._spin has been submitted to the pool to be called once and
+        # that call has not yet returned, False otherwise.
+        self._spinning = False
+        self._values = []
+        self._active = True
+
+    def _spin(self, sink, value, terminate):
+        while True:
+            try:
+                if value is _NO_VALUE:
+                    sink.terminate()
+                elif terminate:
+                    sink.consume_and_terminate(value)
+                else:
+                    sink.consume(value)
+            except Exception as e:  # pylint:disable=broad-except
+                _LOGGER.exception(e)
+
+            with self._lock:
+                if terminate:
+                    self._spinning = False
+                    return
+                elif self._values:
+                    value = self._values.pop(0)
+                    terminate = not self._values and not self._active
+                elif not self._active:
+                    value = _NO_VALUE
+                    terminate = True
+                else:
+                    self._spinning = False
+                    return
+
+    def consume(self, value):
+        with self._lock:
+            if self._active:
+                if self._spinning:
+                    self._values.append(value)
+                else:
+                    self._pool.submit(self._spin, self._sink, value, False)
+                    self._spinning = True
+
+    def terminate(self):
+        with self._lock:
+            if self._active:
+                self._active = False
+                if not self._spinning:
+                    self._pool.submit(self._spin, self._sink, _NO_VALUE, True)
+                    self._spinning = True
+
+    def consume_and_terminate(self, value):
+        with self._lock:
+            if self._active:
+                self._active = False
+                if self._spinning:
+                    self._values.append(value)
+                else:
+                    self._pool.submit(self._spin, self._sink, value, True)
+                    self._spinning = True
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/__init__.py b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/__init__.py
new file mode 100644
index 00000000..5fb4f3c3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/__init__.py b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/__init__.py
new file mode 100644
index 00000000..5fb4f3c3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/base.py b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/base.py
new file mode 100644
index 00000000..ea71ff6a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/base.py
@@ -0,0 +1,328 @@
+# 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.
+"""The base interface of RPC Framework.
+
+Implementations of this interface support the conduct of "operations":
+exchanges between two distinct ends of an arbitrary number of data payloads
+and metadata such as a name for the operation, initial and terminal metadata
+in each direction, and flow control. These operations may be used for transfers
+of data, remote procedure calls, status indication, or anything else
+applications choose.
+"""
+
+# threading is referenced from specification in this module.
+import abc
+import enum
+import threading  # pylint: disable=unused-import
+
+# pylint: disable=too-many-arguments
+
+
+class NoSuchMethodError(Exception):
+    """Indicates that an unrecognized operation has been called.
+
+    Attributes:
+      code: A code value to communicate to the other side of the operation
+        along with indication of operation termination. May be None.
+      details: A details value to communicate to the other side of the
+        operation along with indication of operation termination. May be None.
+    """
+
+    def __init__(self, code, details):
+        """Constructor.
+
+        Args:
+          code: A code value to communicate to the other side of the operation
+            along with indication of operation termination. May be None.
+          details: A details value to communicate to the other side of the
+            operation along with indication of operation termination. May be None.
+        """
+        super(NoSuchMethodError, self).__init__()
+        self.code = code
+        self.details = details
+
+
+class Outcome(object):
+    """The outcome of an operation.
+
+    Attributes:
+      kind: A Kind value coarsely identifying how the operation terminated.
+      code: An application-specific code value or None if no such value was
+        provided.
+      details: An application-specific details value or None if no such value was
+        provided.
+    """
+
+    @enum.unique
+    class Kind(enum.Enum):
+        """Ways in which an operation can terminate."""
+
+        COMPLETED = "completed"
+        CANCELLED = "cancelled"
+        EXPIRED = "expired"
+        LOCAL_SHUTDOWN = "local shutdown"
+        REMOTE_SHUTDOWN = "remote shutdown"
+        RECEPTION_FAILURE = "reception failure"
+        TRANSMISSION_FAILURE = "transmission failure"
+        LOCAL_FAILURE = "local failure"
+        REMOTE_FAILURE = "remote failure"
+
+
+class Completion(abc.ABC):
+    """An aggregate of the values exchanged upon operation completion.
+
+    Attributes:
+      terminal_metadata: A terminal metadata value for the operation.
+      code: A code value for the operation.
+      message: A message value for the operation.
+    """
+
+
+class OperationContext(abc.ABC):
+    """Provides operation-related information and action."""
+
+    @abc.abstractmethod
+    def outcome(self):
+        """Indicates the operation's outcome (or that the operation is ongoing).
+
+        Returns:
+          None if the operation is still active or the Outcome value for the
+            operation if it has terminated.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def add_termination_callback(self, callback):
+        """Adds a function to be called upon operation termination.
+
+        Args:
+          callback: A callable to be passed an Outcome value on operation
+            termination.
+
+        Returns:
+          None if the operation has not yet terminated and the passed callback will
+            later be called when it does terminate, or if the operation has already
+            terminated an Outcome value describing the operation termination and the
+            passed callback will not be called as a result of this method call.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def time_remaining(self):
+        """Describes the length of allowed time remaining for the operation.
+
+        Returns:
+          A nonnegative float indicating the length of allowed time in seconds
+          remaining for the operation to complete before it is considered to have
+          timed out. Zero is returned if the operation has terminated.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def cancel(self):
+        """Cancels the operation if the operation has not yet terminated."""
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def fail(self, exception):
+        """Indicates that the operation has failed.
+
+        Args:
+          exception: An exception germane to the operation failure. May be None.
+        """
+        raise NotImplementedError()
+
+
+class Operator(abc.ABC):
+    """An interface through which to participate in an operation."""
+
+    @abc.abstractmethod
+    def advance(
+        self,
+        initial_metadata=None,
+        payload=None,
+        completion=None,
+        allowance=None,
+    ):
+        """Progresses the operation.
+
+        Args:
+          initial_metadata: An initial metadata value. Only one may ever be
+            communicated in each direction for an operation, and they must be
+            communicated no later than either the first payload or the completion.
+          payload: A payload value.
+          completion: A Completion value. May only ever be non-None once in either
+            direction, and no payloads may be passed after it has been communicated.
+          allowance: A positive integer communicating the number of additional
+            payloads allowed to be passed by the remote side of the operation.
+        """
+        raise NotImplementedError()
+
+
+class ProtocolReceiver(abc.ABC):
+    """A means of receiving protocol values during an operation."""
+
+    @abc.abstractmethod
+    def context(self, protocol_context):
+        """Accepts the protocol context object for the operation.
+
+        Args:
+          protocol_context: The protocol context object for the operation.
+        """
+        raise NotImplementedError()
+
+
+class Subscription(abc.ABC):
+    """Describes customer code's interest in values from the other side.
+
+    Attributes:
+      kind: A Kind value describing the overall kind of this value.
+      termination_callback: A callable to be passed the Outcome associated with
+        the operation after it has terminated. Must be non-None if kind is
+        Kind.TERMINATION_ONLY. Must be None otherwise.
+      allowance: A callable behavior that accepts positive integers representing
+        the number of additional payloads allowed to be passed to the other side
+        of the operation. Must be None if kind is Kind.FULL. Must not be None
+        otherwise.
+      operator: An Operator to be passed values from the other side of the
+        operation. Must be non-None if kind is Kind.FULL. Must be None otherwise.
+      protocol_receiver: A ProtocolReceiver to be passed protocol objects as they
+        become available during the operation. Must be non-None if kind is
+        Kind.FULL.
+    """
+
+    @enum.unique
+    class Kind(enum.Enum):
+        NONE = "none"
+        TERMINATION_ONLY = "termination only"
+        FULL = "full"
+
+
+class Servicer(abc.ABC):
+    """Interface for service implementations."""
+
+    @abc.abstractmethod
+    def service(self, group, method, context, output_operator):
+        """Services an operation.
+
+        Args:
+          group: The group identifier of the operation to be serviced.
+          method: The method identifier of the operation to be serviced.
+          context: An OperationContext object affording contextual information and
+            actions.
+          output_operator: An Operator that will accept output values of the
+            operation.
+
+        Returns:
+          A Subscription via which this object may or may not accept more values of
+            the operation.
+
+        Raises:
+          NoSuchMethodError: If this Servicer does not handle operations with the
+            given group and method.
+          abandonment.Abandoned: If the operation has been aborted and there no
+            longer is any reason to service the operation.
+        """
+        raise NotImplementedError()
+
+
+class End(abc.ABC):
+    """Common type for entry-point objects on both sides of an operation."""
+
+    @abc.abstractmethod
+    def start(self):
+        """Starts this object's service of operations."""
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def stop(self, grace):
+        """Stops this object's service of operations.
+
+        This object will refuse service of new operations as soon as this method is
+        called but operations under way at the time of the call may be given a
+        grace period during which they are allowed to finish.
+
+        Args:
+          grace: A duration of time in seconds to allow ongoing operations to
+            terminate before being forcefully terminated by the stopping of this
+            End. May be zero to terminate all ongoing operations and immediately
+            stop.
+
+        Returns:
+          A threading.Event that will be set to indicate all operations having
+            terminated and this End having completely stopped. The returned event
+            may not be set until after the full grace period (if some ongoing
+            operation continues for the full length of the period) or it may be set
+            much sooner (if for example this End had no operations in progress at
+            the time its stop method was called).
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def operate(
+        self,
+        group,
+        method,
+        subscription,
+        timeout,
+        initial_metadata=None,
+        payload=None,
+        completion=None,
+        protocol_options=None,
+    ):
+        """Commences an operation.
+
+        Args:
+          group: The group identifier of the invoked operation.
+          method: The method identifier of the invoked operation.
+          subscription: A Subscription to which the results of the operation will be
+            passed.
+          timeout: A length of time in seconds to allow for the operation.
+          initial_metadata: An initial metadata value to be sent to the other side
+            of the operation. May be None if the initial metadata will be later
+            passed via the returned operator or if there will be no initial metadata
+            passed at all.
+          payload: An initial payload for the operation.
+          completion: A Completion value indicating the end of transmission to the
+            other side of the operation.
+          protocol_options: A value specified by the provider of a Base interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          A pair of objects affording information about the operation and action
+            continuing the operation. The first element of the returned pair is an
+            OperationContext for the operation and the second element of the
+            returned pair is an Operator to which operation values not passed in
+            this call should later be passed.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def operation_stats(self):
+        """Reports the number of terminated operations broken down by outcome.
+
+        Returns:
+          A dictionary from Outcome.Kind value to an integer identifying the number
+            of operations that terminated with that outcome kind.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def add_idle_action(self, action):
+        """Adds an action to be called when this End has no ongoing operations.
+
+        Args:
+          action: A callable that accepts no arguments.
+        """
+        raise NotImplementedError()
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/utilities.py b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/utilities.py
new file mode 100644
index 00000000..5b601f3b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/base/utilities.py
@@ -0,0 +1,83 @@
+# 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 use with the base interface of RPC Framework."""
+
+import collections
+
+from grpc.framework.interfaces.base import base
+
+
+class _Completion(
+    base.Completion,
+    collections.namedtuple(
+        "_Completion",
+        (
+            "terminal_metadata",
+            "code",
+            "message",
+        ),
+    ),
+):
+    """A trivial implementation of base.Completion."""
+
+
+class _Subscription(
+    base.Subscription,
+    collections.namedtuple(
+        "_Subscription",
+        (
+            "kind",
+            "termination_callback",
+            "allowance",
+            "operator",
+            "protocol_receiver",
+        ),
+    ),
+):
+    """A trivial implementation of base.Subscription."""
+
+
+_NONE_SUBSCRIPTION = _Subscription(
+    base.Subscription.Kind.NONE, None, None, None, None
+)
+
+
+def completion(terminal_metadata, code, message):
+    """Creates a base.Completion aggregating the given operation values.
+
+    Args:
+      terminal_metadata: A terminal metadata value for an operation.
+      code: A code value for an operation.
+      message: A message value for an operation.
+
+    Returns:
+      A base.Completion aggregating the given operation values.
+    """
+    return _Completion(terminal_metadata, code, message)
+
+
+def full_subscription(operator, protocol_receiver):
+    """Creates a "full" base.Subscription for the given base.Operator.
+
+    Args:
+      operator: A base.Operator to be used in an operation.
+      protocol_receiver: A base.ProtocolReceiver to be used in an operation.
+
+    Returns:
+      A base.Subscription of kind base.Subscription.Kind.FULL wrapping the given
+        base.Operator and base.ProtocolReceiver.
+    """
+    return _Subscription(
+        base.Subscription.Kind.FULL, None, None, operator, protocol_receiver
+    )
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/__init__.py b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/__init__.py
new file mode 100644
index 00000000..5fb4f3c3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/face.py b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/face.py
new file mode 100644
index 00000000..9239fcc9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/face.py
@@ -0,0 +1,1084 @@
+# 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.
+"""Interfaces defining the Face layer of RPC Framework."""
+
+import abc
+import collections
+import enum
+
+# cardinality, style, abandonment, future, and stream are
+# referenced from specification in this module.
+from grpc.framework.common import cardinality  # pylint: disable=unused-import
+from grpc.framework.common import style  # pylint: disable=unused-import
+from grpc.framework.foundation import future  # pylint: disable=unused-import
+from grpc.framework.foundation import stream  # pylint: disable=unused-import
+
+# pylint: disable=too-many-arguments
+
+
+class NoSuchMethodError(Exception):
+    """Raised by customer code to indicate an unrecognized method.
+
+    Attributes:
+      group: The group of the unrecognized method.
+      name: The name of the unrecognized method.
+    """
+
+    def __init__(self, group, method):
+        """Constructor.
+
+        Args:
+          group: The group identifier of the unrecognized RPC name.
+          method: The method identifier of the unrecognized RPC name.
+        """
+        super(NoSuchMethodError, self).__init__()
+        self.group = group
+        self.method = method
+
+    def __repr__(self):
+        return "face.NoSuchMethodError(%s, %s)" % (
+            self.group,
+            self.method,
+        )
+
+
+class Abortion(
+    collections.namedtuple(
+        "Abortion",
+        (
+            "kind",
+            "initial_metadata",
+            "terminal_metadata",
+            "code",
+            "details",
+        ),
+    )
+):
+    """A value describing RPC abortion.
+
+    Attributes:
+      kind: A Kind value identifying how the RPC failed.
+      initial_metadata: The initial metadata from the other side of the RPC or
+        None if no initial metadata value was received.
+      terminal_metadata: The terminal metadata from the other side of the RPC or
+        None if no terminal metadata value was received.
+      code: The code value from the other side of the RPC or None if no code value
+        was received.
+      details: The details value from the other side of the RPC or None if no
+        details value was received.
+    """
+
+    @enum.unique
+    class Kind(enum.Enum):
+        """Types of RPC abortion."""
+
+        CANCELLED = "cancelled"
+        EXPIRED = "expired"
+        LOCAL_SHUTDOWN = "local shutdown"
+        REMOTE_SHUTDOWN = "remote shutdown"
+        NETWORK_FAILURE = "network failure"
+        LOCAL_FAILURE = "local failure"
+        REMOTE_FAILURE = "remote failure"
+
+
+class AbortionError(Exception, metaclass=abc.ABCMeta):
+    """Common super type for exceptions indicating RPC abortion.
+
+    initial_metadata: The initial metadata from the other side of the RPC or
+      None if no initial metadata value was received.
+    terminal_metadata: The terminal metadata from the other side of the RPC or
+      None if no terminal metadata value was received.
+    code: The code value from the other side of the RPC or None if no code value
+      was received.
+    details: The details value from the other side of the RPC or None if no
+      details value was received.
+    """
+
+    def __init__(self, initial_metadata, terminal_metadata, code, details):
+        super(AbortionError, self).__init__()
+        self.initial_metadata = initial_metadata
+        self.terminal_metadata = terminal_metadata
+        self.code = code
+        self.details = details
+
+    def __str__(self):
+        return '%s(code=%s, details="%s")' % (
+            self.__class__.__name__,
+            self.code,
+            self.details,
+        )
+
+
+class CancellationError(AbortionError):
+    """Indicates that an RPC has been cancelled."""
+
+
+class ExpirationError(AbortionError):
+    """Indicates that an RPC has expired ("timed out")."""
+
+
+class LocalShutdownError(AbortionError):
+    """Indicates that an RPC has terminated due to local shutdown of RPCs."""
+
+
+class RemoteShutdownError(AbortionError):
+    """Indicates that an RPC has terminated due to remote shutdown of RPCs."""
+
+
+class NetworkError(AbortionError):
+    """Indicates that some error occurred on the network."""
+
+
+class LocalError(AbortionError):
+    """Indicates that an RPC has terminated due to a local defect."""
+
+
+class RemoteError(AbortionError):
+    """Indicates that an RPC has terminated due to a remote defect."""
+
+
+class RpcContext(abc.ABC):
+    """Provides RPC-related information and action."""
+
+    @abc.abstractmethod
+    def is_active(self):
+        """Describes whether the RPC is active or has terminated."""
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def time_remaining(self):
+        """Describes the length of allowed time remaining for the RPC.
+
+        Returns:
+          A nonnegative float indicating the length of allowed time in seconds
+          remaining for the RPC to complete before it is considered to have timed
+          out.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def add_abortion_callback(self, abortion_callback):
+        """Registers a callback to be called if the RPC is aborted.
+
+        Args:
+          abortion_callback: A callable to be called and passed an Abortion value
+            in the event of RPC abortion.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def cancel(self):
+        """Cancels the RPC.
+
+        Idempotent and has no effect if the RPC has already terminated.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def protocol_context(self):
+        """Accesses a custom object specified by an implementation provider.
+
+        Returns:
+          A value specified by the provider of a Face interface implementation
+            affording custom state and behavior.
+        """
+        raise NotImplementedError()
+
+
+class Call(RpcContext, metaclass=abc.ABCMeta):
+    """Invocation-side utility object for an RPC."""
+
+    @abc.abstractmethod
+    def initial_metadata(self):
+        """Accesses the initial metadata from the service-side of the RPC.
+
+        This method blocks until the value is available or is known not to have been
+        emitted from the service-side of the RPC.
+
+        Returns:
+          The initial metadata object emitted by the service-side of the RPC, or
+            None if there was no such value.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def terminal_metadata(self):
+        """Accesses the terminal metadata from the service-side of the RPC.
+
+        This method blocks until the value is available or is known not to have been
+        emitted from the service-side of the RPC.
+
+        Returns:
+          The terminal metadata object emitted by the service-side of the RPC, or
+            None if there was no such value.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def code(self):
+        """Accesses the code emitted by the service-side of the RPC.
+
+        This method blocks until the value is available or is known not to have been
+        emitted from the service-side of the RPC.
+
+        Returns:
+          The code object emitted by the service-side of the RPC, or None if there
+            was no such value.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def details(self):
+        """Accesses the details value emitted by the service-side of the RPC.
+
+        This method blocks until the value is available or is known not to have been
+        emitted from the service-side of the RPC.
+
+        Returns:
+          The details value emitted by the service-side of the RPC, or None if there
+            was no such value.
+        """
+        raise NotImplementedError()
+
+
+class ServicerContext(RpcContext, metaclass=abc.ABCMeta):
+    """A context object passed to method implementations."""
+
+    @abc.abstractmethod
+    def invocation_metadata(self):
+        """Accesses the metadata from the invocation-side of the RPC.
+
+        This method blocks until the value is available or is known not to have been
+        emitted from the invocation-side of the RPC.
+
+        Returns:
+          The metadata object emitted by the invocation-side of the RPC, or None if
+            there was no such value.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def initial_metadata(self, initial_metadata):
+        """Accepts the service-side initial metadata value of the RPC.
+
+        This method need not be called by method implementations if they have no
+        service-side initial metadata to transmit.
+
+        Args:
+          initial_metadata: The service-side initial metadata value of the RPC to
+            be transmitted to the invocation side of the RPC.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def terminal_metadata(self, terminal_metadata):
+        """Accepts the service-side terminal metadata value of the RPC.
+
+        This method need not be called by method implementations if they have no
+        service-side terminal metadata to transmit.
+
+        Args:
+          terminal_metadata: The service-side terminal metadata value of the RPC to
+            be transmitted to the invocation side of the RPC.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def code(self, code):
+        """Accepts the service-side code of the RPC.
+
+        This method need not be called by method implementations if they have no
+        code to transmit.
+
+        Args:
+          code: The code of the RPC to be transmitted to the invocation side of the
+            RPC.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def details(self, details):
+        """Accepts the service-side details of the RPC.
+
+        This method need not be called by method implementations if they have no
+        service-side details to transmit.
+
+        Args:
+          details: The service-side details value of the RPC to be transmitted to
+            the invocation side of the RPC.
+        """
+        raise NotImplementedError()
+
+
+class ResponseReceiver(abc.ABC):
+    """Invocation-side object used to accept the output of an RPC."""
+
+    @abc.abstractmethod
+    def initial_metadata(self, initial_metadata):
+        """Receives the initial metadata from the service-side of the RPC.
+
+        Args:
+          initial_metadata: The initial metadata object emitted from the
+            service-side of the RPC.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def response(self, response):
+        """Receives a response from the service-side of the RPC.
+
+        Args:
+          response: A response object emitted from the service-side of the RPC.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def complete(self, terminal_metadata, code, details):
+        """Receives the completion values emitted from the service-side of the RPC.
+
+        Args:
+          terminal_metadata: The terminal metadata object emitted from the
+            service-side of the RPC.
+          code: The code object emitted from the service-side of the RPC.
+          details: The details object emitted from the service-side of the RPC.
+        """
+        raise NotImplementedError()
+
+
+class UnaryUnaryMultiCallable(abc.ABC):
+    """Affords invoking a unary-unary RPC in any call style."""
+
+    @abc.abstractmethod
+    def __call__(
+        self,
+        request,
+        timeout,
+        metadata=None,
+        with_call=False,
+        protocol_options=None,
+    ):
+        """Synchronously invokes the underlying RPC.
+
+        Args:
+          request: The request value for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of
+            the RPC.
+          with_call: Whether or not to include return a Call for the RPC in addition
+            to the response.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          The response value for the RPC, and a Call for the RPC if with_call was
+            set to True at invocation.
+
+        Raises:
+          AbortionError: Indicating that the RPC was aborted.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def future(self, request, timeout, metadata=None, protocol_options=None):
+        """Asynchronously invokes the underlying RPC.
+
+        Args:
+          request: The request value for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of
+            the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          An object that is both a Call for the RPC and a future.Future. In the
+            event of RPC completion, the return Future's result value will be the
+            response value of the RPC. In the event of RPC abortion, the returned
+            Future's exception value will be an AbortionError.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def event(
+        self,
+        request,
+        receiver,
+        abortion_callback,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Asynchronously invokes the underlying RPC.
+
+        Args:
+          request: The request value for the RPC.
+          receiver: A ResponseReceiver to be passed the response data of the RPC.
+          abortion_callback: A callback to be called and passed an Abortion value
+            in the event of RPC abortion.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of
+            the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          A Call for the RPC.
+        """
+        raise NotImplementedError()
+
+
+class UnaryStreamMultiCallable(abc.ABC):
+    """Affords invoking a unary-stream RPC in any call style."""
+
+    @abc.abstractmethod
+    def __call__(self, request, timeout, metadata=None, protocol_options=None):
+        """Invokes the underlying RPC.
+
+        Args:
+          request: The request value for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of
+            the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          An object that is both a Call for the RPC and an iterator of response
+            values. Drawing response values from the returned iterator may raise
+            AbortionError indicating abortion of the RPC.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def event(
+        self,
+        request,
+        receiver,
+        abortion_callback,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Asynchronously invokes the underlying RPC.
+
+        Args:
+          request: The request value for the RPC.
+          receiver: A ResponseReceiver to be passed the response data of the RPC.
+          abortion_callback: A callback to be called and passed an Abortion value
+            in the event of RPC abortion.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of
+            the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          A Call object for the RPC.
+        """
+        raise NotImplementedError()
+
+
+class StreamUnaryMultiCallable(abc.ABC):
+    """Affords invoking a stream-unary RPC in any call style."""
+
+    @abc.abstractmethod
+    def __call__(
+        self,
+        request_iterator,
+        timeout,
+        metadata=None,
+        with_call=False,
+        protocol_options=None,
+    ):
+        """Synchronously invokes the underlying RPC.
+
+        Args:
+          request_iterator: An iterator that yields request values for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of
+            the RPC.
+          with_call: Whether or not to include return a Call for the RPC in addition
+            to the response.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          The response value for the RPC, and a Call for the RPC if with_call was
+            set to True at invocation.
+
+        Raises:
+          AbortionError: Indicating that the RPC was aborted.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def future(
+        self, request_iterator, timeout, metadata=None, protocol_options=None
+    ):
+        """Asynchronously invokes the underlying RPC.
+
+        Args:
+          request_iterator: An iterator that yields request values for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of
+            the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          An object that is both a Call for the RPC and a future.Future. In the
+            event of RPC completion, the return Future's result value will be the
+            response value of the RPC. In the event of RPC abortion, the returned
+            Future's exception value will be an AbortionError.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def event(
+        self,
+        receiver,
+        abortion_callback,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Asynchronously invokes the underlying RPC.
+
+        Args:
+          receiver: A ResponseReceiver to be passed the response data of the RPC.
+          abortion_callback: A callback to be called and passed an Abortion value
+            in the event of RPC abortion.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of
+            the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          A single object that is both a Call object for the RPC and a
+            stream.Consumer to which the request values of the RPC should be passed.
+        """
+        raise NotImplementedError()
+
+
+class StreamStreamMultiCallable(abc.ABC):
+    """Affords invoking a stream-stream RPC in any call style."""
+
+    @abc.abstractmethod
+    def __call__(
+        self, request_iterator, timeout, metadata=None, protocol_options=None
+    ):
+        """Invokes the underlying RPC.
+
+        Args:
+          request_iterator: An iterator that yields request values for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of
+            the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          An object that is both a Call for the RPC and an iterator of response
+            values. Drawing response values from the returned iterator may raise
+            AbortionError indicating abortion of the RPC.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def event(
+        self,
+        receiver,
+        abortion_callback,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Asynchronously invokes the underlying RPC.
+
+        Args:
+          receiver: A ResponseReceiver to be passed the response data of the RPC.
+          abortion_callback: A callback to be called and passed an Abortion value
+            in the event of RPC abortion.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of
+            the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          A single object that is both a Call object for the RPC and a
+            stream.Consumer to which the request values of the RPC should be passed.
+        """
+        raise NotImplementedError()
+
+
+class MethodImplementation(abc.ABC):
+    """A sum type that describes a method implementation.
+
+    Attributes:
+      cardinality: A cardinality.Cardinality value.
+      style: A style.Service value.
+      unary_unary_inline: The implementation of the method as a callable value
+        that takes a request value and a ServicerContext object and returns a
+        response value. Only non-None if cardinality is
+        cardinality.Cardinality.UNARY_UNARY and style is style.Service.INLINE.
+      unary_stream_inline: The implementation of the method as a callable value
+        that takes a request value and a ServicerContext object and returns an
+        iterator of response values. Only non-None if cardinality is
+        cardinality.Cardinality.UNARY_STREAM and style is style.Service.INLINE.
+      stream_unary_inline: The implementation of the method as a callable value
+        that takes an iterator of request values and a ServicerContext object and
+        returns a response value. Only non-None if cardinality is
+        cardinality.Cardinality.STREAM_UNARY and style is style.Service.INLINE.
+      stream_stream_inline: The implementation of the method as a callable value
+        that takes an iterator of request values and a ServicerContext object and
+        returns an iterator of response values. Only non-None if cardinality is
+        cardinality.Cardinality.STREAM_STREAM and style is style.Service.INLINE.
+      unary_unary_event: The implementation of the method as a callable value that
+        takes a request value, a response callback to which to pass the response
+        value of the RPC, and a ServicerContext. Only non-None if cardinality is
+        cardinality.Cardinality.UNARY_UNARY and style is style.Service.EVENT.
+      unary_stream_event: The implementation of the method as a callable value
+        that takes a request value, a stream.Consumer to which to pass the
+        response values of the RPC, and a ServicerContext. Only non-None if
+        cardinality is cardinality.Cardinality.UNARY_STREAM and style is
+        style.Service.EVENT.
+      stream_unary_event: The implementation of the method as a callable value
+        that takes a response callback to which to pass the response value of the
+        RPC and a ServicerContext and returns a stream.Consumer to which the
+        request values of the RPC should be passed. Only non-None if cardinality
+        is cardinality.Cardinality.STREAM_UNARY and style is style.Service.EVENT.
+      stream_stream_event: The implementation of the method as a callable value
+        that takes a stream.Consumer to which to pass the response values of the
+        RPC and a ServicerContext and returns a stream.Consumer to which the
+        request values of the RPC should be passed. Only non-None if cardinality
+        is cardinality.Cardinality.STREAM_STREAM and style is
+        style.Service.EVENT.
+    """
+
+
+class MultiMethodImplementation(abc.ABC):
+    """A general type able to service many methods."""
+
+    @abc.abstractmethod
+    def service(self, group, method, response_consumer, context):
+        """Services an RPC.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+          response_consumer: A stream.Consumer to be called to accept the response
+            values of the RPC.
+          context: a ServicerContext object.
+
+        Returns:
+          A stream.Consumer with which to accept the request values of the RPC. The
+            consumer returned from this method may or may not be invoked to
+            completion: in the case of RPC abortion, RPC Framework will simply stop
+            passing values to this object. Implementations must not assume that this
+            object will be called to completion of the request stream or even called
+            at all.
+
+        Raises:
+          abandonment.Abandoned: May or may not be raised when the RPC has been
+            aborted.
+          NoSuchMethodError: If this MultiMethod does not recognize the given group
+            and name for the RPC and is not able to service the RPC.
+        """
+        raise NotImplementedError()
+
+
+class GenericStub(abc.ABC):
+    """Affords RPC invocation via generic methods."""
+
+    @abc.abstractmethod
+    def blocking_unary_unary(
+        self,
+        group,
+        method,
+        request,
+        timeout,
+        metadata=None,
+        with_call=False,
+        protocol_options=None,
+    ):
+        """Invokes a unary-request-unary-response method.
+
+        This method blocks until either returning the response value of the RPC
+        (in the event of RPC completion) or raising an exception (in the event of
+        RPC abortion).
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+          request: The request value for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of the RPC.
+          with_call: Whether or not to include return a Call for the RPC in addition
+            to the response.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          The response value for the RPC, and a Call for the RPC if with_call was
+            set to True at invocation.
+
+        Raises:
+          AbortionError: Indicating that the RPC was aborted.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def future_unary_unary(
+        self,
+        group,
+        method,
+        request,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Invokes a unary-request-unary-response method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+          request: The request value for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          An object that is both a Call for the RPC and a future.Future. In the
+            event of RPC completion, the return Future's result value will be the
+            response value of the RPC. In the event of RPC abortion, the returned
+            Future's exception value will be an AbortionError.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def inline_unary_stream(
+        self,
+        group,
+        method,
+        request,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Invokes a unary-request-stream-response method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+          request: The request value for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          An object that is both a Call for the RPC and an iterator of response
+            values. Drawing response values from the returned iterator may raise
+            AbortionError indicating abortion of the RPC.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def blocking_stream_unary(
+        self,
+        group,
+        method,
+        request_iterator,
+        timeout,
+        metadata=None,
+        with_call=False,
+        protocol_options=None,
+    ):
+        """Invokes a stream-request-unary-response method.
+
+        This method blocks until either returning the response value of the RPC
+        (in the event of RPC completion) or raising an exception (in the event of
+        RPC abortion).
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+          request_iterator: An iterator that yields request values for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of the RPC.
+          with_call: Whether or not to include return a Call for the RPC in addition
+            to the response.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          The response value for the RPC, and a Call for the RPC if with_call was
+            set to True at invocation.
+
+        Raises:
+          AbortionError: Indicating that the RPC was aborted.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def future_stream_unary(
+        self,
+        group,
+        method,
+        request_iterator,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Invokes a stream-request-unary-response method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+          request_iterator: An iterator that yields request values for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          An object that is both a Call for the RPC and a future.Future. In the
+            event of RPC completion, the return Future's result value will be the
+            response value of the RPC. In the event of RPC abortion, the returned
+            Future's exception value will be an AbortionError.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def inline_stream_stream(
+        self,
+        group,
+        method,
+        request_iterator,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Invokes a stream-request-stream-response method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+          request_iterator: An iterator that yields request values for the RPC.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          An object that is both a Call for the RPC and an iterator of response
+            values. Drawing response values from the returned iterator may raise
+            AbortionError indicating abortion of the RPC.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def event_unary_unary(
+        self,
+        group,
+        method,
+        request,
+        receiver,
+        abortion_callback,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Event-driven invocation of a unary-request-unary-response method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+          request: The request value for the RPC.
+          receiver: A ResponseReceiver to be passed the response data of the RPC.
+          abortion_callback: A callback to be called and passed an Abortion value
+            in the event of RPC abortion.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          A Call for the RPC.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def event_unary_stream(
+        self,
+        group,
+        method,
+        request,
+        receiver,
+        abortion_callback,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Event-driven invocation of a unary-request-stream-response method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+          request: The request value for the RPC.
+          receiver: A ResponseReceiver to be passed the response data of the RPC.
+          abortion_callback: A callback to be called and passed an Abortion value
+            in the event of RPC abortion.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          A Call for the RPC.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def event_stream_unary(
+        self,
+        group,
+        method,
+        receiver,
+        abortion_callback,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Event-driven invocation of a unary-request-unary-response method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+          receiver: A ResponseReceiver to be passed the response data of the RPC.
+          abortion_callback: A callback to be called and passed an Abortion value
+            in the event of RPC abortion.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          A pair of a Call object for the RPC and a stream.Consumer to which the
+            request values of the RPC should be passed.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def event_stream_stream(
+        self,
+        group,
+        method,
+        receiver,
+        abortion_callback,
+        timeout,
+        metadata=None,
+        protocol_options=None,
+    ):
+        """Event-driven invocation of a unary-request-stream-response method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+          receiver: A ResponseReceiver to be passed the response data of the RPC.
+          abortion_callback: A callback to be called and passed an Abortion value
+            in the event of RPC abortion.
+          timeout: A duration of time in seconds to allow for the RPC.
+          metadata: A metadata value to be passed to the service-side of the RPC.
+          protocol_options: A value specified by the provider of a Face interface
+            implementation affording custom state and behavior.
+
+        Returns:
+          A pair of a Call object for the RPC and a stream.Consumer to which the
+            request values of the RPC should be passed.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def unary_unary(self, group, method):
+        """Creates a UnaryUnaryMultiCallable for a unary-unary method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+
+        Returns:
+          A UnaryUnaryMultiCallable value for the named unary-unary method.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def unary_stream(self, group, method):
+        """Creates a UnaryStreamMultiCallable for a unary-stream method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+
+        Returns:
+          A UnaryStreamMultiCallable value for the name unary-stream method.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def stream_unary(self, group, method):
+        """Creates a StreamUnaryMultiCallable for a stream-unary method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+
+        Returns:
+          A StreamUnaryMultiCallable value for the named stream-unary method.
+        """
+        raise NotImplementedError()
+
+    @abc.abstractmethod
+    def stream_stream(self, group, method):
+        """Creates a StreamStreamMultiCallable for a stream-stream method.
+
+        Args:
+          group: The group identifier of the RPC.
+          method: The method identifier of the RPC.
+
+        Returns:
+          A StreamStreamMultiCallable value for the named stream-stream method.
+        """
+        raise NotImplementedError()
+
+
+class DynamicStub(abc.ABC):
+    """Affords RPC invocation via attributes corresponding to afforded methods.
+
+    Instances of this type may be scoped to a single group so that attribute
+    access is unambiguous.
+
+    Instances of this type respond to attribute access as follows: if the
+    requested attribute is the name of a unary-unary method, the value of the
+    attribute will be a UnaryUnaryMultiCallable with which to invoke an RPC; if
+    the requested attribute is the name of a unary-stream method, the value of the
+    attribute will be a UnaryStreamMultiCallable with which to invoke an RPC; if
+    the requested attribute is the name of a stream-unary method, the value of the
+    attribute will be a StreamUnaryMultiCallable with which to invoke an RPC; and
+    if the requested attribute is the name of a stream-stream method, the value of
+    the attribute will be a StreamStreamMultiCallable with which to invoke an RPC.
+    """
diff --git a/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/utilities.py b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/utilities.py
new file mode 100644
index 00000000..b02ea530
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/grpc/framework/interfaces/face/utilities.py
@@ -0,0 +1,245 @@
+# 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 RPC Framework's Face interface."""
+
+import collections
+
+# stream is referenced from specification in this module.
+from grpc.framework.common import cardinality
+from grpc.framework.common import style
+from grpc.framework.foundation import stream  # pylint: disable=unused-import
+from grpc.framework.interfaces.face import face
+
+
+class _MethodImplementation(
+    face.MethodImplementation,
+    collections.namedtuple(
+        "_MethodImplementation",
+        [
+            "cardinality",
+            "style",
+            "unary_unary_inline",
+            "unary_stream_inline",
+            "stream_unary_inline",
+            "stream_stream_inline",
+            "unary_unary_event",
+            "unary_stream_event",
+            "stream_unary_event",
+            "stream_stream_event",
+        ],
+    ),
+):
+    pass
+
+
+def unary_unary_inline(behavior):
+    """Creates an face.MethodImplementation for the given behavior.
+
+    Args:
+      behavior: The implementation of a unary-unary RPC method as a callable value
+        that takes a request value and an face.ServicerContext object and
+        returns a response value.
+
+    Returns:
+      An face.MethodImplementation derived from the given behavior.
+    """
+    return _MethodImplementation(
+        cardinality.Cardinality.UNARY_UNARY,
+        style.Service.INLINE,
+        behavior,
+        None,
+        None,
+        None,
+        None,
+        None,
+        None,
+        None,
+    )
+
+
+def unary_stream_inline(behavior):
+    """Creates an face.MethodImplementation for the given behavior.
+
+    Args:
+      behavior: The implementation of a unary-stream RPC method as a callable
+        value that takes a request value and an face.ServicerContext object and
+        returns an iterator of response values.
+
+    Returns:
+      An face.MethodImplementation derived from the given behavior.
+    """
+    return _MethodImplementation(
+        cardinality.Cardinality.UNARY_STREAM,
+        style.Service.INLINE,
+        None,
+        behavior,
+        None,
+        None,
+        None,
+        None,
+        None,
+        None,
+    )
+
+
+def stream_unary_inline(behavior):
+    """Creates an face.MethodImplementation for the given behavior.
+
+    Args:
+      behavior: The implementation of a stream-unary RPC method as a callable
+        value that takes an iterator of request values and an
+        face.ServicerContext object and returns a response value.
+
+    Returns:
+      An face.MethodImplementation derived from the given behavior.
+    """
+    return _MethodImplementation(
+        cardinality.Cardinality.STREAM_UNARY,
+        style.Service.INLINE,
+        None,
+        None,
+        behavior,
+        None,
+        None,
+        None,
+        None,
+        None,
+    )
+
+
+def stream_stream_inline(behavior):
+    """Creates an face.MethodImplementation for the given behavior.
+
+    Args:
+      behavior: The implementation of a stream-stream RPC method as a callable
+        value that takes an iterator of request values and an
+        face.ServicerContext object and returns an iterator of response values.
+
+    Returns:
+      An face.MethodImplementation derived from the given behavior.
+    """
+    return _MethodImplementation(
+        cardinality.Cardinality.STREAM_STREAM,
+        style.Service.INLINE,
+        None,
+        None,
+        None,
+        behavior,
+        None,
+        None,
+        None,
+        None,
+    )
+
+
+def unary_unary_event(behavior):
+    """Creates an face.MethodImplementation for the given behavior.
+
+    Args:
+      behavior: The implementation of a unary-unary RPC method as a callable
+        value that takes a request value, a response callback to which to pass
+        the response value of the RPC, and an face.ServicerContext.
+
+    Returns:
+      An face.MethodImplementation derived from the given behavior.
+    """
+    return _MethodImplementation(
+        cardinality.Cardinality.UNARY_UNARY,
+        style.Service.EVENT,
+        None,
+        None,
+        None,
+        None,
+        behavior,
+        None,
+        None,
+        None,
+    )
+
+
+def unary_stream_event(behavior):
+    """Creates an face.MethodImplementation for the given behavior.
+
+    Args:
+      behavior: The implementation of a unary-stream RPC method as a callable
+        value that takes a request value, a stream.Consumer to which to pass the
+        response values of the RPC, and an face.ServicerContext.
+
+    Returns:
+      An face.MethodImplementation derived from the given behavior.
+    """
+    return _MethodImplementation(
+        cardinality.Cardinality.UNARY_STREAM,
+        style.Service.EVENT,
+        None,
+        None,
+        None,
+        None,
+        None,
+        behavior,
+        None,
+        None,
+    )
+
+
+def stream_unary_event(behavior):
+    """Creates an face.MethodImplementation for the given behavior.
+
+    Args:
+      behavior: The implementation of a stream-unary RPC method as a callable
+        value that takes a response callback to which to pass the response value
+        of the RPC and an face.ServicerContext and returns a stream.Consumer to
+        which the request values of the RPC should be passed.
+
+    Returns:
+      An face.MethodImplementation derived from the given behavior.
+    """
+    return _MethodImplementation(
+        cardinality.Cardinality.STREAM_UNARY,
+        style.Service.EVENT,
+        None,
+        None,
+        None,
+        None,
+        None,
+        None,
+        behavior,
+        None,
+    )
+
+
+def stream_stream_event(behavior):
+    """Creates an face.MethodImplementation for the given behavior.
+
+    Args:
+      behavior: The implementation of a stream-stream RPC method as a callable
+        value that takes a stream.Consumer to which to pass the response values
+        of the RPC and an face.ServicerContext and returns a stream.Consumer to
+        which the request values of the RPC should be passed.
+
+    Returns:
+      An face.MethodImplementation derived from the given behavior.
+    """
+    return _MethodImplementation(
+        cardinality.Cardinality.STREAM_STREAM,
+        style.Service.EVENT,
+        None,
+        None,
+        None,
+        None,
+        None,
+        None,
+        None,
+        behavior,
+    )