Skip to content

Commit

Permalink
Added type aliases for Level and Logger (#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
etianen authored Feb 7, 2024
1 parent 4372f8d commit e7d3f70
Show file tree
Hide file tree
Showing 9 changed files with 36 additions and 24 deletions.
4 changes: 3 additions & 1 deletion logot/_format.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from __future__ import annotations

from logot._typing import Level

def format_level(level: str | int) -> str:

def format_level(level: Level) -> str:
# Format `str` level.
if isinstance(level, str):
return level
Expand Down
5 changes: 3 additions & 2 deletions logot/_logged.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from logot._capture import Captured
from logot._format import format_level, format_log
from logot._msg import compile_msg_matcher
from logot._typing import Level
from logot._validate import validate_level


Expand Down Expand Up @@ -58,7 +59,7 @@ def _str(self, *, indent: str) -> str:
raise NotImplementedError


def log(level: str | int, msg: str) -> Logged:
def log(level: Level, msg: str) -> Logged:
"""
Creates a :doc:`log pattern </log-pattern-matching>` representing a log record at the given ``level`` with the given
``msg``.
Expand Down Expand Up @@ -122,7 +123,7 @@ def critical(msg: str) -> Logged:
class _RecordLogged(Logged):
__slots__ = ("_level", "_msg", "_msg_matcher")

def __init__(self, level: str | int, msg: str) -> None:
def __init__(self, level: Level, msg: str) -> None:
self._level = level
self._msg = msg
self._msg_matcher = compile_msg_matcher(msg)
Expand Down
5 changes: 3 additions & 2 deletions logot/_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from logot._capture import Captured
from logot._logot import Capturer, Logot
from logot._typing import Level, Logger


class LoggingCapturer(Capturer):
Expand All @@ -17,7 +18,7 @@ class LoggingCapturer(Capturer):

__slots__ = ("_logger", "_handler", "_prev_levelno")

def start_capturing(self, logot: Logot, /, *, level: str | int, logger: str | None) -> None:
def start_capturing(self, logot: Logot, /, *, level: Level, logger: Logger) -> None:
logger = self._logger = logging.getLogger(logger)
handler = self._handler = _Handler(level, logot)
# If the logger is less verbose than the handler, force it to the necessary verboseness.
Expand All @@ -36,7 +37,7 @@ def stop_capturing(self) -> None:
class _Handler(logging.Handler):
__slots__ = ("_logot",)

def __init__(self, level: str | int, logot: Logot) -> None:
def __init__(self, level: Level, logot: Logot) -> None:
super().__init__(level)
self._logot = logot

Expand Down
13 changes: 7 additions & 6 deletions logot/_logot.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from logot._capture import Captured
from logot._import import LazyCallable
from logot._logged import Logged
from logot._typing import Level, Logger
from logot._validate import validate_level, validate_logger, validate_timeout
from logot._wait import AsyncWaiter, W, create_threading_waiter

Expand All @@ -29,12 +30,12 @@ class Logot:

__slots__ = ("capturer", "timeout", "async_waiter", "_lock", "_queue", "_wait")

DEFAULT_LEVEL: ClassVar[str | int] = "DEBUG"
DEFAULT_LEVEL: ClassVar[Level] = "DEBUG"
"""
The default ``level`` used by :meth:`capturing`.
"""

DEFAULT_LOGGER: ClassVar[str | None] = None
DEFAULT_LOGGER: ClassVar[Logger] = None
"""
The default ``logger`` used by :meth:`capturing`.
Expand Down Expand Up @@ -102,8 +103,8 @@ def __init__(
def capturing(
self,
*,
level: str | int = DEFAULT_LEVEL,
logger: str | None = DEFAULT_LOGGER,
level: Level = DEFAULT_LEVEL,
logger: Logger = DEFAULT_LOGGER,
capturer: Callable[[], Capturer] | None = None,
) -> AbstractContextManager[Logot]:
"""
Expand Down Expand Up @@ -292,7 +293,7 @@ class Capturer(ABC):
__slots__ = ()

@abstractmethod
def start_capturing(self, logot: Logot, /, *, level: str | int, logger: str | None) -> None:
def start_capturing(self, logot: Logot, /, *, level: Level, logger: Logger) -> None:
"""
Starts capturing logs for the given :class:`Logot`.
Expand All @@ -315,7 +316,7 @@ def stop_capturing(self) -> None:
class _Capturing:
__slots__ = ("_logot", "_capturer_obj", "_level", "_logger")

def __init__(self, logot: Logot, capturer: Capturer, *, level: str | int, logger: str | None) -> None:
def __init__(self, logot: Logot, capturer: Capturer, *, level: Level, logger: Logger) -> None:
self._logot = logot
self._capturer_obj = capturer
self._level = level
Expand Down
10 changes: 5 additions & 5 deletions logot/_pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from logot._import import import_any_parsed
from logot._logot import Capturer, Logot
from logot._typing import MISSING, T
from logot._typing import MISSING, Level, Logger, T
from logot._wait import AsyncWaiter


Expand Down Expand Up @@ -47,8 +47,8 @@ def pytest_addoption(parser: pytest.Parser, pluginmanager: pytest.PytestPluginMa

@pytest.fixture()
def logot(
logot_level: str | int,
logot_logger: str | None,
logot_level: Level,
logot_logger: Logger,
logot_capturer: Callable[[], Capturer],
logot_timeout: float,
logot_async_waiter: Callable[[], AsyncWaiter],
Expand All @@ -62,15 +62,15 @@ def logot(


@pytest.fixture(scope="session")
def logot_level(request: pytest.FixtureRequest) -> str | int:
def logot_level(request: pytest.FixtureRequest) -> Level:
"""
The `level` used for automatic log capturing.
"""
return _get_option(request, name="level", parser=str, default=Logot.DEFAULT_LEVEL)


@pytest.fixture(scope="session")
def logot_logger(request: pytest.FixtureRequest) -> str | None:
def logot_logger(request: pytest.FixtureRequest) -> Logger:
"""
The `logger` used for automatic log capturing.
"""
Expand Down
6 changes: 5 additions & 1 deletion logot/_typing.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import sys
from typing import Any, TypeVar
from typing import Any, TypeVar, Union

if sys.version_info >= (3, 10):
from typing import ParamSpec as ParamSpec
Expand All @@ -13,4 +13,8 @@
P = ParamSpec("P")
T = TypeVar("T")

# TODO: Use `UnionType` when we only need to support Python 3.10+.
Level: TypeAlias = Union[str, int]
Logger: TypeAlias = Union[str, None]

MISSING: Any = object()
5 changes: 3 additions & 2 deletions logot/_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from unittest import TestCase, TestResult

from logot._logot import Capturer, Logot
from logot._typing import Level, Logger
from logot._wait import AsyncWaiter


Expand All @@ -19,14 +20,14 @@ class LogotTestCase(TestCase):
Use this to make log assertions in your tests.
"""

logot_level: ClassVar[str | int] = Logot.DEFAULT_LEVEL
logot_level: ClassVar[Level] = Logot.DEFAULT_LEVEL
"""
The ``level`` used for automatic :doc:`log capturing </log-capturing>`.
Defaults to :attr:`logot.Logot.DEFAULT_LEVEL`.
"""

logot_logger: ClassVar[str | None] = Logot.DEFAULT_LOGGER
logot_logger: ClassVar[Logger] = Logot.DEFAULT_LOGGER
"""
The ``logger`` used for automatic :doc:`log capturing </log-capturing>`.
Expand Down
6 changes: 4 additions & 2 deletions logot/_validate.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
from __future__ import annotations

from logot._typing import Level, Logger

def validate_level(level: str | int) -> str | int:

def validate_level(level: Level) -> Level:
# Handle `str` or `int` level.
if isinstance(level, (str, int)):
return level
# Handle invalid level.
raise TypeError(f"Invalid level: {level!r}")


def validate_logger(logger: str | None) -> str | None:
def validate_logger(logger: Logger) -> Logger:
# Handle `None` or `str` logger.
if logger is None or isinstance(logger, str):
return logger
Expand Down
6 changes: 3 additions & 3 deletions tests/test_pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from logot import Capturer, Logot
from logot._pytest import get_optname, get_qualname
from logot._typing import MISSING
from logot._typing import MISSING, Level, Logger
from logot._wait import AsyncWaiter
from logot.asyncio import AsyncioWaiter
from logot.logging import LoggingCapturer
Expand Down Expand Up @@ -56,15 +56,15 @@ def test_{name}({qualname}):
EXPECTED_VAR.reset(expected_token)


def test_level_default(logot_level: str | int) -> None:
def test_level_default(logot_level: Level) -> None:
assert logot_level == Logot.DEFAULT_LEVEL


def test_level_config_pass(pytester: pytest.Pytester) -> None:
assert_fixture_config(pytester, "level", "INFO")


def test_logger_default(logot_logger: str | int) -> None:
def test_logger_default(logot_logger: Logger) -> None:
assert logot_logger == Logot.DEFAULT_LOGGER


Expand Down

0 comments on commit e7d3f70

Please sign in to comment.