This is an automated email from the ASF dual-hosted git repository.

jdanek pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git


The following commit(s) were added to refs/heads/main by this push:
     new e6b249f  DISPATCH-2321 Add mypy check for the Python code
e6b249f is described below

commit e6b249fcd239e23e3e074496c2cf9ca113d64d9a
Author: Jiri DanÄ›k <[email protected]>
AuthorDate: Sat Jan 29 13:53:17 2022 +0100

    DISPATCH-2321 Add mypy check for the Python code
---
 .github/workflows/build.yaml               | 43 +++++++++++++++
 python/qpid_dispatch/management/error.py   | 12 ++---
 python/qpid_dispatch_internal/dispatch.pyi | 68 ++++++++++++++++++++++++
 tests/TCP_echo_server.py                   |  5 +-
 tests/http2_server.py                      | 13 ++++-
 tests/http2_slow_q2_server.py              | 43 +++++++++------
 tests/hyperh2_server.py                    | 43 +++++++++------
 tests/run_system_tests.py                  |  2 -
 tests/system_test.py                       |  6 ++-
 tests/system_tests_edge_router.py          |  4 +-
 tests/system_tests_priority.py             |  2 +-
 tests/system_tests_qdmanage.py             |  4 --
 tests/system_tests_sasl_plain.py           |  4 --
 tests/system_tests_ssl.py                  | 10 ++--
 tests/system_tests_topology.py             |  2 +-
 tests/system_tests_topology_addition.py    |  2 +-
 tests/system_tests_topology_disposition.py |  2 +-
 tests/test_command.py                      |  4 +-
 tests/tox.ini.in                           | 85 ++++++++++++++++++++++++++++--
 19 files changed, 276 insertions(+), 78 deletions(-)

diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index e5c5636..2d1a1a2 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -543,6 +543,49 @@ jobs:
           name: book.pdf
           path: ${{github.workspace}}/docs/books/user-guide/book.pdf
 
+  python:
+    name: 'Python Checkers (${{ matrix.container }})'
+    runs-on: '${{ matrix.os }}'
+    strategy:
+      matrix:
+        os: [ 'ubuntu-20.04' ]
+        container: [ 'fedora' ]
+        containerTag: [ '35' ]
+
+    container:
+      image: 'library/${{ matrix.container }}:${{ matrix.containerTag }}'
+      volumes:
+        - ${{github.workspace}}:${{github.workspace}}
+
+    env:
+      DispatchBuildDir: ${{github.workspace}}/build
+      InstallPrefix: ${{github.workspace}}/install
+      DispatchCMakeExtraArgs: >
+        -GNinja
+        -DCONSOLE_INSTALL=OFF
+
+    steps:
+
+      - name: Install build dependencies
+        run: |
+          dnf install -y 'dnf-command(builddep)' && dnf builddep -y 
qpid-dispatch-router && dnf install -y git tox ninja-build
+
+      - uses: actions/checkout@v2
+
+      - name: Create Build and Install directories
+        run: mkdir -p "${DispatchBuildDir}" "{InstallPrefix}"
+
+      - name: qpid-dispatch cmake configure
+        working-directory: ${{env.DispatchBuildDir}}
+        run: >
+          cmake "${{github.workspace}}" \
+            "-DCMAKE_INSTALL_PREFIX=${InstallPrefix}" \
+            ${DispatchCMakeExtraArgs}
+
+      - name: CTest -R python-checker
+        working-directory: ${{env.DispatchBuildDir}}
+        run: ctest -VV -R python-checker
+
   console-test:
     name: Console Tests
     runs-on: ubuntu-latest
diff --git a/python/qpid_dispatch/management/error.py 
b/python/qpid_dispatch/management/error.py
index 49b43f7..95ee1f2 100644
--- a/python/qpid_dispatch/management/error.py
+++ b/python/qpid_dispatch/management/error.py
@@ -114,27 +114,27 @@ def _error_class(status):
     return Error
 
 
-class BadRequestStatus(_error_class(BAD_REQUEST)):
+class BadRequestStatus(_error_class(BAD_REQUEST)):  # type: ignore[misc]  #  
Unsupported dynamic base class "_error_class"
     pass
 
 
