App, cmds, lib: Fix Any returns from typed functions

Add type annotations and casts to functions that were returning Any
where a specific type was declared, satisfying the new warn_return_any
mypy rule.

Fixes:
- log.py: get_caller_pos return type via cast
- AsyncRunner.py: cast T for fut.result()
- util.py: cast for getattr result, str() for args.username
- FileContext.py: verbose_default bool annotation
- SSHClient.py: cast SSHClient for dynamic import
- lib/App.py: cast ArgumentParser, add return types to inner funcs
- pm/rpm.py, dpkg.py: cast Iterable[Package]
- App.py: cast for self.args.func(), add return types to inner funcs
- BaseCmdPkgRelations.py: cast str for args.delimiter

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2026-07-22 23:03:53 +02:00
commit 1e613a39c6
40 changed files with 228 additions and 179 deletions

View file

@ -10,7 +10,7 @@ import sys
from enum import Enum, auto from enum import Enum, auto
from functools import cache from functools import cache
from typing import Any, override, TYPE_CHECKING from typing import Any, cast, override, TYPE_CHECKING
from .lib.App import App as Base from .lib.App import App as Base
from .lib.Distro import Distro from .lib.Distro import Distro
@ -40,7 +40,7 @@ class ResultCache(object):
def __init__(self) -> None: def __init__(self) -> None:
self.__cache: dict[str, Any] = {} self.__cache: dict[str, Any] = {}
def run(self, func, args: list[Any]) -> object: def run(self, func: Any, args: list[Any]) -> object:
d = self.__cache d = self.__cache
depth = 0 depth = 0
keys = [func.__name__] + args keys = [func.__name__] + args
@ -137,21 +137,21 @@ class App(Base):
if search_absdirs is None: if search_absdirs is None:
search_absdirs = [] search_absdirs = []
def __format_relpath(path: str): def __format_relpath(path: str) -> str:
if path.startswith('./'): if path.startswith('./'):
return path[2:] return path[2:]
if path.endswith('/.'): if path.endswith('/.'):
return path[:-2] return path[:-2]
return path return path
def __relpath(target: str, base: str): def __relpath(target: str, base: str) -> str:
return __format_relpath(os.path.relpath(target, base)) return __format_relpath(os.path.relpath(target, base))
def __format_pd(name: str, pd: str, pretty: bool): def __format_pd(name: str, pd: str, pretty: bool) -> str | None:
if not pretty: if not pretty:
return pd return pd
if self.__topdir_fmt == 'absolute': if self.__topdir_fmt == 'absolute':
return os.path.abspath(pd) return str(os.path.abspath(pd))
if self.__topdir_fmt == 'unaltered': if self.__topdir_fmt == 'unaltered':
return pd return pd
if self.__topdir_fmt == 'relative': if self.__topdir_fmt == 'relative':
@ -175,6 +175,7 @@ class App(Base):
path = pd + '/' + sd path = pd + '/' + sd
if os.path.isdir(path): if os.path.isdir(path):
ret = __format_pd(name, pd, pretty) ret = __format_pd(name, pd, pretty)
assert ret is not None
if sd and sd[0] != '/': if sd and sd[0] != '/':
if ret == '.': if ret == '.':
ret = '' ret = ''
@ -210,10 +211,13 @@ class App(Base):
add_self: bool, add_self: bool,
scope: Scope, scope: Scope,
names_only: bool, names_only: bool,
): ) -> list[str]:
return self.__res_cache.run( return cast(
self.__get_project_refs, 'list[str]',
[buf, visited, spec, section, key, add_self, scope, names_only], self.__res_cache.run(
self.__get_project_refs,
[buf, visited, spec, section, key, add_self, scope, names_only],
),
) )
def __get_project_refs( def __get_project_refs(
@ -292,7 +296,7 @@ class App(Base):
for dep in deps: for dep in deps:
self.__read_dep_graph([dep], sections, graph) self.__read_dep_graph([dep], sections, graph)
def __flip_dep_graph(self, graph: Graph): def __flip_dep_graph(self, graph: Graph) -> Graph:
ret: Graph = {} ret: Graph = {}
for project, deps in graph.items(): for project, deps in graph.items():
for d in deps: for d in deps:
@ -384,7 +388,7 @@ class App(Base):
) )
@override @override
async def __aexit__(self, exc_type, exc, tb) -> None: async def __aexit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
if self.__exec_context is not None: if self.__exec_context is not None:
await self.__exec_context.close() await self.__exec_context.close()
self.__exec_context = None self.__exec_context = None
@ -494,7 +498,7 @@ class App(Base):
return self.__exec_context return self.__exec_context
@property @property
def top_name(self): def top_name(self) -> str | None:
return self.__top_name return self.__top_name
@property @property
@ -581,7 +585,7 @@ class App(Base):
return ret return ret
@cache @cache
def get_version(self, project) -> str: def get_version(self, project: str) -> str:
ret = self.get_value(project, 'version', '') ret = self.get_value(project, 'version', '')
if ret is None: if ret is None:
raise Exception(f"Can't get version of project {project}") raise Exception(f"Can't get version of project {project}")
@ -610,9 +614,9 @@ class App(Base):
projects: list[str], projects: list[str],
sections: list[str], sections: list[str],
keys: str | list[str], keys: str | list[str],
add_self: bool, scope: Scope = Scope.One,
scope: Scope, add_self: bool = False,
names_only = True, names_only: bool = False,
) -> list[str]: ) -> list[str]:
if isinstance(keys, str): if isinstance(keys, str):
keys = [keys] keys = [keys]

