diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 47e187c..5434819 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -44,3 +44,6 @@ jobs: pip install -r requirements.txt -r test-requirements.txt - name: Type-check with mypy run: mypy + - name: Type-check the public API as a strict consumer + # Errors inside logtail itself stay silent, as they are for an installed package. + run: mypy --strict --follow-imports=silent tests/typecheck diff --git a/logtail/__init__.py b/logtail/__init__.py index 83fa334..18b9332 100644 --- a/logtail/__init__.py +++ b/logtail/__init__.py @@ -8,3 +8,5 @@ __version__ = '0.5.0' context = DEFAULT_CONTEXT + +__all__ = ['LogtailHandler', 'LogtailContext', 'DEFAULT_CONTEXT', 'LogtailFormatter', 'context', '__version__'] diff --git a/logtail/helpers.py b/logtail/helpers.py index 65a1f21..1be3a9d 100644 --- a/logtail/helpers.py +++ b/logtail/helpers.py @@ -28,8 +28,7 @@ def __enter__(self) -> 'LogtailContext': return self def __exit__(self, type_: Optional[type[BaseException]], value: Optional[BaseException], traceback: Optional[TracebackType]) -> None: - if type_ is None: - self.extras.pop() + self.extras.pop() def exists(self) -> bool: return bool(self.extras) diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 8a2accd..877a5cc 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -33,6 +33,15 @@ def test_does_not_suppress_exceptions(self): with c(user={'name': 'a'}): raise ValueError('should be thrown') + def test_exception_leaves_the_context(self): + c = LogtailContext() + with c(user={'name': 'a'}): + with self.assertRaises(ValueError): + with c(request={'id': 'r'}): + raise ValueError('leaves the inner block') + self.assertEqual(c.collapse(), {'user': {'name': 'a'}}) + self.assertFalse(c.exists()) + def test_nested_collapse(self): c = LogtailContext() self.assertEqual(c.collapse(), {}) diff --git a/tests/typecheck/public_api.py b/tests/typecheck/public_api.py new file mode 100644 index 0000000..a183fbf --- /dev/null +++ b/tests/typecheck/public_api.py @@ -0,0 +1,17 @@ +# Checked with `mypy --strict` in CI, never run: imports and calls the public API the +# way applications do, so it fails if a name stops being exported from `logtail`. +import json +import logging + +import logtail +from logtail import DEFAULT_CONTEXT, LogtailContext, LogtailFormatter, LogtailHandler + +handler = LogtailHandler(source_token='token', host='in.logs.betterstack.com', timeout=(3.05, 27), flush_timeout=None) +handler.setFormatter(LogtailFormatter(context=DEFAULT_CONTEXT, json_default=str, json_encoder=json.JSONEncoder)) +logging.getLogger(__name__).addHandler(handler) + +request_context: LogtailContext = logtail.context +with request_context(request={'id': 'abc'}): + logging.getLogger(__name__).info('typed') + +version: str = logtail.__version__