Skip to content

Commit

Permalink
Merge pull request #323 from Carreau/mypy
Browse files Browse the repository at this point in the history
Introduce mypy to catch typing error ahead of time
  • Loading branch information
Carreau authored Apr 9, 2024
2 parents ddc49e3 + 9a18175 commit 5853b14
Show file tree
Hide file tree
Showing 14 changed files with 66 additions and 24 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ jobs:
- name: Install and update Python dependencies on Python 3
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install --upgrade pyflakes flake8
python -m pip install --upgrade pyflakes flake8 mypy
python -m pip install types-six
pip install -e .
- name: Mypy
run: |
mypy lib/python --ignore-missing-imports
- name: lint
run: |
flake8 --exclude known_imports,etc,__init__.py --select=F;
Expand Down
4 changes: 3 additions & 1 deletion lib/python/pyflyby/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
enable_signal_handler_breakpoint,
waitpoint)

from typing import Sequence


# Promote the function & classes that we've chosen to expose publicly to be
# known as pyflyby.Foo instead of pyflyby._module.Foo.
Expand All @@ -51,4 +53,4 @@

# Discourage "from pyflyby import *".
# Use the tidy-imports/autoimporter instead!
__all__ = []
__all__:Sequence[str] = []
12 changes: 9 additions & 3 deletions lib/python/pyflyby/_autoimp.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
from pyflyby._modules import ModuleHandle
from pyflyby._parse import PythonBlock, infer_compile_mode, _is_ast_str

from typing import Set, Any

if sys.version_info >= (3, 12):
ATTRIBUTE_NAME = "value"
else:
Expand All @@ -39,8 +41,12 @@
else:
LOAD_SHIFT = 0

NoneType = type(None)
EllipsisType = type(Ellipsis)
if sys.version_info >= (3,10):
from types import NoneType, EllipsisType
else:
NoneType = type(None)
EllipsisType = type(Ellipsis)


class _ClassScope(dict):
pass
Expand Down Expand Up @@ -1605,7 +1611,7 @@ def get_known_import(fullname, db=None):
return None


_IMPORT_FAILED = set()
_IMPORT_FAILED:Set[Any] = set()
"""
Set of imports we've already attempted and failed.
"""
Expand Down
4 changes: 2 additions & 2 deletions lib/python/pyflyby/_cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,8 +415,8 @@ def on_error_filename_arg(arg):
continue
if errors:
msg = "\n%s: encountered the following problems:\n" % (sys.argv[0],)
for e in errors:
lines = e.splitlines()
for er in errors:
lines = er.splitlines()
msg += " " + lines[0] + '\n'.join(
(" %s"%line for line in lines[1:]))
raise SystemExit(msg)
Expand Down
4 changes: 3 additions & 1 deletion lib/python/pyflyby/_comms.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from pyflyby._importstmt import Import
from pyflyby._log import logger

from typing import Dict, Any

# These are comm targets that the frontend (lab/notebook) is expected to
# open. At this point, we handle only missing imports and
# formatting imports
Expand All @@ -23,7 +25,7 @@
pyflyby_comm_targets= [MISSING_IMPORTS, FORMATTING_IMPORTS, TIDY_IMPORTS]

# A map of the comms opened with a given target name.
comms = {}
comms:Dict[str, Any] = {}

# TODO: Document the expected contract for the different
# custom comm messages
Expand Down
8 changes: 5 additions & 3 deletions lib/python/pyflyby/_file.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
# pyflyby/_file.py.
# Copyright (C) 2011, 2012, 2013, 2014, 2015, 2018 Karl Chen.
# License: MIT http://opensource.org/licenses/MIT


from __future__ import annotations

from functools import total_ordering, cached_property
import io
import os
import re
import sys
from typing import Optional, Tuple
from typing import Optional, Tuple, ClassVar

from pyflyby._util import cmp, memoize

Expand All @@ -30,6 +29,7 @@ class Filename(object):
"""
_filename: str
STDIN: Filename

def __new__(cls, arg):
if isinstance(arg, cls):
Expand Down Expand Up @@ -236,6 +236,8 @@ class FilePos(object):
lineno: int
colno: int

_ONE_ONE: ClassVar[FilePos]

def __new__(cls, *args):
if len(args) == 0:
return cls._ONE_ONE
Expand Down
2 changes: 1 addition & 1 deletion lib/python/pyflyby/_flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def from_ast(cls, nodes):
return cls(flags)

@cached_attribute
def names(self) -> Tuple[str]:
def names(self) -> Tuple[str, ...]:
return tuple(
n
for f, n in _FLAGNAME_ITEMS
Expand Down
7 changes: 6 additions & 1 deletion lib/python/pyflyby/_importclns.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Copyright (C) 2011, 2012, 2013, 2014 Karl Chen.
# License: MIT http://opensource.org/licenses/MIT

from __future__ import annotations



from collections import defaultdict
Expand All @@ -16,7 +18,7 @@
from pyflyby._util import (cached_attribute, cmp, partition,
stable_unique)

from typing import Dict
from typing import Dict, ClassVar


class NoSuchImportError(ValueError):
Expand Down Expand Up @@ -46,6 +48,8 @@ class ImportSet(object):
An ``ImportSet`` is an immutable data structure.
"""

_EMPTY : ClassVar[ImportSet]

def __new__(cls, arg, ignore_nonimports=False, ignore_shadowed=False):
"""
Return as an `ImportSet`.
Expand Down Expand Up @@ -519,6 +523,7 @@ class ImportMap(object):
"""

_data: Dict
_EMPTY : ClassVar[ImportSet]

def __new__(cls, arg):
if isinstance(arg, cls):
Expand Down
6 changes: 4 additions & 2 deletions lib/python/pyflyby/_importdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@
import os
import re

from pyflyby._file import Filename, expand_py_files_from_args, UnsafeFilenameError
from pyflyby._file import Filename, expand_py_files_from_args, UnsafeFilenameError
from pyflyby._idents import dotted_prefixes
from pyflyby._importclns import ImportMap, ImportSet
from pyflyby._importstmt import Import, ImportStatement
from pyflyby._log import logger
from pyflyby._parse import PythonBlock
from pyflyby._util import cached_attribute, memoize, stable_unique

from typing import Dict, Any


@memoize
def _find_etc_dirs():
Expand Down Expand Up @@ -195,7 +197,7 @@ def __new__(cls, *args):
return cls._from_args(arg) # PythonBlock, Filename, etc


_default_cache = {}
_default_cache: Dict[Any, Any] = {}

@classmethod
def clear_default_cache(cls):
Expand Down
4 changes: 2 additions & 2 deletions lib/python/pyflyby/_interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -1048,9 +1048,9 @@ def complete_symbol(fullname, namespaces, db=None, autoimported=None, ip=None,
except LoadSymbolError as e2:
# Even after attempting auto-import, the symbol is still
# unavailable, or some other error occurred. Nothing to complete.
e = getattr(e2, "__cause__", e2)
e3 = getattr(e2, "__cause__", e2)
logger.debug("complete_symbol(%r): couldn't load symbol %r: %s: %s",
fullname, pname, type(e).__name__, e)
fullname, pname, type(e3).__name__, e3)
return []
logger.debug("complete_symbol(%r): %s == %r", fullname, pname, parent)
results = set()
Expand Down
4 changes: 3 additions & 1 deletion lib/python/pyflyby/_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from six import reraise
import sys
import types
from typing import Dict, Any

from pyflyby._file import FileText, Filename
from pyflyby._idents import DottedIdentifier, is_identifier
Expand All @@ -22,6 +23,7 @@
prefixes)



class ErrorDuringImportError(ImportError):
"""
Exception raised by import_module if the module exists but an exception
Expand Down Expand Up @@ -138,7 +140,7 @@ def __new__(cls, arg):
return cls._from_module(arg)
raise TypeError("ModuleHandle: unexpected %s" % (type(arg).__name__,))

_cls_cache = {}
_cls_cache:Dict[Any, Any] = {}

@classmethod
def _from_modulename(cls, modulename):
Expand Down
13 changes: 8 additions & 5 deletions lib/python/pyflyby/_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import sys
from textwrap import dedent
import types
from typing import Optional
from typing import Optional, Union
import warnings

from pyflyby._file import FilePos, FileText, Filename
Expand Down Expand Up @@ -760,12 +760,15 @@ class PythonStatement:
block: PythonBlock

def __new__(cls, arg:PythonStatement, filename=None, startpos=None, flags=None):
arg_ : Union[PythonBlock, FileText, str, PythonStatement]
if isinstance(arg, cls):
if filename is startpos is flags is None:
return arg
arg = arg.block
arg_ = arg.block
# Fall through
if isinstance(arg, (PythonBlock, FileText, str)):
else:
arg_ = arg
if isinstance(arg_, (PythonBlock, FileText, str)):
block = PythonBlock(arg, filename=filename,
startpos=startpos, flags=flags)
statements = block.statements
Expand All @@ -776,7 +779,7 @@ def __new__(cls, arg:PythonStatement, filename=None, startpos=None, flags=None):
statement, = statements
assert isinstance(statement, cls)
return statement
raise TypeError("PythonStatement: unexpected %s" % (type(arg).__name__,))
raise TypeError("PythonStatement: unexpected %s" % type(arg_).__name__)

@classmethod
def _construct_from_block(cls, block:PythonBlock):
Expand All @@ -796,7 +799,7 @@ def text(self) -> FileText:
return self.block.text

@property
def filename(self) -> Optional[str]:
def filename(self) -> Optional[Filename]:
"""
:rtype:
`Filename`
Expand Down
2 changes: 1 addition & 1 deletion lib/python/pyflyby/autoimport.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@

install_auto_importer = enable_auto_importer

__all__ = [install_auto_importer]
__all__ = ['install_auto_importer']
14 changes: 14 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[mypy]
warn_incomplete_stub = False
warn_unused_configs = True

exclude = (?x)(
_dbg\.py
|_py\.py
)

[mypy-epydoc]
ignore_missing_imports = True

[mypy-IPython]
ignore_missing_imports = True

0 comments on commit 5853b14

Please sign in to comment.