-class UnauthorizedStatus(_error_class(UNAUTHORIZED)):
+class UnauthorizedStatus(_error_class(UNAUTHORIZED)):  # type: ignore[misc]
     pass
 
 
-class ForbiddenStatus(_error_class(FORBIDDEN)):
+class ForbiddenStatus(_error_class(FORBIDDEN)):  # type: ignore[misc]
     pass
 
 
-class NotFoundStatus(_error_class(NOT_FOUND)):
+class NotFoundStatus(_error_class(NOT_FOUND)):  # type: ignore[misc]
     pass
 
 
-class InternalServerErrorStatus(_error_class(INTERNAL_SERVER_ERROR)):
+class InternalServerErrorStatus(_error_class(INTERNAL_SERVER_ERROR)):  # type: 
ignore[misc]
     pass
 
 
-class NotImplementedStatus(_error_class(NOT_IMPLEMENTED)):
+class NotImplementedStatus(_error_class(NOT_IMPLEMENTED)):  # type: 
ignore[misc]
     pass
 
 
diff --git a/python/qpid_dispatch_internal/dispatch.pyi 
b/python/qpid_dispatch_internal/dispatch.pyi
new file mode 100644
index 0000000..9fdbc46
--- /dev/null
+++ b/python/qpid_dispatch_internal/dispatch.pyi
@@ -0,0 +1,68 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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
+#
+
+"""Type stubs for objects implemented in the C extension module"""
+
+import ctypes
+from typing import List
+
+
+class QdDll(ctypes.PyDLL):
+    def __init__(self, handle):
+        ...
+
+    def _prototype(self, f, restype, argtypes, check=True):
+        ...
+
+    def function(self, fname, restype, argtypes, check=True):
+        ...
+
+
+FORBIDDEN: List[str]
+
+LOG_TRACE: int
+LOG_DEBUG: int
+LOG_INFO: int
+LOG_NOTICE: int
+LOG_WARNING: int
+LOG_ERROR: int
+LOG_CRITICAL: int
+LOG_STACK_LIMIT: int
+
+TREATMENT_MULTICAST_FLOOD: int
+TREATMENT_MULTICAST_ONCE: int
+TREATMENT_ANYCAST_CLOSEST: int
+TREATMENT_ANYCAST_BALANCED: int
+TREATMENT_LINK_BALANCED: int
+
+
+class LogAdapter:
+    def __init__(self, mod_name):
+        ...
+
+    def log(self, level, text):
+        ...
+
+
+class IoAdapter:
+    def __init__(self, handler, address, global_address=False):
+        ...
+
+    def send(self, address, properties, application_properties, body, 
correlation_id=None):
+        ...
diff --git a/tests/TCP_echo_server.py b/tests/TCP_echo_server.py
index db15c02..2da12d1 100755
--- a/tests/TCP_echo_server.py
+++ b/tests/TCP_echo_server.py
@@ -83,7 +83,7 @@ def split_chunk_for_display(raw_bytes):
 class TcpEchoServer:
 
     def __init__(self, prefix="ECHO_SERVER", port: Union[str, int] = "0", 
echo_count=0, timeout=0.0, logger=None,
-                 conn_stall=0.0, close_on_conn=False, close_on_data=False):
+                 conn_stall=0.0, close_on_conn=False, close_on_data=False) -> 
None:
         """
         Start echo server in separate thread
 
@@ -92,9 +92,8 @@ class TcpEchoServer:
         :param echo_count: exit after echoing this many bytes
         :param timeout: exit after this many seconds
         :param logger: Logger() object
-        :return:
         """
-        self.sock = None
+        self.sock: socket.socket
         self.prefix = prefix
         self.port = int(port)
         self.echo_count = echo_count
diff --git a/tests/http2_server.py b/tests/http2_server.py
index 7cad010..895a5a9 100644
--- a/tests/http2_server.py
+++ b/tests/http2_server.py
@@ -117,5 +117,14 @@ async def process_upload_data():
     return "Success!"
 
 
