Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ A command line client for MySQL with auto-completion and syntax highlighting.
├── mycli/packages/hybrid_redirection.py # implementation of shell-style redirects
├── mycli/packages/interactive_utils.py # utilities for confirming on destructive statements
├── mycli/packages/key_binding_utils.py # handlers for key bindings and related special commands
├── mycli/packages/paramiko_stub/ # stub in case the Paramiko library is not installed
├── mycli/packages/sql_utils.py # utilities for parsing SQL statements
├── mycli/packages/ptoolkit/ # extends prompt_toolkit
├── mycli/packages/special/ # implementation of mycli special commands
Expand Down
8 changes: 8 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
Upcoming (TBD)
==============

Breaking Changes
--------
* Remove support for deprecated SSH jump functionality.


1.75.0 (2026/06/20)
==============

Expand Down
50 changes: 5 additions & 45 deletions mycli/cli_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
from mycli.main_modes.checkup import main_checkup
from mycli.main_modes.execute import main_execute_from_cli
from mycli.main_modes.list_dsn import main_list_dsn
from mycli.main_modes.list_ssh_config import main_list_ssh_config
from mycli.packages.cli_utils import is_valid_connection_scheme
from mycli.packages.ssh_utils import read_ssh_config

if TYPE_CHECKING:
from mycli.main import CliArgs
Expand Down Expand Up @@ -73,30 +71,9 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
fg="yellow",
)

# ssh_port and ssh_config_path have truthy defaults and are not included
if (
any([
cli_args.ssh_user,
cli_args.ssh_host,
cli_args.ssh_password,
cli_args.ssh_key_filename,
cli_args.list_ssh_config,
cli_args.ssh_config_host,
])
and not cli_args.ssh_warning_off
):
click.secho(
f"Warning: The built-in SSH functionality is deprecated and will be removed in a future release. See issue {ISSUES_URL}/1464",
err=True,
fg="red",
)

if cli_args.list_dsn:
sys.exit(main_list_dsn(mycli))

if cli_args.list_ssh_config:
sys.exit(main_list_ssh_config(mycli, cli_args))

if 'MYSQL_UNIX_PORT' in os.environ:
# deprecated 2026-03
click.secho(
Expand Down Expand Up @@ -161,6 +138,11 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
mycli.dsn_alias = cli_args.dsn

if dsn_uri:
is_valid_scheme, scheme = is_valid_connection_scheme(dsn_uri)
if not is_valid_scheme:
click.secho(f'Error: Unknown connection scheme provided for DSN URI ({scheme}://)', err=True, fg='red')
sys.exit(1)

uri = urlparse(dsn_uri)
if not database:
database = uri.path[1:] # ignore the leading fwd slash
Expand Down Expand Up @@ -255,23 +237,6 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
else:
ssl = None

if cli_args.ssh_config_host:
ssh_config = read_ssh_config(cli_args.ssh_config_path).lookup(cli_args.ssh_config_host)
ssh_host = cli_args.ssh_host if cli_args.ssh_host else ssh_config.get("hostname")
ssh_user = cli_args.ssh_user if cli_args.ssh_user else ssh_config.get("user")
if ssh_config.get("port") and cli_args.ssh_port == 22:
# port has a default value, overwrite it if it's in the config
ssh_port = int(ssh_config.get("port"))
else:
ssh_port = cli_args.ssh_port
ssh_key_filename = cli_args.ssh_key_filename if cli_args.ssh_key_filename else ssh_config.get("identityfile", [None])[0]
else:
ssh_host = cli_args.ssh_host
ssh_user = cli_args.ssh_user
ssh_port = cli_args.ssh_port
ssh_key_filename = cli_args.ssh_key_filename

ssh_key_filename = ssh_key_filename and os.path.expanduser(ssh_key_filename)
# Merge init-commands: global, DSN-specific, then CLI
init_cmds: list[str] = []
# 1) Global init-commands
Expand Down Expand Up @@ -391,11 +356,6 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
socket=cli_args.socket,
local_infile=cli_args.local_infile,
ssl=ssl,
ssh_user=ssh_user,
ssh_host=ssh_host,
ssh_port=ssh_port,
ssh_password=cli_args.ssh_password,
ssh_key_filename=ssh_key_filename,
init_command=combined_init_cmd,
unbuffered=cli_args.unbuffered,
character_set=cli_args.character_set,
Expand Down
10 changes: 0 additions & 10 deletions mycli/client_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ def connect(
character_set: str | None = "",
local_infile: bool | None = False,
ssl: dict[str, Any] | None = None,
ssh_user: str | None = "",
ssh_host: str | None = "",
ssh_port: int = 22,
ssh_password: str | None = "",
ssh_key_filename: str | None = "",
init_command: str | None = "",
unbuffered: bool | None = None,
use_keyring: bool | None = None,
Expand Down Expand Up @@ -200,11 +195,6 @@ def connect(
"character_set": character_set,
"local_infile": use_local_infile,
"ssl": ssl_config_or_none,
"ssh_user": ssh_user,
"ssh_host": ssh_host,
"ssh_port": int(ssh_port) if ssh_port else None,
"ssh_password": ssh_password,
"ssh_key_filename": ssh_key_filename,
"init_command": init_command,
"unbuffered": unbuffered,
}
Expand Down
5 changes: 0 additions & 5 deletions mycli/completion_refresher.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ def _bg_refresh(
e.character_set,
e.local_infile,
e.ssl,
e.ssh_user,
e.ssh_host,
e.ssh_port,
e.ssh_password,
e.ssh_key_filename,
)
except pymysql.err.OperationalError:
return
Expand Down
38 changes: 0 additions & 38 deletions mycli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,44 +86,6 @@ class CliArgs:
type=click.Path(),
help='File or FIFO path containing the password to connect to the db if not specified otherwise.',
)
ssh_user: str | None = clickdc.option(
type=str,
help='User name to connect to ssh server.',
)
ssh_host: str | None = clickdc.option(
type=str,
help='Host name to connect to ssh server.',
)
ssh_port: int = clickdc.option(
type=int,
default=22,
help='Port to connect to ssh server.',
)
ssh_password: str | None = clickdc.option(
type=str,
help='Password to connect to ssh server.',
)
ssh_key_filename: str | None = clickdc.option(
type=str,
help='Private key filename (identify file) for the ssh connection.',
)
ssh_config_path: str = clickdc.option(
type=str,
help='Path to ssh configuration.',
default=os.path.expanduser('~') + '/.ssh/config',
)
ssh_config_host: str | None = clickdc.option(
type=str,
help='Host to connect to ssh server reading from ssh configuration.',
)
list_ssh_config: bool = clickdc.option(
is_flag=True,
help='list ssh configurations in the ssh config (requires paramiko).',
)
ssh_warning_off: bool = clickdc.option(
is_flag=True,
help='Suppress the SSH deprecation notice.',
)
ssl_mode: str = clickdc.option(
type=click.Choice(['auto', 'on', 'off']),
help='Set desired SSL behavior. auto=preferred if TCP/IP, on=required, off=off.',
Expand Down
27 changes: 0 additions & 27 deletions mycli/main_modes/list_ssh_config.py

This file was deleted.

2 changes: 1 addition & 1 deletion mycli/packages/cli_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def is_valid_connection_scheme(text: str) -> tuple[bool, str | None]:
if "://" not in text:
return False, None
scheme = text.split("://")[0]
if scheme not in ("mysql", "mysqlx", "tcp", "socket", "ssh"):
if scheme not in ("mysql", "mysqlx", "tcp", "socket"):
return False, scheme
else:
return True, None
36 changes: 0 additions & 36 deletions mycli/packages/paramiko_stub/__init__.py

This file was deleted.

27 changes: 0 additions & 27 deletions mycli/packages/ssh_utils.py

This file was deleted.

5 changes: 0 additions & 5 deletions mycli/schema_prefetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,6 @@ def _make_executor(self) -> SQLExecute:
sqlexecute.character_set,
sqlexecute.local_infile,
sqlexecute.ssl,
sqlexecute.ssh_user,
sqlexecute.ssh_host,
sqlexecute.ssh_port,
sqlexecute.ssh_password,
sqlexecute.ssh_key_filename,
)

def _invalidate_app(self) -> None:
Expand Down
Loading
Loading