Skip to content

[Python] [Typeguard] Part 5 - Add Typeguard SYNC Stack in tests#40278

Closed
asheshvidyut wants to merge 412 commits into
grpc:masterfrom
asheshvidyut:feature/type-hints/typeguard-sync-stack-part-1
Closed

[Python] [Typeguard] Part 5 - Add Typeguard SYNC Stack in tests#40278
asheshvidyut wants to merge 412 commits into
grpc:masterfrom
asheshvidyut:feature/type-hints/typeguard-sync-stack-part-1

Conversation

@asheshvidyut

@asheshvidyut asheshvidyut commented Jul 22, 2025

Copy link
Copy Markdown
Member

Description

First Part of Add Typeguard to SYNC stack - runs only in tests, fixes type hints for SYNC Stack.

This has changes from Part 4 #40226

Changes

Add typeguard for sync stack for following files -

  • grpc._auth
  • grpc._channel
  • grpc._common
  • grpc._compression
  • grpc._interceptor
  • grpc._observability
  • grpc._plugin_wrapping
  • grpc._runtime_protos

Testing

CI

Related Work

@linux-foundation-easycla

linux-foundation-easycla Bot commented Jul 28, 2025

Copy link
Copy Markdown

CLA Signed

The committers listed above are authorized under a signed CLA.

