diff --git a/src/pms/__init__.py b/src/pms/__init__.py index c5b76af..5fb2db0 100644 --- a/src/pms/__init__.py +++ b/src/pms/__init__.py @@ -1,3 +1,8 @@ +from loguru import logger + +logger.disable("pms") # disable logging by default + + class SensorWarning(UserWarning): """Recoverable errors""" diff --git a/src/pms/cli.py b/src/pms/cli.py index 21d1bd7..76ea6d8 100644 --- a/src/pms/cli.py +++ b/src/pms/cli.py @@ -10,12 +10,11 @@ import importlib_metadata as metadata from loguru import logger -from typer import Argument, Context, Exit, Option, Typer, echo +from typer import Argument, Context, Exit, Option, Typer, echo, run from pms.core import MessageReader, SensorReader, Supported, exit_on_fail -main = Typer(help="Data acquisition and logging for Air Quality Sensors with UART interface") - +app = Typer(help="Data acquisition and logging for Air Quality Sensors with UART interface") """ Extra cli commands from plugins @@ -23,7 +22,12 @@ additional Typer commands are loaded from plugins (entry points) advertized as `"pypms.extras"` """ for ep in metadata.entry_points(group="pypms.extras"): - main.command(name=ep.name)(ep.load()) + app.command(name=ep.name)(ep.load()) + + +def main(): # pragma: no cover + logger.enable("pms") + app() def version_callback(value: bool): # pragma: no cover @@ -35,7 +39,7 @@ def version_callback(value: bool): # pragma: no cover raise Exit() -@main.callback() +@app.callback() def callback( ctx: Context, model: Supported = Option(Supported.default, "--sensor-model", "-m", help="sensor model"), @@ -60,7 +64,7 @@ def callback( ctx.obj = {"reader": SensorReader(model, port, seconds, samples)} -@main.command() +@app.command() def info(ctx: Context): # pragma: no cover """Information about the sensor observations""" sensor = ctx.obj["reader"].sensor @@ -84,7 +88,7 @@ def __str__(self) -> str: return self.value -@main.command() +@app.command() def serial( ctx: Context, format: Optional[Format] = Option(None, "--format", "-f", help="formatted output"), @@ -111,7 +115,7 @@ def serial( echo(str(obs)) -@main.command() +@app.command() def csv( ctx: Context, capture: bool = Option(False, "--capture", help="write raw messages instead of observations"), diff --git a/tests/core/reader/test_SensorReader.py b/tests/core/reader/test_SensorReader.py index 3db3d02..3d24263 100644 --- a/tests/core/reader/test_SensorReader.py +++ b/tests/core/reader/test_SensorReader.py @@ -1,10 +1,19 @@ import pytest +from _pytest.logging import LogCaptureFixture +from loguru import logger from pms import SensorWarmingUp, SensorWarning from pms.core.reader import SensorReader, UnableToRead from pms.core.sensor import Sensor +@pytest.fixture +def caplog(caplog: LogCaptureFixture): + handler_id = logger.add(caplog.handler, format="{message}") + yield caplog + logger.remove(handler_id) + + @pytest.fixture def mock_sleep(monkeypatch): def sleep(seconds): @@ -233,3 +242,15 @@ def test_reader_sensor_no_response(reader: SensorReader): pass assert "did not respond" in str(e.value) + + +def test_logging(reader: SensorReader, capfd, caplog): + with reader: + obs = tuple(reader()) + + # check data was read + assert len(obs) == 1 + assert obs[0].pm10 == 11822 # type:ignore + + # check no logs output + assert caplog.text == "" diff --git a/tests/extra/test_cli.py b/tests/extra/test_cli.py index 63e2dc7..7c0893c 100644 --- a/tests/extra/test_cli.py +++ b/tests/extra/test_cli.py @@ -39,9 +39,9 @@ def client_sub( def test_mqtt(capture, mock_mqtt): - from pms.cli import main + from pms.cli import app - result = runner.invoke(main, capture.options("mqtt")) + result = runner.invoke(app, capture.options("mqtt")) assert result.exit_code == 0 @@ -62,9 +62,9 @@ def pub(*, time: int, tags: Dict[str, str], data: Dict[str, float]) -> None: def test_influxdb(capture, mock_influxdb): - from pms.cli import main + from pms.cli import app - result = runner.invoke(main, capture.options("influxdb")) + result = runner.invoke(app, capture.options("influxdb")) assert result.exit_code == 0 @@ -110,8 +110,8 @@ def client_sub( def test_bridge(mock_bridge): - from pms.cli import main + from pms.cli import app capture = mock_bridge - result = runner.invoke(main, capture.options("bridge")) + result = runner.invoke(app, capture.options("bridge")) assert result.exit_code == 0 diff --git a/tests/test_cli.py b/tests/test_cli.py index 4facb64..72837b5 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -9,18 +9,18 @@ @pytest.mark.parametrize("format", {"csv", "hexdump"}) def test_serial(capture, format): - from pms.cli import main + from pms.cli import app - result = runner.invoke(main, capture.options(f"serial_{format}")) + result = runner.invoke(app, capture.options(f"serial_{format}")) assert result.exit_code == 0 assert result.stdout == capture.output(format) def test_csv(capture): - from pms.cli import main + from pms.cli import app - result = runner.invoke(main, capture.options("csv")) + result = runner.invoke(app, capture.options("csv")) assert result.exit_code == 0 csv = Path(capture.options("csv")[-1]) @@ -31,15 +31,15 @@ def test_csv(capture): def test_capture_decode(capture): - from pms.cli import main + from pms.cli import app - result = runner.invoke(main, capture.options("capture")) + result = runner.invoke(app, capture.options("capture")) assert result.exit_code == 0 csv = Path(capture.options("capture")[-1]) assert csv.exists() - result = runner.invoke(main, capture.options("decode")) + result = runner.invoke(app, capture.options("decode")) assert result.exit_code == 0 csv.unlink() assert result.stdout == capture.output("csv")