View file

@ -6,6 +6,7 @@ from ..App import App as Parent
from ..CmdBase import CmdBase as Base from ..CmdBase import CmdBase as Base
if TYPE_CHECKING: if TYPE_CHECKING:
from argparse import Namespace
from typing import Iterable from typing import Iterable
from ..lib.Distro import Distro from ..lib.Distro import Distro
@ -21,7 +22,7 @@ class Cmd(Base): # export
super().__init__(parent, name, help, aliases = aliases) super().__init__(parent, name, help, aliases = aliases)
@override @override
async def _run(self, args): async def _run(self, args: 'Namespace') -> None:
# Missing subcommand # Missing subcommand
self.print_help(1) self.print_help(1)

View file

@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, override
from .Cmd import Cmd, Parent from .Cmd import Cmd, Parent
if TYPE_CHECKING: if TYPE_CHECKING:
from argparse import ArgumentParser from argparse import ArgumentParser, Namespace
class CmdPkg(Cmd): # export class CmdPkg(Cmd): # export
@ -19,7 +19,7 @@ class CmdPkg(Cmd): # export
self.load_subcommands() self.load_subcommands()
@override @override
async def _run(self, args): async def _run(self, args: Namespace) -> None:
import sys import sys
# Missing subcommand # Missing subcommand

View file

@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, override
from .Cmd import Cmd, Parent from .Cmd import Cmd, Parent
if TYPE_CHECKING: if TYPE_CHECKING:
from argparse import ArgumentParser from argparse import ArgumentParser, Namespace
class CmdPlatform(Cmd): # export class CmdPlatform(Cmd): # export
@ -16,7 +16,7 @@ class CmdPlatform(Cmd): # export
self.load_subcommands() self.load_subcommands()
@override @override
async def _run(self, args): async def _run(self, args: Namespace) -> None:
import sys import sys
# Missing subcommand # Missing subcommand

View file

@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, override
from .Cmd import Cmd, Parent from .Cmd import Cmd, Parent
if TYPE_CHECKING: if TYPE_CHECKING:
from argparse import ArgumentParser from argparse import ArgumentParser, Namespace
class CmdPosix(Cmd): # export class CmdPosix(Cmd): # export
@ -21,7 +21,7 @@ class CmdPosix(Cmd): # export
self.load_subcommands() self.load_subcommands()
@override @override
async def _run(self, args): async def _run(self, args: Namespace) -> None:
import sys import sys
# Missing subcommand # Missing subcommand

View file

