From ca30c8079ce28a0cf6b2fc23d717d8f5f6abe406 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 10 Apr 2022 06:34:45 -0500 Subject: [PATCH 1/8] Add basic mypy support --- .pre-commit-config.yaml | 9 ++++++++ MANIFEST.in | 1 + docs/conf.py | 6 ++--- ipykernel/_eventloop_macos.py | 4 ++-- ipykernel/_version.py | 3 ++- ipykernel/connect.py | 11 +++++---- ipykernel/debugger.py | 7 +++--- ipykernel/displayhook.py | 2 +- ipykernel/eventloops.py | 10 ++++----- ipykernel/gui/gtk3embed.py | 7 +++--- ipykernel/gui/gtkembed.py | 7 +++--- ipykernel/heartbeat.py | 2 +- ipykernel/inprocess/blocking.py | 2 +- ipykernel/inprocess/channels.py | 2 +- ipykernel/inprocess/socket.py | 2 +- ipykernel/iostream.py | 24 +++++++++++--------- ipykernel/ipkernel.py | 9 ++++---- ipykernel/jsonutil.py | 2 +- ipykernel/kernelapp.py | 8 ++++--- ipykernel/kernelbase.py | 10 +++++---- ipykernel/log.py | 4 ++-- ipykernel/parentpoller.py | 8 +++---- ipykernel/pickleutil.py | 18 ++++++++------- ipykernel/py.typed | 0 ipykernel/pylab/backend_inline.py | 2 +- ipykernel/pylab/config.py | 2 +- ipykernel/serialize.py | 6 ++--- ipykernel/trio_runner.py | 2 +- ipykernel/zmqshell.py | 4 ++-- pyproject.toml | 37 +++++++++++++++++++++++++++++++ setup.py | 8 +++---- 31 files changed, 142 insertions(+), 77 deletions(-) create mode 100644 ipykernel/py.typed diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c121ded00..0ff9a5bff 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -41,6 +41,15 @@ repos: args: [--max-line-length=200] stages: [manual] + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.942 + hooks: + - id: mypy + exclude: 'ipykernel.*tests' + args: ["--config-file", "pyproject.toml"] + additional_dependencies: [tornado, jupyter_client, pytest] + stages: [manual] + - repo: https://github.com/pycqa/flake8 rev: 4.0.1 hooks: diff --git a/MANIFEST.in b/MANIFEST.in index e75739460..1fb3d59ee 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,6 @@ include *.md include pyproject.toml +include ipykernel/py.typed # Documentation graft docs diff --git a/docs/conf.py b/docs/conf.py index a1ad70d12..95f7219ec 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -61,7 +61,7 @@ # built documents. # -version_ns = {} +version_ns: dict = {} here = os.path.dirname(__file__) version_py = os.path.join(here, os.pardir, "ipykernel", "_version.py") with open(version_py) as f: @@ -150,7 +150,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = [] +html_static_path: list = [] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -217,7 +217,7 @@ # -- Options for LaTeX output --------------------------------------------- -latex_elements = {} +latex_elements: dict = {} # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, diff --git a/ipykernel/_eventloop_macos.py b/ipykernel/_eventloop_macos.py index 94762b65d..7598f8f6e 100644 --- a/ipykernel/_eventloop_macos.py +++ b/ipykernel/_eventloop_macos.py @@ -10,7 +10,7 @@ import ctypes.util from threading import Event -objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("objc")) +objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("objc")) # type:ignore[arg-type] void_p = ctypes.c_void_p @@ -42,7 +42,7 @@ def C(classname): # end obj-c boilerplate from appnope # CoreFoundation C-API calls we will use: -CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library("CoreFoundation")) +CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library("CoreFoundation")) # type:ignore[arg-type] CFAbsoluteTimeGetCurrent = CoreFoundation.CFAbsoluteTimeGetCurrent CFAbsoluteTimeGetCurrent.restype = ctypes.c_double diff --git a/ipykernel/_version.py b/ipykernel/_version.py index 7b545dd0d..31dc1d3c5 100644 --- a/ipykernel/_version.py +++ b/ipykernel/_version.py @@ -9,7 +9,8 @@ # Build up version_info tuple for backwards compatibility pattern = r"(?P\d+).(?P\d+).(?P\d+)(?P.*)" match = re.match(pattern, __version__) -parts = [int(match[part]) for part in ["major", "minor", "patch"]] +assert match is not None +parts: list = [int(match[part]) for part in ["major", "minor", "patch"]] if match["rest"]: parts.append(match["rest"]) version_info = tuple(parts) diff --git a/ipykernel/connect.py b/ipykernel/connect.py index b56b9b8ff..39e00e25a 100644 --- a/ipykernel/connect.py +++ b/ipykernel/connect.py @@ -6,6 +6,7 @@ import json import sys from subprocess import PIPE, Popen +from typing import Any import jupyter_client from jupyter_client import write_connection_file @@ -68,13 +69,15 @@ def get_connection_info(connection_file=None, unpack=False): cf = _find_connection_file(connection_file) with open(cf) as f: - info = f.read() + info_str = f.read() if unpack: - info = json.loads(info) + info = json.loads(info_str) # ensure key is bytes: info["key"] = info.get("key", "").encode() - return info + return info + + return info_str def connect_qtconsole(connection_file=None, argv=None): @@ -105,7 +108,7 @@ def connect_qtconsole(connection_file=None, argv=None): cmd = ";".join(["from IPython.qt.console import qtconsoleapp", "qtconsoleapp.main()"]) - kwargs = {} + kwargs: dict[str, Any] = {} # Launch the Qt console in a separate session & process group, so # interrupting the kernel doesn't kill it. kwargs["start_new_session"] = True diff --git a/ipykernel/debugger.py b/ipykernel/debugger.py index 8368acccc..da275ed21 100644 --- a/ipykernel/debugger.py +++ b/ipykernel/debugger.py @@ -1,6 +1,7 @@ import os import re import sys +import typing as t import zmq from IPython.core.getipython import get_ipython @@ -89,7 +90,7 @@ def __init__(self, event_callback, log): self.tcp_buffer = "" self._reset_tcp_pos() self.event_callback = event_callback - self.message_queue = Queue() + self.message_queue: Queue = Queue() self.log = log def _reset_tcp_pos(self): @@ -100,7 +101,7 @@ def _reset_tcp_pos(self): def _put_message(self, raw_msg): self.log.debug("QUEUE - _put_message:") - msg = jsonapi.loads(raw_msg) + msg = t.cast(dict, jsonapi.loads(raw_msg)) if msg["type"] == "event": self.log.debug("QUEUE - received event:") self.log.debug(msg) @@ -290,7 +291,7 @@ def __init__( self.is_started = False self.event_callback = event_callback self.just_my_code = just_my_code - self.stopped_queue = Queue() + self.stopped_queue: Queue = Queue() self.started_debug_handlers = {} for msg_type in Debugger.started_debug_msg_types: diff --git a/ipykernel/displayhook.py b/ipykernel/displayhook.py index 2ba2c08c3..e7c98c01d 100644 --- a/ipykernel/displayhook.py +++ b/ipykernel/displayhook.py @@ -32,7 +32,7 @@ def __call__(self, obj): if obj is None: return - builtins._ = obj + builtins._ = obj # type:ignore[attr-defined] sys.stdout.flush() sys.stderr.flush() contents = { diff --git a/ipykernel/eventloops.py b/ipykernel/eventloops.py index fbf0c4cae..fdc5ddd60 100644 --- a/ipykernel/eventloops.py +++ b/ipykernel/eventloops.py @@ -248,7 +248,7 @@ def process_stream_events(stream, *a, **kw): notifier = partial(process_stream_events, kernel.shell_stream) # seems to be needed for tk - notifier.__name__ = "notifier" + notifier.__name__ = "notifier" # type:ignore[attr-defined] app.tk.createfilehandler(kernel.shell_stream.getsockopt(zmq.FD), READABLE, notifier) # schedule initial call after start app.after(0, notifier) @@ -386,7 +386,7 @@ def loop_asyncio(kernel): # main loop is closed, create a new one loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) - loop._should_close = False + loop._should_close = False # type:ignore[attr-defined] # pause eventloop when there's an event on a zmq socket def process_stream_events(stream): @@ -406,7 +406,7 @@ def process_stream_events(stream): continue except Exception as e: error = e - if loop._should_close: + if loop._should_close: # type:ignore[attr-defined] loop.close() if error is not None: raise error @@ -424,14 +424,14 @@ def loop_asyncio_exit(kernel): def close_loop(): if hasattr(loop, "shutdown_asyncgens"): yield from loop.shutdown_asyncgens() - loop._should_close = True + loop._should_close = True # type:ignore[attr-defined] loop.stop() if loop.is_running(): close_loop() elif not loop.is_closed(): - loop.run_until_complete(close_loop) + loop.run_until_complete(close_loop) # type:ignore[call-overload] loop.close() diff --git a/ipykernel/gui/gtk3embed.py b/ipykernel/gui/gtk3embed.py index 198f8cacd..1a9542a9b 100644 --- a/ipykernel/gui/gtk3embed.py +++ b/ipykernel/gui/gtk3embed.py @@ -14,11 +14,11 @@ import sys # Third-party -import gi +import gi # type:ignore[import] gi.require_version("Gdk", "3.0") gi.require_version("Gtk", "3.0") -from gi.repository import GObject, Gtk +from gi.repository import GObject, Gtk # type:ignore[import] # ----------------------------------------------------------------------------- # Classes and functions @@ -63,7 +63,8 @@ def stop(self): # FIXME: this one isn't getting called because we have no reliable # kernel shutdown. We need to fix that: once the kernel has a # shutdown mechanism, it can call this. - self.gtk_main_quit() + if self.gtk_main_quit: + self.gtk_main_quit() sys.exit() def _hijack_gtk(self): diff --git a/ipykernel/gui/gtkembed.py b/ipykernel/gui/gtkembed.py index 19522c441..47cf48421 100644 --- a/ipykernel/gui/gtkembed.py +++ b/ipykernel/gui/gtkembed.py @@ -14,8 +14,8 @@ import sys # Third-party -import gobject -import gtk +import gobject # type:ignore[import] +import gtk # type:ignore[import] # ----------------------------------------------------------------------------- # Classes and functions @@ -60,7 +60,8 @@ def stop(self): # FIXME: this one isn't getting called because we have no reliable # kernel shutdown. We need to fix that: once the kernel has a # shutdown mechanism, it can call this. - self.gtk_main_quit() + if self.gtk_main_quit: + self.gtk_main_quit() sys.exit() def _hijack_gtk(self): diff --git a/ipykernel/heartbeat.py b/ipykernel/heartbeat.py index 6f5ddbec3..6f3bd9092 100644 --- a/ipykernel/heartbeat.py +++ b/ipykernel/heartbeat.py @@ -64,7 +64,7 @@ def _try_bind_socket(self): def _bind_socket(self): try: - win_in_use = errno.WSAEADDRINUSE + win_in_use = errno.WSAEADDRINUSE # type:ignore[attr-defined] except AttributeError: win_in_use = None diff --git a/ipykernel/inprocess/blocking.py b/ipykernel/inprocess/blocking.py index 269eb4158..1ac7829fc 100644 --- a/ipykernel/inprocess/blocking.py +++ b/ipykernel/inprocess/blocking.py @@ -23,7 +23,7 @@ class BlockingInProcessChannel(InProcessChannel): def __init__(self, *args, **kwds): super().__init__(*args, **kwds) - self._in_queue = Queue() + self._in_queue: Queue = Queue() def call_handlers(self, msg): self._in_queue.put(msg) diff --git a/ipykernel/inprocess/channels.py b/ipykernel/inprocess/channels.py index b81d69321..6648a0f37 100644 --- a/ipykernel/inprocess/channels.py +++ b/ipykernel/inprocess/channels.py @@ -13,7 +13,7 @@ class InProcessChannel: """Base class for in-process channels.""" - proxy_methods = [] + proxy_methods: list = [] def __init__(self, client=None): super().__init__() diff --git a/ipykernel/inprocess/socket.py b/ipykernel/inprocess/socket.py index 477c36a47..ff826ea0c 100644 --- a/ipykernel/inprocess/socket.py +++ b/ipykernel/inprocess/socket.py @@ -31,7 +31,7 @@ def recv_multipart(self, flags=0, copy=True, track=False): return self.queue.get_nowait() def send_multipart(self, msg_parts, flags=0, copy=True, track=False): - msg_parts = list(map(zmq.Message, msg_parts)) + msg_parts = list(map(zmq.Message, msg_parts)) # type:ignore[arg-type] self.queue.put_nowait(msg_parts) self.message_sent += 1 diff --git a/ipykernel/iostream.py b/ipykernel/iostream.py index 1cc4c8f16..f2737ebc1 100644 --- a/ipykernel/iostream.py +++ b/ipykernel/iostream.py @@ -13,6 +13,7 @@ from binascii import b2a_hex from collections import deque from io import StringIO, TextIOBase +from typing import Any, Optional from weakref import WeakSet import zmq @@ -66,13 +67,13 @@ def __init__(self, socket, pipe=False): if pipe: self._setup_pipe_in() self._local = threading.local() - self._events = deque() - self._event_pipes = WeakSet() + self._events: deque = deque() + self._event_pipes: WeakSet = WeakSet() self._setup_event_pipe() self.thread = threading.Thread(target=self._thread_main, name="IOPub") self.thread.daemon = True - self.thread.pydev_do_not_trace = True - self.thread.is_pydev_daemon_thread = True + self.thread.pydev_do_not_trace = True # type:ignore[attr-defined] + self.thread.is_pydev_daemon_thread = True # type:ignore[attr-defined] self.thread.name = "IOPub" def _thread_main(self): @@ -256,7 +257,8 @@ def __getattr__(self, attr): """Wrap socket attr access for backward-compatibility""" if attr.startswith("__") and attr.endswith("__"): # don't wrap magic methods - super().__getattr__(attr) + super().__getattr__(attr) # type:ignore[misc] + assert self.io_thread is not None if hasattr(self.io_thread.socket, attr): warnings.warn( f"Accessing zmq Socket attribute {attr} on BackgroundSocket" @@ -266,7 +268,7 @@ def __getattr__(self, attr): stacklevel=2, ) return getattr(self.io_thread.socket, attr) - super().__getattr__(attr) + super().__getattr__(attr) # type:ignore[misc] def __setattr__(self, attr, value): if attr == "io_thread" or (attr.startswith("__" and attr.endswith("__"))): @@ -279,6 +281,7 @@ def __setattr__(self, attr, value): DeprecationWarning, stacklevel=2, ) + assert self.io_thread is not None setattr(self.io_thread.socket, attr, value) def send(self, msg, *args, **kwargs): @@ -286,6 +289,7 @@ def send(self, msg, *args, **kwargs): def send_multipart(self, *args, **kwargs): """Schedule send in IO thread""" + assert self.io_thread is not None return self.io_thread.send_multipart(*args, **kwargs) @@ -302,6 +306,7 @@ class OutStream(TextIOBase): flush_interval = 0.2 topic = None encoding = "UTF-8" + _exc: Optional[Any] = None def fileno(self): """ @@ -362,8 +367,7 @@ def __init__( """ if pipe is not None: warnings.warn( - "pipe argument to OutStream is deprecated and ignored", - " since ipykernel 4.2.3.", + "pipe argument to OutStream is deprecated and ignored since ipykernel 4.2.3.", DeprecationWarning, stacklevel=2, ) @@ -518,7 +522,7 @@ def _flush(self): ident=self.topic, ) - def write(self, string: str) -> int: + def write(self, string: str) -> Optional[int]: # type:ignore[override] """Write to current stream after encoding if necessary Returns @@ -550,7 +554,7 @@ def write(self, string: str) -> int: # mp.Pool cannot be trusted to flush promptly (or ever), # and this helps. if self._subprocess_flush_pending: - return + return None self._subprocess_flush_pending = True # We can not rely on self._io_loop.call_later from a subprocess self.pub_thread.schedule(self._flush) diff --git a/ipykernel/ipkernel.py b/ipykernel/ipkernel.py index 3c695975f..889782cc7 100644 --- a/ipykernel/ipkernel.py +++ b/ipykernel/ipkernel.py @@ -5,6 +5,7 @@ import getpass import signal import sys +import typing as t from contextlib import contextmanager from functools import partial @@ -242,7 +243,7 @@ def _restore_input(self): getpass.getpass = self._save_getpass - @property + @property # type:ignore[override] def execution_count(self): return self.shell.execution_count @@ -263,7 +264,7 @@ def _cancel_on_sigint(self, future): but this turns it into a CancelledError. At least it gets a decent traceback to the user. """ - sigint_future = asyncio.Future() + sigint_future: asyncio.Future[int] = asyncio.Future() # whichever future finishes first, # cancel the other one @@ -310,7 +311,7 @@ async def do_execute( self._forward_input(allow_stdin) - reply_content = {} + reply_content: dict[str, t.Any] = {} if hasattr(shell, "run_cell_async") and hasattr(shell, "should_run_async"): run_cell = shell.run_cell_async should_run_async = shell.should_run_async @@ -506,7 +507,7 @@ def _experimental_do_complete(self, code, cursor_pos): def do_inspect(self, code, cursor_pos, detail_level=0, omit_sections=()): name = token_at_cursor(code, cursor_pos) - reply_content = {"status": "ok"} + reply_content: dict[str, t.Any] = {"status": "ok"} reply_content["data"] = {} reply_content["metadata"] = {} try: diff --git a/ipykernel/jsonutil.py b/ipykernel/jsonutil.py index 36565a842..eafc171c3 100644 --- a/ipykernel/jsonutil.py +++ b/ipykernel/jsonutil.py @@ -98,7 +98,7 @@ def json_clean(obj): it simply sanitizes it so that there will be no encoding errors later. """ - if JUPYTER_CLIENT_MAJOR_VERSION >= 7: + if int(JUPYTER_CLIENT_MAJOR_VERSION) >= 7: return obj # types that are 'atomic' and ok in json as-is. diff --git a/ipykernel/kernelapp.py b/ipykernel/kernelapp.py index 6eba8f50c..87bf36c82 100644 --- a/ipykernel/kernelapp.py +++ b/ipykernel/kernelapp.py @@ -232,7 +232,7 @@ def _try_bind_socket(self, s, port): def _bind_socket(self, s, port): try: - win_in_use = errno.WSAEADDRINUSE + win_in_use = errno.WSAEADDRINUSE # type:ignore[attr-defined] except AttributeError: win_in_use = None @@ -464,7 +464,7 @@ def init_io(self): self.log.debug("Seeing logger to stderr, rerouting to raw filedescriptor.") handler.stream = TextIOWrapper( - FileIO(sys.stderr._original_stdstream_copy, "w") + FileIO(sys.stderr._original_stdstream_copy, "w") # type:ignore[attr-defined] ) if self.displayhook_class: displayhook_factory = import_item(str(self.displayhook_class)) @@ -560,11 +560,13 @@ def init_gui_pylab(self): # is not associated with any execute request. shell = self.shell + assert shell is not None _showtraceback = shell._showtraceback try: # replace error-sending traceback with stderr def print_tb(etype, evalue, stb): print("GUI event loop or pylab initialization failed", file=sys.stderr) + assert shell is not None print(shell.InteractiveTB.stb2text(stb), file=sys.stderr) shell._showtraceback = print_tb @@ -644,7 +646,7 @@ def init_pdb(self): if hasattr(debugger, "InterruptiblePdb"): # Only available in newer IPython releases: debugger.Pdb = debugger.InterruptiblePdb - pdb.Pdb = debugger.Pdb + pdb.Pdb = debugger.Pdb # type:ignore[misc] pdb.set_trace = debugger.set_trace @catch_config_error diff --git a/ipykernel/kernelbase.py b/ipykernel/kernelbase.py index 62059ef2b..80cdae5cd 100644 --- a/ipykernel/kernelbase.py +++ b/ipykernel/kernelbase.py @@ -12,6 +12,7 @@ import socket import sys import time +import typing as t import uuid import warnings from datetime import datetime @@ -142,7 +143,7 @@ def _default_ident(self): # This should be overridden by wrapper kernels that implement any real # language. - language_info = {} + language_info: dict[str, object] = {} # any links that should go in the help menu help_links = List() @@ -262,7 +263,7 @@ def __init__(self, **kwargs): for msg_type in self.control_msg_types: self.control_handlers[msg_type] = getattr(self, msg_type) - self.control_queue = Queue() + self.control_queue: Queue = Queue() def dispatch_control(self, msg): self.control_queue.put_nowait(msg) @@ -278,6 +279,7 @@ async def poll_control_queue(self): async def _flush_control_queue(self): """Flush the control queue, wait for processing of any pending messages""" + tracer_future: t.Union[concurrent.futures.Future, asyncio.Future] if self.control_thread: control_loop = self.control_thread.io_loop # concurrent.futures.Futures are threadsafe @@ -529,7 +531,7 @@ def schedule_dispatch(self, dispatch, *args): def start(self): """register dispatchers for streams""" self.io_loop = ioloop.IOLoop.current() - self.msg_queue = Queue() + self.msg_queue: Queue = Queue() self.io_loop.add_callback(self.dispatch_queue) self.control_stream.on_recv(self.dispatch_control, copy=False) @@ -1191,7 +1193,7 @@ def _input_request(self, prompt, ident, parent, password=False): # zmq.select() is also uninterruptible, but at least this # way reads get noticed immediately and KeyboardInterrupts # get noticed fairly quickly by human response time standards. - rlist, _, xlist = zmq.select([self.stdin_socket], [], [self.stdin_socket], 0.01) + rlist, _, xlist = zmq.select([self.stdin_socket], [], [self.stdin_socket], 0.01) # type:ignore[arg-type] if rlist or xlist: ident, reply = self.session.recv(self.stdin_socket) if (ident, reply) != (None, None): diff --git a/ipykernel/log.py b/ipykernel/log.py index 66bb6722c..aca21d25b 100644 --- a/ipykernel/log.py +++ b/ipykernel/log.py @@ -18,11 +18,11 @@ def __init__(self, engine, *args, **kwargs): PUBHandler.__init__(self, *args, **kwargs) self.engine = engine - @property + @property # type:ignore[misc] def root_topic(self): """this is a property, in case the handler is created before the engine gets registered with an id""" if isinstance(getattr(self.engine, "id", None), int): - return "engine.%i" % self.engine.id + return "engine.%i" % self.engine.id # type:ignore[union-attr] else: return "engine" diff --git a/ipykernel/parentpoller.py b/ipykernel/parentpoller.py index d120f5000..a18f0440b 100644 --- a/ipykernel/parentpoller.py +++ b/ipykernel/parentpoller.py @@ -4,7 +4,7 @@ try: import ctypes except ImportError: - ctypes = None + ctypes = None # type:ignore[assignment] import os import platform import signal @@ -71,9 +71,9 @@ def __init__(self, interrupt_handle=None, parent_handle=None): def run(self): """Run the poll loop. This method never returns.""" try: - from _winapi import INFINITE, WAIT_OBJECT_0 + from _winapi import INFINITE, WAIT_OBJECT_0 # type:ignore[attr-defined] except ImportError: - from _subprocess import INFINITE, WAIT_OBJECT_0 + from _subprocess import INFINITE, WAIT_OBJECT_0 # type:ignore[import] # Build the list of handle to listen on. handles = [] @@ -86,7 +86,7 @@ def run(self): # Listen forever. while True: - result = ctypes.windll.kernel32.WaitForMultipleObjects( + result = ctypes.windll.kernel32.WaitForMultipleObjects( # type:ignore[attr-defined] len(handles), # nCount (c_int * len(handles))(*handles), # lpHandles False, # bWaitAll diff --git a/ipykernel/pickleutil.py b/ipykernel/pickleutil.py index 9ebd904d7..8f612e65a 100644 --- a/ipykernel/pickleutil.py +++ b/ipykernel/pickleutil.py @@ -35,7 +35,7 @@ def _get_cell_type(a=None): def inner(): return a - return type(inner.__closure__[0]) + return type(inner.__closure__[0]) # type:ignore[index] cell_type = _get_cell_type() @@ -72,7 +72,7 @@ def use_dill(): adds support for object methods and closures to serialization. """ # import dill causes most of the magic - import dill + import dill # type:ignore[import] # dill doesn't work with cPickle, # tell the two relevant modules to use plain pickle @@ -96,7 +96,7 @@ def use_cloudpickle(): adds support for object methods and closures to serialization. """ - import cloudpickle + import cloudpickle # type:ignore[import] global pickle pickle = cloudpickle @@ -188,18 +188,20 @@ def get_object(self, g=None): def inner(): return cell_contents - return inner.__closure__[0] + return inner.__closure__[0] # type:ignore[index] class CannedFunction(CannedObject): def __init__(self, f): self._check_type(f) self.code = f.__code__ + self.defaults: typing.Optional[list] if f.__defaults__: self.defaults = [can(fd) for fd in f.__defaults__] else: self.defaults = None + self.closure: typing.Optional[tuple] closure = f.__closure__ if closure: self.closure = tuple(can(cell) for cell in closure) @@ -260,7 +262,7 @@ def get_object(self, g=None): class CannedArray(CannedObject): def __init__(self, obj): - from numpy import ascontiguousarray + from numpy import ascontiguousarray # type:ignore[import] self.shape = obj.shape self.dtype = obj.dtype.descr if obj.dtype.fields else obj.dtype.str @@ -310,11 +312,11 @@ def get_object(self, g=None): class CannedBuffer(CannedBytes): - wrap = buffer + wrap = buffer # type:ignore[assignment] class CannedMemoryView(CannedBytes): - wrap = memoryview + wrap = memoryview # type:ignore[assignment] # ------------------------------------------------------------------------------- @@ -459,7 +461,7 @@ def uncan_sequence(obj, g=None): if buffer is not memoryview: can_map[buffer] = CannedBuffer -uncan_map = { +uncan_map: dict[type, typing.Callable] = { CannedObject: lambda obj, g: obj.get_object(g), dict: uncan_dict, } diff --git a/ipykernel/py.typed b/ipykernel/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/ipykernel/pylab/backend_inline.py b/ipykernel/pylab/backend_inline.py index b1627cac5..1466c9d34 100644 --- a/ipykernel/pylab/backend_inline.py +++ b/ipykernel/pylab/backend_inline.py @@ -5,7 +5,7 @@ import warnings -from matplotlib_inline.backend_inline import * # analysis: ignore # noqa F401 +from matplotlib_inline.backend_inline import * # type:ignore[import] # analysis: ignore # noqa F401 warnings.warn( "`ipykernel.pylab.backend_inline` is deprecated, directly " diff --git a/ipykernel/pylab/config.py b/ipykernel/pylab/config.py index 7622f9e11..8fbb53bae 100644 --- a/ipykernel/pylab/config.py +++ b/ipykernel/pylab/config.py @@ -5,7 +5,7 @@ import warnings -from matplotlib_inline.config import * # analysis: ignore # noqa F401 +from matplotlib_inline.config import * # type:ignore[import] # analysis: ignore # noqa F401 warnings.warn( "`ipykernel.pylab.config` is deprecated, directly use `matplotlib_inline.config`", diff --git a/ipykernel/serialize.py b/ipykernel/serialize.py index 6a1b79f78..6b77d8536 100644 --- a/ipykernel/serialize.py +++ b/ipykernel/serialize.py @@ -188,11 +188,11 @@ def unpack_apply_message(bufs, g=None, copy=True): info = pickle.loads(pinfo) arg_bufs, kwarg_bufs = bufs[: info["narg_bufs"]], bufs[info["narg_bufs"] :] - args = [] + args_list = [] for _ in range(info["nargs"]): arg, arg_bufs = deserialize_object(arg_bufs, g) - args.append(arg) - args = tuple(args) + args_list.append(arg) + args = tuple(args_list) assert not arg_bufs, "Shouldn't be any arg bufs left over" kwargs = {} diff --git a/ipykernel/trio_runner.py b/ipykernel/trio_runner.py index c72f6455e..7b8f2166c 100644 --- a/ipykernel/trio_runner.py +++ b/ipykernel/trio_runner.py @@ -41,7 +41,7 @@ async def trio_main(): # TODO This hack prevents the nursery from cancelling all child # tasks when an uncaught exception occurs, but it's ugly. nursery._add_exc = log_nursery_exc - builtins.GLOBAL_NURSERY = nursery + builtins.GLOBAL_NURSERY = nursery # type:ignore[attr-defined] await trio.sleep_forever() trio.run(trio_main) diff --git a/ipykernel/zmqshell.py b/ipykernel/zmqshell.py index 1d6627cb4..45ac57507 100644 --- a/ipykernel/zmqshell.py +++ b/ipykernel/zmqshell.py @@ -575,11 +575,11 @@ def set_parent(self, parent): if hasattr(self, "_data_pub"): self.data_pub.set_parent(parent) try: - sys.stdout.set_parent(parent) + sys.stdout.set_parent(parent) # type:ignore[attr-defined] except AttributeError: pass try: - sys.stderr.set_parent(parent) + sys.stderr.set_parent(parent) # type:ignore[attr-defined] except AttributeError: pass diff --git a/pyproject.toml b/pyproject.toml index 79d9375d3..6bbf2801e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,43 @@ tag_template = "v{new_version}" [[tool.tbump.file]] src = "ipykernel/_version.py" +[tool.mypy] +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_untyped_decorators = true +no_implicit_optional = true +pretty = true +show_error_context = true +show_error_codes = true +strict_equality = true +warn_unused_configs = true +warn_unused_ignores = true +warn_redundant_casts = true + +[[tool.mypy.overrides]] +module = [ + "appnope", + "traitlets.*", + "jupyter_core.*", + "jupyter_console.*", + "_pydevd_bundle.*", + "debugpy.*", + "nest_asyncio", + "flaky", + "ipykernel.*", + "ipyparallel.*", + "IPython.*", + "entrypoints", + "trio", + "qtconsole.*", + "psutil", + "wx", + "PyQt4", + "PyQt5", + "PySide2" +] +ignore_missing_imports = true + [tool.pytest.ini_options] addopts = "-raXs --durations 10 --color=yes --doctest-modules --ignore=ipykernel/pylab/backend_inline.py --ignore=ipykernel/pylab/config.py --ignore=ipykernel/gui/gtk3embed.py --ignore=ipykernel/gui/gtkembed.py --ignore=ipykernel/datapub.py --ignore=ipykernel/log.py --ignore=ipykernel/pickleutil.py --ignore=ipykernel/serialize.py --ignore=ipykernel/_eventloop_macos.py" testpaths = [ diff --git a/setup.py b/setup.py index 54dcaa762..e28c54b78 100644 --- a/setup.py +++ b/setup.py @@ -8,8 +8,8 @@ import sys from glob import glob -from setuptools import setup -from setuptools.command.bdist_egg import bdist_egg +from setuptools import setup # type:ignore[import] +from setuptools.command.bdist_egg import bdist_egg # type:ignore[import] # the name of the package name = "ipykernel" @@ -36,13 +36,13 @@ def run(self): packages.append(d[len(here) + 1 :].replace(os.path.sep, ".")) package_data = { - "ipykernel": ["resources/*.*"], + "ipykernel": ["resources/*.*", "py.typed"], } with open(pjoin(here, "README.md")) as fid: LONG_DESCRIPTION = fid.read() -setup_args = dict( +setup_args: dict[str, object] = dict( name=name, cmdclass={ "bdist_egg": bdist_egg if "bdist_egg" in sys.argv else bdist_egg_disabled, From 29eb387d36605a9fe154075aec36babebebc0cf4 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 10 Apr 2022 06:39:41 -0500 Subject: [PATCH 2/8] clean up list --- pyproject.toml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6bbf2801e..3f20fd84a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,25 +44,25 @@ warn_redundant_casts = true [[tool.mypy.overrides]] module = [ - "appnope", - "traitlets.*", - "jupyter_core.*", - "jupyter_console.*", "_pydevd_bundle.*", + "appnope", "debugpy.*", - "nest_asyncio", + "entrypoints", "flaky", "ipykernel.*", "ipyparallel.*", "IPython.*", - "entrypoints", - "trio", - "qtconsole.*", + "jupyter_console.*", + "jupyter_core.*", + "nest_asyncio", "psutil", - "wx", + "PySide2", "PyQt4", "PyQt5", - "PySide2" + "qtconsole.*", + "traitlets.*", + "trio", + "wx", ] ignore_missing_imports = true From 537604ab9471d9f6a3565e7e12bd616c2d977571 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 10 Apr 2022 06:40:04 -0500 Subject: [PATCH 3/8] clean up list --- .pre-commit-config.yaml | 2 +- ipykernel/_eventloop_macos.py | 4 +++- ipykernel/kernelapp.py | 4 +++- ipykernel/kernelbase.py | 4 +++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0ff9a5bff..41a7de4c2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,7 +45,7 @@ repos: rev: v0.942 hooks: - id: mypy - exclude: 'ipykernel.*tests' + exclude: "ipykernel.*tests" args: ["--config-file", "pyproject.toml"] additional_dependencies: [tornado, jupyter_client, pytest] stages: [manual] diff --git a/ipykernel/_eventloop_macos.py b/ipykernel/_eventloop_macos.py index 7598f8f6e..896d991c3 100644 --- a/ipykernel/_eventloop_macos.py +++ b/ipykernel/_eventloop_macos.py @@ -42,7 +42,9 @@ def C(classname): # end obj-c boilerplate from appnope # CoreFoundation C-API calls we will use: -CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library("CoreFoundation")) # type:ignore[arg-type] +CoreFoundation = ctypes.cdll.LoadLibrary( + ctypes.util.find_library("CoreFoundation") +) # type:ignore[arg-type] CFAbsoluteTimeGetCurrent = CoreFoundation.CFAbsoluteTimeGetCurrent CFAbsoluteTimeGetCurrent.restype = ctypes.c_double diff --git a/ipykernel/kernelapp.py b/ipykernel/kernelapp.py index 87bf36c82..14432e117 100644 --- a/ipykernel/kernelapp.py +++ b/ipykernel/kernelapp.py @@ -464,7 +464,9 @@ def init_io(self): self.log.debug("Seeing logger to stderr, rerouting to raw filedescriptor.") handler.stream = TextIOWrapper( - FileIO(sys.stderr._original_stdstream_copy, "w") # type:ignore[attr-defined] + FileIO( + sys.stderr._original_stdstream_copy, "w" + ) # type:ignore[attr-defined] ) if self.displayhook_class: displayhook_factory = import_item(str(self.displayhook_class)) diff --git a/ipykernel/kernelbase.py b/ipykernel/kernelbase.py index 80cdae5cd..33a5e30ec 100644 --- a/ipykernel/kernelbase.py +++ b/ipykernel/kernelbase.py @@ -1193,7 +1193,9 @@ def _input_request(self, prompt, ident, parent, password=False): # zmq.select() is also uninterruptible, but at least this # way reads get noticed immediately and KeyboardInterrupts # get noticed fairly quickly by human response time standards. - rlist, _, xlist = zmq.select([self.stdin_socket], [], [self.stdin_socket], 0.01) # type:ignore[arg-type] + rlist, _, xlist = zmq.select( + [self.stdin_socket], [], [self.stdin_socket], 0.01 + ) # type:ignore[arg-type] if rlist or xlist: ident, reply = self.session.recv(self.stdin_socket) if (ident, reply) != (None, None): From 42f6ae345bd27a56205903bde5faae7db3080196 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 10 Apr 2022 06:45:10 -0500 Subject: [PATCH 4/8] fix ignores --- ipykernel/_eventloop_macos.py | 4 ++-- ipykernel/kernelapp.py | 4 ++-- ipykernel/kernelbase.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ipykernel/_eventloop_macos.py b/ipykernel/_eventloop_macos.py index 896d991c3..3a6692fce 100644 --- a/ipykernel/_eventloop_macos.py +++ b/ipykernel/_eventloop_macos.py @@ -43,8 +43,8 @@ def C(classname): # CoreFoundation C-API calls we will use: CoreFoundation = ctypes.cdll.LoadLibrary( - ctypes.util.find_library("CoreFoundation") -) # type:ignore[arg-type] + ctypes.util.find_library("CoreFoundation") # type:ignore[arg-type] +) CFAbsoluteTimeGetCurrent = CoreFoundation.CFAbsoluteTimeGetCurrent CFAbsoluteTimeGetCurrent.restype = ctypes.c_double diff --git a/ipykernel/kernelapp.py b/ipykernel/kernelapp.py index 14432e117..72043d6a0 100644 --- a/ipykernel/kernelapp.py +++ b/ipykernel/kernelapp.py @@ -465,8 +465,8 @@ def init_io(self): handler.stream = TextIOWrapper( FileIO( - sys.stderr._original_stdstream_copy, "w" - ) # type:ignore[attr-defined] + sys.stderr._original_stdstream_copy, "w" # type:ignore[attr-defined] + ) ) if self.displayhook_class: displayhook_factory = import_item(str(self.displayhook_class)) diff --git a/ipykernel/kernelbase.py b/ipykernel/kernelbase.py index 33a5e30ec..e448e6544 100644 --- a/ipykernel/kernelbase.py +++ b/ipykernel/kernelbase.py @@ -1194,8 +1194,8 @@ def _input_request(self, prompt, ident, parent, password=False): # way reads get noticed immediately and KeyboardInterrupts # get noticed fairly quickly by human response time standards. rlist, _, xlist = zmq.select( - [self.stdin_socket], [], [self.stdin_socket], 0.01 - ) # type:ignore[arg-type] + [self.stdin_socket], [], [self.stdin_socket], 0.01 # type:ignore[arg-type] + ) if rlist or xlist: ident, reply = self.session.recv(self.stdin_socket) if (ident, reply) != (None, None): From b51eb0048089505920ebdfe182541c169de7962f Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 10 Apr 2022 06:57:42 -0500 Subject: [PATCH 5/8] more cleanup --- docs/conf.py | 7 +++--- examples/embedding/inprocess_terminal.py | 2 +- ipykernel/_version.py | 2 +- ipykernel/debugger.py | 6 ++--- ipykernel/gui/gtk3embed.py | 4 +-- ipykernel/gui/gtkembed.py | 4 +-- ipykernel/inprocess/blocking.py | 2 +- ipykernel/inprocess/channels.py | 2 +- ipykernel/iostream.py | 6 ++--- ipykernel/kernelbase.py | 6 ++--- ipykernel/parentpoller.py | 2 +- ipykernel/pickleutil.py | 16 ++++++------ ipykernel/pylab/backend_inline.py | 2 +- ipykernel/pylab/config.py | 2 +- pyproject.toml | 32 ++++++------------------ setup.py | 4 +-- 16 files changed, 41 insertions(+), 58 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 95f7219ec..33e1c2dba 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,6 +14,7 @@ import os import shutil +from typing import Any # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -61,7 +62,7 @@ # built documents. # -version_ns: dict = {} +version_ns: dict[str, Any] = {} here = os.path.dirname(__file__) version_py = os.path.join(here, os.pardir, "ipykernel", "_version.py") with open(version_py) as f: @@ -150,7 +151,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path: list = [] +html_static_path: list[str] = [] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -217,7 +218,7 @@ # -- Options for LaTeX output --------------------------------------------- -latex_elements: dict = {} +latex_elements: dict[str, object] = {} # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, diff --git a/examples/embedding/inprocess_terminal.py b/examples/embedding/inprocess_terminal.py index 543adba64..4121619d0 100644 --- a/examples/embedding/inprocess_terminal.py +++ b/examples/embedding/inprocess_terminal.py @@ -4,7 +4,7 @@ import tornado from jupyter_console.ptshell import ZMQTerminalInteractiveShell -from ipykernel.inprocess import InProcessKernelManager +from ipykernel.inprocess.manager import InProcessKernelManager def print_process_id(): diff --git a/ipykernel/_version.py b/ipykernel/_version.py index 31dc1d3c5..32c639edc 100644 --- a/ipykernel/_version.py +++ b/ipykernel/_version.py @@ -10,7 +10,7 @@ pattern = r"(?P\d+).(?P\d+).(?P\d+)(?P.*)" match = re.match(pattern, __version__) assert match is not None -parts: list = [int(match[part]) for part in ["major", "minor", "patch"]] +parts: list[object] = [int(match[part]) for part in ["major", "minor", "patch"]] if match["rest"]: parts.append(match["rest"]) version_info = tuple(parts) diff --git a/ipykernel/debugger.py b/ipykernel/debugger.py index da275ed21..e025de24e 100644 --- a/ipykernel/debugger.py +++ b/ipykernel/debugger.py @@ -90,7 +90,7 @@ def __init__(self, event_callback, log): self.tcp_buffer = "" self._reset_tcp_pos() self.event_callback = event_callback - self.message_queue: Queue = Queue() + self.message_queue: Queue[t.Any] = Queue() self.log = log def _reset_tcp_pos(self): @@ -101,7 +101,7 @@ def _reset_tcp_pos(self): def _put_message(self, raw_msg): self.log.debug("QUEUE - _put_message:") - msg = t.cast(dict, jsonapi.loads(raw_msg)) + msg = t.cast(dict[str, t.Any], jsonapi.loads(raw_msg)) if msg["type"] == "event": self.log.debug("QUEUE - received event:") self.log.debug(msg) @@ -291,7 +291,7 @@ def __init__( self.is_started = False self.event_callback = event_callback self.just_my_code = just_my_code - self.stopped_queue: Queue = Queue() + self.stopped_queue: Queue[t.Any] = Queue() self.started_debug_handlers = {} for msg_type in Debugger.started_debug_msg_types: diff --git a/ipykernel/gui/gtk3embed.py b/ipykernel/gui/gtk3embed.py index 1a9542a9b..baef9fd71 100644 --- a/ipykernel/gui/gtk3embed.py +++ b/ipykernel/gui/gtk3embed.py @@ -14,11 +14,11 @@ import sys # Third-party -import gi # type:ignore[import] +import gi gi.require_version("Gdk", "3.0") gi.require_version("Gtk", "3.0") -from gi.repository import GObject, Gtk # type:ignore[import] +from gi.repository import GObject, Gtk # ----------------------------------------------------------------------------- # Classes and functions diff --git a/ipykernel/gui/gtkembed.py b/ipykernel/gui/gtkembed.py index 47cf48421..ed6647226 100644 --- a/ipykernel/gui/gtkembed.py +++ b/ipykernel/gui/gtkembed.py @@ -14,8 +14,8 @@ import sys # Third-party -import gobject # type:ignore[import] -import gtk # type:ignore[import] +import gobject +import gtk # ----------------------------------------------------------------------------- # Classes and functions diff --git a/ipykernel/inprocess/blocking.py b/ipykernel/inprocess/blocking.py index 1ac7829fc..17f334f48 100644 --- a/ipykernel/inprocess/blocking.py +++ b/ipykernel/inprocess/blocking.py @@ -23,7 +23,7 @@ class BlockingInProcessChannel(InProcessChannel): def __init__(self, *args, **kwds): super().__init__(*args, **kwds) - self._in_queue: Queue = Queue() + self._in_queue: Queue[object] = Queue() def call_handlers(self, msg): self._in_queue.put(msg) diff --git a/ipykernel/inprocess/channels.py b/ipykernel/inprocess/channels.py index 6648a0f37..a0dff04f7 100644 --- a/ipykernel/inprocess/channels.py +++ b/ipykernel/inprocess/channels.py @@ -13,7 +13,7 @@ class InProcessChannel: """Base class for in-process channels.""" - proxy_methods: list = [] + proxy_methods: list[object] = [] def __init__(self, client=None): super().__init__() diff --git a/ipykernel/iostream.py b/ipykernel/iostream.py index f2737ebc1..6255d717e 100644 --- a/ipykernel/iostream.py +++ b/ipykernel/iostream.py @@ -13,7 +13,7 @@ from binascii import b2a_hex from collections import deque from io import StringIO, TextIOBase -from typing import Any, Optional +from typing import Any, Optional, Callable from weakref import WeakSet import zmq @@ -67,8 +67,8 @@ def __init__(self, socket, pipe=False): if pipe: self._setup_pipe_in() self._local = threading.local() - self._events: deque = deque() - self._event_pipes: WeakSet = WeakSet() + self._events: deque[Callable[..., Any]] = deque() + self._event_pipes: WeakSet[Any] = WeakSet() self._setup_event_pipe() self.thread = threading.Thread(target=self._thread_main, name="IOPub") self.thread.daemon = True diff --git a/ipykernel/kernelbase.py b/ipykernel/kernelbase.py index e448e6544..d4530be64 100644 --- a/ipykernel/kernelbase.py +++ b/ipykernel/kernelbase.py @@ -263,7 +263,7 @@ def __init__(self, **kwargs): for msg_type in self.control_msg_types: self.control_handlers[msg_type] = getattr(self, msg_type) - self.control_queue: Queue = Queue() + self.control_queue: Queue[Any] = Queue() def dispatch_control(self, msg): self.control_queue.put_nowait(msg) @@ -279,7 +279,7 @@ async def poll_control_queue(self): async def _flush_control_queue(self): """Flush the control queue, wait for processing of any pending messages""" - tracer_future: t.Union[concurrent.futures.Future, asyncio.Future] + tracer_future: t.Union[concurrent.futures.Future[object], asyncio.Future[object]] if self.control_thread: control_loop = self.control_thread.io_loop # concurrent.futures.Futures are threadsafe @@ -531,7 +531,7 @@ def schedule_dispatch(self, dispatch, *args): def start(self): """register dispatchers for streams""" self.io_loop = ioloop.IOLoop.current() - self.msg_queue: Queue = Queue() + self.msg_queue: Queue[Any] = Queue() self.io_loop.add_callback(self.dispatch_queue) self.control_stream.on_recv(self.dispatch_control, copy=False) diff --git a/ipykernel/parentpoller.py b/ipykernel/parentpoller.py index a18f0440b..139b833e4 100644 --- a/ipykernel/parentpoller.py +++ b/ipykernel/parentpoller.py @@ -73,7 +73,7 @@ def run(self): try: from _winapi import INFINITE, WAIT_OBJECT_0 # type:ignore[attr-defined] except ImportError: - from _subprocess import INFINITE, WAIT_OBJECT_0 # type:ignore[import] + from _subprocess import INFINITE, WAIT_OBJECT_0 # Build the list of handle to listen on. handles = [] diff --git a/ipykernel/pickleutil.py b/ipykernel/pickleutil.py index 8f612e65a..70c9bede4 100644 --- a/ipykernel/pickleutil.py +++ b/ipykernel/pickleutil.py @@ -72,7 +72,7 @@ def use_dill(): adds support for object methods and closures to serialization. """ # import dill causes most of the magic - import dill # type:ignore[import] + import dill # dill doesn't work with cPickle, # tell the two relevant modules to use plain pickle @@ -85,7 +85,7 @@ def use_dill(): except ImportError: pass else: - serialize.pickle = dill + serialize.pickle = dill # type:ignore[attr-defined] # disable special function handling, let dill take care of it can_map.pop(FunctionType, None) @@ -96,7 +96,7 @@ def use_cloudpickle(): adds support for object methods and closures to serialization. """ - import cloudpickle # type:ignore[import] + import cloudpickle global pickle pickle = cloudpickle @@ -106,7 +106,7 @@ def use_cloudpickle(): except ImportError: pass else: - serialize.pickle = cloudpickle + serialize.pickle = cloudpickle # type:ignore[attr-defined] # disable special function handling, let cloudpickle take care of it can_map.pop(FunctionType, None) @@ -195,13 +195,13 @@ class CannedFunction(CannedObject): def __init__(self, f): self._check_type(f) self.code = f.__code__ - self.defaults: typing.Optional[list] + self.defaults: typing.Optional[list[typing.Any]] if f.__defaults__: self.defaults = [can(fd) for fd in f.__defaults__] else: self.defaults = None - self.closure: typing.Optional[tuple] + self.closure: typing.Any closure = f.__closure__ if closure: self.closure = tuple(can(cell) for cell in closure) @@ -262,7 +262,7 @@ def get_object(self, g=None): class CannedArray(CannedObject): def __init__(self, obj): - from numpy import ascontiguousarray # type:ignore[import] + from numpy import ascontiguousarray self.shape = obj.shape self.dtype = obj.dtype.descr if obj.dtype.fields else obj.dtype.str @@ -461,7 +461,7 @@ def uncan_sequence(obj, g=None): if buffer is not memoryview: can_map[buffer] = CannedBuffer -uncan_map: dict[type, typing.Callable] = { +uncan_map: dict[type, typing.Any] = { CannedObject: lambda obj, g: obj.get_object(g), dict: uncan_dict, } diff --git a/ipykernel/pylab/backend_inline.py b/ipykernel/pylab/backend_inline.py index 1466c9d34..b1627cac5 100644 --- a/ipykernel/pylab/backend_inline.py +++ b/ipykernel/pylab/backend_inline.py @@ -5,7 +5,7 @@ import warnings -from matplotlib_inline.backend_inline import * # type:ignore[import] # analysis: ignore # noqa F401 +from matplotlib_inline.backend_inline import * # analysis: ignore # noqa F401 warnings.warn( "`ipykernel.pylab.backend_inline` is deprecated, directly " diff --git a/ipykernel/pylab/config.py b/ipykernel/pylab/config.py index 8fbb53bae..7622f9e11 100644 --- a/ipykernel/pylab/config.py +++ b/ipykernel/pylab/config.py @@ -5,7 +5,7 @@ import warnings -from matplotlib_inline.config import * # type:ignore[import] # analysis: ignore # noqa F401 +from matplotlib_inline.config import * # analysis: ignore # noqa F401 warnings.warn( "`ipykernel.pylab.config` is deprecated, directly use `matplotlib_inline.config`", diff --git a/pyproject.toml b/pyproject.toml index 3f20fd84a..a3e7541a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,40 +31,22 @@ src = "ipykernel/_version.py" [tool.mypy] check_untyped_defs = true +disallow_any_generics = true disallow_incomplete_defs = true disallow_untyped_decorators = true +follow_imports = "normal" +ignore_missing_imports = true no_implicit_optional = true +no_implicit_reexport = true pretty = true show_error_context = true show_error_codes = true strict_equality = true +strict_optional = true warn_unused_configs = true -warn_unused_ignores = true warn_redundant_casts = true - -[[tool.mypy.overrides]] -module = [ - "_pydevd_bundle.*", - "appnope", - "debugpy.*", - "entrypoints", - "flaky", - "ipykernel.*", - "ipyparallel.*", - "IPython.*", - "jupyter_console.*", - "jupyter_core.*", - "nest_asyncio", - "psutil", - "PySide2", - "PyQt4", - "PyQt5", - "qtconsole.*", - "traitlets.*", - "trio", - "wx", -] -ignore_missing_imports = true +warn_return_any = true +warn_unused_ignores = true [tool.pytest.ini_options] addopts = "-raXs --durations 10 --color=yes --doctest-modules --ignore=ipykernel/pylab/backend_inline.py --ignore=ipykernel/pylab/config.py --ignore=ipykernel/gui/gtk3embed.py --ignore=ipykernel/gui/gtkembed.py --ignore=ipykernel/datapub.py --ignore=ipykernel/log.py --ignore=ipykernel/pickleutil.py --ignore=ipykernel/serialize.py --ignore=ipykernel/_eventloop_macos.py" diff --git a/setup.py b/setup.py index e28c54b78..d6f4d352a 100644 --- a/setup.py +++ b/setup.py @@ -8,8 +8,8 @@ import sys from glob import glob -from setuptools import setup # type:ignore[import] -from setuptools.command.bdist_egg import bdist_egg # type:ignore[import] +from setuptools import setup +from setuptools.command.bdist_egg import bdist_egg # the name of the package name = "ipykernel" From e81d6028d6804132a4ea997bba8d865481479540 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 10 Apr 2022 07:01:07 -0500 Subject: [PATCH 6/8] fix py37 syntax --- docs/conf.py | 8 ++++---- ipykernel/_version.py | 3 ++- ipykernel/connect.py | 4 ++-- ipykernel/debugger.py | 2 +- ipykernel/inprocess/channels.py | 3 ++- ipykernel/ipkernel.py | 4 ++-- ipykernel/kernelbase.py | 2 +- ipykernel/pickleutil.py | 4 ++-- setup.py | 3 ++- 9 files changed, 18 insertions(+), 15 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 33e1c2dba..2b23af52a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,7 +14,7 @@ import os import shutil -from typing import Any +from typing import Dict, Any, List # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -62,7 +62,7 @@ # built documents. # -version_ns: dict[str, Any] = {} +version_ns: Dict[str, Any] = {} here = os.path.dirname(__file__) version_py = os.path.join(here, os.pardir, "ipykernel", "_version.py") with open(version_py) as f: @@ -151,7 +151,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path: list[str] = [] +html_static_path: List[str] = [] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -218,7 +218,7 @@ # -- Options for LaTeX output --------------------------------------------- -latex_elements: dict[str, object] = {} +latex_elements: Dict[str, object] = {} # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, diff --git a/ipykernel/_version.py b/ipykernel/_version.py index 32c639edc..7ea05f2a4 100644 --- a/ipykernel/_version.py +++ b/ipykernel/_version.py @@ -2,6 +2,7 @@ store the current version info of the server. """ import re +from typing import List # Version string must appear intact for tbump versioning __version__ = "6.12.1" @@ -10,7 +11,7 @@ pattern = r"(?P\d+).(?P\d+).(?P\d+)(?P.*)" match = re.match(pattern, __version__) assert match is not None -parts: list[object] = [int(match[part]) for part in ["major", "minor", "patch"]] +parts: List[object] = [int(match[part]) for part in ["major", "minor", "patch"]] if match["rest"]: parts.append(match["rest"]) version_info = tuple(parts) diff --git a/ipykernel/connect.py b/ipykernel/connect.py index 39e00e25a..b9ee76e4b 100644 --- a/ipykernel/connect.py +++ b/ipykernel/connect.py @@ -6,7 +6,7 @@ import json import sys from subprocess import PIPE, Popen -from typing import Any +from typing import Any, Dict import jupyter_client from jupyter_client import write_connection_file @@ -108,7 +108,7 @@ def connect_qtconsole(connection_file=None, argv=None): cmd = ";".join(["from IPython.qt.console import qtconsoleapp", "qtconsoleapp.main()"]) - kwargs: dict[str, Any] = {} + kwargs: Dict[str, Any] = {} # Launch the Qt console in a separate session & process group, so # interrupting the kernel doesn't kill it. kwargs["start_new_session"] = True diff --git a/ipykernel/debugger.py b/ipykernel/debugger.py index e025de24e..92021352d 100644 --- a/ipykernel/debugger.py +++ b/ipykernel/debugger.py @@ -101,7 +101,7 @@ def _reset_tcp_pos(self): def _put_message(self, raw_msg): self.log.debug("QUEUE - _put_message:") - msg = t.cast(dict[str, t.Any], jsonapi.loads(raw_msg)) + msg = t.cast(t.Dict[str, t.Any], jsonapi.loads(raw_msg)) if msg["type"] == "event": self.log.debug("QUEUE - received event:") self.log.debug(msg) diff --git a/ipykernel/inprocess/channels.py b/ipykernel/inprocess/channels.py index a0dff04f7..93bf2a7e1 100644 --- a/ipykernel/inprocess/channels.py +++ b/ipykernel/inprocess/channels.py @@ -4,6 +4,7 @@ # Distributed under the terms of the Modified BSD License. from jupyter_client.channelsabc import HBChannelABC +from typing import List # ----------------------------------------------------------------------------- # Channel classes @@ -13,7 +14,7 @@ class InProcessChannel: """Base class for in-process channels.""" - proxy_methods: list[object] = [] + proxy_methods: List[object] = [] def __init__(self, client=None): super().__init__() diff --git a/ipykernel/ipkernel.py b/ipykernel/ipkernel.py index 889782cc7..c4ef68d3d 100644 --- a/ipykernel/ipkernel.py +++ b/ipykernel/ipkernel.py @@ -311,7 +311,7 @@ async def do_execute( self._forward_input(allow_stdin) - reply_content: dict[str, t.Any] = {} + reply_content: t.Dict[str, t.Any] = {} if hasattr(shell, "run_cell_async") and hasattr(shell, "should_run_async"): run_cell = shell.run_cell_async should_run_async = shell.should_run_async @@ -507,7 +507,7 @@ def _experimental_do_complete(self, code, cursor_pos): def do_inspect(self, code, cursor_pos, detail_level=0, omit_sections=()): name = token_at_cursor(code, cursor_pos) - reply_content: dict[str, t.Any] = {"status": "ok"} + reply_content: t.Dict[str, t.Any] = {"status": "ok"} reply_content["data"] = {} reply_content["metadata"] = {} try: diff --git a/ipykernel/kernelbase.py b/ipykernel/kernelbase.py index d4530be64..74e0ba71e 100644 --- a/ipykernel/kernelbase.py +++ b/ipykernel/kernelbase.py @@ -143,7 +143,7 @@ def _default_ident(self): # This should be overridden by wrapper kernels that implement any real # language. - language_info: dict[str, object] = {} + language_info: t.Dict[str, object] = {} # any links that should go in the help menu help_links = List() diff --git a/ipykernel/pickleutil.py b/ipykernel/pickleutil.py index 70c9bede4..ed7d4a7b8 100644 --- a/ipykernel/pickleutil.py +++ b/ipykernel/pickleutil.py @@ -195,7 +195,7 @@ class CannedFunction(CannedObject): def __init__(self, f): self._check_type(f) self.code = f.__code__ - self.defaults: typing.Optional[list[typing.Any]] + self.defaults: typing.Optional[typing.List[typing.Any]] if f.__defaults__: self.defaults = [can(fd) for fd in f.__defaults__] else: @@ -461,7 +461,7 @@ def uncan_sequence(obj, g=None): if buffer is not memoryview: can_map[buffer] = CannedBuffer -uncan_map: dict[type, typing.Any] = { +uncan_map: typing.Dict[type, typing.Any] = { CannedObject: lambda obj, g: obj.get_object(g), dict: uncan_dict, } diff --git a/setup.py b/setup.py index d6f4d352a..9bb5e05ce 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ import shutil import sys from glob import glob +from typing import Dict from setuptools import setup from setuptools.command.bdist_egg import bdist_egg @@ -42,7 +43,7 @@ def run(self): with open(pjoin(here, "README.md")) as fid: LONG_DESCRIPTION = fid.read() -setup_args: dict[str, object] = dict( +setup_args: Dict[str, object] = dict( name=name, cmdclass={ "bdist_egg": bdist_egg if "bdist_egg" in sys.argv else bdist_egg_disabled, From 99d97213757bc969b4a2fd9875abc7ad8815844e Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 10 Apr 2022 07:01:24 -0500 Subject: [PATCH 7/8] fix py37 syntax --- docs/conf.py | 2 +- ipykernel/inprocess/channels.py | 3 ++- ipykernel/iostream.py | 2 +- ipykernel/kernelapp.py | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 2b23af52a..21c16dda6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,7 +14,7 @@ import os import shutil -from typing import Dict, Any, List +from typing import Any, Dict, List # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the diff --git a/ipykernel/inprocess/channels.py b/ipykernel/inprocess/channels.py index 93bf2a7e1..84629ff5d 100644 --- a/ipykernel/inprocess/channels.py +++ b/ipykernel/inprocess/channels.py @@ -3,9 +3,10 @@ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. -from jupyter_client.channelsabc import HBChannelABC from typing import List +from jupyter_client.channelsabc import HBChannelABC + # ----------------------------------------------------------------------------- # Channel classes # ----------------------------------------------------------------------------- diff --git a/ipykernel/iostream.py b/ipykernel/iostream.py index 6255d717e..3d66a7239 100644 --- a/ipykernel/iostream.py +++ b/ipykernel/iostream.py @@ -13,7 +13,7 @@ from binascii import b2a_hex from collections import deque from io import StringIO, TextIOBase -from typing import Any, Optional, Callable +from typing import Any, Callable, Optional from weakref import WeakSet import zmq diff --git a/ipykernel/kernelapp.py b/ipykernel/kernelapp.py index 72043d6a0..944b01bc2 100644 --- a/ipykernel/kernelapp.py +++ b/ipykernel/kernelapp.py @@ -465,7 +465,8 @@ def init_io(self): handler.stream = TextIOWrapper( FileIO( - sys.stderr._original_stdstream_copy, "w" # type:ignore[attr-defined] + sys.stderr._original_stdstream_copy, + "w", # type:ignore[attr-defined] ) ) if self.displayhook_class: From 71b926551f6bc725524a1160dad3411ec020ae39 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 10 Apr 2022 07:20:32 -0500 Subject: [PATCH 8/8] pre-commit --- ipykernel/debugger.py | 6 +++--- ipykernel/kernelapp.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ipykernel/debugger.py b/ipykernel/debugger.py index 92021352d..841966a72 100644 --- a/ipykernel/debugger.py +++ b/ipykernel/debugger.py @@ -358,9 +358,9 @@ async def handle_stopped_event(self): event = await self.stopped_queue.get() req = {"seq": event["seq"] + 1, "type": "request", "command": "threads"} rep = await self._forward_message(req) - for t in rep["body"]["threads"]: - if self._accept_stopped_thread(t["name"]): - self.stopped_threads.add(t["id"]) + for thread in rep["body"]["threads"]: + if self._accept_stopped_thread(thread["name"]): + self.stopped_threads.add(thread["id"]) self.event_callback(event) @property diff --git a/ipykernel/kernelapp.py b/ipykernel/kernelapp.py index 944b01bc2..1f5804871 100644 --- a/ipykernel/kernelapp.py +++ b/ipykernel/kernelapp.py @@ -465,8 +465,8 @@ def init_io(self): handler.stream = TextIOWrapper( FileIO( - sys.stderr._original_stdstream_copy, - "w", # type:ignore[attr-defined] + sys.stderr._original_stdstream_copy, # type:ignore[attr-defined] + "w", ) ) if self.displayhook_class: