general: update mypy config, seems that logs of type: ignore aren't necessary anymore

This commit is contained in:
Dima Gerasimov 2023-05-15 21:53:33 +01:00 committed by karlicoss
parent a445d2cbfe
commit c34656e8fb
52 changed files with 142 additions and 105 deletions

View file

@ -40,7 +40,7 @@ class Measurement:
# fixme: later, rely on the timezone provider # fixme: later, rely on the timezone provider
# NOTE: the timezone should be set with respect to the export date!!! # NOTE: the timezone should be set with respect to the export date!!!
import pytz # type: ignore import pytz
tz = pytz.timezone('Europe/London') tz = pytz.timezone('Europe/London')
# TODO when I change tz, check the diff # TODO when I change tz, check the diff

View file

@ -9,7 +9,7 @@ from ..core.error import Res
from ..core.orgmode import parse_org_datetime, one_table from ..core.orgmode import parse_org_datetime, one_table
import pandas as pd # type: ignore import pandas as pd
import orgparse import orgparse

View file

@ -10,7 +10,7 @@ def dataframe() -> DataFrameT:
from ...endomondo import dataframe as EDF from ...endomondo import dataframe as EDF
from ...runnerup import dataframe as RDF from ...runnerup import dataframe as RDF
import pandas as pd # type: ignore import pandas as pd
return pd.concat([ return pd.concat([
EDF(), EDF(),
RDF(), RDF(),

View file

@ -78,7 +78,7 @@ def cross_trainer_manual_dataframe() -> DataFrameT:
''' '''
Only manual org-mode entries Only manual org-mode entries
''' '''
import pandas as pd # type: ignore[import] import pandas as pd
df = pd.DataFrame(cross_trainer_data()) df = pd.DataFrame(cross_trainer_data())
return df return df
@ -91,7 +91,7 @@ def dataframe() -> DataFrameT:
''' '''
Attaches manually logged data (which Endomondo can't capture) and attaches it to Endomondo Attaches manually logged data (which Endomondo can't capture) and attaches it to Endomondo
''' '''
import pandas as pd # type: ignore[import] import pandas as pd
from ...endomondo import dataframe as EDF from ...endomondo import dataframe as EDF
edf = EDF() edf = EDF()

View file

@ -8,7 +8,7 @@ class Combine:
@cdf @cdf
def dataframe(self, with_temperature: bool=True) -> DataFrameT: def dataframe(self, with_temperature: bool=True) -> DataFrameT:
import pandas as pd # type: ignore import pandas as pd
# todo include 'source'? # todo include 'source'?
df = pd.concat([m.dataframe() for m in self.modules]) df = pd.concat([m.dataframe() for m in self.modules])

View file

@ -56,7 +56,7 @@ def from_orgmode() -> Iterator[Result]:
def make_dataframe(data: Iterator[Result]): def make_dataframe(data: Iterator[Result]):
import pandas as pd # type: ignore import pandas as pd
def it(): def it():
for e in data: for e in data:
if isinstance(e, Exception): if isinstance(e, Exception):

View file

@ -38,8 +38,8 @@ def config() -> commits_cfg:
########################## ##########################
import git # type: ignore import git
from git.repo.fun import is_git_dir # type: ignore from git.repo.fun import is_git_dir
log = LazyLogger(__name__, level='info') log = LazyLogger(__name__, level='info')

View file

@ -135,7 +135,7 @@ def config_ok() -> bool:
# at this point 'my' should already be imported, so doesn't hurt to extract paths from it # at this point 'my' should already be imported, so doesn't hurt to extract paths from it
import my import my
try: try:
paths: List[str] = list(my.__path__) # type: ignore[attr-defined] paths: List[str] = list(my.__path__)
except Exception as e: except Exception as e:
errors.append(e) errors.append(e)
error('failed to determine module import path') error('failed to determine module import path')
@ -152,7 +152,7 @@ def config_ok() -> bool:
## check we're not using stub config ## check we're not using stub config
import my.core import my.core
try: try:
core_pkg_path = str(Path(my.core.__path__[0]).parent) # type: ignore[attr-defined] core_pkg_path = str(Path(my.core.__path__[0]).parent)
if str(cfg_path).startswith(core_pkg_path): if str(cfg_path).startswith(core_pkg_path):
error(f''' error(f'''
Seems that the stub config is used ({cfg_path}). This is likely not going to work. Seems that the stub config is used ({cfg_path}). This is likely not going to work.

View file

@ -30,7 +30,7 @@ def disabled_cachew() -> Iterator[None]:
def _appdirs_cache_dir() -> Path: def _appdirs_cache_dir() -> Path:
import appdirs # type: ignore import appdirs
cd = Path(appdirs.user_cache_dir('my')) cd = Path(appdirs.user_cache_dir('my'))
cd.mkdir(exist_ok=True, parents=True) cd.mkdir(exist_ok=True, parents=True)
return cd return cd

View file

@ -21,7 +21,7 @@ def make_config(cls: Type[C], migration: Callable[[Attrs], Attrs]=lambda x: x) -
if k in {f.name for f in fields(cls)} # type: ignore[arg-type] # see https://github.com/python/typing_extensions/issues/115 if k in {f.name for f in fields(cls)} # type: ignore[arg-type] # see https://github.com/python/typing_extensions/issues/115
} }
# todo maybe return type here? # todo maybe return type here?
return cls(**params) # type: ignore[call-arg] return cls(**params)
F = TypeVar('F') F = TypeVar('F')

View file

@ -3,6 +3,7 @@ from pathlib import Path
from datetime import datetime from datetime import datetime
import functools import functools
from contextlib import contextmanager from contextlib import contextmanager
import sys
import types import types
from typing import Union, Callable, Dict, Iterable, TypeVar, Sequence, List, Optional, Any, cast, Tuple, TYPE_CHECKING, NoReturn from typing import Union, Callable, Dict, Iterable, TypeVar, Sequence, List, Optional, Any, cast, Tuple, TYPE_CHECKING, NoReturn
import warnings import warnings
@ -21,13 +22,12 @@ def import_file(p: PathIsh, name: Optional[str] = None) -> types.ModuleType:
assert spec is not None, f"Fatal error; Could not create module spec from {name} {p}" assert spec is not None, f"Fatal error; Could not create module spec from {name} {p}"
foo = importlib.util.module_from_spec(spec) foo = importlib.util.module_from_spec(spec)
loader = spec.loader; assert loader is not None loader = spec.loader; assert loader is not None
loader.exec_module(foo) # type: ignore[attr-defined] loader.exec_module(foo)
return foo return foo
def import_from(path: PathIsh, name: str) -> types.ModuleType: def import_from(path: PathIsh, name: str) -> types.ModuleType:
path = str(path) path = str(path)
import sys
try: try:
sys.path.append(path) sys.path.append(path)
import importlib import importlib
@ -94,7 +94,7 @@ def ensure_unique(
def test_ensure_unique() -> None: def test_ensure_unique() -> None:
import pytest # type: ignore import pytest
assert list(ensure_unique([1, 2, 3], key=lambda i: i)) == [1, 2, 3] assert list(ensure_unique([1, 2, 3], key=lambda i: i)) == [1, 2, 3]
dups = [1, 2, 1, 4] dups = [1, 2, 1, 4]
@ -432,7 +432,7 @@ def warn_if_empty(f):
def wrapped(*args, **kwargs): def wrapped(*args, **kwargs):
res = f(*args, **kwargs) res = f(*args, **kwargs)
return _warn_iterable(res, f=f) return _warn_iterable(res, f=f)
return wrapped # type: ignore return wrapped
# global state that turns on/off quick stats # global state that turns on/off quick stats
@ -620,6 +620,10 @@ def assert_subpackage(name: str) -> None:
assert name == '__main__' or 'my.core' in name, f'Expected module __name__ ({name}) to be __main__ or start with my.core' assert name == '__main__' or 'my.core' in name, f'Expected module __name__ ({name}) to be __main__ or start with my.core'
from .compat import ParamSpec
_P = ParamSpec('_P')
_T = TypeVar('_T')
# https://stackoverflow.com/a/10436851/706389 # https://stackoverflow.com/a/10436851/706389
from concurrent.futures import Future, Executor from concurrent.futures import Future, Executor
class DummyExecutor(Executor): class DummyExecutor(Executor):
@ -627,10 +631,15 @@ class DummyExecutor(Executor):
self._shutdown = False self._shutdown = False
self._max_workers = max_workers self._max_workers = max_workers
# TODO: once support for 3.7 is dropped, if TYPE_CHECKING:
# can make 'fn' a positional only parameter, if sys.version_info[:2] <= (3, 8):
# which fixes the mypy error this throws without the type: ignore # 3.8 doesn't support ParamSpec as Callable arg :(
def submit(self, fn, *args, **kwargs) -> Future: # type: ignore[override] # and any attempt to type results in incompatible supertype.. so whatever
def submit(self, fn, *args, **kwargs): ...
else:
def submit(self, fn: Callable[_P, _T], /, *args: _P.args, **kwargs: _P.kwargs) -> Future[_T]: ...
else:
def submit(self, fn, *args, **kwargs):
if self._shutdown: if self._shutdown:
raise RuntimeError('cannot schedule new futures after shutdown') raise RuntimeError('cannot schedule new futures after shutdown')
@ -646,7 +655,7 @@ class DummyExecutor(Executor):
return f return f
def shutdown(self, wait: bool=True) -> None: # type: ignore[override] def shutdown(self, wait: bool=True, **kwargs) -> None:
self._shutdown = True self._shutdown = True

View file

@ -86,7 +86,7 @@ else:
def cached_property(f: Callable[[Cl], R]) -> R: def cached_property(f: Callable[[Cl], R]) -> R:
import functools import functools
return property(functools.lru_cache(maxsize=1)(f)) # type: ignore return property(functools.lru_cache(maxsize=1)(f))
del Cl del Cl
del R del R
@ -111,7 +111,7 @@ if sys.version_info[:2] >= (3, 8):
from typing import Protocol from typing import Protocol
else: else:
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Protocol # type: ignore[misc] from typing_extensions import Protocol
else: else:
# todo could also use NamedTuple? # todo could also use NamedTuple?
Protocol = object Protocol = object
@ -121,12 +121,29 @@ if sys.version_info[:2] >= (3, 8):
from typing import TypedDict from typing import TypedDict
else: else:
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import TypedDict # type: ignore[misc] from typing_extensions import TypedDict
else: else:
from typing import Dict from typing import Dict
TypedDict = Dict TypedDict = Dict
if sys.version_info[:2] >= (3, 10):
from typing import ParamSpec
else:
if TYPE_CHECKING:
from typing_extensions import ParamSpec
else:
from typing import NamedTuple, Any
# erm.. I guess as long as it's not crashing, whatever...
class _ParamSpec:
def __call__(self, args):
class _res:
args = None
kwargs = None
return _res
ParamSpec = _ParamSpec()
# bisect_left doesn't have a 'key' parameter (which we use) # bisect_left doesn't have a 'key' parameter (which we use)
# till python3.10 # till python3.10
if sys.version_info[:2] <= (3, 9): if sys.version_info[:2] <= (3, 9):
@ -156,4 +173,4 @@ if sys.version_info[:2] <= (3, 9):
hi = mid hi = mid
return lo return lo
else: else:
from bisect import bisect_left # type: ignore[misc] from bisect import bisect_left

View file

@ -10,13 +10,13 @@ try:
from my.config import core as user_config # type: ignore[attr-defined] from my.config import core as user_config # type: ignore[attr-defined]
except Exception as e: except Exception as e:
try: try:
from my.config import common as user_config # type: ignore[attr-defined, assignment, misc] from my.config import common as user_config # type: ignore[attr-defined]
warnings.high("'common' config section is deprecated. Please rename it to 'core'.") warnings.high("'common' config section is deprecated. Please rename it to 'core'.")
except Exception as e2: except Exception as e2:
# make it defensive, because it's pretty commonly used and would be annoying if it breaks hpi doctor etc. # make it defensive, because it's pretty commonly used and would be annoying if it breaks hpi doctor etc.
# this way it'll at least use the defaults # this way it'll at least use the defaults
# todo actually not sure if needs a warning? Perhaps it's okay without it, because the defaults are reasonable enough # todo actually not sure if needs a warning? Perhaps it's okay without it, because the defaults are reasonable enough
user_config = object # type: ignore[assignment, misc] user_config = object
_HPI_CACHE_DIR_DEFAULT = '' _HPI_CACHE_DIR_DEFAULT = ''

View file

@ -144,7 +144,7 @@ def all_modules() -> Iterable[HPIModule]:
def _iter_my_roots() -> Iterable[Path]: def _iter_my_roots() -> Iterable[Path]:
import my # doesn't import any code, because of namespace package import my # doesn't import any code, because of namespace package
paths: List[str] = list(my.__path__) # type: ignore[attr-defined] paths: List[str] = list(my.__path__)
if len(paths) == 0: if len(paths) == 0:
# should probably never happen?, if this code is running, it was imported # should probably never happen?, if this code is running, it was imported
# because something was added to __path__ to match this name # because something was added to __path__ to match this name

View file

@ -125,7 +125,7 @@ def test_sort_res_by() -> None:
1, 1,
Exc('last'), Exc('last'),
] ]
results = sort_res_by(ress, lambda x: int(x)) # type: ignore results = sort_res_by(ress, lambda x: int(x))
assert results == [ assert results == [
1, 1,
'bad', 'bad',
@ -137,11 +137,11 @@ def test_sort_res_by() -> None:
Exc('last'), Exc('last'),
] ]
results2 = sort_res_by(ress + [0], lambda x: int(x)) # type: ignore results2 = sort_res_by(ress + [0], lambda x: int(x))
assert results2 == [Exc('last'), 0] + results[:-1] assert results2 == [Exc('last'), 0] + results[:-1]
assert sort_res_by(['caba', 'a', 'aba', 'daba'], key=lambda x: len(x)) == ['a', 'aba', 'caba', 'daba'] assert sort_res_by(['caba', 'a', 'aba', 'daba'], key=lambda x: len(x)) == ['a', 'aba', 'caba', 'daba']
assert sort_res_by([], key=lambda x: x) == [] # type: ignore assert sort_res_by([], key=lambda x: x) == []
# helpers to associate timestamps with the errors (so something meaningful could be displayed on the plots, for example) # helpers to associate timestamps with the errors (so something meaningful could be displayed on the plots, for example)
@ -215,7 +215,7 @@ See {help_url}\
if hasattr(err, 'obj') and hasattr(err, "name"): if hasattr(err, 'obj') and hasattr(err, "name"):
config_obj = cast(object, getattr(err, 'obj')) # the object that caused the attribute error config_obj = cast(object, getattr(err, 'obj')) # the object that caused the attribute error
# e.g. active_browser for my.browser # e.g. active_browser for my.browser
nested_block_name = err.name # type: ignore[attr-defined] nested_block_name = err.name
if config_obj.__module__ == 'my.config': if config_obj.__module__ == 'my.config':
click.secho(f"""You're likely missing the nested config block for '{getattr(config_obj, '__name__', str(config_obj))}.{nested_block_name}'. click.secho(f"""You're likely missing the nested config block for '{getattr(config_obj, '__name__', str(config_obj))}.{nested_block_name}'.
See {help_url} or check the corresponding module.py file for an example\ See {help_url} or check the corresponding module.py file for an example\

View file

@ -82,7 +82,7 @@ def kopen(path: PathIsh, *args, mode: str='rt', **kwargs) -> IO:
ifile.read1 = ifile.read # type: ignore ifile.read1 = ifile.read # type: ignore
# TODO pass all kwargs here?? # TODO pass all kwargs here??
# todo 'expected "BinaryIO"'?? # todo 'expected "BinaryIO"'??
return io.TextIOWrapper(ifile, encoding=encoding) # type: ignore[arg-type] return io.TextIOWrapper(ifile, encoding=encoding)
elif name.endswith(Ext.lz4): elif name.endswith(Ext.lz4):
import lz4.frame # type: ignore import lz4.frame # type: ignore
return lz4.frame.open(str(pp), mode, *args, **kwargs) return lz4.frame.open(str(pp), mode, *args, **kwargs)
@ -95,7 +95,7 @@ def kopen(path: PathIsh, *args, mode: str='rt', **kwargs) -> IO:
tf = tarfile.open(pp) tf = tarfile.open(pp)
# TODO pass encoding? # TODO pass encoding?
x = tf.extractfile(*args); assert x is not None x = tf.extractfile(*args); assert x is not None
return x # type: ignore[return-value] return x
else: else:
return pp.open(mode, *args, **kwargs) return pp.open(mode, *args, **kwargs)
@ -209,7 +209,7 @@ class ZipPath(zipfile_Path):
def __truediv__(self, key) -> ZipPath: def __truediv__(self, key) -> ZipPath:
# need to implement it so the return type is not zipfile.Path # need to implement it so the return type is not zipfile.Path
tmp = zipfile_Path(self.root) / self.at / key tmp = zipfile_Path(self.root) / self.at / key
return ZipPath(self.root, tmp.at) # type: ignore[attr-defined] return ZipPath(self.root, tmp.at)
def iterdir(self) -> Iterator[ZipPath]: def iterdir(self) -> Iterator[ZipPath]:
for s in self._as_dir().iterdir(): for s in self._as_dir().iterdir():

View file

@ -19,7 +19,7 @@ def zoom(w, *keys):
# TODO need to support lists # TODO need to support lists
class Zoomable: class Zoomable:
def __init__(self, parent, *args, **kwargs) -> None: def __init__(self, parent, *args, **kwargs) -> None:
super().__init__(*args, **kwargs) # type: ignore super().__init__(*args, **kwargs)
self.parent = parent self.parent = parent
# TODO not sure, maybe do it via del?? # TODO not sure, maybe do it via del??
@ -147,7 +147,7 @@ Expected {c} to be fully consumed by the parser.
from typing import cast from typing import cast
def test_unconsumed() -> None: def test_unconsumed() -> None:
import pytest # type: ignore import pytest
with pytest.raises(UnconsumedError): with pytest.raises(UnconsumedError):
with wrap({'a': 1234}) as w: with wrap({'a': 1234}) as w:
w = cast(Wdict, w) w = cast(Wdict, w)
@ -200,7 +200,7 @@ def test_consume_few() -> None:
def test_zoom() -> None: def test_zoom() -> None:
import pytest # type: ignore import pytest
with wrap({'aaa': 'whatever'}) as w: with wrap({'aaa': 'whatever'}) as w:
w = cast(Wdict, w) w = cast(Wdict, w)
with pytest.raises(KeyError): with pytest.raises(KeyError):

View file

@ -62,20 +62,21 @@ def setup_logger(logger: logging.Logger, level: LevelIsh) -> None:
lvl = mklevel(level) lvl = mklevel(level)
try: try:
import logzero # type: ignore[import] import logzero # type: ignore[import]
except ModuleNotFoundError:
warnings.warn("You might want to install 'logzero' for nice colored logs!")
formatter = logging.Formatter(fmt=FORMAT_NOCOLOR, datefmt=DATEFMT)
use_logzero = False
else:
formatter = logzero.LogFormatter( formatter = logzero.LogFormatter(
fmt=FORMAT_COLOR, fmt=FORMAT_COLOR,
datefmt=DATEFMT, datefmt=DATEFMT,
) )
use_logzero = True use_logzero = True
except ModuleNotFoundError:
warnings.warn("You might want to install 'logzero' for nice colored logs!")
formatter = logging.Formatter(fmt=FORMAT_NOCOLOR, datefmt=DATEFMT)
use_logzero = False
logger.addFilter(AddExceptionTraceback()) logger.addFilter(AddExceptionTraceback())
if use_logzero and not COLLAPSE_DEBUG_LOGS: # all set, nothing to do if use_logzero and not COLLAPSE_DEBUG_LOGS: # all set, nothing to do
# 'simple' setup # 'simple' setup
logzero.setup_logger(logger.name, level=lvl, formatter=formatter) logzero.setup_logger(logger.name, level=lvl, formatter=formatter) # type: ignore[possibly-undefined]
return return
h = CollapseDebugHandler() if COLLAPSE_DEBUG_LOGS else logging.StreamHandler() h = CollapseDebugHandler() if COLLAPSE_DEBUG_LOGS else logging.StreamHandler()
@ -101,7 +102,7 @@ class LazyLogger(logging.Logger):
# oh god.. otherwise might go into an inf loop # oh god.. otherwise might go into an inf loop
if not hasattr(logger, _init_done): if not hasattr(logger, _init_done):
setattr(logger, _init_done, False) # will setup on the first call setattr(logger, _init_done, False) # will setup on the first call
logger.isEnabledFor = isEnabledFor_lazyinit # type: ignore[assignment] logger.isEnabledFor = isEnabledFor_lazyinit # type: ignore[method-assign]
return cast(LazyLogger, logger) return cast(LazyLogger, logger)

View file

@ -15,7 +15,7 @@ logger = LazyLogger(__name__)
if TYPE_CHECKING: if TYPE_CHECKING:
# this is kinda pointless at the moment, but handy to annotate DF returning methods now # this is kinda pointless at the moment, but handy to annotate DF returning methods now
# later will be unignored when they implement type annotations # later will be unignored when they implement type annotations
import pandas as pd # type: ignore import pandas as pd
# DataFrameT = pd.DataFrame # DataFrameT = pd.DataFrame
# TODO ugh. pretty annoying, having any is not very useful since it would allow arbitrary coercions.. # TODO ugh. pretty annoying, having any is not very useful since it would allow arbitrary coercions..
# ideally want to use a type that's like Any but doesn't allow arbitrary coercions?? # ideally want to use a type that's like Any but doesn't allow arbitrary coercions??
@ -26,7 +26,7 @@ else:
def check_dateish(s) -> Iterable[str]: def check_dateish(s) -> Iterable[str]:
import pandas as pd # type: ignore # noqa: F811 not actually a redefinition import pandas as pd # noqa: F811 not actually a redefinition
ctype = s.dtype ctype = s.dtype
if str(ctype).startswith('datetime64'): if str(ctype).startswith('datetime64'):
return return

View file

@ -1,7 +1,7 @@
from pathlib import Path from pathlib import Path
def get_mycfg_dir() -> Path: def get_mycfg_dir() -> Path:
import appdirs # type: ignore[import] import appdirs
import os import os
# not sure if that's necessary, i.e. could rely on PYTHONPATH instead # not sure if that's necessary, i.e. could rely on PYTHONPATH instead
# on the other hand, by using MY_CONFIG we are guaranteed to load it from the desired path? # on the other hand, by using MY_CONFIG we are guaranteed to load it from the desired path?

View file

@ -495,7 +495,7 @@ Will attempt to call iter() on the value""")
unsortable, itr = _handle_unsorted(itr, order_by_chosen, drop_unsorted, wrap_unsorted) unsortable, itr = _handle_unsorted(itr, order_by_chosen, drop_unsorted, wrap_unsorted)
# run the sort, with the computed order by function # run the sort, with the computed order by function
itr = iter(sorted(itr, key=order_by_chosen, reverse=reverse)) # type: ignore[arg-type, type-var] itr = iter(sorted(itr, key=order_by_chosen, reverse=reverse)) # type: ignore[arg-type]
# re-attach unsortable values to the front/back of the list # re-attach unsortable values to the front/back of the list
if reverse: if reverse:

View file

@ -40,7 +40,7 @@ def parse_timedelta_string(timedelta_str: str) -> timedelta:
if parts is None: if parts is None:
raise ValueError(f"Could not parse time duration from {timedelta_str}.\nValid examples: '8h', '1w2d8h5m20s', '2m4s'") raise ValueError(f"Could not parse time duration from {timedelta_str}.\nValid examples: '8h', '1w2d8h5m20s', '2m4s'")
time_params = {name: float(param) for name, param in parts.groupdict().items() if param} time_params = {name: float(param) for name, param in parts.groupdict().items() if param}
return timedelta(**time_params) # type: ignore[arg-type] return timedelta(**time_params)
def parse_timedelta_float(timedelta_str: str) -> float: def parse_timedelta_float(timedelta_str: str) -> float:
@ -83,7 +83,7 @@ def parse_datetime_float(date_str: str) -> float:
pass pass
try: try:
import dateparser # type: ignore[import] import dateparser
except ImportError: except ImportError:
pass pass
else: else:

View file

@ -188,8 +188,8 @@ def test_nt_serialize() -> None:
# test orjson option kwarg # test orjson option kwarg
data = {datetime.date(year=1970, month=1, day=1): 5} data = {datetime.date(year=1970, month=1, day=1): 5}
res = jsn.loads(dumps(data, option=orjson.OPT_NON_STR_KEYS)) res2 = jsn.loads(dumps(data, option=orjson.OPT_NON_STR_KEYS))
assert res == {'1970-01-01': 5} assert res2 == {'1970-01-01': 5}
def test_default_serializer() -> None: def test_default_serializer() -> None:

View file

@ -22,7 +22,7 @@ def test_sqlite_connect_immutable(tmp_path: Path) -> None:
with sqlite3.connect(db) as conn: with sqlite3.connect(db) as conn:
conn.execute('CREATE TABLE testtable (col)') conn.execute('CREATE TABLE testtable (col)')
import pytest # type: ignore import pytest
with pytest.raises(sqlite3.OperationalError, match='readonly database'): with pytest.raises(sqlite3.OperationalError, match='readonly database'):
with sqlite_connect_immutable(db) as conn: with sqlite_connect_immutable(db) as conn:
conn.execute('DROP TABLE testtable') conn.execute('DROP TABLE testtable')

View file

@ -62,7 +62,7 @@ def _iter_all_importables(pkg: ModuleType) -> Iterable[HPIModule]:
_discover_path_importables(Path(p), pkg.__name__) _discover_path_importables(Path(p), pkg.__name__)
# todo might need to handle __path__ for individual modules too? # todo might need to handle __path__ for individual modules too?
# not sure why __path__ was duplicated, but it did happen.. # not sure why __path__ was duplicated, but it did happen..
for p in set(pkg.__path__) # type: ignore[attr-defined] for p in set(pkg.__path__)
) )

View file

@ -133,7 +133,7 @@ def dataframe() -> DataFrameT:
dicts.append(d) dicts.append(d)
import pandas # type: ignore import pandas
return pandas.DataFrame(dicts) return pandas.DataFrame(dicts)

View file

@ -66,7 +66,7 @@ def dataframe(defensive: bool=True) -> DataFrameT:
# todo check for 'defensive' # todo check for 'defensive'
d = {'error': f'{e} {w}'} d = {'error': f'{e} {w}'}
yield d yield d
import pandas as pd # type: ignore import pandas as pd
df = pd.DataFrame(it()) df = pd.DataFrame(it())
# pandas guesses integer, which is pointless for this field (might get coerced to float too) # pandas guesses integer, which is pointless for this field (might get coerced to float too)
df['id'] = df['id'].astype(str) df['id'] = df['id'].astype(str)

View file

@ -133,7 +133,7 @@ def _parse_repository(d: Dict) -> Event:
rt = d['type'] rt = d['type']
assert url.startswith(pref); name = url[len(pref):] assert url.startswith(pref); name = url[len(pref):]
eid = EventIds.repo_created(dts=dts, name=name, ref_type=rt, ref=None) eid = EventIds.repo_created(dts=dts, name=name, ref_type=rt, ref=None)
return Event( # type: ignore[misc] return Event(
**_parse_common(d), **_parse_common(d),
summary='created ' + name, summary='created ' + name,
eid=eid, eid=eid,
@ -143,7 +143,7 @@ def _parse_repository(d: Dict) -> Event:
def _parse_issue_comment(d: Dict) -> Event: def _parse_issue_comment(d: Dict) -> Event:
url = d['url'] url = d['url']
is_bot = "[bot]" in d["user"] is_bot = "[bot]" in d["user"]
return Event( # type: ignore[misc] return Event(
**_parse_common(d), **_parse_common(d),
summary=f'commented on issue {url}', summary=f'commented on issue {url}',
eid='issue_comment_' + url, eid='issue_comment_' + url,
@ -155,7 +155,7 @@ def _parse_issue(d: Dict) -> Event:
url = d['url'] url = d['url']
title = d['title'] title = d['title']
is_bot = "[bot]" in d["user"] is_bot = "[bot]" in d["user"]
return Event( # type: ignore[misc] return Event(
**_parse_common(d), **_parse_common(d),
summary=f'opened issue {title}', summary=f'opened issue {title}',
eid='issue_comment_' + url, eid='issue_comment_' + url,
@ -168,7 +168,7 @@ def _parse_pull_request(d: Dict) -> Event:
url = d['url'] url = d['url']
title = d['title'] title = d['title']
is_bot = "[bot]" in d["user"] is_bot = "[bot]" in d["user"]
return Event( # type: ignore[misc] return Event(
**_parse_common(d), **_parse_common(d),
# TODO distinguish incoming/outgoing? # TODO distinguish incoming/outgoing?
# TODO action? opened/closed?? # TODO action? opened/closed??
@ -195,7 +195,7 @@ def _parse_project(d: Dict) -> Event:
def _parse_release(d: Dict) -> Event: def _parse_release(d: Dict) -> Event:
tag = d['tag_name'] tag = d['tag_name']
return Event( # type: ignore[misc] return Event(
**_parse_common(d), **_parse_common(d),
summary=f'released {tag}', summary=f'released {tag}',
eid='release_' + tag, eid='release_' + tag,
@ -204,7 +204,7 @@ def _parse_release(d: Dict) -> Event:
def _parse_commit_comment(d: Dict) -> Event: def _parse_commit_comment(d: Dict) -> Event:
url = d['url'] url = d['url']
return Event( # type: ignore[misc] return Event(
**_parse_common(d), **_parse_common(d),
summary=f'commented on {url}', summary=f'commented on {url}',
eid='commit_comment_' + url, eid='commit_comment_' + url,

View file

@ -71,7 +71,7 @@ def estimate_location(dt: DateExact) -> Iterator[FallbackLocation]:
# search to find the first possible location which contains dt (something that started up to # search to find the first possible location which contains dt (something that started up to
# config.for_duration ago, and ends after dt) # config.for_duration ago, and ends after dt)
idx = bisect_left(fl, dt_ts - config.for_duration.total_seconds(), key=lambda l: l.dt.timestamp()) # type: ignore[operator,call-arg,type-var] idx = bisect_left(fl, dt_ts - config.for_duration.total_seconds(), key=lambda l: l.dt.timestamp())
# all items are before the given dt # all items are before the given dt
if idx == len(fl): if idx == len(fl):

View file

@ -22,7 +22,7 @@ from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
from typing import Iterator, Sequence, List from typing import Iterator, Sequence, List
import gpxpy # type: ignore[import] import gpxpy
from more_itertools import unique_everseen from more_itertools import unique_everseen
from my.core import Stats, LazyLogger from my.core import Stats, LazyLogger

View file

@ -36,7 +36,7 @@ _rgx = re.compile(orgparse.date.gene_timestamp_regex(brtype='inactive'), re.VERB
def _created(n: orgparse.OrgNode) -> Tuple[Optional[datetime], str]: def _created(n: orgparse.OrgNode) -> Tuple[Optional[datetime], str]:
heading = n.heading heading = n.heading
# meh.. support in orgparse? # meh.. support in orgparse?
pp = {} if n.is_root() else n.properties # type: ignore pp = {} if n.is_root() else n.properties
createds = pp.get('CREATED', None) createds = pp.get('CREATED', None)
if createds is None: if createds is None:
# try to guess from heading # try to guess from heading

View file

@ -1,8 +1,8 @@
from pathlib import Path from pathlib import Path
from typing import Dict from typing import Dict
import PIL.Image # type: ignore import PIL.Image
from PIL.ExifTags import TAGS, GPSTAGS # type: ignore from PIL.ExifTags import TAGS, GPSTAGS
Exif = Dict Exif = Dict

View file

@ -224,9 +224,9 @@ def events(*args, **kwargs) -> List[Event]:
inp = inputs() inp = inputs()
# 2.2s for 300 files without cachew # 2.2s for 300 files without cachew
# 0.2s for 300 files with cachew # 0.2s for 300 files with cachew
evit = _get_events(inp, *args, **kwargs) # type: ignore[call-arg] evit = _get_events(inp, *args, **kwargs)
# todo mypy is confused here and thinks it's iterable of Path? perhaps something to do with mcachew? # todo mypy is confused here and thinks it's iterable of Path? perhaps something to do with mcachew?
return list(sorted(evit, key=lambda e: e.cmp_key)) # type: ignore[attr-defined,arg-type] return list(sorted(evit, key=lambda e: e.cmp_key))
def stats() -> Stats: def stats() -> Stats:

View file

@ -33,7 +33,7 @@ from typing import Iterable
from .common import SubscriptionState from .common import SubscriptionState
def states() -> Iterable[SubscriptionState]: def states() -> Iterable[SubscriptionState]:
# meh # meh
from dateutil.parser import isoparse # type: ignore from dateutil.parser import isoparse
for f in inputs(): for f in inputs():
# TODO ugh. depends on my naming. not sure if useful? # TODO ugh. depends on my naming. not sure if useful?
dts = f.stem.split('_')[-1] dts = f.stem.split('_')[-1]

View file

@ -78,7 +78,7 @@ def dataframe() -> DataFrameT:
yield error_to_row(w) yield error_to_row(w)
else: else:
yield w yield w
import pandas as pd # type: ignore import pandas as pd
df = pd.DataFrame(it()) df = pd.DataFrame(it())
if 'error' not in df: if 'error' not in df:
df['error'] = None df['error'] = None

View file

@ -22,7 +22,7 @@ from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
from typing import NamedTuple, Iterator, Set, Tuple, Optional from typing import NamedTuple, Iterator, Set, Tuple, Optional
from lxml import etree # type: ignore from lxml import etree
from my.core.common import get_files, Stats from my.core.common import get_files, Stats
from my.core.error import Res from my.core.error import Res

View file

@ -65,7 +65,7 @@ logger = LazyLogger(__name__, level='warning')
def _timezone_finder(fast: bool) -> Any: def _timezone_finder(fast: bool) -> Any:
if fast: if fast:
# less precise, but faster # less precise, but faster
from timezonefinder import TimezoneFinderL as Finder # type: ignore from timezonefinder import TimezoneFinderL as Finder
else: else:
from timezonefinder import TimezoneFinder as Finder # type: ignore from timezonefinder import TimezoneFinder as Finder # type: ignore
return Finder(in_memory=True) return Finder(in_memory=True)
@ -158,7 +158,7 @@ def _iter_local_dates_fallback() -> Iterator[DayWithZone]:
def most_common(lst: List[DayWithZone]) -> DayWithZone: def most_common(lst: List[DayWithZone]) -> DayWithZone:
res, _ = Counter(lst).most_common(1)[0] # type: ignore[var-annotated] res, _ = Counter(lst).most_common(1)[0]
return res return res

View file

@ -12,7 +12,7 @@ except ImportError as ie:
# must be caused by something else # must be caused by something else
raise ie raise ie
try: try:
from my.config import twitter as user_config # type: ignore[misc,assignment] from my.config import twitter as user_config # type: ignore[assignment]
except ImportError: except ImportError:
raise ie # raise the original exception.. must be something else raise ie # raise the original exception.. must be something else
else: else:

View file

@ -1,9 +1,19 @@
[mypy] [mypy]
namespace_packages = True
pretty = True pretty = True
show_error_context = True show_error_context = True
show_error_codes = True show_error_codes = True
show_column_numbers = True
show_error_end = True
warn_unused_ignores = True
check_untyped_defs = True check_untyped_defs = True
namespace_packages = True enable_error_code = possibly-undefined
strict_equality = True
# a bit annoying, it has optional ipython import which should be ignored in mypy-core configuration..
[mypy-my.core.__main__]
warn_unused_ignores = False
# todo ok, maybe it wasn't such a good idea.. # todo ok, maybe it wasn't such a good idea..
# mainly because then tox picks it up and running against the user config, not the repository config # mainly because then tox picks it up and running against the user config, not the repository config
# mypy_path=~/.config/my # mypy_path=~/.config/my

View file

@ -1,6 +1,6 @@
from pathlib import Path from pathlib import Path
import pytest # type: ignore import pytest
from my.calendar.holidays import is_holiday from my.calendar.holidays import is_holiday

View file

@ -23,7 +23,7 @@ def test_dynamic_configuration(notes: Path) -> None:
0.0, 0.0,
] ]
import pytest # type: ignore import pytest
def test_environment_variable(tmp_path: Path) -> None: def test_environment_variable(tmp_path: Path) -> None:

View file

@ -1,4 +1,4 @@
import pytest # type: ignore import pytest
# I guess makes sense by default # I guess makes sense by default
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)

View file

@ -6,7 +6,7 @@ import zipfile
from my.core.kompress import kopen, kexists, CPath from my.core.kompress import kopen, kexists, CPath
import pytest # type: ignore import pytest
structure_data: Path = Path(__file__).parent / "structure_data" structure_data: Path = Path(__file__).parent / "structure_data"

View file

@ -38,7 +38,7 @@ def test_dynamic_config_2(tmp_path: Path) -> None:
assert item1.username == 'user2' assert item1.username == 'user2'
import pytest # type: ignore import pytest
@pytest.mark.skip(reason="won't work at the moment because of inheritance") @pytest.mark.skip(reason="won't work at the moment because of inheritance")
def test_dynamic_config_simplenamespace(tmp_path: Path) -> None: def test_dynamic_config_simplenamespace(tmp_path: Path) -> None:

View file

@ -7,7 +7,7 @@ ROOT = Path(__file__).parent.absolute()
OUTPUTS = ROOT / 'outputs' OUTPUTS = ROOT / 'outputs'
import pytest # type: ignore import pytest
def test_hpi(prepare: str) -> None: def test_hpi(prepare: str) -> None:
@ -19,7 +19,7 @@ def test_orger(prepare: str, tmp_path: Path) -> None:
om = import_file(ROOT / 'orger/modules/polar.py') om = import_file(ROOT / 'orger/modules/polar.py')
# reload(om) # reload(om)
pv = om.PolarView() # type: ignore pv = om.PolarView()
# TODO hmm. worth making public? # TODO hmm. worth making public?
OUTPUTS.mkdir(exist_ok=True) OUTPUTS.mkdir(exist_ok=True)
out = OUTPUTS / (get_valid_filename(prepare) + '.org') out = OUTPUTS / (get_valid_filename(prepare) + '.org')

View file

@ -5,7 +5,7 @@ from typing import TYPE_CHECKING
from my.core.compat import windows from my.core.compat import windows
from my.core.common import get_files from my.core.common import get_files
import pytest # type: ignore import pytest
# hack to replace all /tmp with 'real' tmp dir # hack to replace all /tmp with 'real' tmp dir

View file

@ -1,6 +1,6 @@
from pathlib import Path from pathlib import Path
import pytest # type: ignore import pytest
def test() -> None: def test() -> None:

View file

@ -49,7 +49,7 @@ def with_config():
import my.core.cfg as C import my.core.cfg as C
with C.tmp_config() as config: with C.tmp_config() as config:
config.pdfs = user_config # type: ignore config.pdfs = user_config
try: try:
yield yield
finally: finally:

View file

@ -64,7 +64,7 @@ def test_preserves_extra_attr() -> None:
assert isinstance(getattr(config, 'please_keep_me'), str) assert isinstance(getattr(config, 'please_keep_me'), str)
import pytest # type: ignore import pytest
@pytest.fixture(autouse=True, scope='module') @pytest.fixture(autouse=True, scope='module')
def prepare(): def prepare():
from .common import testdata from .common import testdata

View file

@ -18,7 +18,7 @@ def test_location_perf() -> None:
# in theory should support any HTML takeout file? # in theory should support any HTML takeout file?
# although IIRC bookmarks and search-history.html weren't working # although IIRC bookmarks and search-history.html weren't working
import pytest # type: ignore import pytest
@pytest.mark.parametrize( @pytest.mark.parametrize(
'path', [ 'path', [
'YouTube/history/watch-history.html', 'YouTube/history/watch-history.html',

View file

@ -10,7 +10,7 @@ def _init_default_config() -> None:
import my.config import my.config
class default_config: class default_config:
count = 5 count = 5
my.config.simple = default_config # type: ignore[attr-defined,assignment,misc] my.config.simple = default_config # type: ignore[assignment,misc]
def test_tmp_config() -> None: def test_tmp_config() -> None:

View file

@ -2,8 +2,8 @@ import sys
from datetime import datetime, timedelta from datetime import datetime, timedelta
from pathlib import Path from pathlib import Path
import pytest # type: ignore import pytest
import pytz # type: ignore import pytz
from my.core.error import notnone from my.core.error import notnone