@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, override
from .Cmd import Cmd, Parent from .Cmd import Cmd, Parent
if TYPE_CHECKING: if TYPE_CHECKING:
from argparse import ArgumentParser from argparse import ArgumentParser, Namespace
class CmdProjects(Cmd): # export class CmdProjects(Cmd): # export
@ -18,7 +18,7 @@ class CmdProjects(Cmd): # export
self.load_subcommands() self.load_subcommands()
@override @override
async def _run(self, args): async def _run(self, args: Namespace) -> None:
import sys import sys
# Missing subcommand # Missing subcommand

View file

@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, override
from .Cmd import Cmd, Parent from .Cmd import Cmd, Parent
if TYPE_CHECKING: if TYPE_CHECKING:
from argparse import ArgumentParser from argparse import ArgumentParser, Namespace
class CmdSecrets(Cmd): # export class CmdSecrets(Cmd): # export
@ -14,7 +14,7 @@ class CmdSecrets(Cmd): # export
self.load_subcommands() self.load_subcommands()
@override @override
async def _run(self, args): async def _run(self, args: Namespace) -> None:
import sys import sys
# Missing subcommand # Missing subcommand

View file

@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, override
from .Cmd import Cmd, Parent from .Cmd import Cmd, Parent
if TYPE_CHECKING: if TYPE_CHECKING:
from argparse import ArgumentParser from argparse import ArgumentParser, Namespace
class CmdTar(Cmd): # export class CmdTar(Cmd): # export
@ -14,7 +14,7 @@ class CmdTar(Cmd): # export
self.load_subcommands() self.load_subcommands()
@override @override
async def _run(self, args): async def _run(self, args: Namespace) -> None:
import sys import sys
# Missing subcommand # Missing subcommand

View file

