Skip to content

Commit c8514ad

Browse files
committed
fix: Explicitly export top-level functions and make the logger object typed attributes.
1 parent 9e2ac99 commit c8514ad

File tree

9 files changed

+521
-326
lines changed

9 files changed

+521
-326
lines changed

poetry.lock

Lines changed: 438 additions & 302 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "setuplog"
3-
version = "0.2.3"
3+
version = "0.3.0"
44
description = ""
55
authors = []
66
license = "MIT"
@@ -22,6 +22,7 @@ python = ">=3.3, !=3.3.*, !=3.4.*, !=3.5.*, <4"
2222
bandit = "*"
2323
black = { version = "19.3b0", allow-prereleases = true, python = ">=3.6" }
2424
coverage = ">=5"
25+
mypy = ">=0.931"
2526
flake8 = "^3.7"
2627
isort = "^4.3"
2728
pydocstyle = "*"
@@ -43,6 +44,13 @@ order_by_type = false
4344
known_first_party = 'tests'
4445
use_parentheses = true
4546

47+
[tool.mypy]
48+
strict_optional = true
49+
ignore_missing_imports = true
50+
warn_unused_ignores = true
51+
implicit_reexport = true
52+
incremental = true
53+
4654
[build-system]
4755
requires = [ "poetry>=0.12" ]
4856
build-backend = "poetry.masonry.api"

setup.cfg

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22
ignore = D1,D200,D202,D203,D204,D213,D406,D407,D413
33
match_dir = ^[^\.{]*
44

5-
[mypy]
6-
strict_optional = True
7-
ignore_missing_imports = True
8-
warn_unused_ignores = True
9-
incremental = True
10-
115
[tool:pytest]
126
doctest_optionflags = NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL ELLIPSIS
137
addopts = --ff --doctest-modules

src/setuplog/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
# flake8: noqa
21
from setuplog.adaptors import M, StyleAdapter
32
from setuplog.decorator import log_duration, log_exceptions
43
from setuplog.logger import create_log_handler, log
54
from setuplog.setup import setup_logging
5+
6+
__all__ = [
7+
"create_log_handler",
8+
"log",
9+
"log_duration",
10+
"log_exceptions",
11+
"M",
12+
"setup_logging",
13+
"StyleAdapter",
14+
]

src/setuplog/adaptors.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
https://docs.python.org/3/howto/logging-cookbook.html#use-of-alternative-formatting-styles
44
"""
55
import logging
6+
from typing import Any, Optional
67

78

89
class M:
@@ -12,7 +13,7 @@ class M:
1213
>>> logging.info(M('foo={foo}', foo=1))
1314
"""
1415

15-
def __init__(self, fmt, *args, **kwargs):
16+
def __init__(self, fmt: str, *args: Any, **kwargs: Any):
1617
self.fmt = fmt
1718
self.args = args
1819
self.kwargs = kwargs
@@ -25,7 +26,7 @@ def __str__(self):
2526

2627

2728
class StyleAdapter(logging.LoggerAdapter):
28-
def __init__(self, logger, extra=None):
29+
def __init__(self, logger: logging.Logger, extra: Optional[dict] = None):
2930
super(StyleAdapter, self).__init__(logger, extra or {})
3031

3132
def log(self, level, msg, *args, **kwargs):

src/setuplog/decorator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def log_exceptions(func):
2020
def decorator(*args, **kwargs):
2121
try:
2222
return func(*args, **kwargs)
23-
except Exception as e:
23+
except Exception:
2424
log.exception("")
2525
raise
2626

src/setuplog/logger.py

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
import logging.config
1414
import sys
1515
from functools import lru_cache
16+
from typing import Any, Union
17+
18+
from setuplog.adaptors import M
1619

1720

1821
def create_log_handler(name, log_level=None, style_adaptor=None):
@@ -29,22 +32,51 @@ def create_log_handler(name, log_level=None, style_adaptor=None):
2932
return log
3033

3134

35+
def get_logger() -> logging.Logger:
36+
segments = []
37+
namespace = getattr(logging.config, "namespace", "")
38+
if namespace:
39+
segments.append(namespace)
40+
41+
style_adaptor = getattr(logging.config, "style_adaptor", None)
42+
43+
# Ensure the logger name is pulled from 2 frames up rather than from the local frame. One frame for this function, and one for the
44+
# `_Logging` function calls.
45+
frame_name = sys._getframe(2).f_globals["__name__"]
46+
segments.append(frame_name)
47+
48+
name = ".".join(segments)
49+
return _cached_logger(name, style_adaptor=style_adaptor)
50+
51+
3252
class _Logging(object):
33-
def __getattr__(self, attr):
34-
segments = []
35-
namespace = getattr(logging.config, "namespace", "")
36-
if namespace:
37-
segments.append(namespace)
53+
def debug(self, msg: Union[str, M], *args: Any, **kwargs: Any) -> None:
54+
logger = get_logger()
55+
logger.debug(msg, *args, **kwargs)
56+
57+
def info(self, msg: Union[str, M], *args: Any, **kwargs: Any) -> None:
58+
logger = get_logger()
59+
logger.info(msg, *args, **kwargs)
60+
61+
def warning(self, msg: Union[str, M], *args: Any, **kwargs: Any) -> None:
62+
logger = get_logger()
63+
logger.warning(msg, *args, **kwargs)
64+
65+
def error(self, msg: Union[str, M], *args: Any, **kwargs: Any) -> None:
66+
logger = get_logger()
67+
logger.error(msg, *args, **kwargs)
3868

39-
style_adaptor = getattr(logging.config, "style_adaptor", None)
69+
def exception(self, msg: Union[str, M], *args: Any, exc_info=True, **kwargs: Any) -> None:
70+
logger = get_logger()
71+
logger.exception(msg, *args, exc_info=exc_info, **kwargs)
4072

41-
# Ensure the logger name is pulled from 1 frame up rather than from the local frame.
42-
frame_name = sys._getframe(1).f_globals["__name__"]
43-
segments.append(frame_name)
73+
def critical(self, msg: Union[str, M], *args: Any, **kwargs: Any) -> None:
74+
logger = get_logger()
75+
logger.critical(msg, *args, **kwargs)
4476

45-
name = ".".join(segments)
46-
logger = _cached_logger(name, style_adaptor=style_adaptor)
47-
return getattr(logger, attr)
77+
def log(self, level: int, msg: Union[str, M], *args: Any, **kwargs: Any) -> None:
78+
logger = get_logger()
79+
logger.log(level, msg, *args, **kwargs)
4880

4981

5082
_cached_logger = lru_cache()(create_log_handler)

tests/test_adaptor.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import logging
2+
13
from setuplog import log, M, setup_logging
24

35

@@ -51,3 +53,12 @@ def __repr__(self):
5153
log.info(Foo())
5254
console_out, _ = capsys.readouterr()
5355
assert " - INFO - Foo(1, 2, 3)" in console_out
56+
57+
58+
def test_level_filter(caplog):
59+
caplog.set_level(logging.INFO)
60+
61+
setup_logging(style="format")
62+
63+
log.debug("asdf")
64+
assert len(caplog.records) == 0

tests/test_logger.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
import logging
12
import tempfile
23

3-
from setuplog import log, M, setup_logging, create_log_handler
4+
from setuplog import create_log_handler, log, M, setup_logging
45

56

67
def log_levels(logger):
78
logger.info("")
89
logger.warning("")
910
logger.error("")
11+
logger.exception("")
12+
logger.critical("")
13+
logger.log(logging.INFO, "")
1014

1115

1216
def log_multiple_lines(logger):

0 commit comments

Comments
 (0)