-#app.run(port=5000, certfile='cert.pem', keyfile='key.pem')
-app.run(port=os.getenv('SERVER_LISTEN_PORT'))
+def main():
+    port = os.getenv('SERVER_LISTEN_PORT')
+    if port is None:
+        raise RuntimeError("Environment variable `SERVER_LISTEN_PORT` is not 
set.")
+
+    # app.run(port=5000, certfile='cert.pem', keyfile='key.pem')
+    app.run(port=int(port))
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/http2_slow_q2_server.py b/tests/http2_slow_q2_server.py
index 82ef2a6..e2c6a3e 100644
--- a/tests/http2_slow_q2_server.py
+++ b/tests/http2_slow_q2_server.py
@@ -88,20 +88,29 @@ def handle(sock):
             sock.sendall(data_to_send)
 
 
-signal.signal(signal.SIGHUP, receive_signal)
-signal.signal(signal.SIGINT, receive_signal)
-signal.signal(signal.SIGQUIT, receive_signal)
-signal.signal(signal.SIGILL, receive_signal)
-signal.signal(signal.SIGTERM, receive_signal)
-
-sock = socket.socket()
-sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-sock.bind(('0.0.0.0', int(os.getenv('SERVER_LISTEN_PORT'))))
-sock.listen(5)
-
-while True:
-    # The accept method blocks until someone attempts to connect to our TCP
-    # port: when they do, it returns a tuple: the first element is a new
-    # socket object, the second element is a tuple of the address the new
-    # connection is from
-    handle(sock.accept()[0])
+def main():
+    signal.signal(signal.SIGHUP, receive_signal)
+    signal.signal(signal.SIGINT, receive_signal)
+    signal.signal(signal.SIGQUIT, receive_signal)
+    signal.signal(signal.SIGILL, receive_signal)
+    signal.signal(signal.SIGTERM, receive_signal)
+
+    port = os.getenv('SERVER_LISTEN_PORT')
+    if port is None:
+        raise RuntimeError("Environment variable `SERVER_LISTEN_PORT` is not 
set.")
+
+    sock = socket.socket()
+    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+    sock.bind(('0.0.0.0', int(port)))
+    sock.listen(5)
+
+    while True:
+        # The accept method blocks until someone attempts to connect to our TCP
+        # port: when they do, it returns a tuple: the first element is a new
+        # socket object, the second element is a tuple of the address the new
+        # connection is from
+        handle(sock.accept()[0])
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/hyperh2_server.py b/tests/hyperh2_server.py
index 13e5798..2784e45 100644
--- a/tests/hyperh2_server.py
+++ b/tests/hyperh2_server.py
@@ -88,20 +88,29 @@ def handle(sock):
             sock.sendall(data_to_send)
 
 
-signal.signal(signal.SIGHUP, receive_signal)
-signal.signal(signal.SIGINT, receive_signal)
-signal.signal(signal.SIGQUIT, receive_signal)
-signal.signal(signal.SIGILL, receive_signal)
-signal.signal(signal.SIGTERM, receive_signal)
-
-sock = socket.socket()
-sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-sock.bind(('0.0.0.0', int(os.getenv('SERVER_LISTEN_PORT'))))
-sock.listen(5)
-
-while True:
-    # The accept method blocks until someone attempts to connect to our TCP
-    # port: when they do, it returns a tuple: the first element is a new
-    # socket object, the second element is a tuple of the address the new
-    # connection is from
-    handle(sock.accept()[0])
+def main():
+    signal.signal(signal.SIGHUP, receive_signal)
+    signal.signal(signal.SIGINT, receive_signal)
+    signal.signal(signal.SIGQUIT, receive_signal)
+    signal.signal(signal.SIGILL, receive_signal)
+    signal.signal(signal.SIGTERM, receive_signal)
+
+    port = os.getenv('SERVER_LISTEN_PORT')
+    if port is None:
+        raise RuntimeError("Environment variable `SERVER_LISTEN_PORT` is not 
set.")
+
+    sock = socket.socket()
+    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+    sock.bind(('0.0.0.0', int(port)))
+    sock.listen(5)
+
+    while True:
+        # The accept method blocks until someone attempts to connect to our TCP
+        # port: when they do, it returns a tuple: the first element is a new
+        # socket object, the second element is a tuple of the address the new
+        # connection is from
+        handle(sock.accept()[0])
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/run_system_tests.py b/tests/run_system_tests.py
index 51f82e1..cad6b5e 100644
--- a/tests/run_system_tests.py
+++ b/tests/run_system_tests.py
@@ -42,5 +42,3 @@ for m in test_modules:
     all_tests.addTest(tests)
 result = unittest.TextTestRunner(verbosity=2).run(all_tests)
 sys.exit(not result.wasSuccessful())
-
-sys.argv = ['unittest', '-v'] + tests
diff --git a/tests/system_test.py b/tests/system_test.py
index 4255554..280f0a3 100755
--- a/tests/system_test.py
+++ b/tests/system_test.py
@@ -28,6 +28,8 @@ Features:
 - Sundry other tools.
 """
 
+from typing import Callable
+
 import errno
 import sys
 import time
@@ -126,7 +128,7 @@ def retry_delay(deadline, delay, max_delay):
 TIMEOUT = float(os.environ.get("QPID_SYSTEM_TEST_TIMEOUT", 60))
 
 
-def retry(function, timeout=TIMEOUT, delay=.001, max_delay=1):
+def retry(function: Callable[[], bool], timeout: float = TIMEOUT, delay: float 
= .001, max_delay: float = 1):
     """Call function until it returns a true value or timeout expires.
     Double the delay for each retry up to max_delay.
     Returns what function returns or None if timeout expires.
@@ -363,7 +365,7 @@ class Http2Server(HttpServer):
 class Qdrouterd(Process):
     """Run a Qpid Dispatch Router Daemon"""
 
-    class Config(list, Config):
+    class Config(list, Config):  # type: ignore[misc]  # Cannot resolve name 
"Config" (possible cyclic definition)  # mypy#10958
         """
         A router configuration.
 
diff --git a/tests/system_tests_edge_router.py 
b/tests/system_tests_edge_router.py
index 8cd1f17..97f1f5e 100644
--- a/tests/system_tests_edge_router.py
+++ b/tests/system_tests_edge_router.py
@@ -2540,6 +2540,7 @@ class MobileAddressMulticastTest(MessagingHandler):
 
     def on_released(self, event):
         self.n_released += 1
+        self.send_test_message()
 
     def timeout(self):
         if self.dup_msg:
@@ -2655,9 +2656,6 @@ class MobileAddressMulticastTest(MessagingHandler):
             self.receiver3_conn.close()
             self.sender_conn.close()
 
-    def on_released(self, event):
-        self.send_test_message()
-
     def run(self):
         Container(self).run()
 
diff --git a/tests/system_tests_priority.py b/tests/system_tests_priority.py
index 70e42f9..d6e5063 100644
--- a/tests/system_tests_priority.py
+++ b/tests/system_tests_priority.py
@@ -18,7 +18,7 @@
 #
 
 
-from proton import Message, Timeout
+from proton import Message
 from proton.handlers import MessagingHandler
 from proton.reactor import Container
 
diff --git a/tests/system_tests_qdmanage.py b/tests/system_tests_qdmanage.py
index c7fad58..c42cf7a 100644
--- a/tests/system_tests_qdmanage.py
+++ b/tests/system_tests_qdmanage.py
@@ -210,10 +210,6 @@ class QdmanageTest(TestCase):
 
     def test_get_attributes(self):
         out = json.loads(self.run_qdmanage("get-attributes"))
-        self.assertEqual(len(out), 28)
-
-    def test_get_attributes(self):
-        out = json.loads(self.run_qdmanage("get-attributes"))
         self.assertEqual(len(out), TOTAL_ENTITIES)
 
     def test_get_operations(self):
diff --git a/tests/system_tests_sasl_plain.py b/tests/system_tests_sasl_plain.py
index 6afc9f3..af5edc6 100644
--- a/tests/system_tests_sasl_plain.py
+++ b/tests/system_tests_sasl_plain.py
@@ -676,10 +676,6 @@ class 
RouterTestVerifyHostNameNo(RouterTestPlainSaslCommon):
 
         cls.routers[1].wait_router_connected('QDR.X')
 
-    @staticmethod
-    def ssl_file(name):
-        return os.path.join(DIR, 'ssl_certs', name)
-
     def common_asserts(self, results):
         search = "QDR.X"
         found = False
diff --git a/tests/system_tests_ssl.py b/tests/system_tests_ssl.py
index 196a910..2d55b0b 100644
--- a/tests/system_tests_ssl.py
+++ b/tests/system_tests_ssl.py
@@ -117,6 +117,7 @@ class RouterTestSslClient(RouterTestSslBase):
             p = Popen(['openssl', 'version'], stdout=PIPE, 
universal_newlines=True)
             openssl_out = p.communicate()[0]
             m = re.search(r'[0-9]+\.[0-9]+\.[0-9]+', openssl_out)
+            assert m is not None
             OPENSSL_OUT_VER = m.group(0)
             OPENSSL_VER_1_1_GT = StrictVersion(OPENSSL_OUT_VER) >= 
StrictVersion('1.1')
             print("OpenSSL Version found = %s" % OPENSSL_OUT_VER)
@@ -132,13 +133,8 @@ class RouterTestSslClient(RouterTestSslBase):
     OPENSSL_ALLOW_TLSV1_3 = False
 
     # Test if OpenSSL has TLSv1_3
-    OPENSSL_HAS_TLSV1_3 = False
-    if OPENSSL_VER_1_1_GT:
-        try:
-            _ = ssl.TLSVersion.TLSv1_3
-            OPENSSL_HAS_TLSV1_3 = True
-        except AttributeError:
-            pass
+    #  (see 
https://mypy.readthedocs.io/en/stable/common_issues.html#python-version-and-system-platform-checks
 for mypy considerations)
+    OPENSSL_HAS_TLSV1_3 = OPENSSL_VER_1_1_GT and sys.version_info >= (3, 7) 
and ssl.HAS_TLSv1_3
 
     # Test if Proton supports TLSv1_3
     try:
diff --git a/tests/system_tests_topology.py b/tests/system_tests_topology.py
index c10122b..c5dcf08 100644
--- a/tests/system_tests_topology.py
+++ b/tests/system_tests_topology.py
@@ -19,7 +19,7 @@
 
 import time
 
-from proton import Message, Timeout
+from proton import Message
 from proton.handlers import MessagingHandler
 from proton.reactor import Container
 
diff --git a/tests/system_tests_topology_addition.py 
b/tests/system_tests_topology_addition.py
index 5972425..60a20a7 100644
--- a/tests/system_tests_topology_addition.py
+++ b/tests/system_tests_topology_addition.py
@@ -19,7 +19,7 @@
 
 import unittest
 
-from proton import Message, Timeout
+from proton import Message
 from proton.handlers import MessagingHandler
 from proton.reactor import Container
 
diff --git a/tests/system_tests_topology_disposition.py 
b/tests/system_tests_topology_disposition.py
index 2f7aadd..25e8046 100644
--- a/tests/system_tests_topology_disposition.py
+++ b/tests/system_tests_topology_disposition.py
@@ -24,7 +24,7 @@ import unittest
 from subprocess import PIPE, STDOUT
 
 import proton
-from proton import Message, Timeout
+from proton import Message
 from proton.handlers import MessagingHandler
 from proton.reactor import Container
 from qpid_dispatch_internal.compat import UNICODE
diff --git a/tests/test_command.py b/tests/test_command.py
index d82b713..38a7fe3 100644
--- a/tests/test_command.py
+++ b/tests/test_command.py
@@ -34,9 +34,9 @@ def mock_error(self, message):
     raise ValueError(message)
 
 
-argparse.ArgumentParser.error = mock_error
+argparse.ArgumentParser.error = mock_error  # type: ignore[assignment]  # 
Cannot assign to a method
 
-# Since BusManager file is definded in tools/qdmanage.in -> tools/qdmanage
+# Since BusManager file is defined in tools/qdmanage.in -> tools/qdmanage
 # otherwise it could be just imported
 
 
diff --git a/tests/tox.ini.in b/tests/tox.ini.in
index 6c0d1fb..7f9c91c 100644
--- a/tests/tox.ini.in
+++ b/tests/tox.ini.in
@@ -28,7 +28,6 @@ skip_install = True
 commands =
   flake8 --count --show-source \
     ${CMAKE_SOURCE_DIR}/python \
-    ${CMAKE_SOURCE_DIR}/console \
     ${CMAKE_SOURCE_DIR}/docs \
     ${CMAKE_SOURCE_DIR}/tests \
     ${CMAKE_SOURCE_DIR}/tools \
@@ -36,19 +35,31 @@ commands =
     ${CMAKE_SOURCE_DIR}/tools/qdmanage
 
   # TODO(pylint#5648): crash while parsing system_test.py
-  pylint --rcfile ${CMAKE_BINARY_DIR}/tests/tox.ini \
+  pylint --jobs 2 --rcfile ${CMAKE_BINARY_DIR}/tests/tox.ini \
     --ignore=system_test.py \
     ${CMAKE_SOURCE_DIR}/python \
-    ${CMAKE_SOURCE_DIR}/console \
     ${CMAKE_SOURCE_DIR}/docs \
     ${CMAKE_SOURCE_DIR}/tests \
     ${CMAKE_SOURCE_DIR}/tools \
     ${CMAKE_SOURCE_DIR}/tools/qdstat \
     ${CMAKE_SOURCE_DIR}/tools/qdmanage
 
+  mypy --config-file ${CMAKE_BINARY_DIR}/tests/tox.ini \
+    ${CMAKE_SOURCE_DIR}/python \
+    ${CMAKE_SOURCE_DIR}/docs \
+    ${CMAKE_SOURCE_DIR}/tests \
+    ${CMAKE_SOURCE_DIR}/tools \
+    ${CMAKE_BINARY_DIR}/python/qpid_dispatch_site.py
+
+# new checker versions sometimes add new checks; pin the versions to avoid 
unexpected
+#  surprises to folks just trying to get their job done (c.f. DISPATCH-1305, 
DISPATCH-1466, DISPATCH-1834)
 deps =
-    hacking>=1.1.0
-    pylint
+  # TODO(DISPATCH-2321) also install python-qpid-proton here
+  hacking==4.1.0
+  # hacking 4.1.0 requires flake8<3.9.0 and >=3.8.0
+  flake8==3.8.4
+  pylint==2.12.2
+  mypy==0.910
 
 [testenv:py36]
 basepython = python3.6
@@ -205,3 +216,67 @@ disable =
     useless-else-on-loop,
     useless-super-delegation,
     wrong-import-position,
+
+[mypy]
+warn_redundant_casts = True
+warn_unused_ignores = True
+
+# mypy cannot handle overridden attributes
+# https://github.com/python/mypy/issues/7505
+allow_untyped_globals = True
+
+# https://mypy.readthedocs.io/en/stable/error_codes.html#displaying-error-codes
+show_error_codes = True
+
+# this would print lots and lots of errors
+# check_untyped_defs = True
+
+# ignore missing stub files for dependencies
+
+#[mypy-_ssl]
+#ignore_missing_imports = True
+
+[mypy-proton.*]
+ignore_missing_imports = True
+
+[mypy-cproton]
+ignore_missing_imports = True
+
+[mypy-qpidtoollibs]
+ignore_missing_imports = True
+
+[mypy-qpid_messaging]
+ignore_missing_imports = True
+
+[mypy-pyprof2calltree]
+ignore_missing_imports = True
+
+[mypy-quart.*]
+ignore_missing_imports = True
+
+[mypy-werkzeug.*]
+ignore_missing_imports = True
+
+[mypy-selectors]
+ignore_missing_imports = True
+
+[mypy-h2.*]
+ignore_missing_imports = True
+
+[mypy-google.protobuf]
+ignore_missing_imports = True
+
+[mypy-grpc]
+ignore_missing_imports = True
+
+[mypy-grpcio]
+ignore_missing_imports = True
+
+[mypy-protobuf]
+ignore_missing_imports = True
+
+[mypy-websockets]
+ignore_missing_imports = True
+
+[mypy-pytest]
+ignore_missing_imports = True

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to