mirror of
https://github.com/XuehaiPan/nvitop.git
synced 2026-05-15 14:15:55 -06:00
deps(termcolor): vendor third-party dependency termcolor (#148)
This commit is contained in:
parent
652859c84b
commit
37b95d859e
13 changed files with 315 additions and 40 deletions
|
|
@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Removed
|
||||
|
||||
- Vendor third-party dependency `termcolor` by [@XuehaiPan](https://github.com/XuehaiPan) in [#148](https://github.com/XuehaiPan/nvitop/pull/148).
|
||||
- Remove third-party dependency `cachetools` by [@XuehaiPan](https://github.com/XuehaiPan) in [#147](https://github.com/XuehaiPan/nvitop/pull/147).
|
||||
|
||||
------
|
||||
|
|
|
|||
|
|
@ -115,7 +115,6 @@ An interactive NVIDIA-GPU process viewer and beyond, the one-stop solution for G
|
|||
- NVIDIA Management Library (NVML)
|
||||
- nvidia-ml-py
|
||||
- psutil
|
||||
- termcolor
|
||||
- curses<sup>[*](#curses)</sup> (with `libncursesw`)
|
||||
|
||||
**NOTE:** The [NVIDIA Management Library (*NVML*)](https://developer.nvidia.com/nvidia-management-library-nvml) is a C-based programmatic interface for monitoring and managing various states. The runtime version of the NVML library ships with the NVIDIA display driver (available at [Download Drivers | NVIDIA](https://www.nvidia.com/Download/index.aspx)), or can be downloaded as part of the NVIDIA CUDA Toolkit (available at [CUDA Toolkit | NVIDIA Developer](https://developer.nvidia.com/cuda-downloads)). The lists of OS platforms and NVIDIA-GPUs supported by the NVML library can be found in the [NVML API Reference](https://docs.nvidia.com/deploy/nvml-api/nvml-api-reference.html).
|
||||
|
|
|
|||
|
|
@ -158,3 +158,5 @@ hostname
|
|||
len
|
||||
maxsize
|
||||
reentrant
|
||||
env
|
||||
tty
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ def cprint(text: str = '', *, file: TextIO | None = None) -> None:
|
|||
if text.startswith(prefix):
|
||||
text = text.replace(
|
||||
prefix.rstrip(),
|
||||
colored(prefix.rstrip(), color=color, attrs=('bold',)),
|
||||
colored(prefix.rstrip(), color=color, attrs=('bold',)), # type: ignore[arg-type]
|
||||
1,
|
||||
)
|
||||
print(text, file=file)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ from nvitop.api import (
|
|||
libcudart,
|
||||
libnvml,
|
||||
process,
|
||||
termcolor,
|
||||
utils,
|
||||
)
|
||||
from nvitop.select import select_devices
|
||||
|
|
@ -38,7 +39,18 @@ from nvitop.version import __version__
|
|||
__all__ = [*api.__all__, 'select_devices']
|
||||
|
||||
# Add submodules to the top-level namespace
|
||||
for submodule in (caching, collector, device, host, libcuda, libcudart, libnvml, process, utils):
|
||||
for submodule in (
|
||||
caching,
|
||||
collector,
|
||||
device,
|
||||
host,
|
||||
libcuda,
|
||||
libcudart,
|
||||
libnvml,
|
||||
process,
|
||||
termcolor,
|
||||
utils,
|
||||
):
|
||||
sys.modules[f'{__name__}.{submodule.__name__.rpartition(".")[-1]}'] = submodule
|
||||
|
||||
# Remove the nvitop.select module from sys.modules
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ from nvitop.api import (
|
|||
libcudart,
|
||||
libnvml,
|
||||
process,
|
||||
termcolor,
|
||||
utils,
|
||||
)
|
||||
from nvitop.api.caching import ttl_cache
|
||||
|
|
|
|||
|
|
@ -29,7 +29,10 @@ if TYPE_CHECKING:
|
|||
from collections.abc import Callable, Hashable, Sized
|
||||
from collections.abc import Set as AbstractSet
|
||||
from typing import TypeVar
|
||||
from typing_extensions import ParamSpec, Self
|
||||
from typing_extensions import (
|
||||
ParamSpec, # Python 3.10+
|
||||
Self, # Python 3.11+
|
||||
)
|
||||
|
||||
_P = ParamSpec('_P')
|
||||
_T = TypeVar('_T')
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ def nvmlInitWithFlags(flags: int) -> None: # pylint: disable=function-redefined
|
|||
('https://developer.nvidia.com/cuda-downloads', None, ('underline',)),
|
||||
('https://docs.nvidia.com/deploy/nvml-api', None, ('underline',)),
|
||||
):
|
||||
message = message.replace(text, __colored(text, color=color, attrs=attrs))
|
||||
message = message.replace(text, __colored(text, color=color, attrs=attrs)) # type: ignore[arg-type]
|
||||
|
||||
LOGGER.critical(message)
|
||||
raise
|
||||
|
|
@ -340,7 +340,7 @@ def nvmlInitWithFlags(flags: int) -> None: # pylint: disable=function-redefined
|
|||
('pynvml', None, ('bold',)),
|
||||
('nvitop', None, ('bold',)),
|
||||
):
|
||||
message = message.replace(text, __colored(text, color=color, attrs=attrs), 1)
|
||||
message = message.replace(text, __colored(text, color=color, attrs=attrs), 1) # type: ignore[arg-type]
|
||||
|
||||
LOGGER.critical(message)
|
||||
raise
|
||||
|
|
|
|||
283
nvitop/api/termcolor.py
Normal file
283
nvitop/api/termcolor.py
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
# This file is part of nvitop, the interactive NVIDIA-GPU process viewer.
|
||||
#
|
||||
# Copyright 2021-2025 Xuehai Pan. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ==============================================================================
|
||||
# pylint: disable=wrong-spelling-in-comment
|
||||
# Vendored from the `termcolor` package: https://github.com/termcolor/termcolor
|
||||
# ==============================================================================
|
||||
# Copyright (c) 2008-2011 Volvox Development Team
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
# Author: Konstantin Lepa <konstantin.lepa@gmail.com>
|
||||
# ==============================================================================
|
||||
"""ANSI color formatting for output in terminal."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterable
|
||||
from typing_extensions import Literal # Python 3.8+
|
||||
|
||||
Attribute = Literal[
|
||||
'bold',
|
||||
'dark',
|
||||
'underline',
|
||||
'blink',
|
||||
'reverse',
|
||||
'concealed',
|
||||
'strike',
|
||||
]
|
||||
Highlight = Literal[
|
||||
'on_black',
|
||||
'on_grey',
|
||||
'on_red',
|
||||
'on_green',
|
||||
'on_yellow',
|
||||
'on_blue',
|
||||
'on_magenta',
|
||||
'on_cyan',
|
||||
'on_light_grey',
|
||||
'on_dark_grey',
|
||||
'on_light_red',
|
||||
'on_light_green',
|
||||
'on_light_yellow',
|
||||
'on_light_blue',
|
||||
'on_light_magenta',
|
||||
'on_light_cyan',
|
||||
'on_white',
|
||||
]
|
||||
Color = Literal[
|
||||
'black',
|
||||
'grey',
|
||||
'red',
|
||||
'green',
|
||||
'yellow',
|
||||
'blue',
|
||||
'magenta',
|
||||
'cyan',
|
||||
'light_grey',
|
||||
'dark_grey',
|
||||
'light_red',
|
||||
'light_green',
|
||||
'light_yellow',
|
||||
'light_blue',
|
||||
'light_magenta',
|
||||
'light_cyan',
|
||||
'white',
|
||||
]
|
||||
|
||||
|
||||
__all__ = ['colored', 'cprint']
|
||||
|
||||
|
||||
if os.name == 'nt': # Windows
|
||||
try:
|
||||
from colorama import init
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
init()
|
||||
|
||||
|
||||
ATTRIBUTES: dict[Attribute, int] = {
|
||||
'bold': 1,
|
||||
'dark': 2,
|
||||
'underline': 4,
|
||||
'blink': 5,
|
||||
'reverse': 7,
|
||||
'concealed': 8,
|
||||
'strike': 9,
|
||||
}
|
||||
|
||||
HIGHLIGHTS: dict[Highlight, int] = {
|
||||
'on_black': 40,
|
||||
'on_grey': 40, # Actually black but kept for backwards compatibility
|
||||
'on_red': 41,
|
||||
'on_green': 42,
|
||||
'on_yellow': 43,
|
||||
'on_blue': 44,
|
||||
'on_magenta': 45,
|
||||
'on_cyan': 46,
|
||||
'on_light_grey': 47,
|
||||
'on_dark_grey': 100,
|
||||
'on_light_red': 101,
|
||||
'on_light_green': 102,
|
||||
'on_light_yellow': 103,
|
||||
'on_light_blue': 104,
|
||||
'on_light_magenta': 105,
|
||||
'on_light_cyan': 106,
|
||||
'on_white': 107,
|
||||
}
|
||||
|
||||
COLORS: dict[Color, int] = {
|
||||
'black': 30,
|
||||
'grey': 30, # Actually black but kept for backwards compatibility
|
||||
'red': 31,
|
||||
'green': 32,
|
||||
'yellow': 33,
|
||||
'blue': 34,
|
||||
'magenta': 35,
|
||||
'cyan': 36,
|
||||
'light_grey': 37,
|
||||
'dark_grey': 90,
|
||||
'light_red': 91,
|
||||
'light_green': 92,
|
||||
'light_yellow': 93,
|
||||
'light_blue': 94,
|
||||
'light_magenta': 95,
|
||||
'light_cyan': 96,
|
||||
'white': 97,
|
||||
}
|
||||
|
||||
|
||||
RESET = '\033[0m'
|
||||
|
||||
|
||||
# pylint: disable-next=too-many-return-statements
|
||||
def _can_do_color(
|
||||
*,
|
||||
no_color: bool | None = None,
|
||||
force_color: bool | None = None,
|
||||
) -> bool:
|
||||
"""Check env vars and for tty/dumb terminal."""
|
||||
# First check overrides:
|
||||
# "User-level configuration files and per-instance command-line arguments should
|
||||
# override $NO_COLOR. A user should be able to export $NO_COLOR in their shell
|
||||
# configuration file as a default, but configure a specific program in its
|
||||
# configuration file to specifically enable color."
|
||||
# https://no-color.org
|
||||
if no_color is not None and no_color:
|
||||
return False
|
||||
if force_color is not None and force_color:
|
||||
return True
|
||||
|
||||
# Then check env vars:
|
||||
if 'ANSI_COLORS_DISABLED' in os.environ:
|
||||
return False
|
||||
if 'NO_COLOR' in os.environ:
|
||||
return False
|
||||
if 'FORCE_COLOR' in os.environ:
|
||||
return True
|
||||
|
||||
# Then check system:
|
||||
if os.environ.get('TERM') == 'dumb':
|
||||
return False
|
||||
if not hasattr(sys.stdout, 'fileno'):
|
||||
return False
|
||||
|
||||
try:
|
||||
return os.isatty(sys.stdout.fileno())
|
||||
except io.UnsupportedOperation:
|
||||
return sys.stdout.isatty()
|
||||
|
||||
|
||||
# pylint: disable-next=too-many-arguments
|
||||
def colored(
|
||||
text: Any,
|
||||
color: Color | None = None,
|
||||
on_color: Highlight | None = None,
|
||||
attrs: Iterable[Attribute] | None = None,
|
||||
*,
|
||||
no_color: bool | None = None,
|
||||
force_color: bool | None = None,
|
||||
) -> str:
|
||||
"""Colorize text.
|
||||
|
||||
Available text colors:
|
||||
black, red, green, yellow, blue, magenta, cyan, white,
|
||||
light_grey, dark_grey, light_red, light_green, light_yellow, light_blue,
|
||||
light_magenta, light_cyan.
|
||||
|
||||
Available text highlights:
|
||||
on_black, on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan, on_white,
|
||||
on_light_grey, on_dark_grey, on_light_red, on_light_green, on_light_yellow,
|
||||
on_light_blue, on_light_magenta, on_light_cyan.
|
||||
|
||||
Available attributes:
|
||||
bold, dark, underline, blink, reverse, concealed.
|
||||
|
||||
Example:
|
||||
colored('Hello, World!', 'red', 'on_black', ['bold', 'blink'])
|
||||
colored('Hello, World!', 'green')
|
||||
"""
|
||||
result = str(text)
|
||||
if not _can_do_color(no_color=no_color, force_color=force_color):
|
||||
return result
|
||||
|
||||
fmt_str = '\033[%dm%s'
|
||||
if color is not None:
|
||||
result = fmt_str % (COLORS[color], result)
|
||||
|
||||
if on_color is not None:
|
||||
result = fmt_str % (HIGHLIGHTS[on_color], result)
|
||||
|
||||
if attrs is not None:
|
||||
for attr in attrs:
|
||||
result = fmt_str % (ATTRIBUTES[attr], result)
|
||||
|
||||
result += RESET
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# pylint: disable-next=too-many-arguments
|
||||
def cprint(
|
||||
text: object,
|
||||
color: Color | None = None,
|
||||
on_color: Highlight | None = None,
|
||||
attrs: Iterable[Attribute] | None = None,
|
||||
*,
|
||||
no_color: bool | None = None,
|
||||
force_color: bool | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Print colorized text.
|
||||
|
||||
It accepts arguments of print function.
|
||||
"""
|
||||
print(
|
||||
colored(
|
||||
text,
|
||||
color,
|
||||
on_color,
|
||||
attrs,
|
||||
no_color=no_color,
|
||||
force_color=force_color,
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
|
@ -31,7 +31,7 @@ import time
|
|||
from collections.abc import KeysView
|
||||
from typing import TYPE_CHECKING, Any, Callable, TypeVar
|
||||
|
||||
from psutil import WINDOWS
|
||||
from nvitop.api import termcolor
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -62,30 +62,6 @@ __all__ = [
|
|||
]
|
||||
|
||||
|
||||
if WINDOWS:
|
||||
try:
|
||||
from colorama import init
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
init()
|
||||
|
||||
try:
|
||||
from termcolor import colored as _colored
|
||||
except ImportError:
|
||||
|
||||
def _colored( # type: ignore[misc] # pylint: disable=unused-argument,too-many-arguments
|
||||
text: str,
|
||||
color: str | None = None,
|
||||
on_color: str | None = None,
|
||||
attrs: Iterable[str] | None = None,
|
||||
*,
|
||||
no_color: bool | None = None,
|
||||
force_color: bool | None = None,
|
||||
) -> str:
|
||||
return text
|
||||
|
||||
|
||||
COLOR: bool = sys.stdout.isatty()
|
||||
|
||||
|
||||
|
|
@ -102,10 +78,10 @@ def set_color(value: bool) -> None:
|
|||
|
||||
|
||||
def colored(
|
||||
text: str,
|
||||
color: str | None = None,
|
||||
on_color: str | None = None,
|
||||
attrs: Iterable[str] | None = None,
|
||||
text: Any,
|
||||
color: termcolor.Color | None = None,
|
||||
on_color: termcolor.Highlight | None = None,
|
||||
attrs: Iterable[termcolor.Attribute] | None = None,
|
||||
) -> str:
|
||||
"""Colorize text with ANSI color escape codes.
|
||||
|
||||
|
|
@ -123,8 +99,8 @@ def colored(
|
|||
>>> colored('Hello, World!', 'green')
|
||||
"""
|
||||
if COLOR:
|
||||
return _colored(text, color=color, on_color=on_color, attrs=attrs) # type: ignore[arg-type]
|
||||
return text
|
||||
return termcolor.colored(text, color=color, on_color=on_color, attrs=attrs)
|
||||
return str(text)
|
||||
|
||||
|
||||
class NaType(str):
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ def main() -> int:
|
|||
if message.startswith(prefix):
|
||||
message = message.replace(
|
||||
prefix,
|
||||
colored(prefix, color=color, attrs=('bold',)),
|
||||
colored(prefix, color=color, attrs=('bold',)), # type: ignore[arg-type]
|
||||
1,
|
||||
)
|
||||
break
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ dependencies = [
|
|||
# Sync with nvitop/version.py and requirements.txt
|
||||
"nvidia-ml-py >= 11.450.51, < 12.561.0a0",
|
||||
"psutil >= 5.6.6",
|
||||
"termcolor >= 1.0.0",
|
||||
"colorama >= 0.4.0; platform_system == 'Windows'",
|
||||
"windows-curses >= 2.2.0; platform_system == 'Windows'",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
# Sync with pyproject.toml and nvitop/version.py
|
||||
nvidia-ml-py >= 11.450.51, < 12.561.0a0
|
||||
psutil >= 5.6.6
|
||||
termcolor >= 1.0.0
|
||||
colorama >= 0.4.0; platform_system == 'Windows'
|
||||
windows-curses >= 2.2.0; platform_system == 'Windows'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue