-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from pomponchik/develop
0.0.6
- Loading branch information
Showing
17 changed files
with
520 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
from emptylog.empty_logger import EmptyLogger as EmptyLogger # noqa: F401 | ||
from emptylog.protocol import LoggerProtocol as LoggerProtocol # noqa: F401 | ||
from emptylog.protocols import LoggerProtocol as LoggerProtocol # noqa: F401 | ||
from emptylog.memory_logger import MemoryLogger as MemoryLogger # noqa: F401 | ||
from emptylog.printing_logger import PrintingLogger as PrintingLogger # noqa: F401 | ||
from emptylog.loggers_group import LoggersGroup as LoggersGroup # noqa: F401 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from abc import ABC | ||
|
||
from emptylog.protocols import LoggerProtocol | ||
|
||
|
||
class AbstractLogger(LoggerProtocol, ABC): | ||
def __repr__(self) -> str: | ||
return f'{type(self).__name__}()' | ||
|
||
def __add__(self, other: LoggerProtocol) -> 'LoggersGroup': # type: ignore[name-defined] # noqa: F821 | ||
if not isinstance(other, LoggerProtocol): | ||
raise NotImplementedError('The addition operation is defined only for loggers.') | ||
|
||
from emptylog import LoggersGroup | ||
|
||
local_loggers = self.loggers if isinstance(self, LoggersGroup) else [self] | ||
other_loggers = other.loggers if isinstance(other, LoggersGroup) else [other] | ||
|
||
return LoggersGroup(*local_loggers, *other_loggers) | ||
|
||
def __radd__(self, other: LoggerProtocol) -> 'LoggersGroup': # type: ignore[name-defined] # noqa: F821 | ||
if not isinstance(other, LoggerProtocol): | ||
raise NotImplementedError('The addition operation is defined only for loggers.') | ||
|
||
from emptylog import LoggersGroup | ||
|
||
local_loggers = self.loggers if isinstance(self, LoggersGroup) else [self] | ||
other_loggers = other.loggers if isinstance(other, LoggersGroup) else [other] | ||
|
||
return LoggersGroup(*other_loggers, *local_loggers) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
from emptylog.protocol import LoggerProtocol | ||
from emptylog.abstract_logger import AbstractLogger | ||
|
||
|
||
class EmptyLogger(LoggerProtocol): | ||
class EmptyLogger(AbstractLogger): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import sys | ||
from typing import Tuple, Callable, Any | ||
from threading import Lock | ||
from collections.abc import Iterator | ||
|
||
from printo import descript_data_object | ||
|
||
from emptylog.protocols import LoggerProtocol, LoggerMethodProtocol | ||
from emptylog.abstract_logger import AbstractLogger | ||
|
||
|
||
if sys.version_info < (3, 9): | ||
GroupIterator = Iterator # pragma: no cover | ||
else: | ||
GroupIterator = Iterator[LoggerProtocol] # pragma: no cover | ||
|
||
class LoggersGroup(AbstractLogger): | ||
loggers: Tuple[LoggerProtocol, ...] | ||
|
||
def __init__(self, *loggers: LoggerProtocol) -> None: | ||
for logger in loggers: | ||
if not isinstance(logger, LoggerProtocol): | ||
raise TypeError(f'A logger group can only be created from loggers. You passed {repr(logger)} ({type(logger).__name__}).') | ||
|
||
self.loggers = loggers | ||
self.lock = Lock() | ||
|
||
def __repr__(self) -> str: | ||
return descript_data_object(type(self).__name__, self.loggers, {}, serializator=repr) | ||
|
||
def __len__(self) -> int: | ||
return len(self.loggers) | ||
|
||
def __iter__(self) -> GroupIterator: # type: ignore[type-arg] | ||
yield from self.loggers | ||
|
||
def debug(self, message: str, *args: Any, **kwargs: Any) -> None: | ||
self.run_loggers(lambda x: x.debug, message, *args, **kwargs) | ||
|
||
def info(self, message: str, *args: Any, **kwargs: Any) -> None: | ||
self.run_loggers(lambda x: x.info, message, *args, **kwargs) | ||
|
||
def warning(self, message: str, *args: Any, **kwargs: Any) -> None: | ||
self.run_loggers(lambda x: x.warning, message, *args, **kwargs) | ||
|
||
def error(self, message: str, *args: Any, **kwargs: Any) -> None: | ||
self.run_loggers(lambda x: x.error, message, *args, **kwargs) | ||
|
||
def exception(self, message: str, *args: Any, **kwargs: Any) -> None: | ||
self.run_loggers(lambda x: x.exception, message, *args, **kwargs) | ||
|
||
def critical(self, message: str, *args: Any, **kwargs: Any) -> None: | ||
self.run_loggers(lambda x: x.critical, message, *args, **kwargs) | ||
|
||
def run_loggers(self, get_method: Callable[[LoggerProtocol], LoggerMethodProtocol], message: str, *args: Any, **kwargs: Any) -> None: | ||
with self.lock: | ||
for logger in self.loggers: | ||
method = get_method(logger) | ||
method(message, *args, **kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' | |
|
||
[project] | ||
name = 'emptylog' | ||
version = '0.0.5' | ||
version = '0.0.6' | ||
authors = [ | ||
{ name='Evgeniy Blinov', email='[email protected]' }, | ||
] | ||
|
@@ -13,6 +13,7 @@ readme = 'README.md' | |
requires-python = '>=3.7' | ||
dependencies = [ | ||
'typing_extensions ; python_version < "3.8"', | ||
'printo>=0.0.2', | ||
] | ||
classifiers = [ | ||
'Operating System :: MacOS :: MacOS X', | ||
|
@@ -26,13 +27,18 @@ classifiers = [ | |
'Programming Language :: Python :: 3.12', | ||
'License :: OSI Approved :: MIT License', | ||
'Topic :: Software Development :: Libraries', | ||
'Topic :: Software Development :: Interpreters', | ||
'Topic :: Utilities', | ||
'Topic :: System :: Archiving :: Packaging', | ||
'Intended Audience :: System Administrators', | ||
'Topic :: Software Development :: Testing', | ||
'Topic :: Software Development :: Testing :: Mocking', | ||
'Topic :: Software Development :: Testing :: Unit', | ||
'Topic :: System :: Logging', | ||
'Intended Audience :: Developers', | ||
'Typing :: Typed', | ||
] | ||
keywords = [ | ||
'logging', | ||
'protocols', | ||
'loggers mocks', | ||
] | ||
|
||
[tool.setuptools.package-data] | ||
"emptylog" = ["py.typed"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,5 @@ twine==4.0.2 | |
mypy==1.4.1 | ||
ruff==0.0.290 | ||
mutmut==2.4.4 | ||
full_match==0.0.1 | ||
loguru==0.7.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import logging | ||
|
||
import pytest | ||
import full_match | ||
from loguru import logger as loguru_logger | ||
|
||
from emptylog.abstract_logger import AbstractLogger | ||
from emptylog import EmptyLogger, LoggersGroup, MemoryLogger, PrintingLogger | ||
|
||
|
||
@pytest.mark.parametrize( | ||
['first_logger'], | ||
( | ||
(EmptyLogger(),), | ||
(MemoryLogger(),), | ||
(PrintingLogger(),), | ||
), | ||
) | ||
@pytest.mark.parametrize( | ||
['second_logger'], | ||
( | ||
(EmptyLogger(),), | ||
(MemoryLogger(),), | ||
(PrintingLogger(),), | ||
(logging,), | ||
(logging.getLogger('kek'),), | ||
(loguru_logger,), | ||
), | ||
) | ||
def test_sum_of_inner_loggers(first_logger, second_logger): | ||
sum = first_logger + second_logger | ||
|
||
assert isinstance(sum, LoggersGroup) | ||
|
||
assert sum is not first_logger | ||
assert sum is not second_logger | ||
|
||
assert sum.loggers[0] is first_logger | ||
assert sum.loggers[1] is second_logger | ||
|
||
|
||
@pytest.mark.parametrize( | ||
['first_logger'], | ||
( | ||
(logging,), | ||
(logging.getLogger('kek'),), | ||
(loguru_logger,), | ||
), | ||
) | ||
@pytest.mark.parametrize( | ||
['second_logger'], | ||
( | ||
(EmptyLogger(),), | ||
(MemoryLogger(),), | ||
(PrintingLogger(),), | ||
), | ||
) | ||
def test_sum_with_another_loggers_as_first_operand(first_logger, second_logger): | ||
sum = first_logger + second_logger | ||
|
||
assert isinstance(sum, LoggersGroup) | ||
|
||
assert sum is not first_logger | ||
assert sum is not second_logger | ||
|
||
assert sum.loggers[0] is first_logger | ||
assert sum.loggers[1] is second_logger | ||
|
||
|
||
@pytest.mark.parametrize( | ||
['logger'], | ||
( | ||
(EmptyLogger(),), | ||
(LoggersGroup(),), | ||
(MemoryLogger(),), | ||
(PrintingLogger(),), | ||
), | ||
) | ||
def test_all_loggers_are_instances_of_abstract_logger(logger): | ||
assert isinstance(logger, AbstractLogger) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
['logger'], | ||
( | ||
(EmptyLogger(),), | ||
(LoggersGroup(),), | ||
(MemoryLogger(),), | ||
(PrintingLogger(),), | ||
), | ||
) | ||
@pytest.mark.parametrize( | ||
['wrong_operand'], | ||
( | ||
(1,), | ||
('kek',), | ||
(None,), | ||
), | ||
) | ||
def test_sum_with_wrong_first_operand(logger, wrong_operand): | ||
with pytest.raises(NotImplementedError, match=full_match('The addition operation is defined only for loggers.')): | ||
wrong_operand + logger | ||
|
||
|
||
@pytest.mark.parametrize( | ||
['logger'], | ||
( | ||
(EmptyLogger(),), | ||
(LoggersGroup(),), | ||
(MemoryLogger(),), | ||
(PrintingLogger(),), | ||
), | ||
) | ||
@pytest.mark.parametrize( | ||
['wrong_operand'], | ||
( | ||
(1,), | ||
('kek',), | ||
(None,), | ||
), | ||
) | ||
def test_sum_with_wrong_second_operand(logger, wrong_operand): | ||
with pytest.raises(NotImplementedError, match=full_match('The addition operation is defined only for loggers.')): | ||
logger + wrong_operand | ||
|
||
|
||
def test_sum_of_three_loggers(): | ||
first_logger = EmptyLogger() | ||
second_logger = MemoryLogger() | ||
third_logger = PrintingLogger() | ||
|
||
sum = first_logger + second_logger + third_logger | ||
|
||
assert isinstance(sum, LoggersGroup) | ||
|
||
assert len(sum) == 3 | ||
assert len(sum.loggers) == 3 | ||
|
||
assert sum.loggers[0] is first_logger | ||
assert sum.loggers[1] is second_logger | ||
assert sum.loggers[2] is third_logger |
Oops, something went wrong.