@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from typing import override, TYPE_CHECKING from typing import Any, override, TYPE_CHECKING
from ....CmdBase import CmdBase as Base from ....CmdBase import CmdBase as Base
from ....lib.FileContext import FileContext from ....lib.FileContext import FileContext
@ -20,7 +20,7 @@ class Cmd(Base): # export
self.__tar_io: None = None self.__tar_io: None = None
@asynccontextmanager @asynccontextmanager
async def ctx(self, **kwargs) -> AsyncIterator[TarIo]: async def ctx(self, **kwargs: Any) -> AsyncIterator[TarIo]:
async with TarIo.create(src = self.app.args.archive_path, **kwargs) as ret: async with TarIo.create(src = self.app.args.archive_path, **kwargs) as ret:
ret.src.add_proc_filter( ret.src.add_proc_filter(
FileContext.Direction.In, ProcFilterGpg(ec = self.app.exec_context) FileContext.Direction.In, ProcFilterGpg(ec = self.app.exec_context)

View file

@ -2,7 +2,7 @@ from __future__ import annotations
import re import re
from typing import TYPE_CHECKING, override from typing import TYPE_CHECKING, cast, override
from .Cmd import Cmd, Parent from .Cmd import Cmd, Parent
from .lib.pkg_relations import VersionSyntax from .lib.pkg_relations import VersionSyntax
@ -17,7 +17,7 @@ class BaseCmdPkgRelations(Cmd):
def pkg_relations(self, rel_type: str, args: Namespace) -> str: def pkg_relations(self, rel_type: str, args: Namespace) -> str:
return args.delimiter.join( return cast('str', args.delimiter).join(
pkg_relations_list( pkg_relations_list(
self.app, self.app,
rel_type = rel_type, rel_type = rel_type,

View file

@ -34,7 +34,7 @@ class CmdCanonicalizeRemotes(Cmd): # export
@override @override
async def _run(self, args: Namespace) -> None: async def _run(self, args: Namespace) -> None:
async def git(cmd: list[str], ro = False, throw = True) -> Result: async def git(cmd: list[str], ro: bool = False, throw: bool = True) -> Result:
cmd = ['/usr/bin/git', *cmd] cmd = ['/usr/bin/git', *cmd]
log(NOTICE, f'-- {" ".join(cmd)}') log(NOTICE, f'-- {" ".join(cmd)}')
if ro or not args.dry_run: if ro or not args.dry_run:

View file

@ -4,7 +4,7 @@ from .Cmd import Cmd, Parent
from typing import TYPE_CHECKING, override from typing import TYPE_CHECKING, override
if TYPE_CHECKING: if TYPE_CHECKING:
from argparse import ArgumentParser from argparse import ArgumentParser, Namespace
class CmdCheck(Cmd): # export class CmdCheck(Cmd): # export
@ -17,7 +17,7 @@ class CmdCheck(Cmd): # export
self.load_subcommands() self.load_subcommands()
@override @override
async def _run(self, args): async def _run(self, args: Namespace) -> None:
import sys import sys
# Missing subcommand # Missing subcommand

View file

@ -7,7 +7,7 @@ from .Cmd import Cmd, Parent
from .lib.pkg_relations import VersionSyntax, pkg_relations from .lib.pkg_relations import VersionSyntax, pkg_relations
from .lib.templates import ListDict, RenderValues, tmpl_render from .lib.templates import ListDict, RenderValues, tmpl_render
def key_value(s): def key_value(s: str) -> tuple[str, str]:
try: try:
key, value = s.split('=', 1) key, value = s.split('=', 1)
except ValueError: except ValueError:
@ -51,8 +51,8 @@ class CmdCreateFile(Cmd): # export
self, self,
template_name: str, template_name: str,
values: list[RenderValues], values: list[RenderValues],
li_quote = False, li_quote: bool = False,
li_delimiter = '\n', li_delimiter: str = '\n',
) -> str: ) -> str:
return tmpl_render( return tmpl_render(
template_name, template_name,

View file

@ -26,8 +26,8 @@ def pkg_relations(
ignore: set[str] = set(), ignore: set[str] = set(),
quote: bool = False, quote: bool = False,
skip_excluded: bool = False, skip_excluded: bool = False,
hide_self = False, hide_self: bool = False,
hide_jw_pkg = False, hide_jw_pkg: bool = False,
) -> list[str]: ) -> list[str]:
if subsections is None: if subsections is None:

View file

@ -1,5 +1,5 @@
import textwrap import textwrap
from typing import Iterable, TypeAlias, TypeGuard from typing import Any, Iterable, TypeAlias, TypeGuard
TupleList: TypeAlias = Iterable[tuple[str, str]] TupleList: TypeAlias = Iterable[tuple[str, str]]
ListDict: TypeAlias = dict[str, list[str]] ListDict: TypeAlias = dict[str, list[str]]
@ -73,7 +73,7 @@ def format_list_dict(
template: str, values: ListDict | dict[str, str], li_quote: bool, li_delimiter: str template: str, values: ListDict | dict[str, str], li_quote: bool, li_delimiter: str
) -> str: ) -> str:
def __format_value(val): def __format_value(val: Any) -> str:
if not li_quote: if not li_quote:
return str(val) return str(val)
return f'"{val}"' return f'"{val}"'
@ -144,9 +144,9 @@ _templates = {
def tmpl_render( def tmpl_render(
template_name: str, template_name: str,
values: list[RenderValues], values: list[RenderValues],
li_quote = False, li_quote: bool = False,
li_delimiter = '\n', li_delimiter: str = '\n',
search_path: list[str] = [] search_path: list[str] | None = None,
) -> str: ) -> str:
def __format(template: str) -> str: def __format(template: str) -> str:
@ -157,7 +157,7 @@ def tmpl_render(
li_delimiter = li_delimiter, li_delimiter = li_delimiter,
) )
for d in search_path: for d in search_path if search_path else []:
path = d + '/' + template_name path = d + '/' + template_name
try: try:
with open(path, 'r') as f: with open(path, 'r') as f:

View file

@ -23,7 +23,11 @@ class FilesContext:
def ctx(self) -> FileContext: def ctx(self) -> FileContext:
return self.__ctx return self.__ctx
async def _read_key_value_file(self, path: str, throw = False) -> dict[str, str]: async def _read_key_value_file(
self,
path: str,
throw: bool = False,
) -> dict[str, str]:
ret: dict[str, str] = {} ret: dict[str, str] = {}
try: try:
result = await self.ctx.get(path) result = await self.ctx.get(path)

View file

@ -6,7 +6,7 @@ import os
import sys import sys
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, Namespace from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, Namespace
from typing import override, TYPE_CHECKING, Any from typing import Any, cast, override, TYPE_CHECKING
from .AsyncRunner import AsyncRunner from .AsyncRunner import AsyncRunner
from .log import DEBUG, ERR, NOTICE, log, log_m, set_log_flags, set_log_level from .log import DEBUG, ERR, NOTICE, log, log_m, set_log_flags, set_log_level
@ -52,12 +52,15 @@ class App: # export
) -> None: ) -> None:
def add_cmd_to_parser(cmd: AbstractCmd, parsers: Any) -> ArgumentParser: def add_cmd_to_parser(cmd: AbstractCmd, parsers: Any) -> ArgumentParser:
parser = parsers.add_parser( parser = cast(
cmd.name, 'ArgumentParser',
help = cmd.help, parsers.add_parser(
description = cmd.description, cmd.name,
aliases = cmd.aliases, help = cmd.help,
formatter_class = ArgumentDefaultsHelpFormatter, description = cmd.description,
aliases = cmd.aliases,
formatter_class = ArgumentDefaultsHelpFormatter,
)
) )
parser.set_defaults(func = cmd.run) parser.set_defaults(func = cmd.run)
cmd.add_arguments(parser) cmd.add_arguments(parser)
@ -68,7 +71,7 @@ class App: # export
parent: AbstractCmd | App, parent: AbstractCmd | App,
parser: ArgumentParser, parser: ArgumentParser,
cmds: Collection[AbstractCmd], cmds: Collection[AbstractCmd],
all = False all: bool = False
) -> None: ) -> None:
if not cmds: if not cmds:
return return
@ -168,7 +171,7 @@ class App: # export
'-h', '--help', action = 'help', help = 'Show this help message and exit' '-h', '--help', action = 'help', help = 'Show this help message and exit'
) )
def __del__(self): def __del__(self) -> None:
if self.__own_eloop: if self.__own_eloop:
if self.__eloop is not None: if self.__eloop is not None:
self.__eloop.close() self.__eloop.close()
@ -178,10 +181,10 @@ class App: # export
async def __aenter__(self) -> None: async def __aenter__(self) -> None:
pass pass
async def __aexit__(self, exc_type, exc, tb) -> None: async def __aexit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
pass pass
async def __run(self, argv = None) -> None: async def __run(self, argv: list[str] | None = None) -> None:
try: try:
# Import argcomplete only here to not require it to be compatible # Import argcomplete only here to not require it to be compatible
@ -194,8 +197,8 @@ class App: # export
@override @override
def __call__( # pyright: ignore[reportGeneralTypeIssues] def __call__( # pyright: ignore[reportGeneralTypeIssues]
self, *args, **kwargs self, *args: Any, **kwargs: Any
): ) -> None:
return None return None
import argcomplete # type: ignore[import-not-found, unused-ignore] import argcomplete # type: ignore[import-not-found, unused-ignore]
@ -249,7 +252,7 @@ class App: # export
self.__parser.print_help() self.__parser.print_help()
return None return None
# Run sub-command. Overwrite if you want to do anything before or after # Run sub-command. Overwrite if you want to do anything before or after
return await self.args.func(args) return cast('None | int', await self.args.func(args))
def call_async(self, awaitable: Awaitable[T], timeout: float | None = None) -> T: def call_async(self, awaitable: Awaitable[T], timeout: float | None = None) -> T:
return self.async_runner.call(awaitable, timeout) return self.async_runner.call(awaitable, timeout)
@ -286,7 +289,7 @@ class App: # export
def parser(self) -> ArgumentParser: def parser(self) -> ArgumentParser:
return self.__parser return self.__parser
def run(self, argv = None) -> None: def run(self, argv: list[str] | None = None) -> None:
try: try:
ret = self.eloop.run_until_complete(self.__run(argv)) ret = self.eloop.run_until_complete(self.__run(argv))
finally: finally:
@ -296,7 +299,10 @@ class App: # export
return ret return ret
def run_sub_commands( # export def run_sub_commands( # export
description = '', name_filter = '^Cmd.*', modules = None, argv = None description: str = '',
): name_filter: str = '^Cmd.*',
modules: list[str] | None = None,
argv: list[str] | None = None,
) -> None:
app = App(description, name_filter, modules) app = App(description, name_filter, modules)
return app.run(argv = argv) app.run(argv = argv)