@asheshvidyut asheshvidyut force-pushed the feature/type-hints/typeguard-sync-stack-part-1 branch from cd63bfc to d7cf624 Compare July 28, 2025 04:14
@asheshvidyut asheshvidyut changed the title add typeguard to sync stack [Python] [Typeguard] Part 5 - Add Typeguard Jul 28, 2025
@asheshvidyut asheshvidyut changed the title [Python] [Typeguard] Part 5 - Add Typeguard [Python] [Typeguard] Part 5 - Add Typeguard Sync Stack Jul 28, 2025
@asheshvidyut asheshvidyut changed the title [Python] [Typeguard] Part 5 - Add Typeguard Sync Stack [Python] [Typeguard] Part 5 - Add Typeguard Sync Stack in tests Jul 30, 2025
Comment thread src/python/grpcio/grpc/_channel.py Outdated
def __init__(
self,
due: Sequence[cygrpc.OperationType],
due: Sequence[int],

@asheshvidyut asheshvidyut Jul 30, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_server (src.python.grpcio_tests.tests_aio.unit.compatibility_test.TestCompatibility) ... Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/threading.py".src/python/grpcio_tests/tests_aio/unit/compatibility_test.py:208> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f3f56f285b0>()] created at /usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py:422> cb=[_run_until_complete_cb() at /usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py:184] created at /usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py:595> took 0.140 seconds
    self.run()
  File "/usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File ".src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 88, in thread_work
    func()
  File ".src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 205, in sync_work
    response = channel.unary_unary("/test/test")(b"\x07\x08")
  File ".src/python/grpcio/grpc/_channel.py", line 1175, in __call__
    state, call = self._blocking(
  File ".src/python/grpcio/grpc/_channel.py", line 1137, in _blocking
    state, operations, deadline, rendezvous = self._prepare(
  File ".src/python/grpcio/grpc/_channel.py", line 1115, in _prepare
    state = _RPCState(_UNARY_UNARY_INITIAL_DUE, None, None, None, None)
  File ".src/python/grpcio/grpc/_channel.py", line 138, in __init__
    def __init__(
  File ".site-packages/typeguard/_functions.py", line 136, in check_argument_types
    check_type_internal(value, annotation, memo)
  File ".site-packages/typeguard/_checkers.py", line 779, in check_type_internal
    checker(value, origin_type, args, memo)
  File ".site-packages/typeguard/_checkers.py", line 322, in check_sequence
    check_type_internal(v, args[0], memo)
  File ".site-packages/typeguard/_checkers.py", line 784, in check_type_internal
    raise TypeCheckError(f"is not an instance of {qualified_name(origin_type)}")
typeguard.TypeCheckError: item 0 of argument "due" (tuple) is not an instance of _cython.cygrpc.OperationType

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember we had to spend quite some time figuring the cause of this compatibility test failure. Good to see what was causing it. However, this change doesn't look quite right to me.

Tracing through the flow, from the test, due is receiving the parameter _UNARY_UNARY_INITIAL_DUE which is a type of different cygrpc.OperationType objects. However each object in it is an enum coming from core (Ref)

I think typeguard is looking for the type of the enum value itself and hence expecting an integer. But I feel, converting the type from cygrpc.OperationType to int is quite misleading because this might then mean any integer value will be accepted. I would suggest looking for any alternative way to specify enum in typeguard, or probably make typeguard ignore this type itself

Also depending on whatever we decide for this type finally after review, you will also have to update it in the line above

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood your point but I think this is an internal class _RPCState. Its not in public APIs - https://grpc.github.io/grpc/python/

Requesting @sergiitk 's input on this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's see if we can convert class OperationType to cdef enum https://cython.readthedocs.io/en/latest/src/userguide/language_basics.html

class OperationType:
  send_initial_metadata = GRPC_OP_SEND_INITIAL_METADATA
  send_message = GRPC_OP_SEND_MESSAGE

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IRRC, OperationType is a regular Python class, so we could just make it an enum

class OperationType(enum.Enum):

Better yet, enum.IntEnum

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sergiitk and @sreenithi it worked!

request: Any,
timeout: Optional[float],
request_serializer: SerializingFunction,
request_serializer: Optional[SerializingFunction],

@asheshvidyut asheshvidyut Jul 30, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-----------------------------------------------------------------------------
test_many_loop (src.python.grpcio_tests.tests_aio.unit.compatibility_test.TestCompatibility) ... Executing <Task finished name='Task-1' coro=<TestCompatibility.setUp() done, defined at /usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/3428/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio_tests/tests_aio/unit/compatibility_test.py:51> result=None created at ./python3.8/asyncio/base_events.py:595> took 0.246 seconds
Exception in callback PollerCompletionQueue._handle_events(<_UnixSelecto...se debug=True>)()
handle: <Handle PollerCompletionQueue._handle_events(<_UnixSelecto...se debug=True>)() created at ./python3.8/asyncio/selector_events.py:259>
source_traceback: Object created at (most recent call last):
  File "./src/python/grpcio_tests/tests_aio/unit/_test_base.py", line 31, in wrapper
    return loop.run_until_complete(f(*args, **kwargs))
  File "./python3.8/asyncio/base_events.py", line 603, in run_until_complete
    self.run_forever()
  File "./python3.8/asyncio/base_events.py", line 570, in run_forever
    self._run_once()
  File "./python3.8/asyncio/base_events.py", line 1851, in _run_once
    handle._run()
  File "./python3.8/asyncio/events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "./src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 52, in setUp
    self._async_server = aio.server(
  File "./src/python/grpcio/grpc/aio/_server.py", line 233, in server
    return Server(
  File "./src/python/grpcio/grpc/aio/_server.py", line 61, in __init__
    self._server = cygrpc.AioServer(
  File "./python3.8/asyncio/selector_events.py", line 334, in add_reader
    return self._add_reader(fd, callback, *args)
  File "./python3.8/asyncio/selector_events.py", line 259, in _add_reader
    handle = events.Handle(callback, args, self, None)
Traceback (most recent call last):
  File "./python3.8/asyncio/events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "src/python/grpcio/grpc/_cython/_cygrpc/aio/completion_queue.pyx.pxi", line 147, in _cython.cygrpc.PollerCompletionQueue._handle_events
BlockingIOError: [Errno 11] Resource temporarily unavailable
Exception in callback PollerCompletionQueue._handle_events(<_UnixSelecto...se debug=True>)()
handle: <Handle PollerCompletionQueue._handle_events(<_UnixSelecto...se debug=True>)() created at ./python3.8/asyncio/selector_events.py:259>
source_traceback: Object created at (most recent call last):
  File "./src/python/grpcio_tests/tests_aio/unit/_test_base.py", line 31, in wrapper
    return loop.run_until_complete(f(*args, **kwargs))
  File "./python3.8/asyncio/base_events.py", line 603, in run_until_complete
    self.run_forever()
  File "./python3.8/asyncio/base_events.py", line 570, in run_forever
    self._run_once()
  File "./python3.8/asyncio/base_events.py", line 1851, in _run_once
    handle._run()
  File "./python3.8/asyncio/events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "./src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 52, in setUp
    self._async_server = aio.server(
  File "./src/python/grpcio/grpc/aio/_server.py", line 233, in server
    return Server(
  File "./src/python/grpcio/grpc/aio/_server.py", line 61, in __init__
    self._server = cygrpc.AioServer(
  File "./python3.8/asyncio/selector_events.py", line 334, in add_reader
    return self._add_reader(fd, callback, *args)
  File "./python3.8/asyncio/selector_events.py", line 259, in _add_reader
    handle = events.Handle(callback, args, self, None)
Traceback (most recent call last):
  File "./python3.8/asyncio/events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "src/python/grpcio/grpc/_cython/_cygrpc/aio/completion_queue.pyx.pxi", line 147, in _cython.cygrpc.PollerCompletionQueue._handle_events
BlockingIOError: [Errno 11] Resource temporarily unavailable
ok

test_server (src.python.grpcio_tests.tests_aio.unit.compatibility_test.TestCompatibility) ... Exception in thread Thread-4:
Traceback (most recent call last):
  File "./python3.8/threading.py"./src/python/grpcio_tests/tests_aio/unit/compatibility_test.py:208> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f59b66fa6d0>()] created at ./python3.8/asyncio/base_events.py:422> cb=[_run_until_complete_cb() at ./python3.8/asyncio/base_events.py:184] created at ./python3.8/asyncio/base_events.py:595> took 0.109 seconds
    self.run()
  File "./python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "./src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 88, in thread_work
    func()
  File "./src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 205, in sync_work
    response = channel.unary_unary("/test/test")(b"\x07\x08")
  File "./src/python/grpcio/grpc/_channel.py", line 1175, in __call__
    state, call = self._blocking(
  File "./src/python/grpcio/grpc/_channel.py", line 1137, in _blocking
    state, operations, deadline, rendezvous = self._prepare(
  File "./src/python/grpcio/grpc/_channel.py", line 1103, in _prepare
    deadline, serialized_request, rendezvous = _start_unary_request(
  File "./src/python/grpcio/grpc/_channel.py", line 972, in _start_unary_request
    def _start_unary_request(
  File "./site-packages/typeguard/_functions.py", line 136, in check_argument_types
    check_type_internal(value, annotation, memo)
  File "./site-packages/typeguard/_checkers.py", line 779, in check_type_internal
    checker(value, origin_type, args, memo)
  File "./site-packages/typeguard/_checkers.py", line 156, in check_callable
    raise TypeCheckError("is not callable")
typeguard.TypeCheckError: argument "request_serializer" (None) is not callable
-- Test timed out at 2025-07-30 09:36:55 UTC --

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this change is fine. We had already verified it in a previous PR: https://github.com/grpc/grpc/pull/40215/files#r2221305142

delivering: bool

def __init__(self, channel: grpc.Channel):
def __init__(self, channel: cygrpc.Channel):

@asheshvidyut asheshvidyut Jul 30, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

======================================================================
ERROR: test_sync_unary_unary_success (src.python.grpcio_tests.tests_aio.unit.compatibility_test.TestCompatibility)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./src/python/grpcio_tests/tests_aio/unit/_test_base.py", line 31, in wrapper
    return loop.run_until_complete(f(*args, **kwargs))
  File "/usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "./src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 74, in setUp
    self._sync_channel = grpc.insecure_channel(
  File "./src/python/grpcio/grpc/__init__.py", line 2119, in insecure_channel
    return _channel.Channel(
  File "./src/python/grpcio/grpc/_channel.py", line 2066, in __init__
    self._connectivity_state = _ChannelConnectivityState(self._channel)
  File "./src/python/grpcio/grpc/_channel.py", line 1834, in __init__
    def __init__(self, channel: grpc.Channel):
  File "./site-packages/typeguard/_functions.py", line 136, in check_argument_types
    check_type_internal(value, annotation, memo)
  File "./site-packages/typeguard/_checkers.py", line 784, in check_type_internal
    raise TypeCheckError(f"is not an instance of {qualified_name(origin_type)}")
typeguard.TypeCheckError: argument "channel" (_cython.cygrpc.Channel) is not an instance of grpc.Channel

======================================================================
ERROR: test_unary_stream (src.python.grpcio_tests.tests_aio.unit.compatibility_test.TestCompatibility)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./src/python/grpcio_tests/tests_aio/unit/_test_base.py", line 31, in wrapper
    return loop.run_until_complete(f(*args, **kwargs))
  File "/usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "./src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 74, in setUp
    self._sync_channel = grpc.insecure_channel(
  File "./src/python/grpcio/grpc/__init__.py", line 2119, in insecure_channel
    return _channel.Channel(
  File "./src/python/grpcio/grpc/_channel.py", line 2066, in __init__
    self._connectivity_state = _ChannelConnectivityState(self._channel)
  File "./src/python/grpcio/grpc/_channel.py", line 1834, in __init__
    def __init__(self, channel: grpc.Channel):
  File "./site-packages/typeguard/_functions.py", line 136, in check_argument_types
    check_type_internal(value, annotation, memo)
  File "./site-packages/typeguard/_checkers.py", line 784, in check_type_internal
    raise TypeCheckError(f"is not an instance of {qualified_name(origin_type)}")
typeguard.TypeCheckError: argument "channel" (_cython.cygrpc.Channel) is not an instance of grpc.Channel

======================================================================
ERROR: test_unary_unary (src.python.grpcio_tests.tests_aio.unit.compatibility_test.TestCompatibility)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./src/python/grpcio_tests/tests_aio/unit/_test_base.py", line 31, in wrapper
    return loop.run_until_complete(f(*args, **kwargs))
  File "/usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "./src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 74, in setUp
    self._sync_channel = grpc.insecure_channel(
  File "./src/python/grpcio/grpc/__init__.py", line 2119, in insecure_channel
    return _channel.Channel(
  File "./src/python/grpcio/grpc/_channel.py", line 2066, in __init__
    self._connectivity_state = _ChannelConnectivityState(self._channel)
  File "./src/python/grpcio/grpc/_channel.py", line 1834, in __init__
    def __init__(self, channel: grpc.Channel):
  File "./site-packages/typeguard/_functions.py", line 136, in check_argument_types
    check_type_internal(value, annotation, memo)
  File "./site-packages/typeguard/_checkers.py", line 784, in check_type_internal
    raise TypeCheckError(f"is not an instance of {qualified_name(origin_type)}")
typeguard.TypeCheckError: argument "channel" (_cython.cygrpc.Channel) is not an instance of grpc.Channel

----------------------------------------------------------------------
Ran 16 tests in 0.390s

FAILED (errors=16)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change seems right to me. We initialize the _ChannelConnectivityState object at only one place in the whole codebase here. And this takes the self._channel object as a parameter which is of the type cygrpc.Channel.

Comment thread src/python/grpcio/grpc/_channel.py Outdated
+ (
(
cygrpc.ChannelArgKey.primary_user_agent_string,
_common.decode(cygrpc.ChannelArgKey.primary_user_agent_string),

@asheshvidyut asheshvidyut Jul 30, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-----------------------------------------------------------------------------
test_server (src.python.grpcio_tests.tests_aio.unit.compatibility_test.TestCompatibility) ... Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/threading.py", line 932, in _bootstrap_inner
Executing <Task pending name='Task-10' coro=<TestCompatibility.test_server() running at /usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio_tests/tests_aio/unit/compatibility_test.py:208> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f0f3417ef10>()] created at /usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py:422> cb=[_run_until_complete_cb() at /usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py:184] created at /usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py:595> took 0.125 seconds
    self.run()
  File "/usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 88, in thread_work
    func()
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 204, in sync_work
    with grpc.insecure_channel("localhost:%d" % port) as channel:
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio/grpc/__init__.py", line 2119, in insecure_channel
    return _channel.Channel(
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio/grpc/_channel.py", line 2061, in __init__
    _augment_options(core_options, compression),
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio/grpc/_channel.py", line 1999, in _augment_options
    return (
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/grpc_python_dependencies_typeguard/site-packages/typeguard/_functions.py", line 165, in check_return_type
    check_type_internal(retval, annotation, memo)
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/grpc_python_dependencies_typeguard/site-packages/typeguard/_checkers.py", line 779, in check_type_internal
    checker(value, origin_type, args, memo)
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/grpc_python_dependencies_typeguard/site-packages/typeguard/_checkers.py", line 322, in check_sequence
    check_type_internal(v, args[0], memo)
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/grpc_python_dependencies_typeguard/site-packages/typeguard/_checkers.py", line 779, in check_type_internal
    checker(value, origin_type, args, memo)
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/grpc_python_dependencies_typeguard/site-packages/typeguard/_checkers.py", line 402, in check_tuple
    check_type_internal(element, element_type, memo)
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/516/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/grpc_python_dependencies_typeguard/site-packages/typeguard/_checkers.py", line 784, in check_type_internal
    raise TypeCheckError(f"is not an instance of {qualified_name(origin_type)}")
typeguard.TypeCheckError: item 0 of item 0 of the return value (tuple) is not an instance of str

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine. Similar to what I had mentioned in the previous PR it looks like the value of cygrpc.ChannelArgKey.primary_user_agent_string is coming from the Core as char * so we need to convert them to string explicitly



def maybe_record_rpc_latency(state: "_channel._RPCState") -> None:
def maybe_record_rpc_latency(state: Any) -> None:

@asheshvidyut asheshvidyut Jul 30, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-----------------------------------------------------------------------------
test_server (src.python.grpcio_tests.tests_aio.unit.compatibility_test.TestCompatibility) ... Executing <Task pending name='Task-10' coro=<TestCompatibility.test_server() running at /usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/851/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio_tests/tests_aio/unit/compatibility_test.py:208> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f07b147e730>()] created at /usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py:422> cb=[_run_until_complete_cb() at /usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py:184] created at /usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/asyncio/base_events.py:595> took 0.136 seconds
Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/usr/local/google/home/asheshvidyut/.pyenv/versions/3.8.20/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/851/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 88, in thread_work
    func()
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/851/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio_tests/tests_aio/unit/compatibility_test.py", line 205, in sync_work
    response = channel.unary_unary("/test/test")(b"\x07\x08")
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/851/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio/grpc/_channel.py", line 1175, in __call__
    state, call = self._blocking(
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/851/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio/grpc/_channel.py", line 1163, in _blocking
    _handle_event(event, state, self._response_deserializer)
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/851/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio/grpc/_channel.py", line 229, in _handle_event
    _observability.maybe_record_rpc_latency(state)
  File "/usr/local/google/home/asheshvidyut/.cache/bazel/_bazel_asheshvidyut/37ab11cdf3f320a86e32407534188cd9/sandbox/linux-sandbox/851/execroot/com_github_grpc_grpc/bazel-out/k8-fastbuild/bin/src/python/grpcio_tests/tests_aio/unit/compatibility_test.runfiles/com_github_grpc_grpc/src/python/grpcio/grpc/_observability.py", line 271, in maybe_record_rpc_latency
    def maybe_record_rpc_latency(state: "_channel._RPCState") -> None:
AttributeError: '_SpecialForm' object has no attribute '_RPCState'
-- Test timed out at 2025-07-30 09:52:37 UTC --

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, is it not possible to do something like this here as well to import the _RPCState symbol?

Comment thread src/python/grpcio/grpc/_plugin_wrapping.py Outdated
@asheshvidyut asheshvidyut force-pushed the feature/type-hints/typeguard-sync-stack-part-1 branch from d9f8990 to d11ff6a Compare July 30, 2025 10:03
@asheshvidyut asheshvidyut marked this pull request as ready for review July 30, 2025 11:00
@asheshvidyut asheshvidyut requested a review from eugeneo as a code owner July 30, 2025 11:00
@asheshvidyut asheshvidyut force-pushed the feature/type-hints/typeguard-sync-stack-part-1 branch from 0496f07 to ab394b1 Compare July 30, 2025 11:07
@asheshvidyut asheshvidyut changed the title [Python] [Typeguard] Part 5 - Add Typeguard Sync Stack in tests [Python] [Typeguard] Part 5 - Add Typeguard SYNC Stack in tests Jul 31, 2025

@sreenithi sreenithi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not reviewing the files in the aio and grpcio_tests/tests_aio/unit folder because it is already reviewed in #40226

Comment thread src/python/grpcio/grpc/_channel.py Outdated
def __init__(
self,
due: Sequence[cygrpc.OperationType],
due: Sequence[int],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember we had to spend quite some time figuring the cause of this compatibility test failure. Good to see what was causing it. However, this change doesn't look quite right to me.

Tracing through the flow, from the test, due is receiving the parameter _UNARY_UNARY_INITIAL_DUE which is a type of different cygrpc.OperationType objects. However each object in it is an enum coming from core (Ref)

I think typeguard is looking for the type of the enum value itself and hence expecting an integer. But I feel, converting the type from cygrpc.OperationType to int is quite misleading because this might then mean any integer value will be accepted. I would suggest looking for any alternative way to specify enum in typeguard, or probably make typeguard ignore this type itself

Also depending on whatever we decide for this type finally after review, you will also have to update it in the line above

request: Any,
timeout: Optional[float],
request_serializer: SerializingFunction,
request_serializer: Optional[SerializingFunction],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this change is fine. We had already verified it in a previous PR: https://github.com/grpc/grpc/pull/40215/files#r2221305142

delivering: bool

def __init__(self, channel: grpc.Channel):
def __init__(self, channel: cygrpc.Channel):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change seems right to me. We initialize the _ChannelConnectivityState object at only one place in the whole codebase here. And this takes the self._channel object as a parameter which is of the type cygrpc.Channel.

Comment thread src/python/grpcio/grpc/_channel.py Outdated
+ (
(
cygrpc.ChannelArgKey.primary_user_agent_string,
_common.decode(cygrpc.ChannelArgKey.primary_user_agent_string),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine. Similar to what I had mentioned in the previous PR it looks like the value of cygrpc.ChannelArgKey.primary_user_agent_string is coming from the Core as char * so we need to convert them to string explicitly



def maybe_record_rpc_latency(state: "_channel._RPCState") -> None:
def maybe_record_rpc_latency(state: Any) -> None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, is it not possible to do something like this here as well to import the _RPCState symbol?

from grpc._typing import ChannelArgumentType

if TYPE_CHECKING:
from grpc._channel import _RPCState

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

asheshvidyut added a commit to asheshvidyut/grpc that referenced this pull request Apr 8, 2026
…#40278)

### Description

First Part of Add Typeguard to SYNC stack - runs only in tests, fixes type hints for SYNC Stack.

This has changes from Part 4 grpc#40226

### Changes
TODO

### Testing

CI

### Related Work
 - Part 1: grpc#40201
 - Part 2: grpc#40215
 - Part 3: grpc#40217
 - Part 4: grpc#40226
 - Part 6: grpc#40353
 - b/423755915

Closes grpc#40278

COPYBARA_INTEGRATE_REVIEW=grpc#40278 from asheshvidyut:feature/type-hints/typeguard-sync-stack-part-1 24987e7
PiperOrigin-RevId: 890732097
copybara-service Bot pushed a commit that referenced this pull request May 27, 2026
### Description

Second Part of Add Typeguard to SYNC stack - runs only in tests, fixes type hints for SYNC Stack

This has changes from Part 5 #40278

#### Changes
TODO

### Testing

CI

### Related Work
 - Part 1: #40201
 - Part 2: #40215
 - Part 3: #40217
 - Part 4: #40226
 - Part 5: #40278
 - b/423755915

Closes #40353

COPYBARA_INTEGRATE_REVIEW=#40353 from asheshvidyut:feature/type-hints/typeguard-sync-stack-part-2 645b086
PiperOrigin-RevId: 922028553
asheshvidyut added a commit to asheshvidyut/grpc that referenced this pull request May 29, 2026
…#40353)

### Description

Second Part of Add Typeguard to SYNC stack - runs only in tests, fixes type hints for SYNC Stack

This has changes from Part 5 grpc#40278

#### Changes
TODO

### Testing

CI

### Related Work
 - Part 1: grpc#40201
 - Part 2: grpc#40215
 - Part 3: grpc#40217
 - Part 4: grpc#40226
 - Part 5: grpc#40278
 - b/423755915

Closes grpc#40353

COPYBARA_INTEGRATE_REVIEW=grpc#40353 from asheshvidyut:feature/type-hints/typeguard-sync-stack-part-2 645b086
PiperOrigin-RevId: 922028553
asheshvidyut added a commit to a-detiste/grpc that referenced this pull request Jun 10, 2026
…#40278)

### Description

First Part of Add Typeguard to SYNC stack - runs only in tests, fixes type hints for SYNC Stack.

This has changes from Part 4 grpc#40226

### Changes
TODO

### Testing

CI

### Related Work
 - Part 1: grpc#40201
 - Part 2: grpc#40215
 - Part 3: grpc#40217
 - Part 4: grpc#40226
 - Part 6: grpc#40353
 - b/423755915

Closes grpc#40278

COPYBARA_INTEGRATE_REVIEW=grpc#40278 from asheshvidyut:feature/type-hints/typeguard-sync-stack-part-1 24987e7
PiperOrigin-RevId: 890732097
asheshvidyut added a commit to a-detiste/grpc that referenced this pull request Jun 10, 2026
…#40353)

### Description

Second Part of Add Typeguard to SYNC stack - runs only in tests, fixes type hints for SYNC Stack

This has changes from Part 5 grpc#40278

#### Changes
TODO

### Testing

CI

### Related Work
 - Part 1: grpc#40201
 - Part 2: grpc#40215
 - Part 3: grpc#40217
 - Part 4: grpc#40226
 - Part 5: grpc#40278
 - b/423755915

Closes grpc#40353

COPYBARA_INTEGRATE_REVIEW=grpc#40353 from asheshvidyut:feature/type-hints/typeguard-sync-stack-part-2 645b086
PiperOrigin-RevId: 922028553
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bloat/none lang/Python release notes: yes Indicates if PR needs to be in release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.