From 74295ca2aef4579253084b9d3f1ef485da0b7dc7 Mon Sep 17 00:00:00 2001 From: Xuehai Pan Date: Fri, 17 Feb 2023 10:06:39 +0000 Subject: [PATCH] feat(pre-commit): enable flake8 in pre-commit --- .flake8 | 30 +++++++++++++++++++++++++++++ .pre-commit-config.yaml | 20 ++++++++++++++++--- docs/source/spelling_wordlist.txt | 1 + nvitop/__init__.py | 2 +- nvitop/api/__init__.py | 2 +- nvitop/api/device.py | 9 ++++----- nvitop/api/host.py | 8 ++++---- nvitop/api/libcuda.py | 6 +++--- nvitop/api/libcudart.py | 6 +++--- nvitop/api/libnvml.py | 12 ++++++------ nvitop/api/process.py | 2 +- nvitop/api/utils.py | 2 +- nvitop/callbacks/lightning.py | 3 ++- nvitop/gui/library/displayable.py | 10 ++++------ nvitop/gui/library/keybinding.py | 16 ++++++++------- nvitop/gui/library/libcurses.py | 11 ++++++++--- nvitop/gui/library/messagebox.py | 14 +++++++------- nvitop/gui/library/utils.py | 2 +- nvitop/gui/screens/main/__init__.py | 2 +- nvitop/gui/screens/main/device.py | 2 +- nvitop/gui/screens/main/process.py | 6 +++--- nvitop/gui/screens/treeview.py | 6 ++---- nvitop/select.py | 4 ++-- setup.py | 2 +- 24 files changed, 113 insertions(+), 65 deletions(-) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..a992307 --- /dev/null +++ b/.flake8 @@ -0,0 +1,30 @@ +[flake8] +max-line-length = 120 +max-doc-length = 100 +select = B,C,E,F,W,Y,SIM +ignore = + # E203: whitespace before ':' + # E241: whitespace after ':' + # W503: line break before binary operator + # W504: line break after binary operator + # format by black + E203,E241,W503,W504, + # E501: line too long + # W505: doc line too long + # too long docstring due to long example blocks + E501,W505, + # SIM105: Use 'contextlib.suppress(...)' + # prefer try-except block + SIM105, +per-file-ignores = + # F401: module imported but unused + # intentionally unused imports + __init__.py: F401 +exclude = + .git, + .vscode, + venv, + __pycache__, + docs/source/conf.py, + build, + dist diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7401127..e9e44e9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,8 +3,8 @@ ci: skip: [pylint] autofix_prs: true - autofix_commit_msg: 'fix: [pre-commit.ci] auto fixes [...]' - autoupdate_commit_msg: 'chore(pre-commit): [pre-commit.ci] autoupdate' + autofix_commit_msg: "fix: [pre-commit.ci] auto fixes [...]" + autoupdate_commit_msg: "chore(pre-commit): [pre-commit.ci] autoupdate" repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 @@ -39,6 +39,20 @@ repos: - id: pyupgrade args: [--py36-plus] stages: [commit, push, manual] + - repo: https://github.com/pycqa/flake8 + rev: 6.0.0 + hooks: + - id: flake8 + additional_dependencies: + - flake8-bugbear + - flake8-comprehensions + - flake8-docstrings + - flake8-pyi + - flake8-simplify + exclude: | + (?x)( + ^docs/source/conf.py$ + ) - repo: local hooks: - id: pylint @@ -52,7 +66,7 @@ repos: rev: 6.3.0 hooks: - id: pydocstyle - additional_dependencies: ['.[toml]'] + additional_dependencies: [".[toml]"] exclude: | (?x)( ^nvitop/gui/| diff --git a/docs/source/spelling_wordlist.txt b/docs/source/spelling_wordlist.txt index 1616eb6..ba6dfcb 100644 --- a/docs/source/spelling_wordlist.txt +++ b/docs/source/spelling_wordlist.txt @@ -136,3 +136,4 @@ CLI submodule submodules namespace +noqa diff --git a/nvitop/__init__.py b/nvitop/__init__.py index 050c288..941ea20 100644 --- a/nvitop/__init__.py +++ b/nvitop/__init__.py @@ -19,7 +19,7 @@ import sys from nvitop import api -from nvitop.api import * +from nvitop.api import * # noqa: F403 from nvitop.api import collector, device, host, libcuda, libcudart, libnvml, process, utils from nvitop.select import select_devices from nvitop.version import __version__ diff --git a/nvitop/api/__init__.py b/nvitop/api/__init__.py index b64b84c..90c1901 100644 --- a/nvitop/api/__init__.py +++ b/nvitop/api/__init__.py @@ -29,7 +29,7 @@ from nvitop.api.device import ( ) from nvitop.api.libnvml import NVMLError, nvmlCheckReturn from nvitop.api.process import GpuProcess, HostProcess, command_join -from nvitop.api.utils import * +from nvitop.api.utils import * # noqa: F403 __all__ = [ diff --git a/nvitop/api/device.py b/nvitop/api/device.py index 478e6ca..72c8f6e 100644 --- a/nvitop/api/device.py +++ b/nvitop/api/device.py @@ -126,7 +126,7 @@ __all__ = [ 'normalize_cuda_visible_devices', ] -### Class definitions ############################################################################## +# Class definitions ################################################################################ class MemoryInfo(NamedTuple): # in bytes # pylint: disable=missing-class-docstring @@ -570,9 +570,8 @@ class Device: # pylint: disable=too-many-instance-attributes,too-many-public-me f'but index = {index!r} was given' ) return super().__new__(MigDevice) - elif uuid is not None: - if match is not None and match.group('MigMode') is not None: - return super().__new__(MigDevice) + elif uuid is not None and match is not None and match.group('MigMode') is not None: + return super().__new__(MigDevice) return super().__new__(PhysicalDevice) def __init__( @@ -2386,7 +2385,7 @@ def normalize_cuda_visible_devices(cuda_visible_devices: Optional[str] = _VALUE_ return ','.join(_parse_cuda_visible_devices(cuda_visible_devices, format='uuid')) -### Helper functions ############################################################################### +# Helper functions ################################################################################# _PhysicalDeviceAttrs = NamedTuple( 'PhysicalDeviceAttrs', diff --git a/nvitop/api/host.py b/nvitop/api/host.py index bd9f6cc..0c79f2e 100644 --- a/nvitop/api/host.py +++ b/nvitop/api/host.py @@ -24,7 +24,7 @@ import os as _os import psutil as _psutil from cachetools.func import ttl_cache as _ttl_cache -from psutil import * # pylint: disable=wildcard-import,unused-wildcard-import,redefined-builtin +from psutil import * # noqa: F403 # pylint: disable=wildcard-import,unused-wildcard-import,redefined-builtin __all__ = [name for name in _psutil.__all__ if not name.startswith('_')] + [ @@ -39,8 +39,8 @@ __all__ = [name for name in _psutil.__all__ if not name.startswith('_')] + [ __all__[__all__.index('Error')] = 'PsutilError' -PsutilError = Error # make alias -del Error # pylint: disable=undefined-variable +PsutilError = Error # make alias # noqa: F405 +del Error # noqa: F405,F821 # pylint: disable=undefined-variable cpu_percent = _ttl_cache(ttl=0.25)(_psutil.cpu_percent) @@ -83,7 +83,7 @@ def reverse_ppid_map(): # pylint: disable=function-redefined return tree -if LINUX: +if LINUX: # noqa: F405 WSL = _os.getenv('WSL_DISTRO_NAME', default=None) if WSL is not None and WSL == '': WSL = 'WSL' diff --git a/nvitop/api/libcuda.py b/nvitop/api/libcuda.py index c8805cd..8d4ac7f 100644 --- a/nvitop/api/libcuda.py +++ b/nvitop/api/libcuda.py @@ -38,7 +38,7 @@ _c_CUdevice_t = _ctypes.POINTER(_struct_c_CUdevice_t) _CUresult_t = _ctypes.c_uint -## Error codes ## +# Error codes # # pylint: disable=line-too-long CUDA_SUCCESS = 0 """The API call returned with no errors. In the case of query calls, this also means that the operation being queried is complete (see :func:`cuEventQuery` and :func:`cuStreamQuery`).""" @@ -211,7 +211,7 @@ CUDA_ERROR_UNKNOWN = 999 # pylint: enable=line-too-long -## Error Checking ## +# Error Checking # class CUDAError(Exception): """Base exception class for CUDA driver query errors.""" @@ -332,7 +332,7 @@ def _cudaCheckReturn(ret: _Any) -> _Any: return ret -## Function access ## +# Function access # __cudaLib = None __initialized = False __libLoadLock = _threading.Lock() diff --git a/nvitop/api/libcudart.py b/nvitop/api/libcudart.py index 1ac3fa9..65e6bbc 100644 --- a/nvitop/api/libcudart.py +++ b/nvitop/api/libcudart.py @@ -31,7 +31,7 @@ from typing import Type as _Type _cudaError_t = _ctypes.c_int -## Error codes ## +# Error codes # # pylint: disable=line-too-long cudaSuccess = 0 """The API call returned with no errors. In the case of query calls, this also means that the operation being queried is complete (see :func:`cudaEventQuery` and :func:`cudaStreamQuery`).""" @@ -262,7 +262,7 @@ cudaErrorUnknown = 999 # pylint: enable=line-too-long -## Error Checking ## +# Error Checking # class cudaError(Exception): """Base exception class for CUDA driver query errors.""" @@ -386,7 +386,7 @@ def _cudaCheckReturn(ret: _Any) -> _Any: return ret -## Function access ## +# Function access # __cudaLib = None __libLoadLock = _threading.Lock() # Function pointers are cached to prevent unnecessary libLoadLock locking diff --git a/nvitop/api/libnvml.py b/nvitop/api/libnvml.py index 1cc0a55..9d9ac80 100644 --- a/nvitop/api/libnvml.py +++ b/nvitop/api/libnvml.py @@ -39,7 +39,7 @@ from typing import Union as _Union # Python Bindings for the NVIDIA Management Library (NVML) # https://pypi.org/project/nvidia-ml-py import pynvml as _pynvml -from pynvml import * # pylint: disable=wildcard-import,unused-wildcard-import +from pynvml import * # noqa: F403 # pylint: disable=wildcard-import,unused-wildcard-import from nvitop.api.utils import NA from nvitop.api.utils import colored as __colored @@ -63,7 +63,7 @@ if not callable(getattr(_pynvml, 'nvmlInitWithFlags', None)): ) -### Members from `pynvml` ########################################################################## +# Members from `pynvml` ############################################################################ NVMLError = _pynvml.NVMLError NVMLError.__doc__ = """Base exception class for NVML query errors.""" @@ -174,7 +174,7 @@ NVMLError_NotSupported = _pynvml.NVMLError_NotSupported NVMLError_Unknown = _pynvml.NVMLError_Unknown # pylint: enable=no-member -### New members in `libnvml` ####################################################################### +# New members in `libnvml` ######################################################################### __flags = [] __initialized = False @@ -441,7 +441,7 @@ def __patch_backward_compatibility_layers() -> None: if __patched_backward_compatibility_layers: return - function_name_mapping_lock = _threading.Lock() + function_name_mapping_lock = _threading.Lock() # noqa: F405 function_name_mapping = {} def function_mapping_update(mapping): @@ -700,7 +700,7 @@ class _CustomModule(_ModuleType): except AttributeError: return getattr(_pynvml, name) - def __enter__(self) -> '_CustomModule': + def __enter__(self) -> '_CustomModule': # noqa: F405 """Entry of the context manager for ``with`` statement.""" _lazy_init() return self @@ -723,6 +723,6 @@ __modself.__class__ = _CustomModule del _CustomModule # Delete imported references -del _inspect, _logging, _os, _re, _sys, _threading +del _logging, _os, _re, _sys, _threading del _OrderedDict, _FunctionType, _ModuleType del _Tuple, _Callable, _Type, _Union, _Optional, _Any diff --git a/nvitop/api/process.py b/nvitop/api/process.py index 1f15834..1805b39 100644 --- a/nvitop/api/process.py +++ b/nvitop/api/process.py @@ -349,7 +349,7 @@ class HostProcess(host.Process, metaclass=ABCMeta): """ return self.memory_info().rss - def parent(self) -> Union['HostProcess', None]: + def parent(self) -> Optional['HostProcess']: """Return the parent process as a :class:`HostProcess` instance or :data:`None` if there is no parent. Raises: diff --git a/nvitop/api/utils.py b/nvitop/api/utils.py index a9b7456..3c222e0 100644 --- a/nvitop/api/utils.py +++ b/nvitop/api/utils.py @@ -702,7 +702,7 @@ def memoize_when_activated(method: Callable[[Any], Any]) -> Callable[[Any], Any] Expects an instance. Cache will be stored as a "_cache" instance attribute. """ if not hasattr(self, '_cache'): - setattr(self, '_cache', {}) + self._cache = {} # pylint: disable=protected-access def cache_deactivate(self): """Deactivate and clear cache.""" diff --git a/nvitop/callbacks/lightning.py b/nvitop/callbacks/lightning.py index 8a83323..58da1f9 100644 --- a/nvitop/callbacks/lightning.py +++ b/nvitop/callbacks/lightning.py @@ -17,4 +17,5 @@ # pylint: disable=missing-module-docstring -from nvitop.callbacks.pytorch_lightning import GpuStatsLogger # pylint: disable=unused-import +# pylint: disable-next=unused-import +from nvitop.callbacks.pytorch_lightning import GpuStatsLogger # noqa: F401 diff --git a/nvitop/gui/library/displayable.py b/nvitop/gui/library/displayable.py index 83e3541..78a8fa3 100644 --- a/nvitop/gui/library/displayable.py +++ b/nvitop/gui/library/displayable.py @@ -232,12 +232,10 @@ class DisplayableContainer(Displayable): if focused_obj and focused_obj.click(event): return True - for displayable in self.container: - if displayable.visible and event in displayable: - if displayable.click(event): - return True - - return False + return any( + displayable.visible and event in displayable and displayable.click(event) + for displayable in self.container + ) # new methods diff --git a/nvitop/gui/library/keybinding.py b/nvitop/gui/library/keybinding.py index 3aeba74..c3ba5ec 100644 --- a/nvitop/gui/library/keybinding.py +++ b/nvitop/gui/library/keybinding.py @@ -96,10 +96,10 @@ def _special_keys_init(): for n in range(64): SPECIAL_KEYS['F' + str(n)] = curses.KEY_F0 + n - SPECIAL_KEYS.update(VERY_SPECIAL_KEYS) + SPECIAL_KEYS.update(VERY_SPECIAL_KEYS) # noqa: F821 # Reorder the keys of SPECIAL_KEYS. - for key in NAMED_SPECIAL_KEYS: + for key in NAMED_SPECIAL_KEYS: # noqa: F821 SPECIAL_KEYS.move_to_end(key, last=True) for key, val in SPECIAL_KEYS.items(): @@ -129,8 +129,7 @@ def parse_keybinding(obj): # pylint: disable=too-many-branches """ assert isinstance(obj, (tuple, int, str)) if isinstance(obj, tuple): - for char in obj: - yield char + yield from obj elif isinstance(obj, int): # pylint: disable=too-many-nested-blocks yield obj else: # pylint: disable=too-many-nested-blocks @@ -325,9 +324,12 @@ class KeyBuffer: # pylint: disable=too-many-instance-attributes self.finished_parsing = False self.parse_error = False - if self.keymap and self.quantifier_key in self.keymap: - if self.keymap[self.quantifier_key] == 'false': - self.finished_parsing_quantifier = True + if ( + self.keymap + and self.quantifier_key in self.keymap + and self.keymap[self.quantifier_key] == 'false' + ): + self.finished_parsing_quantifier = True def clear(self): self.__init__(self.keymap) # pylint: disable=unnecessary-dunder-call diff --git a/nvitop/gui/library/libcurses.py b/nvitop/gui/library/libcurses.py index 22365da..e1c3e1d 100644 --- a/nvitop/gui/library/libcurses.py +++ b/nvitop/gui/library/libcurses.py @@ -261,9 +261,14 @@ class CursesShortcuts: for s in attr_strings: attr |= getattr(curses, f'A_{s.upper()}', 0) - if LIGHT_THEME: # tweak for light themes - if attr & curses.A_REVERSE != 0 and bg == -1 and fg not in (DEFAULT_FOREGROUND, -1): - bg = DEFAULT_FOREGROUND + # Tweak for light themes + if ( + LIGHT_THEME + and attr & curses.A_REVERSE != 0 + and bg == -1 + and fg not in (DEFAULT_FOREGROUND, -1) + ): + bg = DEFAULT_FOREGROUND if fg == -1 and bg == -1: return attr | BASE_ATTR diff --git a/nvitop/gui/library/messagebox.py b/nvitop/gui/library/messagebox.py index c7e7869..bae30ef 100644 --- a/nvitop/gui/library/messagebox.py +++ b/nvitop/gui/library/messagebox.py @@ -287,8 +287,8 @@ def send_signal(signal, panel): panel.selection.terminate, keys=('T',), attrs=( - dict(y=0, x=0, width=7, fg='red'), - dict(y=0, x=3, width=1, fg='red', attr='bold | underline'), + {'y': 0, 'x': 0, 'width': 7, 'fg': 'red'}, + {'y': 0, 'x': 3, 'width': 1, 'fg': 'red', 'attr': 'bold | underline'}, ), ), MessageBox.Option( @@ -297,8 +297,8 @@ def send_signal(signal, panel): panel.selection.kill, keys=('K',), attrs=( - dict(y=0, x=0, width=7, fg='red'), - dict(y=0, x=3, width=1, fg='red', attr='bold | underline'), + {'y': 0, 'x': 0, 'width': 7, 'fg': 'red'}, + {'y': 0, 'x': 3, 'width': 1, 'fg': 'red', 'attr': 'bold | underline'}, ), ), MessageBox.Option( @@ -307,8 +307,8 @@ def send_signal(signal, panel): panel.selection.interrupt, keys=('I',), attrs=( - dict(y=0, x=0, width=6, fg='red'), - dict(y=0, x=3, width=1, fg='red', attr='bold | underline'), + {'y': 0, 'x': 0, 'width': 6, 'fg': 'red'}, + {'y': 0, 'x': 3, 'width': 1, 'fg': 'red', 'attr': 'bold | underline'}, ), ), MessageBox.Option( @@ -316,7 +316,7 @@ def send_signal(signal, panel): 'c', None, keys=('C',), - attrs=(dict(y=0, x=0, width=1, attr='bold | underline'),), + attrs=({'y': 0, 'x': 0, 'width': 1, 'attr': 'bold | underline'},), ), ], default=default, diff --git a/nvitop/gui/library/utils.py b/nvitop/gui/library/utils.py index 6b49817..150939b 100644 --- a/nvitop/gui/library/utils.py +++ b/nvitop/gui/library/utils.py @@ -8,7 +8,7 @@ import math import os import platform -from nvitop.api import NA, colored, host, set_color # pylint: disable=unused-import +from nvitop.api import NA, colored, host, set_color # noqa: F401 # pylint: disable=unused-import from nvitop.gui.library.widestring import WideString diff --git a/nvitop/gui/screens/main/__init__.py b/nvitop/gui/screens/main/__init__.py index 250cbdc..e6bd807 100644 --- a/nvitop/gui/screens/main/__init__.py +++ b/nvitop/gui/screens/main/__init__.py @@ -145,7 +145,7 @@ class MainScreen(DisplayableContainer): # pylint: disable=too-many-instance-att def print(self): if self.device_count > 0: - print_width = min(map(lambda panel: panel.print_width(), self.container)) + print_width = min(panel.print_width() for panel in self.container) self.width = max(print_width, min(self.width, 100)) else: self.width = 79 diff --git a/nvitop/gui/screens/main/device.py b/nvitop/gui/screens/main/device.py index 8b86a88..1a8ddd8 100644 --- a/nvitop/gui/screens/main/device.py +++ b/nvitop/gui/screens/main/device.py @@ -410,7 +410,7 @@ class DevicePanel(Displayable): # pylint: disable=too-many-instance-attributes def colorize(s): if len(s) > 0: # pylint: disable-next=cell-var-from-loop - return colored(s, device.display_color) + return colored(s, device.display_color) # noqa: B023 return '' fmts = self.mig_formats if device.is_mig_device else self.formats_full diff --git a/nvitop/gui/screens/main/process.py b/nvitop/gui/screens/main/process.py index 17d8c1b..3ab199d 100644 --- a/nvitop/gui/screens/main/process.py +++ b/nvitop/gui/screens/main/process.py @@ -313,7 +313,7 @@ class ProcessPanel(Displayable): # pylint: disable=too-many-instance-attributes self.selection.within_window = False if len(self.snapshots) > 0 and self.selection.is_set(): - y = self.y + 5 + y = self.y + 5 # noqa: SIM113 prev_device_index = None for process in self.snapshots: device_index = process.device.physical_index @@ -426,7 +426,7 @@ class ProcessPanel(Displayable): # pylint: disable=too-many-instance-attributes self.selection.within_window = False if len(self.snapshots) > 0: - y = self.y + 5 + y = self.y + 5 # noqa: SIM113 prev_device_index = None prev_device_display_index = None color = -1 @@ -589,7 +589,7 @@ class ProcessPanel(Displayable): # pylint: disable=too-many-instance-attributes if process.is_zombie or process.no_permissions or process.is_gone: info = info.split(process.command) if process.username != USERNAME and not SUPERUSER: - info = map(lambda item: colored(item, attrs=('dark',)), info) + info = (colored(item, attrs=('dark',)) for item in info) info = colored( process.command, color=('red' if process.is_gone else 'yellow') ).join(info) diff --git a/nvitop/gui/screens/treeview.py b/nvitop/gui/screens/treeview.py index d54c282..f07af72 100644 --- a/nvitop/gui/screens/treeview.py +++ b/nvitop/gui/screens/treeview.py @@ -310,10 +310,8 @@ class TreeViewScreen(Displayable): # pylint: disable=too-many-instance-attribut snapshot.prefix = node.prefix if len(node.devices) > 0: snapshot.devices = 'GPU ' + ','.join( - map( - lambda device: device.display_index, - sorted(node.devices, key=lambda device: device.tuple_index), - ) + dev.display_index + for dev in sorted(node.devices, key=lambda device: device.tuple_index) ) else: snapshot.devices = 'Host' diff --git a/nvitop/select.py b/nvitop/select.py index 4ecced8..76418d8 100644 --- a/nvitop/select.py +++ b/nvitop/select.py @@ -165,7 +165,7 @@ def select_devices( available_devices = [] # type: Iterable[DeviceSnapshot] for device in devices: - available_devices.extend(map(lambda device: device.as_snapshot(), device.to_leaf_devices())) + available_devices.extend(dev.as_snapshot() for dev in device.to_leaf_devices()) for device in available_devices: device.loosen_constraints = 0 @@ -528,7 +528,7 @@ def main(): retval = 0 if len(identifiers) < args.min_count: - warnings.warn('Not enough devices found.', RuntimeWarning) + warnings.warn('Not enough devices found.', RuntimeWarning, stacklevel=1) retval = 4 if args.sep == '\0': diff --git a/setup.py b/setup.py index 253465b..eab8a39 100755 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ try: VERSION_FILE.write_text( data=re.sub( r"""__version__\s*=\s*('[^']+'|"[^"]+")""", - f"__version__ = '{version.__version__}'", + f'__version__ = {version.__version__!r}', string=VERSION_CONTENT, ), encoding='UTF-8',