View file

@ -4,7 +4,7 @@ import asyncio
import concurrent.futures import concurrent.futures
import contextlib import contextlib
from typing import TypeVar, TYPE_CHECKING from typing import Any, TypeVar, TYPE_CHECKING, cast
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import Awaitable, Generator from collections.abc import Awaitable, Generator
@ -48,7 +48,7 @@ class AsyncRunner:
awaitable, # type: ignore[arg-type, var-annotated] awaitable, # type: ignore[arg-type, var-annotated]
self._loop, self._loop,
) )
return fut.result(timeout) return cast('T', fut.result(timeout))
def close(self) -> None: def close(self) -> None:
self._cm.__exit__(None, None, None) self._cm.__exit__(None, None, None)
@ -56,5 +56,5 @@ class AsyncRunner:
def __enter__(self) -> AsyncRunner: def __enter__(self) -> AsyncRunner:
return self return self
def __exit__(self, exc_type, exc, tb) -> None: def __exit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
self.close() self.close()

View file

@ -9,7 +9,7 @@ from .log import ERR
from .Types import LoadTypes, Types from .Types import LoadTypes, Types
if TYPE_CHECKING: if TYPE_CHECKING:
from argparse import ArgumentParser from argparse import ArgumentParser, Namespace
from typing import Iterable from typing import Iterable
from .App import App from .App import App
@ -26,7 +26,7 @@ class AbstractCmd(abc.ABC):
self.__child_classes: list[type[Cmd]] = [] self.__child_classes: list[type[Cmd]] = []
self.__parser: ArgumentParser | None = None self.__parser: ArgumentParser | None = None
def set_parent(self, parent: Any | Cmd): def set_parent(self, parent: Any | Cmd) -> None:
self.__parent = parent self.__parent = parent
@property @property
@ -76,7 +76,7 @@ class AbstractCmd(abc.ABC):
return self.__parser return self.__parser
# Don't use a setter decorator to force using a grepable method # Don't use a setter decorator to force using a grepable method
def set_parser(self, parser: ArgumentParser): def set_parser(self, parser: ArgumentParser) -> None:
self.__parser = parser self.__parser = parser
def print_help(self, exit_status: int | None = None) -> None: def print_help(self, exit_status: int | None = None) -> None:
@ -129,11 +129,11 @@ class AbstractCmd(abc.ABC):
pass pass
@abc.abstractmethod @abc.abstractmethod
async def _run(self, args) -> None: async def _run(self, args: Namespace) -> None:
if isinstance(self.__parent, Cmd): # Calling App.run() would loop if isinstance(self.__parent, Cmd): # Calling App.run() would loop
return await self.__parent._run(args) return await self.__parent._run(args)
async def run(self, args): async def run(self, args: Namespace) -> None:
return await self._run(args) return await self._run(args)
@abc.abstractmethod @abc.abstractmethod

View file

@ -1,4 +1,4 @@
from typing import Self from typing import Any, Self
from .FileContext import FileContext from .FileContext import FileContext
from .Uri import Uri from .Uri import Uri
@ -9,7 +9,7 @@ class CopyContext:
self, self,
src: Uri | str | FileContext, src: Uri | str | FileContext,
dst: Uri | str | FileContext, dst: Uri | str | FileContext,
chroot = False chroot: bool = False,
) -> None: ) -> None:
def __uri(ctx: FileContext | Uri | str) -> Uri | str: def __uri(ctx: FileContext | Uri | str) -> Uri | str:
@ -43,7 +43,7 @@ class CopyContext:
await self.__dst.open() await self.__dst.open()
return self return self
async def __aexit__(self, exc_type, exc, tb): async def __aexit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
if self.__src is not None: if self.__src is not None:
await self.__src.close() await self.__src.close()
self.__src = None self.__src = None

Some files were not shown because too many files have changed in this diff Show more