Commit graph jw-pkg/src/python/jw/pkg/lib/ec/SSHClient.py
Author SHA1 Message Date
1e613a39c6 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>
2026-08-09 12:07:37 +00:00
5fa008be5a
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>
2026-08-07 18:02:26 +02:00
dcbe959843
lib: Fix misplaced "# export" markers
A couple of "# export" markers after function prototypes have been
pushed along with the closing parenthesis onto the wrong line by the
code formatter, fix that.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-07-24 13:30:17 +02:00
1e0dee5908
lib: More result log beautification
This commit adds more tweaks to shell command output in order to make
it nicer. The biggest patch is in Result.__summarize(), which makes
it more versatile, and allows removal of some code in SSHClient.

App sees some independent, minor result format beautification.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-06-24 21:23:22 +02:00
5d1ba6e15a
pyproject.toml: Enforce import annotations style
Add new ruff rules and fix their fallout:

  future-annotations = true

   select = [
    "TC",  # type-checking import placement rules
    "FA",  # future annotations rules
   ]

This comprises:

  - Streamline imports and exports in cmds.xxx.Cmd

    - Import base class as "Base"

    - Export types Cmd and Parent via __all__

  - Move all types imported only for annotation below TYPE_CHECKING

  - Use "from __future__ import annotations" all over the place

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-06-01 14:34:25 +02:00
6db73873e7
jw.pkg: Fix "make check" static code check fallout
The previous commits have put rules for linting and formatting via
ruff, yapf, mypy and pyright into place. They are checked with the
make check target, and this commit adds the fixes for the target to
succeed.

It does some refactoring where type checking dug up dirty bits, and
also adds lots of churn in the Python code. To a good deal, that's
owed to mere formatting changes. It would have been better to
seperate those from syntax and refactoring fixes into multiple
commits, so that the interesting changes don't drown in the
formatting nose. However, that would have been a lot of additional
work only to be thrown away by later commits, hence this commit has a
big diff in one piece. The size of the diff is regrettable but
hopefully a one-off: What it buys is automatic format checking for CI
and predictble formats for smaller diffs in the future.

Rules that "make check" enforces are, in the following order

   - Syntax checkers:

      - ruff check .
      - mypy .
      - pyright

   - Format check:

     - yapf --diff --recursive .

The refactoring includes:

  - Turn the Result class into a more elaborate object, capable of
    doing more heavy lifting around stderr and stdout decoding,
    summarizing outcome, and matching error strings.

    Aside from fixing broken type checks, this also removes lots of
    boilerplate calling code which is currently used for handling
    possible call outcome scenarios. Trying to access an inexistent,
    decoded string should raise a meaningful exception by itself now,
    which removes lots of code with case distinctions.

  - Fix Cmd type hierarchy:

    - Add the AbstractCmd class above Cmd. This is necessary because
      the checker rightfully complains it can't instantiate a Cmd
      instance where constructor arguments were needed. They never
      were, but the type used at the instantiating code's location in
      jw.pkg.App so claims.

    - Lots of sub- and sub-subcommands are derived from the base
      class of the invoking command. That provides some properties
      shared across the ancestor hierarchy of a command, but is
      semantically unsound. Fix that by introducing jw.pkg.BaseCmd
      class as a place to provide basic helpers shared across all
      commands used in a jw.pkg.App's context, and derive all command
      classes from that afresh. The parent command is still reachable
      via a common parent property.

Formatting changes are conforming to PEP-8, mostly, with minor
tweaks. All in all they include the following changes.

  - Remove # -*- coding: utf-8 -*-

    The line was needed by Python 2 which is not supported anylonger.
    For Python 3, the default encoding is UTF-8, anyway.

  - Allow to run "make py-format" without having it produce any
    changes. It's basically "yapf --in-place --recursive ." with some
    code style settings, see conf/topdir/pyproject.toml. The settings
    may be debatable. I've had custom tweaks in place on that target,
    too, but then again, IDEs would have more hassle to integrate
    that.

  - Introduce a 88 character line length limit

  - One import per line, reshuffle them semantically, see
    [tool.isort] in pyproject.toml.

  - Hide imports needed for type-checking only behind

      if TYPE_CHECKING

  - Spaces around assignments accounts for much churn. Having having
    no spaces in inline parameter list assignments and default
    parameter values would arguably be more compact where it's
    useful. On the other hand, I have not found a code formatter
    which allows spaces around assignments in parameter lists broken
    into one per line and that's often better than a wall of text.

  - Add two spaces before # export, as this seems to be mandated by
    PEP-8

  - Use single quotes by default

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-05-31 18:20:38 +02:00
d9746cd20b
lib + cmds.projects: Use lib.Uri
Remove the feeble attempts at unifying URI handling, and use class
Uri from lib.Uri instead.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-04-28 13:00:29 +02:00
54aecff8e4 lib.ExecContext.run(), .sudo(): Rename env
The name of the env parameter to ExecContext.run() and .sudo() is not
descriptive enough for which environment is supposed to be modified
and how, so rename and split it up as follows:

  - .run(): env -> mod_env

  - .sudo(): env -> mod_env_sudo and mod_env_cmd

