diff --git a/.pylintrc b/.pylintrc index 59a5f62..2eb4dd7 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,21 +1,4 @@ +# Disable all categories since we're running ruff instead, but VSCode insists on +# invoking pylint all the time [MESSAGES CONTROL] -disable= - consider-using-max-builtin, - disallowed-name, - fixme, - global-statement, - invalid-name, - line-too-long, - missing-class-docstring, - missing-function-docstring, - missing-module-docstring, - protected-access, # Used a lot in tests, maybe make this tests-specific? - too-few-public-methods, - too-many-arguments, - too-many-branches, - too-many-instance-attributes, - too-many-locals, - too-many-return-statements, - too-many-statements, - wrong-import-order, - wrong-import-position, +disable=E,W,R,C,F diff --git a/devbin/benchmark_ipcmap.py b/devbin/benchmark_ipcmap.py index 1640681..e08b0dc 100755 --- a/devbin/benchmark_ipcmap.py +++ b/devbin/benchmark_ipcmap.py @@ -21,8 +21,8 @@ MYDIR = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.join(MYDIR, "..")) -from tests import testutils -from px import px_file +from tests import testutils # noqa: E402 +from px import px_file # noqa: E402 # For how long should we do the benchmarking run (in seconds) diff --git a/devbin/benchmark_proc_get_all.py b/devbin/benchmark_proc_get_all.py index c72b90d..9d2bfc4 100755 --- a/devbin/benchmark_proc_get_all.py +++ b/devbin/benchmark_proc_get_all.py @@ -14,7 +14,7 @@ MYDIR = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.join(MYDIR, "..")) -from px import px_process +from px import px_process # noqa: E402 LAPS = 20 diff --git a/px/px.py b/px/px.py index a09a4c3..3eb85b0 100644 --- a/px/px.py +++ b/px/px.py @@ -98,7 +98,7 @@ def main(): try: _main(argv) - except Exception: # pylint: disable=broad-except + except Exception: LOG = logging.getLogger(__name__) LOG.exception("Uncaught Exception") @@ -139,7 +139,7 @@ def handleLogMessages(messages: Optional[str]) -> None: # even if we don't use it. And this will make test avoidance fail to avoid # px.py tests every time you make a new commit (because committing recreates # version.py). - from . import version # pylint: disable=import-outside-toplevel + from . import version sys.stderr.write("px version: " + version.VERSION + "\n") @@ -168,7 +168,7 @@ def _main(argv: List[str]) -> None: # NOTE: If we "import version" at the top of this file, we will depend on it even if # we don't use it. And this will make test avoidance fail to avoid px.py tests every # time you make a new commit (because committing recreates version.py). - from . import version # pylint: disable=import-outside-toplevel + from . import version print(version.VERSION) return @@ -236,14 +236,14 @@ def _main(argv: List[str]) -> None: if top: # Pulling px_top in on demand like this improves test result caching - from . import px_top # pylint: disable=import-outside-toplevel + from . import px_top px_top.top(search=search) return if tree: # Pulling px_tree in on demand like this improves test result caching - from . import px_tree # pylint: disable=import-outside-toplevel + from . import px_tree px_tree.tree(search=search) return diff --git a/px/px_cpuinfo.py b/px/px_cpuinfo.py index ad8c7c5..a0f8b11 100644 --- a/px/px_cpuinfo.py +++ b/px/px_cpuinfo.py @@ -93,7 +93,6 @@ def get_core_count_from_sysctl() -> Optional[Tuple[int, int]]: def parse_sysctl_output( sysctl_lines: List[str], ) -> Tuple[Optional[int], Optional[int]]: - # Note the ending spaces, they must be there for number extraction to work! PHYSICAL_PREFIX = "hw.physicalcpu: " LOGICAL_PREFIX = "hw.logicalcpu: " diff --git a/px/px_cwdfriends.py b/px/px_cwdfriends.py index dd0b55a..5a46c0c 100644 --- a/px/px_cwdfriends.py +++ b/px/px_cwdfriends.py @@ -19,7 +19,6 @@ def __init__( all_processes: List[px_process.PxProcess], all_files: List[px_file.PxFile], ) -> None: - pid_to_process: Dict[int, px_process.PxProcess] = {} for p in all_processes: pid_to_process[p.pid] = p diff --git a/px/px_file.py b/px/px_file.py index e2d7463..f78ac21 100644 --- a/px/px_file.py +++ b/px/px_file.py @@ -177,7 +177,7 @@ def resolve_endpoint(endpoint: str) -> str: try: host = socket.gethostbyaddr(address)[0] - except Exception: # pylint: disable=broad-except + except Exception: # Lookup failed for whatever reason, give up # # Catching "Exception" because I am (on 2022may27) unable to figure out diff --git a/px/px_install.py b/px/px_install.py index fb66e97..4e42099 100644 --- a/px/px_install.py +++ b/px/px_install.py @@ -12,7 +12,7 @@ def install(src, dest): """ try: _install(src, dest) - except Exception as e: # pylint: disable=broad-except + except Exception as e: sys.stderr.write(f"Installing {dest} failed, please retry with sudo\n") sys.stderr.write(f"Error was: {str(e)}\n") sys.exit(1) diff --git a/px/px_ioload.py b/px/px_ioload.py index 1760873..b3e80a3 100644 --- a/px/px_ioload.py +++ b/px/px_ioload.py @@ -159,7 +159,6 @@ def parse_proc_diskstats(proc_diskstats_contents: str) -> List[Sample]: class SubsystemStat: def __init__(self, throughput: float, high_watermark: float) -> None: - if throughput > high_watermark: raise ValueError( f"High watermark {high_watermark} lower than throughput {throughput}" @@ -247,7 +246,6 @@ def update_baseline_from_system(self, system_state: SystemState) -> None: del self.baseline[remove_me] def update(self) -> None: - self.previous_system_state = self.most_recent_system_state self.most_recent_system_state = SystemState() self.update_baseline_from_system(self.most_recent_system_state) @@ -342,7 +340,6 @@ def get_load_string(self) -> str: math.trunc(bottleneck[1]), math.trunc(bottleneck[2]) ) - # pylint: disable=consider-using-f-string return "[{} / {}] {}".format( px_terminal.bold(current_throughput + "/s"), max_throughput + "/s", diff --git a/px/px_ipc_map.py b/px/px_ipc_map.py index 0683455..bc81485 100644 --- a/px/px_ipc_map.py +++ b/px/px_ipc_map.py @@ -39,7 +39,6 @@ def __str__(self): class IpcMap: - # pylint: disable=attribute-defined-outside-init """ This is a map of process->[channels], where "process" is a process we have IPC communication open with, and a channel is a socket or a pipe that we @@ -59,7 +58,6 @@ def __init__( processes: Iterable[px_process.PxProcess], is_root: bool, ) -> None: - # On Linux, lsof reports the same open file once per thread of a # process. Putting the files in a set gives us each file only once. files = set(files) @@ -130,7 +128,7 @@ def _create_fds(self, is_root: bool) -> Dict[int, str]: fds[network_connection.fd] = str(network_connection) # Traverse our IPC structure and update FDs as required - for target in self.keys(): # pylint: disable=consider-using-dict-items + for target in self.keys(): for link in self[target]: if link.fd is None: # No FD, never mind diff --git a/px/px_launchcounter.py b/px/px_launchcounter.py index af6c816..610588a 100644 --- a/px/px_launchcounter.py +++ b/px/px_launchcounter.py @@ -98,7 +98,6 @@ def _merge_tuple_lists( def _callchain(process: px_process.PxProcess) -> Tuple[str, ...]: - reverse_callchain: List[str] = [] current: Optional[px_process.PxProcess] = process @@ -125,7 +124,6 @@ def _register_launches(self, new_processes: List[px_process.PxProcess]) -> None: self._hierarchies[callchain] = 1 def update(self, procs_snapshot: List[px_process.PxProcess]) -> None: - if self._last_processlist is None: self._last_processlist = procs_snapshot return @@ -155,7 +153,6 @@ def _coalesce_launchers(self) -> List[List[Tuple[str, int]]]: return coalesced def get_screen_lines(self) -> List[str]: - launchers_list = self._coalesce_launchers() launchers_list = sort_launchers_list(launchers_list) diff --git a/px/px_loginhistory.py b/px/px_loginhistory.py index 37d99b3..1fe5379 100644 --- a/px/px_loginhistory.py +++ b/px/px_loginhistory.py @@ -106,7 +106,7 @@ def get_users_at( from_timestamp = _to_timestamp(from_s, now) if timestamp < from_timestamp: continue - except Exception: # pylint: disable=broad-except + except Exception: LOG.error("Problematic1 last line: <%s>", line) continue @@ -120,7 +120,7 @@ def get_users_at( to_timestamp = from_timestamp + duration_delta if timestamp > to_timestamp: continue - except Exception: # pylint: disable=broad-except + except Exception: LOG.error("Problematic2 last line: <%s>", line) users.add(username) diff --git a/px/px_meminfo.py b/px/px_meminfo.py index 8dfd4d2..b48c657 100644 --- a/px/px_meminfo.py +++ b/px/px_meminfo.py @@ -20,7 +20,6 @@ def get_meminfo() -> str: - total_ram_bytes, wanted_ram_bytes = _get_ram_numbers() percentage = (100.0 * wanted_ram_bytes) / total_ram_bytes @@ -82,7 +81,6 @@ def _update_from_meminfo(base: Optional[int], line: str, name: str) -> Optional[ def _get_ram_numbers_from_proc( proc_meminfo: str = "/proc/meminfo", ) -> Optional[Tuple[int, int]]: - total_kb: Optional[int] = None available_kb: Optional[int] = None free_kb: Optional[int] = None @@ -188,7 +186,6 @@ def _update_if_prefix(base: Optional[int], line: str, prefix: str) -> Optional[i def _get_ram_numbers_from_vm_stat_output( vm_stat_lines: List[str], ) -> Optional[Tuple[int, int]]: - # List based on https://apple.stackexchange.com/a/196925/182882 page_size_bytes = None pages_free = None diff --git a/px/px_pager.py b/px/px_pager.py index a4466f0..f72296f 100644 --- a/px/px_pager.py +++ b/px/px_pager.py @@ -36,7 +36,7 @@ def _pump_info_to_fd(with_fileno, process, processes): LOG.warning( "Unexpected OSError pumping process info into pager", exc_info=True ) - except Exception: # pylint: disable=broad-except + except Exception: # Logging exceptions on warning level will make them visible to somebody # who changes the LOGLEVEL in px.py, but not to ordinary users. # @@ -117,7 +117,6 @@ def launch_pager(): def page_process_info( process: px_process.PxProcess, processes: List[px_process.PxProcess] ) -> None: - pager = launch_pager() pager_stdin = pager.stdin assert pager_stdin is not None @@ -130,7 +129,7 @@ def page_process_info( # Terminating ptop while this is running is fine. This is deprecated since # Python 3.10, but we want to support older Pythons as well so let's keep it # this way for now. - info_thread.setDaemon(True) # pylint: disable=deprecated-method + info_thread.setDaemon(True) info_thread.start() diff --git a/px/px_process.py b/px/px_process.py index 0a76f4b..8d8bf69 100644 --- a/px/px_process.py +++ b/px/px_process.py @@ -81,7 +81,6 @@ def _parse_time(time_s: str) -> datetime.datetime: class PxProcess: - # pylint: disable=attribute-defined-outside-init def __init__( self, cmdline: str, @@ -254,7 +253,6 @@ def __init__(self): self.memory_percent: Optional[float] = None def __repr__(self): - # pylint: disable=consider-using-f-string return ( "start_time_string=%r pid=%r ppid=%r user=%r cpu%%=%r cputime=%r mem%%=%r cmd=<%r>" % ( diff --git a/px/px_processinfo.py b/px/px_processinfo.py index 6035ee3..2a971ec 100644 --- a/px/px_processinfo.py +++ b/px/px_processinfo.py @@ -194,7 +194,6 @@ def print_users_when_process_started(fd: int, process: px_process.PxProcess) -> def to_ipc_lines(ipc_map: px_ipc_map.IpcMap) -> Iterable[str]: - return_me = [] for target in sorted(ipc_map.keys(), key=operator.attrgetter("name", "pid")): channels = ipc_map[target] @@ -234,7 +233,6 @@ def print_cwd_friends(fd, process, all_processes, all_files): def print_fds( fd: int, process: px_process.PxProcess, processes: Iterable[px_process.PxProcess] ) -> None: - # It's true, I measured it myself /johan.walles@gmail.com println( fd, @@ -299,7 +297,6 @@ def print_fds( def print_start_time(fd: int, process: px_process.PxProcess) -> None: - # pylint: disable=consider-using-f-string println( fd, "{} {} was started by {}, at {}.".format( @@ -312,7 +309,6 @@ def print_start_time(fd: int, process: px_process.PxProcess) -> None: if process.cpu_time_seconds and process.age_seconds: cpu_percent = 100.0 * process.cpu_time_seconds / process.age_seconds - # pylint: disable=consider-using-f-string println( fd, "{} has been its average CPU usage since then, or {}/{}".format( diff --git a/px/px_top.py b/px/px_top.py index 2329466..d8dfeb4 100644 --- a/px/px_top.py +++ b/px/px_top.py @@ -516,7 +516,6 @@ def get_command(**kwargs): def _top(search: str = "") -> None: - global search_string search_string = search @@ -554,7 +553,6 @@ def _top(search: str = "") -> None: def top(search: str = "") -> None: - if not sys.stdout.isatty(): sys.stderr.write( 'Top mode only works on TTYs, try running just "px" instead.\n' @@ -564,7 +562,7 @@ def top(search: str = "") -> None: with px_terminal.fullscreen_display(): try: _top(search=search) - except Exception: # pylint: disable=broad-except + except Exception: LOG.exception("Running ptop failed") # Make sure we actually end up on a new line diff --git a/setup.py b/setup.py index e8fd904..b5a3f21 100755 --- a/setup.py +++ b/setup.py @@ -85,7 +85,7 @@ "ptop = px.px:main", "pxtree = px.px:main", ], - } + }, # Note that we're by design *not* installing man pages here. # Using "data_files=" only puts the man pages in the egg file, # and installing that egg doesn't put them on the destination diff --git a/tests/px_exec_util_test.py b/tests/px_exec_util_test.py index 4f7ded0..55f37bf 100644 --- a/tests/px_exec_util_test.py +++ b/tests/px_exec_util_test.py @@ -14,10 +14,7 @@ def test_exec_true_with_check(): def test_exec_false_with_check(): try: px_exec_util.run(["false"], check_exitcode=True) - assert ( - False # pylint: disable=condition-evals-to-constant - and "We should never get here" - ) + assert False and "We should never get here" except subprocess.CalledProcessError: # This is the exception we want, done! pass diff --git a/tests/px_loginhistory_test.py b/tests/px_loginhistory_test.py index c1c0436..4e18533 100644 --- a/tests/px_loginhistory_test.py +++ b/tests/px_loginhistory_test.py @@ -9,8 +9,6 @@ # These warnings conflict with how pytest fixtures work: # https://docs.pytest.org/en/6.2.x/fixture.html -# -# pylint: disable=redefined-outer-name,unused-argument @pytest.fixture diff --git a/tox.ini b/tox.ini index c7f52ce..44c2eb8 100644 --- a/tox.ini +++ b/tox.ini @@ -6,14 +6,14 @@ minversion = 3.8.0 mypy_version = 1.2.0 -pylint_version = 2.13.9 +ruff_version = 0.1.3 pytest_version = 7.1.3 envlist= version.py - black + ruff-format mypy - pylint + ruff-check shellcheck installtest pytest @@ -30,21 +30,18 @@ commands = # This creates px/version.py /bin/bash -c './setup.py check' -[testenv:black] +[testenv:ruff-format] deps = - black==22.3.0 + ruff=={[tox]ruff_version} # Format locally, check in CI and fail on not-formatted code -# -# --target-version value taken to match whatever Python flavor ships with the -# Ubuntu version named in tox runs-on in linux-ci.yml. -commands = /bin/bash -c 'if [ "{env:CI:}" ] ; then export CHECK="--check --diff --color" ; fi ; black --target-version=py38 $CHECK ./*.py ./*/*.py' +commands = /bin/bash -c 'if [ "{env:CI:}" ] ; then export CHECK="--check --diff" ; fi ; ruff format $CHECK ./*.py ./*/*.py' [testenv:mypy] -# NOTE: In theory mypy should probably depend on Black to get line numbers in -# any error messages right. But since mypy tends to finish last, and being a bit -# off isn't the end of the world, let's not depend on Black for now and hope -# nobody notices. +# NOTE: In theory mypy should probably depend on ruff-format to get line numbers +# in any error messages right. But since mypy tends to finish last, and being a +# bit off isn't the end of the world, let's not depend on ruff-format for now +# and hope nobody notices. depends = version.py deps = @@ -55,15 +52,15 @@ deps = commands = /bin/bash -c 'mypy --pretty ./*.py ./*/*.py' -[testenv:pylint] -depends = version.py, black +[testenv:ruff-check] +depends = version.py, ruff-format deps = - pylint=={[tox]pylint_version} + ruff=={[tox]ruff_version} pytest=={[tox]pytest_version} -r requirements.txt commands = - /bin/bash -c 'pylint ./*.py ./*/*.py' + /bin/bash -c 'ruff check ./*.py ./*/*.py' [testenv:shellcheck] commands = @@ -75,7 +72,7 @@ commands = {toxinidir}/tests/installtest.sh [testenv:pytest] -depends = version.py black +depends = version.py ruff-format deps = pytest == {[tox]pytest_version} pytest-avoidance == 0.3.0 @@ -85,7 +82,7 @@ commands = [testenv:package] # Create {toxinidir}/px.pex -depends = version.py black +depends = version.py ruff-format allowlist_externals = {toxinidir}/devbin/make-executable-zip.sh deps = # Used by the make-executable-zip.sh script @@ -108,7 +105,7 @@ commands = [testenv:test-wheel] # Test installing using pip -depends = version.py black +depends = version.py ruff-format allowlist_externals = /bin/bash /bin/rm