App, lib, cmds: Fix mypy.explicit-override fallout
This commit adds @override decorators to approximately 300 methods across 76 files that inherit from base classes such as AbstractCmd, FileContext, ExecContext, Distro, SSHClient, and others. The decorator ensures the type checker can verify that overridden methods have compatible signatures and prevents accidental shadowing of inherited methods without intent. Files modified include command classes, library modules, distro implementations, and SSH client implementations. Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL with pi.dev v Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
parent
30a00df5c7
commit
5fa008be5a
78 changed files with 263 additions and 81 deletions
|
|
@ -6,7 +6,7 @@ import os
|
|||
import sys
|
||||
|
||||
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, Namespace
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from typing import override, TYPE_CHECKING, Any
|
||||
|
||||
from .AsyncRunner import AsyncRunner
|
||||
from .log import DEBUG, ERR, NOTICE, log, log_m, set_log_flags, set_log_level
|
||||
|
|
@ -192,6 +192,7 @@ class App: # export
|
|||
|
||||
class NoopCompleter(BaseCompleter):
|
||||
|
||||
@override
|
||||
def __call__(self, *args, **kwargs):
|
||||
return None
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
import abc
|
||||
import sys
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from .log import ERR
|
||||
from .Types import LoadTypes, Types
|
||||
|
|
@ -173,14 +173,18 @@ class Cmd(AbstractCmd): # export
|
|||
self.__description = description if description else help
|
||||
self.__aliases = aliases if aliases else []
|
||||
|
||||
@override
|
||||
def _name(self) -> str:
|
||||
return self.__name
|
||||
|
||||
@override
|
||||
def _help(self) -> str:
|
||||
return self.__help
|
||||
|
||||
@override
|
||||
def _description(self) -> str:
|
||||
return self.__description
|
||||
|
||||
@override
|
||||
def _aliases(self) -> Iterable[str]:
|
||||
return self.__aliases
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import errno
|
|||
import sys
|
||||
|
||||
from decimal import ROUND_FLOOR, Decimal
|
||||
from typing import TYPE_CHECKING, NamedTuple
|
||||
from typing import override, TYPE_CHECKING, NamedTuple
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Type
|
||||
|
|
@ -250,6 +250,7 @@ class ExecContext(Base):
|
|||
super().__init__(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
@override
|
||||
def create(cls, *args, **kwargs) -> ExecContext:
|
||||
ret = super().create(*args, **kwargs)
|
||||
if not isinstance(ret, cls):
|
||||
|
|
@ -451,6 +452,7 @@ class ExecContext(Base):
|
|||
cc.check_exit_code(ret)
|
||||
return ret
|
||||
|
||||
@override
|
||||
async def _get(
|
||||
self, path: str, wd: str | None, throw: bool, verbose: bool | None, title: str
|
||||
) -> Result:
|
||||
|
|
@ -485,6 +487,7 @@ class ExecContext(Base):
|
|||
cc.check_exit_code(ret)
|
||||
return ret
|
||||
|
||||
@override
|
||||
async def _put(
|
||||
self,
|
||||
path: str,
|
||||
|
|
@ -565,22 +568,27 @@ class ExecContext(Base):
|
|||
log(ERR, msg)
|
||||
return ret
|
||||
|
||||
@override
|
||||
async def _unlink(self, path: str) -> None:
|
||||
cmd = ['rm', '-f', path]
|
||||
await self.run(cmd, cmd_input = InputMode.NonInteractive)
|
||||
|
||||
@override
|
||||
async def _erase(self, path: str) -> None:
|
||||
cmd = ['rm', '-rf', path]
|
||||
await self.run(cmd, cmd_input = InputMode.NonInteractive)
|
||||
|
||||
@override
|
||||
async def _rename(self, src: str, dst: str) -> None:
|
||||
cmd = ['mv', src, dst]
|
||||
await self.run(cmd, cmd_input = InputMode.NonInteractive)
|
||||
|
||||
@override
|
||||
async def _mkdir(self, path: str, mode: int) -> None:
|
||||
cmd = ['mkdir', path, '-m', self.__mode_str(mode)]
|
||||
await self.run(cmd, cmd_input = InputMode.NonInteractive)
|
||||
|
||||
@override
|
||||
async def _mktemp(self, tmpl: str, directory: bool) -> str:
|
||||
cmd = ['mktemp']
|
||||
if directory:
|
||||
|
|
@ -593,6 +601,7 @@ class ExecContext(Base):
|
|||
)
|
||||
return result.stdout_str.strip()
|
||||
|
||||
@override
|
||||
async def _stat(self, path: str, follow_symlinks: bool) -> StatResult:
|
||||
|
||||
async def __stat(opts: list[str]) -> Result:
|
||||
|
|
@ -662,6 +671,7 @@ class ExecContext(Base):
|
|||
assert stdout is not None # Just there to pacify the linter
|
||||
return _build_stat_result(stdout.rstrip('\n').split(_US), mode_base = 8)
|
||||
|
||||
@override
|
||||
async def _chown(self, path: str, owner: str | None, group: str | None) -> None:
|
||||
if owner is None and group is None:
|
||||
raise ValueError(f'Tried to chown("{path}") without owner and group')
|
||||
|
|
@ -674,6 +684,7 @@ class ExecContext(Base):
|
|||
assert ownership is not None # Impossible, just there to calm the linter
|
||||
await self.run(['chown', ownership, path], cmd_input = InputMode.NonInteractive)
|
||||
|
||||
@override
|
||||
async def _chmod(self, path: str, mode: int) -> None:
|
||||
await self.run(
|
||||
['chmod', self.__mode_str(mode), path],
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import abc
|
|||
|
||||
from enum import Enum, auto
|
||||
from functools import cached_property
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import override, TYPE_CHECKING
|
||||
|
||||
from .log import DEBUG, ERR, log
|
||||
from .Uri import Uri
|
||||
|
|
@ -50,6 +50,7 @@ class FileContext(abc.ABC):
|
|||
async def __aexit__(self, exc_type, exc, tb):
|
||||
await self.close()
|
||||
|
||||
@override
|
||||
def __repr__(self) -> str:
|
||||
return self.__uri.id
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Any
|
||||
from typing import override, Any
|
||||
|
||||
meta_tags = [
|
||||
'name',
|
||||
|
|
@ -56,6 +56,7 @@ class Package:
|
|||
self.url = url
|
||||
self.maintainer = maintainer
|
||||
|
||||
@override
|
||||
def __repr__(self) -> str:
|
||||
global meta_tags
|
||||
return '\n'.join([f'{key:<15}: {getattr(self, key)}' for key in meta_tags])
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
import abc
|
||||
import re
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .Package import Package
|
||||
|
|
@ -25,6 +25,7 @@ class PackageFilterString(PackageFilter):
|
|||
raise Exception(f'Unsupported filter string "{definition}"')
|
||||
self.__definition = url_rx_str
|
||||
|
||||
@override
|
||||
def _match(self, package: Package) -> bool:
|
||||
url = package.url
|
||||
if url is None:
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import abc
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from .base import Result
|
||||
|
||||
|
|
@ -20,6 +20,7 @@ class ProcFilter(abc.ABC):
|
|||
|
||||
class ProcFilterIdentity(ProcFilter):
|
||||
|
||||
@override
|
||||
async def _run(self, data: bytes | None) -> Result:
|
||||
return Result(data, None, 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from .ProcFilter import ProcFilter
|
||||
|
||||
|
|
@ -13,6 +13,7 @@ class ProcFilterGpg(ProcFilter):
|
|||
def __init__(self, ec: ExecContext) -> None:
|
||||
self.__ec = ec
|
||||
|
||||
@override
|
||||
async def _run(self, data: bytes | None) -> Result:
|
||||
if data is None:
|
||||
raise Exception('No data for GPG to decrypt')
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import override
|
||||
|
||||
class Result:
|
||||
|
||||
def __init__(
|
||||
|
|
@ -113,6 +115,7 @@ class Result:
|
|||
|
||||
return ret
|
||||
|
||||
@override
|
||||
def __repr__(self) -> str:
|
||||
return self.__summarize(verbose = False)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from tarfile import TarFile, TarInfo
|
|||
from .CopyContext import CopyContext
|
||||
from .ExecContext import ExecContext
|
||||
from .log import DEBUG, ERR, log
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .base import StatResult
|
||||
|
|
@ -89,6 +89,7 @@ class TarIo(CopyContext):
|
|||
|
||||
class TarIoTarFile(TarIo):
|
||||
|
||||
@override
|
||||
async def _extract(self, blob: bytes, root: str | None = None) -> None:
|
||||
tf = TarFile(fileobj = io.BytesIO(blob))
|
||||
for info in tf.getmembers():
|
||||
|
|
@ -111,7 +112,16 @@ class TarIoTarFile(TarIo):
|
|||
|
||||
class TarIoTarExec(TarIo):
|
||||
|
||||
@override
|
||||
async def _extract(self, blob: bytes, root: str | None = None) -> None:
|
||||
cmd = ['tar']
|
||||
if root is not None:
|
||||
cmd += ['-C', root]
|
||||
cmd += ['-x', '-f', '-']
|
||||
await self.dst.run(cmd, cmd_input = blob)
|
||||
|
||||
@property
|
||||
@override
|
||||
def dst(self) -> ExecContext:
|
||||
ret = super().dst
|
||||
if not isinstance(ret, ExecContext):
|
||||
|
|
@ -120,10 +130,3 @@ class TarIoTarExec(TarIo):
|
|||
'context, which only has a file context'
|
||||
)
|
||||
return ret
|
||||
|
||||
async def _extract(self, blob: bytes, root: str | None = None) -> None:
|
||||
cmd = ['tar']
|
||||
if root is not None:
|
||||
cmd += ['-C', root]
|
||||
cmd += ['-x', '-f', '-']
|
||||
await self.dst.run(cmd, cmd_input = blob)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import os
|
|||
import re
|
||||
import sys
|
||||
|
||||
from typing import TYPE_CHECKING, Generic, Iterable, TypeVar
|
||||
from typing import override, TYPE_CHECKING, Generic, Iterable, TypeVar
|
||||
|
||||
from .log import ERR, OFF, log, parse_log_level
|
||||
|
||||
|
|
@ -17,6 +17,7 @@ T = TypeVar('T')
|
|||
|
||||
class Types(abc.ABC, Iterable[type[T]], Generic[T]): # export
|
||||
|
||||
@override
|
||||
def __iter__(self) -> Iterator[type[T]]:
|
||||
return iter(self._classes())
|
||||
|
||||
|
|
@ -64,6 +65,7 @@ class LoadTypes(Types[T]): # export
|
|||
if self.__debug_level != OFF:
|
||||
log(self.__debug_level, *args, **kwargs)
|
||||
|
||||
@override
|
||||
def _stringify(self):
|
||||
tf = 'None' if self.__type_filter is None else (
|
||||
', '.join([str(f) for f in self.__type_filter])
|
||||
|
|
@ -74,6 +76,7 @@ class LoadTypes(Types[T]): # export
|
|||
'mod_names: ' + ', '.join(self.__mod_names),
|
||||
]
|
||||
|
||||
@override
|
||||
def _classes(self) -> Iterable[type[T]]:
|
||||
|
||||
if self.__classes is None:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
import copy
|
||||
|
||||
from functools import cached_property
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import override, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import urllib.parse
|
||||
|
|
@ -39,9 +39,11 @@ class Uri:
|
|||
self.__username: str | None = None
|
||||
self.__password: str | None = None
|
||||
|
||||
@override
|
||||
def __repr__(self) -> str:
|
||||
return self.full
|
||||
|
||||
@override
|
||||
def __str__(self) -> str:
|
||||
return self.safe_full_with_username
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import override, TYPE_CHECKING
|
||||
|
||||
from ...Distro import Distro as Base
|
||||
|
||||
|
|
@ -26,27 +26,32 @@ class Distro(Base):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@override
|
||||
async def _ref(self) -> None:
|
||||
raise NotImplementedError(
|
||||
'distro refresh is not yet implemented for Arch-like distributions'
|
||||
)
|
||||
|
||||
@override
|
||||
async def _dup(self, download_only: bool) -> None:
|
||||
args = ['-Su']
|
||||
if download_only:
|
||||
args.append('-w')
|
||||
await self.pacman(args)
|
||||
|
||||
@override
|
||||
async def _reboot_required(self, verbose: bool) -> bool:
|
||||
raise NotImplementedError(
|
||||
'distro reboot-required is not yet implemented for Arch-like distributions'
|
||||
)
|
||||
|
||||
@override
|
||||
async def _select_by_name(self, names: Iterable[str]) -> Iterable[Package]:
|
||||
raise NotImplementedError(
|
||||
'distro select is not yet implemented for Arch-like distributions'
|
||||
)
|
||||
|
||||
@override
|
||||
async def _install(self, names: Iterable[str], only_update: bool) -> None:
|
||||
if only_update:
|
||||
raise NotImplementedError('--only-update is not yet implemented for pacman')
|
||||
|
|
@ -54,11 +59,13 @@ class Distro(Base):
|
|||
args.extend(names)
|
||||
await self.pacman(args)
|
||||
|
||||
@override
|
||||
async def _delete(self, names: Iterable[str]) -> None:
|
||||
raise NotImplementedError(
|
||||
'distro delete not yet implemented for Arch-like distributions'
|
||||
)
|
||||
|
||||
@override
|
||||
async def _pkg_files(self, name: str) -> Iterable[str]:
|
||||
raise NotImplementedError(
|
||||
'distro pkg ls yet implemented for Arch-like distributions'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import os
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import override, TYPE_CHECKING
|
||||
|
||||
from ...Distro import Distro as Base
|
||||
from ...log import NOTICE, log
|
||||
|
|
@ -38,9 +38,11 @@ class Distro(Base):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@override
|
||||
async def _ref(self) -> None:
|
||||
await self.apt_get(['update'])
|
||||
|
||||
@override
|
||||
async def _dup(self, download_only: bool) -> None:
|
||||
args: list[str] = []
|
||||
if download_only:
|
||||
|
|
@ -48,6 +50,7 @@ class Distro(Base):
|
|||
args.append('upgrade')
|
||||
await self.apt_get(args)
|
||||
|
||||
@override
|
||||
async def _reboot_required(self, verbose: bool) -> bool:
|
||||
reboot_required = '/run/reboot_required'
|
||||
if os.path.exists(reboot_required):
|
||||
|
|
@ -64,9 +67,11 @@ class Distro(Base):
|
|||
log(NOTICE, f"No. {reboot_required} doesn't exist.")
|
||||
return False
|
||||
|
||||
@override
|
||||
async def _select_by_name(self, names: Iterable[str]) -> Iterable[Package]:
|
||||
return await query_packages(names, ec = self.ctx)
|
||||
|
||||
@override
|
||||
async def _install(self, names: Iterable[str], only_update: bool) -> None:
|
||||
args = ['install']
|
||||
if only_update:
|
||||
|
|
@ -75,8 +80,10 @@ class Distro(Base):
|
|||
args.extend(names)
|
||||
await self.apt_get(args)
|
||||
|
||||
@override
|
||||
async def _delete(self, names: Iterable[str]) -> None:
|
||||
await self.dpkg(['-P', *names], sudo = True)
|
||||
|
||||
@override
|
||||
async def _pkg_files(self, name: str) -> Iterable[str]:
|
||||
return await list_files(name, ec = self.ctx)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import override, TYPE_CHECKING
|
||||
|
||||
from ...Distro import Distro as Base
|
||||
from ...pm.rpm import list_files, query_packages, run_rpm
|
||||
|
|
@ -43,9 +43,11 @@ class Distro(Base):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@override
|
||||
async def _ref(self) -> None:
|
||||
await self.zypper(['refresh'])
|
||||
|
||||
@override
|
||||
async def _dup(self, download_only: bool) -> None:
|
||||
args = ['dup']
|
||||
if download_only:
|
||||
|
|
@ -53,6 +55,7 @@ class Distro(Base):
|
|||
args += self.__update_extra_opts
|
||||
await self.zypper(args)
|
||||
|
||||
@override
|
||||
async def _reboot_required(self, verbose: bool) -> bool:
|
||||
opts = []
|
||||
if not verbose:
|
||||
|
|
@ -64,22 +67,27 @@ class Distro(Base):
|
|||
return True
|
||||
return False
|
||||
|
||||
@override
|
||||
async def _select_by_name(self, names: Iterable[str]) -> Iterable[Package]:
|
||||
return await query_packages(names, ec = self.ctx)
|
||||
|
||||
@override
|
||||
async def _install(self, names: Iterable[str], only_update: bool) -> None:
|
||||
cmd = ['update' if only_update else 'install']
|
||||
cmd += self.__update_extra_opts
|
||||
cmd += names
|
||||
await self.zypper(cmd)
|
||||
|
||||
@override
|
||||
async def _install_local_files(
|
||||
self, paths: Iterable[str], only_update: bool
|
||||
) -> None:
|
||||
await self.rpm(['-U', '--reinstall', *paths])
|
||||
|
||||
@override
|
||||
async def _delete(self, names: Iterable[str]) -> None:
|
||||
await self.rpm(['-e', *names], sudo = True)
|
||||
|
||||
@override
|
||||
async def _pkg_files(self, name: str) -> Iterable[str]:
|
||||
return await list_files(name, ec = self.ctx)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import override, TYPE_CHECKING
|
||||
|
||||
from ..FileContext import FileContext as Base
|
||||
|
||||
|
|
@ -28,6 +28,7 @@ class Curl(Base):
|
|||
|
||||
self.__ec = ec if ec else __local()
|
||||
|
||||
@override
|
||||
async def _get(
|
||||
self, path: str, wd: str | None, throw: bool, verbose: bool | None, title: str
|
||||
) -> Result:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import pwd
|
|||
import sys
|
||||
|
||||
from functools import cache
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import override, TYPE_CHECKING
|
||||
|
||||
from ..base import Result, StatResult
|
||||
from ..ExecContext import ExecContext as Base
|
||||
|
|
@ -25,6 +25,7 @@ class Local(Base):
|
|||
def _username(self) -> str:
|
||||
return pwd.getpwuid(os.getuid()).pw_name
|
||||
|
||||
@override
|
||||
async def _run(
|
||||
self,
|
||||
cmd: list[str],
|
||||
|
|
@ -155,9 +156,11 @@ class Local(Base):
|
|||
if cwd is not None:
|
||||
os.chdir(cwd)
|
||||
|
||||
@override
|
||||
async def _unlink(self, path: str) -> None:
|
||||
os.unlink(path)
|
||||
|
||||
@override
|
||||
async def _erase(self, path: str) -> None:
|
||||
if os.path.isdir(path):
|
||||
import shutil
|
||||
|
|
@ -165,26 +168,33 @@ class Local(Base):
|
|||
return
|
||||
os.unlink(path)
|
||||
|
||||
@override
|
||||
async def _rename(self, src: str, dst: str) -> None:
|
||||
os.rename(src, dst)
|
||||
|
||||
@override
|
||||
async def _mkdir(self, path: str, mode: int) -> None:
|
||||
os.mkdir(path, mode)
|
||||
|
||||
@override
|
||||
async def _stat(self, path: str, follow_symlinks: bool) -> StatResult:
|
||||
return StatResult.from_os(os.stat(path, follow_symlinks = follow_symlinks))
|
||||
|
||||
@override
|
||||
async def _file_exists(self, path: str) -> bool:
|
||||
return os.path.exists(path)
|
||||
|
||||
@override
|
||||
async def _chown(self, path: str, owner: str | None, group: str | None) -> None:
|
||||
uid = pwd.getpwnam(owner).pw_uid if owner else -1
|
||||
gid = grp.getgrnam(group).gr_gid if group else -1
|
||||
os.chown(path, uid, gid)
|
||||
|
||||
@override
|
||||
async def _chmod(self, path: str, mode: int) -> None:
|
||||
os.chmod(path, mode)
|
||||
|
||||
@override
|
||||
async def _is_dir(self, path: str, follow_symlinks: bool) -> bool:
|
||||
if (not follow_symlinks) and os.path.islink(path):
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import os
|
|||
import pwd
|
||||
|
||||
from enum import Flag, auto
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from ..ExecContext import ExecContext
|
||||
from ..log import DEBUG, ERR, INFO, NOTICE, get_caller_pos, log, log_m
|
||||
|
|
@ -42,6 +42,7 @@ class SSHClient(ExecContext):
|
|||
) -> Result:
|
||||
pass
|
||||
|
||||
@override
|
||||
async def _run(
|
||||
self,
|
||||
cmd: list[str],
|
||||
|
|
@ -102,6 +103,7 @@ class SSHClient(ExecContext):
|
|||
return self.uri.port
|
||||
|
||||
@property
|
||||
@override
|
||||
def username(self) -> str | None:
|
||||
return self.uri.username
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from typing import override
|
||||
import asyncio
|
||||
import os
|
||||
import shlex
|
||||
|
|
@ -42,10 +43,12 @@ class AsyncSSH(Base):
|
|||
self.__connect_timeout = connect_timeout
|
||||
self.__conn: asyncssh.SSHClientConnection | None = None
|
||||
|
||||
@override
|
||||
async def _open(self) -> None:
|
||||
await super()._open()
|
||||
await self._conn
|
||||
|
||||
@override
|
||||
async def _close(self) -> None:
|
||||
if self.__conn is not None:
|
||||
try:
|
||||
|
|
@ -355,6 +358,7 @@ class AsyncSSH(Base):
|
|||
stdout = b''.join(stdout_parts) if stdout_parts else None
|
||||
return Result(stdout, None, exit_code, cmd = cmd)
|
||||
|
||||
@override
|
||||
async def _run_ssh(
|
||||
self,
|
||||
cmd: list[str],
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import os
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import override, TYPE_CHECKING
|
||||
|
||||
from ...base import InputMode
|
||||
from ...util import run_cmd
|
||||
|
|
@ -48,6 +48,7 @@ class Exec(Base):
|
|||
self.__askpass_orig[key] = os.getenv(key)
|
||||
os.environ[key] = val
|
||||
|
||||
@override
|
||||
async def _run_ssh(
|
||||
self,
|
||||
cmd: list[str],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import override, TYPE_CHECKING
|
||||
|
||||
# Tolerate missing paramiko imports. jw-pkg is designed to work with what it
|
||||
# finds.
|
||||
|
|
@ -52,15 +52,18 @@ class Paramiko(Base):
|
|||
def __scp(self) -> Any:
|
||||
return paramiko.SCPClient(self.__client.get_transport())
|
||||
|
||||
@override
|
||||
async def _open(self) -> None:
|
||||
await super()._open()
|
||||
self.__client
|
||||
|
||||
@override
|
||||
async def _close(self) -> None:
|
||||
if self.___client is not None:
|
||||
self.___client.close()
|
||||
self.___client = None
|
||||
|
||||
@override
|
||||
async def _run_ssh(
|
||||
self,
|
||||
cmd: list[str],
|
||||
|
|
|
|||
Loading…
Reference in a new issue