update Mypy & improve typing defs some

This commit is contained in:
ducklet 2023-02-08 23:04:06 +01:00
parent 1b4fad929c
commit 72bd33660b
9 changed files with 115 additions and 75 deletions

View file

@ -5,17 +5,20 @@ import stat
import sys import sys
from contextlib import contextmanager from contextlib import contextmanager
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Generator, TypeVar
from . import config, metadex, utils from . import config, metadex, utils
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
_Command_F = Callable[[argparse.Namespace], "int | None"]
_Command_T = TypeVar("_Command_T", bound=_Command_F)
_commands = {} _commands: "dict[str, _Command_F]" = {}
def command(name): def command(name: str) -> Callable[[_Command_T], _Command_T]:
def wrapper(f): def wrapper(f: _Command_T) -> _Command_T:
assert name not in _commands assert name not in _commands
_commands[name] = f _commands[name] = f
return f return f
@ -23,7 +26,7 @@ def command(name):
return wrapper return wrapper
def getargs(): def getargs() -> argparse.Namespace:
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.set_defaults(mode=None) parser.set_defaults(mode=None)
@ -55,7 +58,9 @@ def getargs():
subparsers = parser.add_subparsers(title="commands") subparsers = parser.add_subparsers(title="commands")
@contextmanager @contextmanager
def command_parser(name, **kwargs): def command_parser(
name: str, **kwargs: Any
) -> Generator[argparse.ArgumentParser, None, None]:
assert name in _commands assert name in _commands
subparser = subparsers.add_parser(name, **kwargs) subparser = subparsers.add_parser(name, **kwargs)
subparser.set_defaults(mode=name) subparser.set_defaults(mode=name)
@ -212,7 +217,7 @@ def getargs():
@command("ingest-rclone-json") @command("ingest-rclone-json")
def cmd_ingest_rclone_json(args): def cmd_ingest_rclone_json(args: argparse.Namespace) -> None:
metadex.init(args.db) metadex.init(args.db)
log.info("Ingesting rclone JSON file %a ...", args.infile.name) log.info("Ingesting rclone JSON file %a ...", args.infile.name)
@ -230,7 +235,7 @@ def cmd_ingest_rclone_json(args):
@command("ingest-ls") @command("ingest-ls")
def cmd_ingest_ls(args): def cmd_ingest_ls(args: argparse.Namespace) -> None:
metadex.init(args.db) metadex.init(args.db)
log.info("Ingesting ls file %a ...", args.infile.name) log.info("Ingesting ls file %a ...", args.infile.name)
@ -245,7 +250,7 @@ def cmd_ingest_ls(args):
@command("ingest-db") @command("ingest-db")
def cmd_ingest_db(args): def cmd_ingest_db(args: argparse.Namespace) -> None:
metadex.init(args.db) metadex.init(args.db)
log.info("Ingesting Metadex DB file %a ...", str(args.infile)) log.info("Ingesting Metadex DB file %a ...", str(args.infile))
@ -260,7 +265,7 @@ def cmd_ingest_db(args):
@command("scan") @command("scan")
def cmd_scan(args): def cmd_scan(args: argparse.Namespace) -> None:
metadex.init(args.db) metadex.init(args.db)
for basedir in args.basedir: for basedir in args.basedir:
@ -279,7 +284,7 @@ def cmd_scan(args):
@command("rm") @command("rm")
def cmd_rm(args): def cmd_rm(args: argparse.Namespace) -> None:
metadex.init(args.db) metadex.init(args.db)
for path in args.files: for path in args.files:
@ -288,7 +293,7 @@ def cmd_rm(args):
metadex.close() metadex.close()
@command("ls") @command("ls")
def cmd_ls(args) -> int: def cmd_ls(args: argparse.Namespace) -> int:
return_code = 0 return_code = 0
metadex.init(args.db) metadex.init(args.db)
@ -341,12 +346,12 @@ def cmd_ls(args) -> int:
return return_code return return_code
def is_stdout_piped(): def is_stdout_piped() -> bool:
s = os.fstat(sys.stdout.fileno()) s = os.fstat(sys.stdout.fileno())
return stat.S_ISFIFO(s.st_mode) return stat.S_ISFIFO(s.st_mode)
def main(): def main() -> int:
logging.basicConfig( logging.basicConfig(
format="%(asctime)s.%(msecs)03d [%(name)s:%(process)d] %(levelname)s: %(message)s", format="%(asctime)s.%(msecs)03d [%(name)s:%(process)d] %(levelname)s: %(message)s",
datefmt="%H:%M:%S", datefmt="%H:%M:%S",
@ -388,7 +393,7 @@ def main():
config.db_allow_slow = False config.db_allow_slow = False
config.dryrun = True config.dryrun = True
cmd = _commands[args.mode] cmd = _commands[args.mode]
return cmd(args) return cmd(args) or 0
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -322,7 +322,16 @@ def _add_parents(conn: Connection, *, location: str, hostname: str):
return p_id return p_id
def get_or_add(conn: Connection, new_data: dict): def get_or_add(conn: Connection, new_data: dict) -> "Row | dict":
"""Return the existing row for the given data, or insert a new row.
If a matching row for the given data can be found in the database the
existing row is returned as a `Row` and no changes are made to the database.\\
If no matching row can be found a new row is inserted using the given data
and the data is returned as a `dict`.\\
BEWARE that the given data dict WILL BE CHANGED IN PLACE if it is inserted
as a new row! It's `id` and other fields may be added or overwritten.
"""
row = get_file(conn, location=new_data["location"], hostname=new_data["hostname"]) row = get_file(conn, location=new_data["location"], hostname=new_data["hostname"])
if row: if row:
return row return row

View file

@ -1,7 +1,7 @@
import re import re
from functools import partial from functools import partial
from pathlib import Path from pathlib import Path
from typing import Match from typing import Callable, Match
_regex_glob_map = { _regex_glob_map = {
"**": r".*", "**": r".*",
@ -19,7 +19,7 @@ _replace_globs_re = re.compile("|".join(re.escape(k) for k in _regex_glob_map))
_replace_globs = partial(_replace_globs_re.sub, _regex_from_glob) _replace_globs = partial(_replace_globs_re.sub, _regex_from_glob)
def parse(path: Path): def parse(path: Path) -> Callable[[str], "Match[str] | None"]:
rules = [] rules = []
for line in path.open(): for line in path.open():
line = line.rstrip() line = line.rstrip()

View file

@ -41,11 +41,11 @@ class File:
path: Path path: Path
@property @property
def is_dir(self): def is_dir(self) -> bool:
return self.mode.startswith("d") return self.mode.startswith("d")
@property @property
def is_symlink(self): def is_symlink(self) -> bool:
return self.mode.startswith("l") return self.mode.startswith("l")
@ -171,7 +171,7 @@ def parse_lines(
yield ChangeDir(from_=dirname, to=None) yield ChangeDir(from_=dirname, to=None)
def get_args(argv: "list[str]"): def get_args(argv: "list[str]") -> argparse.Namespace:
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
# parser.add_argument("--workdir", help="The directory from where 'ls -l' was run") # parser.add_argument("--workdir", help="The directory from where 'ls -l' was run")
parser.add_argument("--ref-year", type=int, help="The year when 'ls -l' was run") parser.add_argument("--ref-year", type=int, help="The year when 'ls -l' was run")
@ -189,7 +189,7 @@ def get_args(argv: "list[str]"):
return args return args
def main(argv: "list[str]"): def main(argv: "list[str]") -> None:
args = get_args(argv) args = get_args(argv)
# workdir = Path(args.workdir or ".") # workdir = Path(args.workdir or ".")
ref_year = args.ref_year or datetime.now().year ref_year = args.ref_year or datetime.now().year

View file

@ -9,7 +9,8 @@ from dataclasses import dataclass
from datetime import datetime, timezone from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
from shutil import get_terminal_size from shutil import get_terminal_size
from typing import Iterable, Literal, TextIO from typing import Any, Iterable, Literal, TextIO
from typing_extensions import TypeAlias
from wcwidth import wcwidth from wcwidth import wcwidth
@ -104,7 +105,7 @@ class _LogContext:
removed: int = 0 removed: int = 0
def _log_context(path, context: _LogContext): def _log_context(path: "str | Path", context: _LogContext) -> None:
if config.is_stdout_piped: if config.is_stdout_piped:
return return
@ -113,7 +114,9 @@ def _log_context(path, context: _LogContext):
) )
def _scan_add_only(path: Path, *, ignore_file: Path, map_pathspecs: "list[str]"): def _scan_add_only(
path: Path, *, ignore_file: Path, map_pathspecs: "list[str]"
) -> _LogContext:
is_ignored = ignore.parse(ignore_file) is_ignored = ignore.parse(ignore_file)
maps = _parse_pathspec_mapping(map_pathspecs) maps = _parse_pathspec_mapping(map_pathspecs)
@ -193,7 +196,9 @@ def _scan_add_only(path: Path, *, ignore_file: Path, map_pathspecs: "list[str]")
return context return context
def _scan_remove_missing(path: Path, *, ignore_file: Path, map_pathspecs: "list[str]"): def _scan_remove_missing(
path: Path, *, ignore_file: Path, map_pathspecs: "list[str]"
) -> _LogContext:
"""Like `scan` but also search for missing files.""" """Like `scan` but also search for missing files."""
is_ignored = ignore.parse(ignore_file) is_ignored = ignore.parse(ignore_file)
@ -278,20 +283,31 @@ def _scan_remove_missing(path: Path, *, ignore_file: Path, map_pathspecs: "list[
for name in expected: for name in expected:
f = str(cwd / name) f = str(cwd / name)
if is_ignored(f): if is_ignored(f):
log.info("Ignoring file (for removal): %a", f)
continue continue
log.info("File removed: %a", f) log.info("File removed: %a", f)
db.remove_all(conn, f) context.removed += db.remove_all(conn, f)
db.recalculate_dir_sizes(conn)
return context return context
# def check_missing():
# """Check if all DB entries can be found."""
# def scan_one(path: Path):
# """Update the given path, but none of its descendants."""
_pathspec_re = re.compile(r"((?P<host>[^:/]*):)?(?P<path>.*)") _pathspec_re = re.compile(r"((?P<host>[^:/]*):)?(?P<path>.*)")
_src_dest_re = re.compile(r"src=(?P<src>.*),dest=(?P<dest>.*)") _src_dest_re = re.compile(r"src=(?P<src>.*),dest=(?P<dest>.*)")
def _parse_pathspec(pathspec: str): def _parse_pathspec(pathspec: str) -> "tuple[str | None, str]":
match = _pathspec_re.fullmatch(pathspec) match = _pathspec_re.fullmatch(pathspec)
assert match assert match
host: "str | None" = match["host"] host: "str | None" = match["host"]
@ -299,7 +315,7 @@ def _parse_pathspec(pathspec: str):
return host, path return host, path
def _clean_dirname(loc: str, *, force_absolute=True): def _clean_dirname(loc: str, *, force_absolute: bool = True) -> str:
if force_absolute and not loc.startswith("/"): if force_absolute and not loc.startswith("/"):
loc = "/" + loc loc = "/" + loc
if not loc.endswith("/"): if not loc.endswith("/"):
@ -310,10 +326,15 @@ def _clean_dirname(loc: str, *, force_absolute=True):
# return loc # return loc
def _parse_pathspec_mapping(map_pathspecs: "list[str]"): _Hostname = str
Hostname = str _Location = str
Location = str _PathspecMapping: TypeAlias = (
maps: dict[Hostname, dict[Location, tuple[Hostname, Location]]] = {} "dict[_Hostname, dict[_Location, tuple[_Hostname, _Location]]]"
)
def _parse_pathspec_mapping(map_pathspecs: "list[str]") -> _PathspecMapping:
maps: _PathspecMapping = {}
for pathspec_mapping in map_pathspecs: for pathspec_mapping in map_pathspecs:
match = _src_dest_re.fullmatch(pathspec_mapping) match = _src_dest_re.fullmatch(pathspec_mapping)
if not match: if not match:
@ -343,7 +364,7 @@ def _parse_pathspec_mapping(map_pathspecs: "list[str]"):
return maps return maps
def _apply_mapping(maps: dict, d: dict): def _apply_mapping(maps: dict, d: dict) -> None:
hostname = d["hostname"] hostname = d["hostname"]
location = ( location = (
d["location"] d["location"]
@ -403,7 +424,7 @@ def ingest_db_file(
return context return context
def _naive_fromisoformat(string, /): def _naive_fromisoformat(string: str, /) -> datetime:
if string.endswith("Z"): if string.endswith("Z"):
string = string[:-1] + "+00:00" string = string[:-1] + "+00:00"
return ( return (
@ -470,7 +491,9 @@ def ingest_ls(
return f(file, ignore_file=ignore_file, ref_year=ref_year) return f(file, ignore_file=ignore_file, ref_year=ref_year)
def _ingest_ls_add_only(file: TextIO, *, ignore_file: Path, ref_year: "int | None"): def _ingest_ls_add_only(
file: TextIO, *, ignore_file: Path, ref_year: "int | None"
) -> _LogContext:
is_ignored = ignore.parse(ignore_file) is_ignored = ignore.parse(ignore_file)
context = _LogContext() context = _LogContext()
@ -502,7 +525,7 @@ def _ingest_ls_add_only(file: TextIO, *, ignore_file: Path, ref_year: "int | Non
return context return context
def _dict_from_lsfile(f: ls_parser.File) -> dict: def _dict_from_lsfile(f: ls_parser.File) -> "dict[str, Any]":
mode = f.mode[0] mode = f.mode[0]
if mode == "-": if mode == "-":
mode = "f" mode = "f"
@ -520,7 +543,7 @@ def _dict_from_lsfile(f: ls_parser.File) -> dict:
def _ingest_ls_remove_missing( def _ingest_ls_remove_missing(
file: TextIO, *, ignore_file: Path, ref_year: "int | None" file: TextIO, *, ignore_file: Path, ref_year: "int | None"
): ) -> _LogContext:
is_ignored = ignore.parse(ignore_file) is_ignored = ignore.parse(ignore_file)
expected: set[str] = set() expected: set[str] = set()
@ -579,7 +602,7 @@ def _ls_files(
type: "models.StatType | None" = None, type: "models.StatType | None" = None,
match: Literal["regex", "glob", "fuzzy"] = "glob", match: Literal["regex", "glob", "fuzzy"] = "glob",
) -> Iterable[models.File]: ) -> Iterable[models.File]:
def map_replace(mapping: dict, string: str): def map_replace(mapping: "dict[str, str]", string: str) -> str:
pattern = "|".join(re.escape(k) for k in mapping.keys()) pattern = "|".join(re.escape(k) for k in mapping.keys())
return re.sub(pattern, lambda m: mapping[m[0]], string) return re.sub(pattern, lambda m: mapping[m[0]], string)
@ -603,7 +626,7 @@ def _ls_files(
elif match == "glob": elif match == "glob":
filters = {"type": type} filters: dict[str, "str | None"] = {"type": type}
if host and _uses_glob(host): if host and _uses_glob(host):
filters["hostname_like"] = liketerm_from_glob(host) filters["hostname_like"] = liketerm_from_glob(host)
else: else:
@ -686,7 +709,7 @@ def ls(
yield from _ls_files(host=host, path=path, type=type, match=match) yield from _ls_files(host=host, path=path, type=type, match=match)
def rm(pathspec: str, *, include_children: bool = False): def rm(pathspec: str, *, include_children: bool = False) -> None:
"""Remove the given path and all its descendants.""" """Remove the given path and all its descendants."""
host, path = _parse_pathspec(pathspec) host, path = _parse_pathspec(pathspec)

View file

@ -5,6 +5,7 @@ from os import DirEntry
from pathlib import Path from pathlib import Path
from stat import S_IFDIR, S_IFLNK, S_IFMT, S_IFREG from stat import S_IFDIR, S_IFLNK, S_IFMT, S_IFREG
from typing import Literal from typing import Literal
from typing_extensions import Self
from . import config from . import config
@ -29,7 +30,7 @@ class File:
stat_type: StatType stat_type: StatType
@classmethod @classmethod
def from_direntry(cls, entry: DirEntry): def from_direntry(cls, entry: DirEntry) -> Self:
now = datetime.now() now = datetime.now()
pstat = entry.stat(follow_symlinks=False) pstat = entry.stat(follow_symlinks=False)
return cls( return cls(
@ -44,7 +45,7 @@ class File:
) )
@classmethod @classmethod
def from_path(cls, path: Path): def from_path(cls, path: Path) -> Self:
now = datetime.now() now = datetime.now()
pstat = os.stat(path, follow_symlinks=False) pstat = os.stat(path, follow_symlinks=False)
return cls( return cls(

View file

@ -1,5 +1,6 @@
import os import os
from pathlib import Path from pathlib import Path
from typing import Literal
_size_quantifiers = "BKMGTP" _size_quantifiers = "BKMGTP"
_size_map: "dict[str, int]" = { _size_map: "dict[str, int]" = {
@ -7,7 +8,11 @@ _size_map: "dict[str, int]" = {
} }
def size_for_display(byte_count: int, precision: int = 2, format="short") -> str: def size_for_display(
byte_count: int,
precision: int = 2,
format: Literal["short", "compact", "long"] = "short",
) -> str:
for qtf in reversed(_size_quantifiers): for qtf in reversed(_size_quantifiers):
qty = byte_count / _size_map[qtf] qty = byte_count / _size_map[qtf]
if qty > 1: if qty > 1:

60
poetry.lock generated
View file

@ -312,42 +312,38 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"]
[[package]] [[package]]
name = "mypy" name = "mypy"
version = "0.991" version = "1.0.0"
description = "Optional static typing for Python" description = "Optional static typing for Python"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "mypy-0.991-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7d17e0a9707d0772f4a7b878f04b4fd11f6f5bcb9b3813975a9b13c9332153ab"}, {file = "mypy-1.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0626db16705ab9f7fa6c249c017c887baf20738ce7f9129da162bb3075fc1af"},
{file = "mypy-0.991-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0714258640194d75677e86c786e80ccf294972cc76885d3ebbb560f11db0003d"}, {file = "mypy-1.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1ace23f6bb4aec4604b86c4843276e8fa548d667dbbd0cb83a3ae14b18b2db6c"},
{file = "mypy-0.991-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c8f3be99e8a8bd403caa8c03be619544bc2c77a7093685dcf308c6b109426c6"}, {file = "mypy-1.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87edfaf344c9401942883fad030909116aa77b0fa7e6e8e1c5407e14549afe9a"},
{file = "mypy-0.991-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc9ec663ed6c8f15f4ae9d3c04c989b744436c16d26580eaa760ae9dd5d662eb"}, {file = "mypy-1.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0ab090d9240d6b4e99e1fa998c2d0aa5b29fc0fb06bd30e7ad6183c95fa07593"},
{file = "mypy-0.991-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4307270436fd7694b41f913eb09210faff27ea4979ecbcd849e57d2da2f65305"}, {file = "mypy-1.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:7cc2c01dfc5a3cbddfa6c13f530ef3b95292f926329929001d45e124342cd6b7"},
{file = "mypy-0.991-cp310-cp310-win_amd64.whl", hash = "sha256:901c2c269c616e6cb0998b33d4adbb4a6af0ac4ce5cd078afd7bc95830e62c1c"}, {file = "mypy-1.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14d776869a3e6c89c17eb943100f7868f677703c8a4e00b3803918f86aafbc52"},
{file = "mypy-0.991-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d13674f3fb73805ba0c45eb6c0c3053d218aa1f7abead6e446d474529aafc372"}, {file = "mypy-1.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb2782a036d9eb6b5a6efcdda0986774bf798beef86a62da86cb73e2a10b423d"},
{file = "mypy-0.991-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c8cd4fb70e8584ca1ed5805cbc7c017a3d1a29fb450621089ffed3e99d1857f"}, {file = "mypy-1.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cfca124f0ac6707747544c127880893ad72a656e136adc935c8600740b21ff5"},
{file = "mypy-0.991-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:209ee89fbb0deed518605edddd234af80506aec932ad28d73c08f1400ef80a33"}, {file = "mypy-1.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8845125d0b7c57838a10fd8925b0f5f709d0e08568ce587cc862aacce453e3dd"},
{file = "mypy-0.991-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37bd02ebf9d10e05b00d71302d2c2e6ca333e6c2a8584a98c00e038db8121f05"}, {file = "mypy-1.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b1b9e1ed40544ef486fa8ac022232ccc57109f379611633ede8e71630d07d2"},
{file = "mypy-0.991-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:26efb2fcc6b67e4d5a55561f39176821d2adf88f2745ddc72751b7890f3194ad"}, {file = "mypy-1.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c7cf862aef988b5fbaa17764ad1d21b4831436701c7d2b653156a9497d92c83c"},
{file = "mypy-0.991-cp311-cp311-win_amd64.whl", hash = "sha256:3a700330b567114b673cf8ee7388e949f843b356a73b5ab22dd7cff4742a5297"}, {file = "mypy-1.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cd187d92b6939617f1168a4fe68f68add749902c010e66fe574c165c742ed88"},
{file = "mypy-0.991-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1f7d1a520373e2272b10796c3ff721ea1a0712288cafaa95931e66aa15798813"}, {file = "mypy-1.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4e5175026618c178dfba6188228b845b64131034ab3ba52acaffa8f6c361f805"},
{file = "mypy-0.991-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:641411733b127c3e0dab94c45af15fea99e4468f99ac88b39efb1ad677da5711"}, {file = "mypy-1.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2f6ac8c87e046dc18c7d1d7f6653a66787a4555085b056fe2d599f1f1a2a2d21"},
{file = "mypy-0.991-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3d80e36b7d7a9259b740be6d8d906221789b0d836201af4234093cae89ced0cd"}, {file = "mypy-1.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7306edca1c6f1b5fa0bc9aa645e6ac8393014fa82d0fa180d0ebc990ebe15964"},
{file = "mypy-0.991-cp37-cp37m-win_amd64.whl", hash = "sha256:e62ebaad93be3ad1a828a11e90f0e76f15449371ffeecca4a0a0b9adc99abcef"}, {file = "mypy-1.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3cfad08f16a9c6611e6143485a93de0e1e13f48cfb90bcad7d5fde1c0cec3d36"},
{file = "mypy-0.991-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b86ce2c1866a748c0f6faca5232059f881cda6dda2a893b9a8373353cfe3715a"}, {file = "mypy-1.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67cced7f15654710386e5c10b96608f1ee3d5c94ca1da5a2aad5889793a824c1"},
{file = "mypy-0.991-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac6e503823143464538efda0e8e356d871557ef60ccd38f8824a4257acc18d93"}, {file = "mypy-1.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a86b794e8a56ada65c573183756eac8ac5b8d3d59daf9d5ebd72ecdbb7867a43"},
{file = "mypy-0.991-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0cca5adf694af539aeaa6ac633a7afe9bbd760df9d31be55ab780b77ab5ae8bf"}, {file = "mypy-1.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:50979d5efff8d4135d9db293c6cb2c42260e70fb010cbc697b1311a4d7a39ddb"},
{file = "mypy-0.991-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12c56bf73cdab116df96e4ff39610b92a348cc99a1307e1da3c3768bbb5b135"}, {file = "mypy-1.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ae4c7a99e5153496243146a3baf33b9beff714464ca386b5f62daad601d87af"},
{file = "mypy-0.991-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:652b651d42f155033a1967739788c436491b577b6a44e4c39fb340d0ee7f0d70"}, {file = "mypy-1.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e398652d005a198a7f3c132426b33c6b85d98aa7dc852137a2a3be8890c4072"},
{file = "mypy-0.991-cp38-cp38-win_amd64.whl", hash = "sha256:4175593dc25d9da12f7de8de873a33f9b2b8bdb4e827a7cae952e5b1a342e243"}, {file = "mypy-1.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be78077064d016bc1b639c2cbcc5be945b47b4261a4f4b7d8923f6c69c5c9457"},
{file = "mypy-0.991-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98e781cd35c0acf33eb0295e8b9c55cdbef64fcb35f6d3aa2186f289bed6e80d"}, {file = "mypy-1.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92024447a339400ea00ac228369cd242e988dd775640755fa4ac0c126e49bb74"},
{file = "mypy-0.991-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6d7464bac72a85cb3491c7e92b5b62f3dcccb8af26826257760a552a5e244aa5"}, {file = "mypy-1.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:fe523fcbd52c05040c7bee370d66fee8373c5972171e4fbc323153433198592d"},
{file = "mypy-0.991-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c9166b3f81a10cdf9b49f2d594b21b31adadb3d5e9db9b834866c3258b695be3"}, {file = "mypy-1.0.0-py3-none-any.whl", hash = "sha256:2efa963bdddb27cb4a0d42545cd137a8d2b883bd181bbc4525b568ef6eca258f"},
{file = "mypy-0.991-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8472f736a5bfb159a5e36740847808f6f5b659960115ff29c7cecec1741c648"}, {file = "mypy-1.0.0.tar.gz", hash = "sha256:f34495079c8d9da05b183f9f7daec2878280c2ad7cc81da686ef0b484cea2ecf"},
{file = "mypy-0.991-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e80e758243b97b618cdf22004beb09e8a2de1af481382e4d84bc52152d1c476"},
{file = "mypy-0.991-cp39-cp39-win_amd64.whl", hash = "sha256:74e259b5c19f70d35fcc1ad3d56499065c601dfe94ff67ae48b85596b9ec1461"},
{file = "mypy-0.991-py3-none-any.whl", hash = "sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb"},
{file = "mypy-0.991.tar.gz", hash = "sha256:3c0165ba8f354a6d9881809ef29f1a9318a236a6d81c690094c5df32107bde06"},
] ]
[package.dependencies] [package.dependencies]
@ -654,4 +650,4 @@ files = [
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.8" python-versions = "^3.8"
content-hash = "07592865dc8732eff7e171dd21be41f9f876d139a7f028e4e6de0d04d7ee77f5" content-hash = "44e138d5ee6fd3739cd1cf027204566d823c3fa432c719f4074761c23eeac543"

View file

@ -8,6 +8,7 @@ authors = ["ducklet <ducklet@noreply.code.dumpr.org>"]
python = "^3.8" python = "^3.8"
SQLAlchemy = {extras = ["mypy"], version = "^1.4.45"} SQLAlchemy = {extras = ["mypy"], version = "^1.4.45"}
wcwidth = "^0.2.5" wcwidth = "^0.2.5"
typing-extensions = "*"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
interrogate = "*" interrogate = "*"