The parameters have the following meaning:

  - "mod_env*" means that the environment is modified, not replaced

  - "mod_env" and "mod_env_cmd" modify the environment "cmd" runs in

  - "mod_env_sudo" modifies the environment sudo runs in

Fix the fallout of the API change all over jw-pkg.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-04-19 14:36:50 +02:00
9f756222fe lib.ExecContext.username: Add property
Add the property .username, backed by the protected _username()
callback. It should return the user run()'s cmd parameter is executed
as.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-04-19 14:36:50 +02:00
5ea6ab0383 lib.ec.SSHClient._run(): Fix empty stderr output logging
If stderr is None, a bogus Exception is thrown in verbose mode, fix
that.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-04-19 14:36:50 +02:00
2f1265b7b2 lib.ec.SSHClient: Fix return value type hints
Add proper type-hinting for port, hostname, username and password
return values.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-04-18 10:43:31 +02:00
fd336ecdcf lib.ec.SSHClient: Support JW_DEFAULT_SSH_CLIENT
Allow to configure via the environment which class ssh_client()
picks. Can currently be exec, asyncssh, paramiko or a comma-separated
search list. The list will be tried through until a class is found
that can be instantiated.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-04-18 10:42:32 +02:00
888c0495ec lib.base: Add module
Add lib.base to provide basic definitions.

For now, move the definiions of Result, Input and InputMode from
ExecContext into lib.base. Having to import them from the ExecContect
module is too heavy-handed for those simple types.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-04-16 12:57:04 +02:00
04b294917f lib.ExecContext: Support bytes-typed cmd_input
The Input instance passed as cmd_input to ExecContext.run() and
.sudo() currently may be of type str. Allow to pass bytes, too.

At the same time, disallow None to be passed as cmd_input. Force the
caller to be more explicit how it wants input to be handled, notably
with respect to interactivity.

Along the way fix a bug: Content in cmd_input should result in
CallContext.interactive == False but doesn't. Fix that.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-04-16 10:21:25 +02:00
a58220a131 lib.ec.SSHClient.ssh_client(): Add type parameter
ssh_client() tries a predefined order of client class implementations
until it finds a workable candidate. For testing all, it's desirable
to be able to target the exact class. Add a "type" parameter to
achieve that.

I'm aware that type is also a function. But the semantics look so
compelling to me that I'm using the variable name anyway.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-04-11 14:53:12 +02:00
61c1a628a1 lib.ec.SSHClient: Exception for empty host name
Instantiating a SSHClient-derived class with an invalid or missing
uri parameter is accepted and fails later down the road. Raise an
Exception early on to make the error log more comprehensible.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-04-11 14:51:50 +02:00
737cbc3e24 lib.ec.ssh.AsyncSSH: Add class
Add a SSHClient implementation using AsyncSSH. This is the first and
currently only class derived from SSHClient which implements
SSHClient.Cap.LogOutput, designed to consume and log command output
as it streams in. It felt like the lower hanging fruit not to do that
with Paramiko: Paramiko doesn't provide a native async API, so it
would need to spawn additional worker threads. I think.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-25 07:32:46 +01:00
279b7789e2 lib.ec.SSHClient: Add property port
Add a port property to SSHClient, parsed from the ctor's URL, to
supply the obvious information.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-25 07:32:46 +01:00
3a84408436 lib.ec.SSHClient.__init__(): Add parameter caps
Add an optional caps ("capabilities") argument to the constructor of
SSHClient. It is meant to be used by derived classes in order to
declare that they don't want the base class to handle a default
behaviour for a certain capability, but that they want to implement
it themselves instead.

Also, give the _run_ssh() callbacks the necessary info as parameters,
so that the derived classes have the means to do so.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-25 07:32:46 +01:00
f4c76ebab9 lib.ec.SSHClientInternal|SSHClientCmd: Own .py
Move the code of SSHClientInternal and SSCClientCmd into lib.ec.ssh,
as "Paramiko" and "Exec", respectively. This makes the class layout
a little more modular, and along the way fixes a bug where
SSHClientInternal could be instantiated but was unusable (if the
Paramiko is not installed).

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-20 13:35:50 +01:00
f37f025b17 lib.SSHClient: Move to lib.ec
SSHClient in an ExecContext, hence it's better off in lib.ec, move it
there and adapt the references.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-03-20 13:35:11 +01:00
Renamed from src/python/jw/pkg/lib/SSHClient.py (Browse further)