From 1ece819bfc8f594c1d72b94330e9fd187c29f5f1 Mon Sep 17 00:00:00 2001 From: Amin Alaee Date: Fri, 29 Sep 2023 11:47:35 +0200 Subject: [PATCH] Add raiseExceptions --- src/picologging/__init__.py | 1 + src/picologging/__init__.pyi | 2 ++ src/picologging/_picologging.cxx | 2 ++ src/picologging/handler.cxx | 13 ++++++++++--- src/picologging/handler.hxx | 1 + src/picologging/streamhandler.cxx | 2 +- tests/unit/test_handler.py | 18 ++++++++++++++---- tests/unit/test_streamhandler.py | 10 ---------- 8 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/picologging/__init__.py b/src/picologging/__init__.py index a44fec9..777cc2c 100644 --- a/src/picologging/__init__.py +++ b/src/picologging/__init__.py @@ -13,6 +13,7 @@ LogRecord, StreamHandler, getLevelName, + raiseExceptions, ) __version__ = "0.9.3" diff --git a/src/picologging/__init__.pyi b/src/picologging/__init__.pyi index 7350c9d..3d8170c 100644 --- a/src/picologging/__init__.pyi +++ b/src/picologging/__init__.pyi @@ -20,6 +20,8 @@ INFO: int DEBUG: int NOTSET: int +raiseExceptions: bool + _SysExcInfoType: TypeAlias = Union[ tuple[type[BaseException], BaseException, TracebackType | None], tuple[None, None, None], diff --git a/src/picologging/_picologging.cxx b/src/picologging/_picologging.cxx index aef0e92..dc3bf6e 100644 --- a/src/picologging/_picologging.cxx +++ b/src/picologging/_picologging.cxx @@ -151,6 +151,8 @@ PyMODINIT_FUNC PyInit__picologging(void) picologging_state *state = get_picologging_state(m); state->g_filepathCache = new FilepathCache(); + PyModule_AddObject(m, "raiseExceptions", Py_NewRef(Py_False)); + Py_INCREF(&LogRecordType); Py_INCREF(&FormatStyleType); Py_INCREF(&FormatterType); diff --git a/src/picologging/handler.cxx b/src/picologging/handler.cxx index 47e95c2..1f07c54 100644 --- a/src/picologging/handler.cxx +++ b/src/picologging/handler.cxx @@ -68,7 +68,10 @@ PyObject* Handler_handle(Handler *self, PyObject *record) { } self->lock->unlock(); - return result == nullptr ? nullptr : Py_True; + + if (PyErr_Occurred()) + return nullptr; + return result == nullptr ? Py_False : Py_True; } PyObject* Handler_setLevel(Handler *self, PyObject *level){ @@ -128,8 +131,12 @@ PyObject* Handler_close(Handler *self){ } PyObject* Handler_handleError(Handler *self, PyObject *record){ - // TODO: Develop this behaviour further. - PyErr_Print(); + PyObject* mod = PICOLOGGING_MODULE(); // borrowed reference + PyObject* modDict = PyModule_GetDict(mod); // borrowed reference + PyObject* raiseExceptions = PyDict_GetItemString(modDict, "raiseExceptions"); // PyDict_GetItemString returns a borrowed reference + if (PyBool_Check(raiseExceptions) && PyErr_Occurred()) { + PyErr_Print(); + } Py_RETURN_NONE; } diff --git a/src/picologging/handler.hxx b/src/picologging/handler.hxx index e766e5a..82d90b3 100644 --- a/src/picologging/handler.hxx +++ b/src/picologging/handler.hxx @@ -22,6 +22,7 @@ PyObject* Handler_handle(Handler *self, PyObject *record); PyObject* Handler_setLevel(Handler *self, PyObject *level); PyObject* Handler_setFormatter(Handler *self, PyObject *formatter); PyObject* Handler_format(Handler *self, PyObject *record); +PyObject* Handler_handleError(Handler *self, PyObject *record); PyObject* Handler_acquire(Handler *self); PyObject* Handler_release(Handler *self); diff --git a/src/picologging/streamhandler.cxx b/src/picologging/streamhandler.cxx index a288a86..d0aabab 100644 --- a/src/picologging/streamhandler.cxx +++ b/src/picologging/streamhandler.cxx @@ -82,7 +82,7 @@ PyObject* StreamHandler_emit(StreamHandler* self, PyObject* const* args, Py_ssiz Py_XDECREF(writeResult); Py_RETURN_NONE; error: - // TODO: #4 handle error path (see handleError(record)) + Handler_handleError(&self->handler, args[0]); Py_XDECREF(msg); return nullptr; } diff --git a/tests/unit/test_handler.py b/tests/unit/test_handler.py index 279da1a..e55cbfa 100644 --- a/tests/unit/test_handler.py +++ b/tests/unit/test_handler.py @@ -2,6 +2,7 @@ from utils import filter_gc import picologging +from picologging import LogRecord @pytest.mark.limit_leaks("192B", filter_fn=filter_gc) @@ -131,13 +132,22 @@ def format(self, record): assert handler.format(record) == "foo" -@pytest.mark.limit_leaks("192B", filter_fn=filter_gc) -def test_handle_error(): - handler = picologging.Handler() +def test_handle_error(capsys): + picologging.raiseExceptions = True + + class BadStream: + def write(self, data): + raise RuntimeError("bad stream") + + handler = picologging.StreamHandler(BadStream()) record = picologging.LogRecord( "test", picologging.INFO, __file__, 1, "test", (), None, None, None ) - assert not handler.handleError(record) + handler.handle(record) + cap = capsys.readouterr() + + assert cap.out == "" + assert cap.err.startswith("Traceback (most recent call last)") @pytest.mark.limit_leaks("192B", filter_fn=filter_gc) diff --git a/tests/unit/test_streamhandler.py b/tests/unit/test_streamhandler.py index fc33147..65af8c1 100644 --- a/tests/unit/test_streamhandler.py +++ b/tests/unit/test_streamhandler.py @@ -40,16 +40,6 @@ def test_stream_handler_bad_init_args(): picologging.StreamHandler(dog=1) -@pytest.mark.limit_leaks("192B", filter_fn=filter_gc) -def test_stream_handler_invalid_stream_type(): - handler = picologging.StreamHandler("potato") - record = picologging.LogRecord( - "test", picologging.INFO, __file__, 1, "test", (), None, None, None - ) - with pytest.raises(AttributeError): - handler.handle(record) - - @pytest.mark.limit_leaks("192B", filter_fn=filter_gc) def test_non_flushable_stream(): class TestStream: