Skip to content

Commit

Permalink
Merge pull request #1545 from davep/cli-diagnose
Browse files Browse the repository at this point in the history
Add a textual diagnose CLI command
  • Loading branch information
davep authored Jan 11, 2023
2 parents 1c4fe0c + 05931c4 commit 328733e
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added read-only public access to the children of a `TreeNode` via `TreeNode.children` https://github.com/Textualize/textual/issues/1398
- Added `Tree.get_node_by_id` to allow getting a node by its ID https://github.com/Textualize/textual/pull/1535
- Added a `Tree.NodeHighlighted` message, giving a `on_tree_node_highlighted` event handler https://github.com/Textualize/textual/issues/1400
- Added `diagnose` as a `textual` command https://github.com/Textualize/textual/issues/1542

### Changed

Expand Down
8 changes: 8 additions & 0 deletions src/textual/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,11 @@ def keys():
from textual.cli.previews import keys

keys.app.run()


@run.command("diagnose")
def run_diagnose():
"""Print information about the Textual environment"""
from textual.cli.tools.diagnose import diagnose

diagnose()
Empty file.
133 changes: 133 additions & 0 deletions src/textual/cli/tools/diagnose.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
"""Textual CLI command code to print diagnostic information."""

import os
import sys
import platform
from importlib_metadata import version
from rich.console import Console


def _section(title: str, values: dict[str, str]) -> None:
"""Print a collection of named values within a titled section.
Args:
title (str): The title for the section.
values (dict[str, str]): The values to print out.
"""
max_name = max(map(len, values.keys()))
max_value = max(map(len, values.values()))
print(f"## {title}")
print()
print(f"| {'Name':{max_name}} | {'Value':{max_value}} |")
print(f"|-{'-' * max_name}-|-{'-'*max_value}-|")
for name, value in values.items():
print(f"| {name:{max_name}} | {value:{max_value}} |")
print()


def _versions() -> None:
"""Print useful version numbers."""
_section("Versions", {"Textual": version("textual"), "Rich": version("rich")})


def _python() -> None:
"""Print information about Python."""
_section(
"Python",
{
"Version": platform.python_version(),
"Implementation": platform.python_implementation(),
"Compiler": platform.python_compiler(),
"Executable": sys.executable,
},
)


def _os() -> None:
_section(
"Operating System",
{
"System": platform.system(),
"Release": platform.release(),
"Version": platform.version(),
},
)


def _guess_term() -> str:
"""Try and guess which terminal is being used."""

# First obvious place to look is in $TERM_PROGRAM.
term_program = os.environ.get("TERM_PROGRAM")

if term_program is None:
# Seems we couldn't get it that way. Let's check for some of the
# more common terminal signatures.
if "ALACRITTY_WINDOW_ID" in os.environ:
term_program = "Alacritty"
elif "KITTY_PID" in os.environ:
term_program = "Kitty"
elif "WT_SESSION" in os.environ:
term_program = "Windows Terminal"
elif "INSIDE_EMACS" in os.environ and os.environ["INSIDE_EMACS"]:
term_program = (
f"GNU Emacs {' '.join(os.environ['INSIDE_EMACS'].split(','))}"
)
elif "JEDITERM_SOURCE_ARGS" in os.environ:
term_program = "PyCharm"

else:
# See if we can pull out some sort of version information too.
term_version = os.environ.get("TERM_PROGRAM_VERSION")
if term_version is not None:
term_program = f"{term_program} ({term_version})"

return "*Unknown*" if term_program is None else term_program


def _env(var_name: str) -> str:
"""Get a representation of an environment variable.
Args:
var_name (str): The name of the variable to get.
Returns:
str: The value, or an indication that it isn't set.
"""
return os.environ.get(var_name, "*Not set*")


def _term() -> None:
"""Print information about the terminal."""
_section(
"Terminal",
{
"Terminal Application": _guess_term(),
"TERM": _env("TERM"),
"COLORTERM": _env("COLORTERM"),
"FORCE_COLOR": _env("FORCE_COLOR"),
"NO_COLOR": _env("NO_COLOR"),
},
)


def _console() -> None:
"""Print The Rich console options."""
_section(
"Rich Console options",
{k: str(v) for k, v in Console().options.__dict__.items()},
)


def diagnose() -> None:
"""Print information about Textual and its environment to help diagnose problems."""
print("# Textual Diagnostics")
print()
_versions()
_python()
_os()
_term()
_console()
# TODO: Recommended changes. Given all of the above, make any useful
# recommendations to the user (eg: don't use Windows console, use
# Windows Terminal; don't use macOS Terminal.app, etc).

0 comments on commit 328733e

Please sign in to comment.