From 1710579c6604bf991cef4402bb263d1356cc7026 Mon Sep 17 00:00:00 2001 From: Xuehai Pan Date: Fri, 16 Feb 2024 09:43:47 +0000 Subject: [PATCH] lint: update `ruff` rules --- .flake8 | 3 +- .pre-commit-config.yaml | 6 +- nvitop-exporter/nvitop_exporter/exporter.py | 2 +- nvitop/api/device.py | 28 +++---- nvitop/api/libnvml.py | 4 +- nvitop/api/process.py | 9 +-- nvitop/api/utils.py | 6 +- nvitop/callbacks/lightning.py | 7 +- nvitop/callbacks/pytorch_lightning.py | 7 +- nvitop/cli.py | 86 +++++++++------------ nvitop/gui/library/device.py | 2 +- nvitop/gui/library/keybinding.py | 22 +++--- nvitop/gui/library/libcurses.py | 4 +- nvitop/gui/library/messagebox.py | 4 +- nvitop/gui/library/selection.py | 10 ++- nvitop/gui/library/utils.py | 2 +- nvitop/gui/screens/help.py | 6 +- nvitop/gui/screens/main/__init__.py | 2 +- nvitop/gui/screens/main/process.py | 9 ++- nvitop/gui/ui.py | 8 +- nvitop/select.py | 11 +-- pyproject.toml | 28 +++++-- 22 files changed, 135 insertions(+), 131 deletions(-) diff --git a/.flake8 b/.flake8 index 2b65009a..bb839373 100644 --- a/.flake8 +++ b/.flake8 @@ -5,10 +5,11 @@ select = B,C,E,F,W,Y,SIM ignore = # E203: whitespace before ':' # E241: whitespace after ':' + # E704: multiple statements on one line (def) # W503: line break before binary operator # W504: line break after binary operator # format by black - E203,E241,W503,W504, + E203,E241,E704,W503,W504, # E501: line too long # W505: doc line too long # too long docstring due to long example blocks diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 48e6d91b..7d9d6099 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: - id: debug-statements - id: double-quote-string-fixer - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.8 + rev: v0.2.1 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] @@ -34,7 +34,7 @@ repos: hooks: - id: isort - repo: https://github.com/psf/black - rev: 23.12.0 + rev: 24.2.0 hooks: - id: black - repo: https://github.com/asottile/pyupgrade @@ -43,7 +43,7 @@ repos: - id: pyupgrade args: [--py37-plus] # sync with requires-python - repo: https://github.com/pycqa/flake8 - rev: 6.1.0 + rev: 7.0.0 hooks: - id: flake8 additional_dependencies: diff --git a/nvitop-exporter/nvitop_exporter/exporter.py b/nvitop-exporter/nvitop_exporter/exporter.py index 631c4531..7d9db604 100644 --- a/nvitop-exporter/nvitop_exporter/exporter.py +++ b/nvitop-exporter/nvitop_exporter/exporter.py @@ -637,5 +637,5 @@ def update_device(self, device: Device) -> None: # pylint: disable=too-many-loc pid, username, ) - except KeyError: + except KeyError: # noqa: PERF203 pass diff --git a/nvitop/api/device.py b/nvitop/api/device.py index fa1c1329..304d80ea 100644 --- a/nvitop/api/device.py +++ b/nvitop/api/device.py @@ -115,7 +115,6 @@ import threading import time from collections import OrderedDict -from collections.abc import Hashable from typing import TYPE_CHECKING, Any, Callable, ClassVar, Generator, Iterable, NamedTuple, overload from nvitop.api import libcuda, libcudart, libnvml @@ -132,6 +131,8 @@ if TYPE_CHECKING: + from collections.abc import Hashable + from typing_extensions import Literal # Python 3.8+ from typing_extensions import Self # Python 3.11+ @@ -1568,7 +1569,7 @@ def query_nvlink_throughput_counters() -> tuple[tuple[int | NaType, int]]: if interval is not None: if not interval >= 0.0: - raise ValueError('`interval` must be a non-negative number, got {interval!r}.') + raise ValueError(f'`interval` must be a non-negative number, got {interval!r}.') if interval > 0.0: self._nvlink_throughput_counters = query_nvlink_throughput_counters() time.sleep(interval) @@ -2125,7 +2126,7 @@ def processes(self) -> dict[int, GpuProcess]: for s in sorted(samples, key=lambda s: s.timeStamp): try: processes[s.pid].set_gpu_utilization(s.smUtil, s.memUtil, s.encUtil, s.decUtil) - except KeyError: + except KeyError: # noqa: PERF203 pass if not found_na: for pid in set(processes).difference(s.pid for s in samples): @@ -2309,7 +2310,7 @@ def mig_devices(self) -> list[MigDevice]: for mig_index in range(max_mig_device_count): try: mig_device = MigDevice(index=(self.index, mig_index)) - except libnvml.NVMLError: + except libnvml.NVMLError: # noqa: PERF203 break else: mig_devices.append(mig_device) @@ -2968,16 +2969,14 @@ def _get_global_physical_device() -> PhysicalDevice: def _parse_cuda_visible_devices( cuda_visible_devices: str | None, format: Literal['index'], # pylint: disable=redefined-builtin -) -> list[int] | list[tuple[int, int]]: - ... +) -> list[int] | list[tuple[int, int]]: ... @overload def _parse_cuda_visible_devices( cuda_visible_devices: str | None, format: Literal['uuid'], # pylint: disable=redefined-builtin -) -> list[str]: - ... +) -> list[str]: ... @functools.lru_cache() @@ -2986,7 +2985,7 @@ def _parse_cuda_visible_devices( # pylint: disable=too-many-branches,too-many-s format: Literal['index', 'uuid'] = 'index', # pylint: disable=redefined-builtin ) -> list[int] | list[tuple[int, int]] | list[str]: """The underlining implementation for :meth:`parse_cuda_visible_devices`. The result will be cached.""" - assert format in ('index', 'uuid') + assert format in {'index', 'uuid'} try: physical_device_attrs = _get_all_physical_device_attrs() @@ -3062,9 +3061,9 @@ def strip_identifier(identifier: str) -> str: identifier = identifier.strip() if len(identifier) > 0 and ( identifier[0].isdigit() - or (len(identifier) > 1 and identifier[0] in ('+', '-') and identifier[1].isdigit()) + or (len(identifier) > 1 and identifier[0] in {'+', '-'} and identifier[1].isdigit()) ): - offset = 1 if identifier[0] in ('+', '-') else 0 + offset = 1 if identifier[0] in {'+', '-'} else 0 while offset < len(identifier) and identifier[offset].isdigit(): offset += 1 identifier = identifier[:offset] @@ -3181,12 +3180,13 @@ def _cuda_visible_devices_parser( count = libcuda.cuDeviceGetCount() uuids = [libcuda.cuDeviceGetUuid(libcuda.cuDeviceGet(i)) for i in range(count)] - queue.put(uuids) - return except Exception as ex: # noqa: BLE001 # pylint: disable=broad-except queue.put(ex) if verbose: - raise ex + raise + else: + queue.put(uuids) + return finally: # Ensure non-empty queue queue.put(libcuda.CUDAError_NotInitialized()) # pylint: disable=no-member diff --git a/nvitop/api/libnvml.py b/nvitop/api/libnvml.py index 50481e7b..86a9af67 100644 --- a/nvitop/api/libnvml.py +++ b/nvitop/api/libnvml.py @@ -66,7 +66,7 @@ if not callable(getattr(_pynvml, 'nvmlInitWithFlags', None)): - raise ImportError( + raise ImportError( # noqa: TRY004 'Your installed package `nvidia-ml-py` is corrupted. Please reinstall package ' '`nvidia-ml-py` via `pip3 install --force-reinstall nvidia-ml-py nvitop`.', ) @@ -444,7 +444,7 @@ def nvmlQuery( and len(UNKNOWN_FUNCTIONS) < UNKNOWN_FUNCTIONS_CACHE_SIZE ): UNKNOWN_FUNCTIONS[identifier] = (func, e2) - LOGGER.error( + LOGGER.exception( ( 'ERROR: A FunctionNotFound error occurred while calling %s.\n' 'Please verify whether the `nvidia-ml-py` package is ' diff --git a/nvitop/api/process.py b/nvitop/api/process.py index 2bbc7128..839fdd2f 100644 --- a/nvitop/api/process.py +++ b/nvitop/api/process.py @@ -132,7 +132,7 @@ def wrapped(self: GpuProcess, *args: Any, **kwargs: Any) -> Any: pass # See also `GpuProcess.failsafe` if fallback is _RAISE or not getattr(_USE_FALLBACK_WHEN_RAISE, 'value', False): - raise ex + raise if isinstance(fallback, tuple): if isinstance(ex, host.AccessDenied) and fallback == ('No Such Process',): return ['No Permissions'] @@ -232,10 +232,7 @@ def _gone(self) -> bool: def _gone(self, value: bool) -> None: if value: with self.INSTANCE_LOCK: - try: - del self.INSTANCES[self.pid] - except KeyError: - pass + self.INSTANCES.pop(self.pid, None) self._super_gone = value def __repr__(self) -> str: @@ -434,7 +431,7 @@ def as_snapshot( for attr in ('command', 'running_time', 'running_time_human'): try: attributes[attr] = getattr(self, attr)() - except (host.AccessDenied, host.ZombieProcess): + except (host.AccessDenied, host.ZombieProcess): # noqa: PERF203 attributes[attr] = ad_value return Snapshot(real=self, **attributes) diff --git a/nvitop/api/utils.py b/nvitop/api/utils.py index 94ad15fd..3f336fd6 100644 --- a/nvitop/api/utils.py +++ b/nvitop/api/utils.py @@ -632,9 +632,9 @@ def utilization2string(utilization: int | float | NaType) -> str: # noqa: PYI04 def boolify(string: str, default: Any = None) -> bool: """Convert the given value, usually a string, to boolean.""" - if string.lower() in ('true', 'yes', 'on', 'enabled', '1'): + if string.lower() in {'true', 'yes', 'on', 'enabled', '1'}: return True - if string.lower() in ('false', 'no', 'off', 'disabled', '0'): + if string.lower() in {'false', 'no', 'off', 'disabled', '0'}: return False if default is not None: return bool(default) @@ -708,7 +708,7 @@ def __iter__(self) -> Iterator[str]: """Support ``for name in snapshot`` syntax and ``*`` tuple unpack ``[*snapshot]`` syntax.""" def gen() -> Generator[str, None, None]: - yield from (name for name in self.__dict__ if name not in ('real', 'timestamp')) + yield from (name for name in self.__dict__ if name not in {'real', 'timestamp'}) return gen() diff --git a/nvitop/callbacks/lightning.py b/nvitop/callbacks/lightning.py index b2bf7f36..a9d094d0 100644 --- a/nvitop/callbacks/lightning.py +++ b/nvitop/callbacks/lightning.py @@ -21,9 +21,8 @@ from __future__ import annotations import time -from typing import Any +from typing import TYPE_CHECKING, Any -import lightning.pytorch as pl # pylint: disable=import-error from lightning.pytorch.callbacks import Callback # pylint: disable=import-error from lightning.pytorch.utilities import rank_zero_only # pylint: disable=import-error from lightning.pytorch.utilities.exceptions import ( # pylint: disable=import-error @@ -34,6 +33,10 @@ from nvitop.callbacks.utils import get_devices_by_logical_ids, get_gpu_stats +if TYPE_CHECKING: + import lightning.pytorch as pl + + # Modified from pytorch_lightning.callbacks.GPUStatsMonitor class GpuStatsLogger(Callback): # pylint: disable=too-many-instance-attributes """Automatically log GPU stats during training stage. :class:`GpuStatsLogger` is a callback and diff --git a/nvitop/callbacks/pytorch_lightning.py b/nvitop/callbacks/pytorch_lightning.py index 3e64d849..79597c8c 100644 --- a/nvitop/callbacks/pytorch_lightning.py +++ b/nvitop/callbacks/pytorch_lightning.py @@ -21,9 +21,8 @@ from __future__ import annotations import time -from typing import Any +from typing import TYPE_CHECKING, Any -import pytorch_lightning as pl # pylint: disable=import-error from pytorch_lightning.callbacks import Callback # pylint: disable=import-error from pytorch_lightning.utilities import rank_zero_only # pylint: disable=import-error from pytorch_lightning.utilities.exceptions import ( # pylint: disable=import-error @@ -34,6 +33,10 @@ from nvitop.callbacks.utils import get_devices_by_logical_ids, get_gpu_stats +if TYPE_CHECKING: + import pytorch_lightning as pl + + # Modified from pytorch_lightning.callbacks.GPUStatsMonitor class GpuStatsLogger(Callback): # pylint: disable=too-many-instance-attributes """Automatically log GPU stats during training stage. :class:`GpuStatsLogger` is a callback and diff --git a/nvitop/cli.py b/nvitop/cli.py index 6b70d222..2050e8df 100644 --- a/nvitop/cli.py +++ b/nvitop/cli.py @@ -7,6 +7,7 @@ import curses import os import sys +import textwrap from nvitop.api import HostProcess, libnvml from nvitop.gui import UI, USERNAME, Device, colored, libcurses, set_color, setlocale_utf8 @@ -240,31 +241,29 @@ def posfloat(argstring: str) -> float: gpu_util_thresh = list( map(int, os.getenv('NVITOP_GPU_UTILIZATION_THRESHOLDS', '').split(',')), )[:2] - if ( - len(gpu_util_thresh) != 2 - or min(gpu_util_thresh) <= 0 - or max(gpu_util_thresh) >= 100 - ): - raise ValueError except ValueError: pass else: - args.gpu_util_thresh = gpu_util_thresh + if ( + len(gpu_util_thresh) == 2 + and min(gpu_util_thresh) > 0 + and max(gpu_util_thresh) < 100 + ): + args.gpu_util_thresh = gpu_util_thresh if args.mem_util_thresh is None: try: mem_util_thresh = list( map(int, os.getenv('NVITOP_MEMORY_UTILIZATION_THRESHOLDS', '').split(',')), )[:2] - if ( - len(mem_util_thresh) != 2 - or min(mem_util_thresh) <= 0 - or max(mem_util_thresh) >= 100 - ): - raise ValueError except ValueError: pass else: - args.mem_util_thresh = mem_util_thresh + if ( + len(mem_util_thresh) == 2 + and min(mem_util_thresh) > 0 + and max(mem_util_thresh) < 100 + ): + args.mem_util_thresh = mem_util_thresh return args @@ -385,9 +384,11 @@ def main() -> int: if len(libnvml.UNKNOWN_FUNCTIONS) > 0: unknown_function_messages = [ - 'ERROR: Some FunctionNotFound errors occurred while calling:' - if len(libnvml.UNKNOWN_FUNCTIONS) > 1 - else 'ERROR: A FunctionNotFound error occurred while calling:', + ( + 'ERROR: Some FunctionNotFound errors occurred while calling:' + if len(libnvml.UNKNOWN_FUNCTIONS) > 1 + else 'ERROR: A FunctionNotFound error occurred while calling:' + ), ] unknown_function_messages.extend( f' nvmlQuery({(func.__name__ if not isinstance(func, str) else func)!r}, *args, **kwargs)' @@ -404,41 +405,30 @@ def main() -> int: ) if libnvml._pynvml_installation_corrupted: # pylint: disable=protected-access - message = '\n'.join( - ( - 'WARNING: The `nvidia-ml-py` package is corrupted. Please reinstall it using:', - '', - ' pip3 install --force-reinstall nvitop nvidia-ml-py', - '', - 'or install `nvitop` in an isolated environment:', - '', - ' pip3 install --upgrade pipx', - ' pipx install nvitop', - '', - ), + message = textwrap.dedent( + """ + WARNING: The `nvidia-ml-py` package is corrupted. Please reinstall it using: + + pip3 install --force-reinstall nvitop nvidia-ml-py + + or install `nvitop` in an isolated environment: + + pip3 install --upgrade pipx + pipx run nvitop + """, ) - messages.append(message) + messages.append(message.strip() + '\n') if len(messages) > 0: for message in messages: - if message.startswith('ERROR:'): - message = message.replace( - 'ERROR:', - colored('ERROR:', color='red', attrs=('bold',)), - 1, - ) - elif message.startswith('WARNING:'): - message = message.replace( - 'WARNING:', - colored('WARNING:', color='yellow', attrs=('bold',)), - 1, - ) - elif message.startswith('HINT:'): - message = message.replace( - 'HINT:', - colored('HINT:', color='green', attrs=('bold',)), - 1, - ) + for prefix, color in (('ERROR:', 'red'), ('WARNING:', 'yellow'), ('HINT:', 'green')): + if message.startswith(prefix): + message = message.replace( + prefix, + colored(prefix, color=color, attrs=('bold',)), + 1, + ) + break print(message, file=sys.stderr) return 1 return 0 diff --git a/nvitop/gui/library/device.py b/nvitop/gui/library/device.py index c8eb2da6..30717a86 100644 --- a/nvitop/gui/library/device.py +++ b/nvitop/gui/library/device.py @@ -87,7 +87,7 @@ def mig_devices(self): for mig_index in range(self.max_mig_device_count()): try: mig_device = MigDevice(index=(self.index, mig_index)) - except libnvml.NVMLError: + except libnvml.NVMLError: # noqa: PERF203 break else: mig_devices.append(mig_device) diff --git a/nvitop/gui/library/keybinding.py b/nvitop/gui/library/keybinding.py index f51e6caf..02578fb5 100644 --- a/nvitop/gui/library/keybinding.py +++ b/nvitop/gui/library/keybinding.py @@ -155,12 +155,11 @@ def parse_keybinding(obj): # pylint: disable=too-many-branches yield keys # it was no tuple, just an int else: bracket_content.append(char) + elif char == '<': + in_brackets = True + bracket_content = [] else: - if char == '<': - in_brackets = True - bracket_content = [] - else: - yield ord(char) + yield ord(char) if in_brackets: yield ord('<') for char in bracket_content: @@ -257,13 +256,10 @@ def bind(self, context, keys, leaf): return last_key = keys[-1] for key in keys[:-1]: - try: - if isinstance(pointer[key], dict): - pointer = pointer[key] - else: - pointer[key] = pointer = {} - except KeyError: - pointer[key] = pointer = {} + if key in pointer and isinstance(pointer[key], dict): + pointer = pointer[key] + else: + pointer = pointer[key] = {} pointer[last_key] = leaf def copy(self, context, source, target): @@ -273,7 +269,7 @@ def copy(self, context, source, target): for key in clean_source: try: pointer = pointer[key] - except KeyError as ex: + except KeyError as ex: # noqa: PERF203 raise KeyError( f'Tried to copy the keybinding `{source}`, but it was not found.', ) from ex diff --git a/nvitop/gui/library/libcurses.py b/nvitop/gui/library/libcurses.py index e8924404..fc3b7307 100644 --- a/nvitop/gui/library/libcurses.py +++ b/nvitop/gui/library/libcurses.py @@ -119,7 +119,7 @@ def setlocale_utf8(): for code in ('C.UTF-8', 'en_US.UTF-8', '', 'C'): try: code = locale.setlocale(locale.LC_ALL, code) - except locale.Error: + except locale.Error: # noqa: PERF203 continue else: if 'utf8' in code.lower() or 'utf-8' in code.lower(): @@ -260,7 +260,7 @@ def get_fg_bg_attr(fg=-1, bg=-1, attr=0): LIGHT_THEME and attr & curses.A_REVERSE != 0 and bg == -1 - and fg not in (DEFAULT_FOREGROUND, -1) + and fg not in {DEFAULT_FOREGROUND, -1} ): bg = DEFAULT_FOREGROUND diff --git a/nvitop/gui/library/messagebox.py b/nvitop/gui/library/messagebox.py index bec309f9..01e16150 100644 --- a/nvitop/gui/library/messagebox.py +++ b/nvitop/gui/library/messagebox.py @@ -57,7 +57,7 @@ def __init__(self, message, options, default, yes, no, cancel, win, root): self.no = no # pylint: disable=invalid-name self.timestamp = time.monotonic() - self.name_len = max(8, max(len(option.name) for option in options)) + self.name_len = max(8, *(len(option.name) for option in options)) for option in self.options: option.offset = (self.name_len - len(option.name)) // 2 option.name = option.name.center(self.name_len) @@ -259,7 +259,7 @@ def select_next(): def send_signal(signal, panel): - assert signal in ('terminate', 'kill', 'interrupt') + assert signal in {'terminate', 'kill', 'interrupt'} default = {'terminate': 0, 'kill': 1, 'interrupt': 2}.get(signal) processes = [] for process in panel.selection.processes(): diff --git a/nvitop/gui/library/selection.py b/nvitop/gui/library/selection.py index 609c439d..8d06d69d 100644 --- a/nvitop/gui/library/selection.py +++ b/nvitop/gui/library/selection.py @@ -107,7 +107,7 @@ def foreach(self, func): for process in self.processes(): try: func(process) - except host.PsutilError: + except host.PsutilError: # noqa: PERF203 pass else: flag = True @@ -122,9 +122,11 @@ def send_signal(self, sig): def interrupt(self): try: self.send_signal( - signal.SIGINT - if not host.WINDOWS - else signal.CTRL_C_EVENT, # pylint: disable=no-member + ( + signal.SIGINT + if not host.WINDOWS + else signal.CTRL_C_EVENT # pylint: disable=no-member + ), ) except SystemError: pass diff --git a/nvitop/gui/library/utils.py b/nvitop/gui/library/utils.py index 97bf8e6d..8d12ccac 100644 --- a/nvitop/gui/library/utils.py +++ b/nvitop/gui/library/utils.py @@ -16,7 +16,7 @@ def cut_string(s, maxlen, padstr='...', align='left'): - assert align in ('left', 'right') + assert align in {'left', 'right'} if not isinstance(s, str): s = str(s) diff --git a/nvitop/gui/screens/help.py b/nvitop/gui/screens/help.py index 75b2862f..c91fded2 100644 --- a/nvitop/gui/screens/help.py +++ b/nvitop/gui/screens/help.py @@ -65,9 +65,9 @@ def __init__(self, win, root): 14: ('cyan', 'red'), 15: (None, 'red'), 16: ('cyan', 'red'), - **{dy: ('cyan', 'green') for dy in range(17, 20)}, - **{dy: ('blue', 'blue') for dy in range(21, 23)}, - **{dy: ('blue', 'blue') for dy in range(24, 28)}, + **dict.fromkeys(range(17, 20), ('cyan', 'green')), + **dict.fromkeys(range(21, 23), ('blue', 'blue')), + **dict.fromkeys(range(24, 28), ('blue', 'blue')), 28: ('magenta', 'magenta'), } diff --git a/nvitop/gui/screens/main/__init__.py b/nvitop/gui/screens/main/__init__.py index c6c6f486..7c3567a0 100644 --- a/nvitop/gui/screens/main/__init__.py +++ b/nvitop/gui/screens/main/__init__.py @@ -25,7 +25,7 @@ def __init__(self, devices, filters, ascii, mode, win, root): self.width = root.width - assert mode in ('auto', 'full', 'compact') + assert mode in {'auto', 'full', 'compact'} compact = mode == 'compact' self.mode = mode self._compact = compact diff --git a/nvitop/gui/screens/main/process.py b/nvitop/gui/screens/main/process.py index e548f9eb..c27d1bea 100644 --- a/nvitop/gui/screens/main/process.py +++ b/nvitop/gui/screens/main/process.py @@ -175,8 +175,9 @@ def compact(self, value): self.need_redraw = True self._compact = value processes = self.snapshots - n_processes, n_devices = len(processes), len( - {p.device.physical_index for p in processes}, + n_processes, n_devices = ( + len(processes), + len({p.device.physical_index for p in processes}), ) self.full_height = 1 + max(6, 5 + n_processes + n_devices - 1) self.compact_height = 1 + max(6, 5 + n_processes) @@ -231,7 +232,7 @@ def snapshots(self, snapshots): self.height = height self.host_offset = max(-1, min(self.host_offset, info_length - self.width + 39)) - if old_host_offset not in (self.host_offset, LARGE_INTEGER): + if old_host_offset not in {self.host_offset, LARGE_INTEGER}: self.beep() if self.selection.is_set(): @@ -398,7 +399,7 @@ def draw(self): # pylint: disable=too-many-locals,too-many-branches,too-many-st column_width = len(column) reverse = xor(reverse, self.reverse) indicator = '▼' if reverse else '▲' - if self.order in ('cpu_percent', 'memory_percent', 'time'): + if self.order in {'cpu_percent', 'memory_percent', 'time'}: offset -= host_offset if self.order == 'time': offset += len(self.host_headers[-2]) - 4 diff --git a/nvitop/gui/ui.py b/nvitop/gui/ui.py index 16469350..0f34a542 100644 --- a/nvitop/gui/ui.py +++ b/nvitop/gui/ui.py @@ -190,14 +190,14 @@ def loop(self): if self.win is None: return - while True: - try: + try: + while True: self.redraw() self.handle_input() if time.monotonic() - self.last_input_time > 1.0: time.sleep(0.2) - except BreakLoop: - break + except BreakLoop: + pass def print(self): self.main_screen.print() diff --git a/nvitop/select.py b/nvitop/select.py index c215177f..7a84a11e 100644 --- a/nvitop/select.py +++ b/nvitop/select.py @@ -98,8 +98,7 @@ def select_devices( # pylint: disable=too-many-arguments free_accounts: list[str] | None, sort: bool, **kwargs: Any, -) -> list[int] | list[tuple[int, int]]: - ... +) -> list[int] | list[tuple[int, int]]: ... @overload @@ -118,8 +117,7 @@ def select_devices( # pylint: disable=too-many-arguments free_accounts: list[str] | None, sort: bool, **kwargs: Any, -) -> list[int] | list[tuple[int, int]]: - ... +) -> list[int] | list[tuple[int, int]]: ... @overload @@ -138,8 +136,7 @@ def select_devices( # pylint: disable=too-many-arguments free_accounts: list[str] | None, sort: bool, **kwargs: Any, -) -> list[Device]: - ... +) -> list[Device]: ... def select_devices( # pylint: disable=too-many-branches,too-many-statements,too-many-locals,unused-argument,too-many-arguments @@ -209,7 +206,7 @@ def select_devices( # pylint: disable=too-many-branches,too-many-statements,too Returns: A list of the device identifiers. """ - assert format in ('index', 'uuid', 'device') + assert format in {'index', 'uuid', 'device'} assert tolerance >= 0 tolerance = tolerance / 100.0 diff --git a/pyproject.toml b/pyproject.toml index 7deb153d..74f4eace 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,6 @@ Documentation = "https://nvitop.readthedocs.io" include = ["nvitop", "nvitop.*"] [tool.black] -safe = true line-length = 100 skip-string-normalization = true target-version = ["py37"] @@ -86,7 +85,7 @@ multi_line_output = 3 [tool.mypy] # Sync with requires-python -python_version = 3.8 # appease mypy for syntax errors in numpy stubs +python_version = "3.8" # appease mypy for syntax errors in numpy stubs mypy_path = [".", "nvitop-exporter"] exclude = ["nvitop-exporter/setup.py"] pretty = true @@ -122,8 +121,10 @@ ignore-words = "docs/source/spelling_wordlist.txt" # Sync with requires-python target-version = "py37" line-length = 100 -show-source = true +output-format = "full" src = ["nvitop", "nvitop-exporter/nvitop_exporter"] + +[tool.ruff.lint] select = [ "E", "W", # pycodestyle "F", # pyflakes @@ -136,7 +137,10 @@ select = [ "COM", # flake8-commas "C4", # flake8-comprehensions "EXE", # flake8-executable + "FA", # flake8-future-annotations + "LOG", # flake8-logging "ISC", # flake8-implicit-str-concat + "INP", # flake8-no-pep420 "PIE", # flake8-pie "PYI", # flake8-pyi "Q", # flake8-quotes @@ -144,6 +148,10 @@ select = [ "RET", # flake8-return "SIM", # flake8-simplify "TID", # flake8-tidy-imports + "TCH", # flake8-type-checking + "PERF", # perflint + "FURB", # refurb + "TRY", # tryceratops "RUF", # ruff ] ignore = [ @@ -164,9 +172,12 @@ ignore = [ # SIM105: use `contextlib.suppress(...)` instead of try-except-pass # reduce unnecessary function call "SIM105", + # TRY003: avoid specifying long messages outside the exception class + # long messages are necessary for clarity + "TRY003", ] -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "__init__.py" = [ "F401", # unused-import ] @@ -183,14 +194,17 @@ ignore = [ "ANN", # flake8-annotations "RUF012", # mutable-class-default ] +"docs/source/conf.py" = [ + "INP001", # flake8-no-pep420 +] -[tool.ruff.flake8-annotations] +[tool.ruff.lint.flake8-annotations] allow-star-arg-any = true -[tool.ruff.flake8-quotes] +[tool.ruff.lint.flake8-quotes] docstring-quotes = "double" multiline-quotes = "double" inline-quotes = "single" -[tool.ruff.flake8-tidy-imports] +[tool.ruff.lint.flake8-tidy-imports] ban-relative-imports = "all"