From 747ef25da61851834d78ed2c943cf22575302ed4 2020-03-30 03:18:40 From: Brett Smith Date: 2020-03-30 03:18:40 Subject: [PATCH] setup: Disallow untyped defs. Mostly this meant giving annotations to low-value functions like the error classes and __init_subclass__, but it's worth it for the future strictness+documentation value. --- diff --git a/conservancy_beancount/errors.py b/conservancy_beancount/errors.py index 3d9bdd207e5137e3060a8fc1677ececad1cdaa13..486676a71651a122c0778b5274efc0800dcc1d95 100644 --- a/conservancy_beancount/errors.py +++ b/conservancy_beancount/errors.py @@ -14,24 +14,53 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import beancount.core.data as bc_data + from typing import ( + Any, Iterable, + Optional, +) + +from .beancount_types import ( + Directive, + MetaKey, + MetaValue, + Posting, + Transaction, + Type, ) +Meta = Optional[bc_data.Meta] + class Error(Exception): - def __init__(self, message, entry, source=None): + def __init__(self, + message: str, + entry: Optional[Directive], + source: Meta=None, + ) -> None: self.message = message self.entry = entry - self.source = entry.meta if source is None else source + if source: + self.source = source + elif entry is not None: + self.source = entry.meta + else: + self.source = {} + self._fill_source(self.source, '') - def __repr__(self): + def __repr__(self) -> str: return "{clsname}<{source[filename]}:{source[lineno]}: {message}>".format( clsname=type(self).__name__, message=self.message, source=self.source, ) - def _fill_source(self, source, filename='conservancy_beancount', lineno=0): + def _fill_source(self, + source: bc_data.Meta, + filename: str='conservancy_beancount', + lineno: int=0, + ) -> None: source.setdefault('filename', filename) source.setdefault('lineno', lineno) @@ -39,15 +68,27 @@ class Error(Exception): Iter = Iterable[Error] class BrokenLinkError(Error): - def __init__(self, txn, key, link, source=None): + def __init__(self, + txn: Transaction, + key: MetaKey, + link: str, + source: Meta=None, + ) -> None: super().__init__( "{} not found in repository: {}".format(key, link), txn, source, ) + class BrokenRTLinkError(Error): - def __init__(self, txn, key, link, parsed=True, source=None): + def __init__(self, + txn: Transaction, + key: MetaKey, + link: str, + parsed: Any=True, + source: Meta=None, + ) -> None: if parsed: msg_fmt = "{} not found in RT: {}" else: @@ -58,8 +99,13 @@ class BrokenRTLinkError(Error): source, ) + class ConfigurationError(Error): - def __init__(self, message, entry=None, source=None): + def __init__(self, + message: str, + entry: Optional[Directive]=None, + source: Meta=None, + ) -> None: if source is None: source = {} self._fill_source(source) @@ -67,7 +113,14 @@ class ConfigurationError(Error): class InvalidMetadataError(Error): - def __init__(self, txn, key, value=None, post=None, need_type=str, source=None): + def __init__(self, + txn: Transaction, + key: MetaKey, + value: Optional[MetaValue]=None, + post: Optional[bc_data.Posting]=None, + need_type: Type=str, + source: Meta=None, + ) -> None: if post is None: srcname = 'transaction' else: diff --git a/conservancy_beancount/plugin/core.py b/conservancy_beancount/plugin/core.py index 241d7f92cf893a48e6f5fff13756ba518e7b2aae..21070452b9b01553371c6bb2bf242faeb9aa116f 100644 --- a/conservancy_beancount/plugin/core.py +++ b/conservancy_beancount/plugin/core.py @@ -69,8 +69,9 @@ class Hook(Generic[Entry], metaclass=abc.ABCMeta): @abc.abstractmethod def run(self, entry: Entry) -> errormod.Iter: ... - def __init_subclass__(cls): - cls.DIRECTIVE = cls.__orig_bases__[0].__args__[0] + def __init_subclass__(cls) -> None: + # cls.__orig_bases__ comes from the ABCMeta metaclass + cls.DIRECTIVE = cls.__orig_bases__[0].__args__[0] # type:ignore[attr-defined] TransactionHook = Hook[Transaction] diff --git a/conservancy_beancount/plugin/meta_project.py b/conservancy_beancount/plugin/meta_project.py index 343a10046bccf1c31247f38b60c15b057d6ab57d..ec221cb3bc56914e9ae2f3020ad332553f6be0db 100644 --- a/conservancy_beancount/plugin/meta_project.py +++ b/conservancy_beancount/plugin/meta_project.py @@ -31,6 +31,7 @@ from ..beancount_types import ( from typing import ( Any, Dict, + NoReturn, Optional, Set, ) @@ -43,7 +44,7 @@ class MetaProject(core._NormalizePostingMetadataHook): def __init__(self, config: configmod.Config, source_path: Path=PROJECT_DATA_PATH) -> None: repo_path = config.repository_path() if repo_path is None: - raise self._config_error("no repository configured") + self._config_error("no repository configured") project_data_path = repo_path / source_path source = {'filename': str(project_data_path)} try: @@ -68,7 +69,7 @@ class MetaProject(core._NormalizePostingMetadataHook): else: self.VALUES_ENUM = core.MetadataEnum(self.METADATA_KEY, names, aliases) - def _config_error(self, msg: str, filename: Optional[Path]=None): + def _config_error(self, msg: str, filename: Optional[Path]=None) -> NoReturn: source = {} if filename is not None: source['filename'] = str(filename) diff --git a/conservancy_beancount/rtutil.py b/conservancy_beancount/rtutil.py index cb2dd371de43b906db49cdf4f532716a79b0133f..2fa8c5fa3143e22d9e56b82f34e5f4c36b5d7d38 100644 --- a/conservancy_beancount/rtutil.py +++ b/conservancy_beancount/rtutil.py @@ -196,11 +196,12 @@ class RT: # to be a method, it's just an internal decrator. def _cache_method(func: _URLLookup) -> _URLLookup: # type:ignore[misc] @functools.wraps(func) - def caching_wrapper(self, + def caching_wrapper(self: 'RT', ticket_id: RTId, attachment_id: Optional[RTId]=None, ) -> Optional[str]: - cache_key = (str(ticket_id), attachment_id and str(attachment_id)) + cache_key = (str(ticket_id), + None if attachment_id is None else str(attachment_id)) url: Optional[str] try: url = self._cache[cache_key] diff --git a/setup.cfg b/setup.cfg index c7858f35b788256d5b94c5b5750e12b5c8a5a75d..7ea8404d9900ece604ea87101892a9e13002feeb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,7 @@ typecheck=pytest --addopts="--mypy conservancy_beancount" [mypy] disallow_any_unimported = True +disallow_untyped_defs = True show_error_codes = True strict_equality = True warn_redundant_casts = True