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.
This commit is contained in:
parent
e6894c2b46
commit
747ef25da6
5 changed files with 71 additions and 14 deletions
|
@ -14,24 +14,53 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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, '<unknown>')
|
||||
|
||||
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:
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue