Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.2
hooks:
- id: ruff
- id: ruff-check
- id: ruff-format

- repo: https://github.com/gitleaks/gitleaks
Expand Down
4 changes: 0 additions & 4 deletions doc/source/abstract_method.rst

This file was deleted.

1 change: 0 additions & 1 deletion doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ shell-logger

shell_logger
shell
abstract_method
stats_collector
trace_collector
html_utilities
Expand Down
44 changes: 42 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,32 +67,62 @@ line-length = 79
[tool.ruff.lint]
extend-select = [
"A",
"AIR",
# "ANN",
"ARG",
"ASYNC",
"B",
"BLE",
"C4",
"C90",
"D",
"DJ",
# "DTZ",
"E",
"EM",
"ERA",
"EXE",
"F",
"FA",
"FBT",
"FIX",
"FLY",
"FURB",
"G",
"I",
"ICN",
"INP",
"INT",
"ISC",
"LOG",
"N",
"NPY",
"PD",
"PERF",
"PGH",
"PIE",
"PL",
"PT",
"PTH",
"PYI",
"Q",
"RET",
"RSE",
"RUF",
# "S",
"SIM",
"SLF",
"SLOT",
"T10",
"T20",
"TC",
"TD",
"TID",
"TCH",
"TRY",
# "UP",
"UP",
"W",
"YTT",
]
ignore = [
"D212",
Expand All @@ -106,14 +136,24 @@ extend-allowed-calls = [


[tool.ruff.lint.per-file-ignores]
"**/test_*.py" = ["S101"]
"**/test_*.py" = [
"S101",
"SLF001",
"T201",
]
"doc/source/conf.py" = ["INP001"]
"example/*.py" = ["T201"]
"html_utilities.py" = ["PLR2004"]


[tool.ruff.lint.pydocstyle]
convention = "google"


[tool.ruff.lint.pyupgrade]
keep-runtime-typing = true



[tool.semantic_release]
build_command = "python3 -m pip install poetry && poetry build"
Expand Down
31 changes: 0 additions & 31 deletions shell_logger/abstract_method.py

This file was deleted.

6 changes: 3 additions & 3 deletions shell_logger/html_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
import pkgutil
import re
import textwrap
from collections.abc import Iterable, Mapping
from collections.abc import Iterable, Iterator, Mapping
from datetime import datetime
from pathlib import Path
from types import SimpleNamespace
from typing import Iterator, TextIO, Union
from typing import TextIO, Union


def nested_simplenamespace_to_dict(
Expand Down Expand Up @@ -851,7 +851,7 @@ def sgr_4bit_color_and_style_to_html(sgr: str) -> str:
"39": "color: inherit;",
"49": "background-color: inherit;",
}
return f'<span style="{sgr_to_css.get(sgr) or str()}">'
return f'<span style="{sgr_to_css.get(sgr) or ""}">'


def sgr_8bit_color_to_html(sgr_params: list[str]) -> str: # noqa: PLR0911
Expand Down
9 changes: 4 additions & 5 deletions shell_logger/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from types import SimpleNamespace
from typing import IO, Optional, TextIO


END_OF_READ = 4


Expand Down Expand Up @@ -118,7 +117,7 @@ def __del__(self) -> None:
]:
try:
os.close(fd)
except OSError as e:
except OSError as e: # noqa: PERF203
if "Bad file descriptor" not in e.strerror:
raise

Expand Down Expand Up @@ -185,12 +184,12 @@ def run(self, command: str, **kwargs) -> SimpleNamespace:

# Set the `RET_CODE` environment variable, such that we can
# access it later.
os.write(self.aux_stdin_wfd, "RET_CODE=$?\n".encode())
os.write(self.aux_stdin_wfd, b"RET_CODE=$?\n")

# Because these writes are non-blocking, tell the shell that the
# writes are complete.
os.write(self.aux_stdin_wfd, "printf '\\4'\n".encode())
os.write(self.aux_stdin_wfd, "printf '\\4' 1>&2\n".encode())
os.write(self.aux_stdin_wfd, b"printf '\\4'\n")
os.write(self.aux_stdin_wfd, b"printf '\\4' 1>&2\n")

# Tee the output to multiple sinks (files, strings,
# `stdout`/`stderr`).
Expand Down
14 changes: 7 additions & 7 deletions shell_logger/shell_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
import shutil
import string
import tempfile
from collections.abc import Iterable, Mapping
from collections.abc import Iterable, Iterator, Mapping
from datetime import datetime, timedelta
from distutils import dir_util
from pathlib import Path
from tempfile import NamedTemporaryFile
from types import SimpleNamespace
from typing import Iterator, Optional, Union
from typing import Optional, Union

from .html_utilities import (
append_html,
Expand Down Expand Up @@ -248,7 +248,7 @@
"""
self.done_time = datetime.now()

def __update_duration(self) -> None:
def update_duration(self) -> None:
"""
Update the :attr:`duration` attribute.

Expand Down Expand Up @@ -385,7 +385,7 @@
msg: The message to print and save to the log.
end: The string appended after the message:
"""
print(msg, end=end)
print(msg, end=end) # noqa: T201
log = {"msg": msg, "timestamp": str(datetime.now()), "cmd": None}
self.log_book.append(log)

Expand Down Expand Up @@ -427,7 +427,7 @@
if isinstance(log, ShellLogger):
# Update the duration of this ShellLogger's commands.
if log.duration is None:
log.__update_duration()
log.update_duration()
html.append(child_logger_card(log))

# Otherwise, if this is a message being logged...
Expand Down Expand Up @@ -559,7 +559,7 @@
# Print the command to be executed.
with stdout_path.open("a"), stderr_path.open("a"):
if verbose:
print(cmd)
print(cmd) # noqa: T201

Check warning on line 562 in shell_logger/shell_logger.py

View check run for this annotation

Codecov / codecov/patch

shell_logger/shell_logger.py#L562

Added line #L562 was not covered by tests

# Initialize the log information.
log = {
Expand Down Expand Up @@ -737,7 +737,7 @@
"""
if isinstance(obj, ShellLogger):
return {
**{"__type__": "ShellLogger"},
"__type__": "ShellLogger",
**{k: self.default(v) for k, v in obj.__dict__.items()},
}
if isinstance(obj, (int, float, str, bytes)):
Expand Down
24 changes: 6 additions & 18 deletions shell_logger/stats_collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
from time import sleep, time
from typing import TYPE_CHECKING

from .abstract_method import AbstractMethod

if TYPE_CHECKING:
from multiprocessing.managers import SyncManager

Expand All @@ -41,14 +39,15 @@ def stats_collectors(**kwargs) -> list[StatsCollector]:
Returns:
A collection of instances of :class:`StatsCollector` subclasses.
"""
collectors = []
if "measure" in kwargs:
interval = kwargs.get("interval", 1.0)
manager = Manager()
for collector in StatsCollector.subclasses:
if collector.stat_name in kwargs["measure"]:
collectors.append(collector(interval, manager))
return collectors
return [
collector(interval, manager)
for collector in StatsCollector.subclasses
if collector.stat_name in kwargs["measure"]
]
return []


class StatsCollector:
Expand Down Expand Up @@ -117,11 +116,7 @@ def collect(self):
Instantaneously collect a statistic.

This is meant to be called repeatedly after some time interval.

Raises:
AbstractMethod: This must be overridden by subclasses.
"""
raise AbstractMethod

@abstractmethod
def unproxied_stats(self):
Expand All @@ -130,11 +125,7 @@ def unproxied_stats(self):

Convert from Python's Manager's data structures to base Python
data structures.

Raises:
AbstractMethod: This must be overridden by subclasses.
"""
raise AbstractMethod

def finish(self):
"""
Expand Down Expand Up @@ -317,7 +308,6 @@ def __init__(self, interval: float, manager: SyncManager) -> None:

def collect(self) -> None:
"""Don't collect any disk statistics."""
pass

def unproxied_stats(self) -> None:
"""
Expand Down Expand Up @@ -352,7 +342,6 @@ def __init__(self, interval: float, manager: SyncManager) -> None:

def collect(self) -> None:
"""Don't collect any CPU statistics."""
pass

def unproxied_stats(self) -> None:
"""
Expand Down Expand Up @@ -387,7 +376,6 @@ def __init__(self, interval: float, manager: SyncManager) -> None:

def collect(self) -> None:
"""Don't collect any memory statistics."""
pass

def unproxied_stats(self) -> None:
"""
Expand Down
6 changes: 0 additions & 6 deletions shell_logger/trace_collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
from abc import abstractmethod
from pathlib import Path

from .abstract_method import AbstractMethod


def trace_collector(**kwargs) -> TraceCollector:
"""
Expand Down Expand Up @@ -87,11 +85,7 @@ def trace_args(self) -> str:

The trace command and the arguments you pass to it, but not the
command you're tracing. E.g., return `strace -f -c -e "open"`.

Raises:
AbstractMethod: This needs to be overridden by subclasses.
"""
raise AbstractMethod

def command(self, command: str):
"""
Expand Down
13 changes: 13 additions & 0 deletions test/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""
Create the ``test`` package.

This ``__init__.py`` file creates the ``test`` package, such that tests
can relative-import from modules in the sibling ``shell_logger``
directory.
"""

# © 2023 National Technology & Engineering Solutions of Sandia, LLC
# (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the
# U.S. Government retains certain rights in this software.

# SPDX-License-Identifier: BSD-3-Clause