Skip to content

Commit

Permalink
Merge branch 'main' into reset
Browse files Browse the repository at this point in the history
  • Loading branch information
hynek authored Aug 27, 2021
2 parents 4aa209b + 37d0b5a commit 892d90a
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 57 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ repos:
language_version: python3.8

- repo: https://github.com/PyCQA/isort
rev: 5.9.2
rev: 5.9.3
hooks:
- id: isort
additional_dependencies: [toml]
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ Changes:
This only works if ``format_exc_info`` is **absent** in the processor chain.
- ``structlog.threadlocal.get_threadlocal()`` and ``structlog.contextvars.get_threadlocal()`` can now be used to get a copy of the current thread-local/context-local context that has been bound using ``structlog.threadlocal.bind_threadlocal()`` and ``structlog.contextvars.bind_contextvars()``.
- ``structlog.threadlocal.get_merged_threadlocal(bl)`` and ``structlog.contextvars.get_merged_contextvars(bl)`` do the same, but also merge the context from a bound logger *bl*.
- All use of ``colorama`` on non-Windows systems has been excised.
Thus, colors are now enabled by default in ``structlog.dev.ConsoleRenderer`` on non-Windows systems.
You can keep using ``colorama`` to customize colors, of course.


----
Expand Down
2 changes: 1 addition & 1 deletion docs/development.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Development

To make development a more pleasurable experience, ``structlog`` comes with the `structlog.dev` module.

The highlight is `structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful (requires the `colorama package <https://pypi.org/project/colorama/>`_ installed) console output.
The highlight is `structlog.dev.ConsoleRenderer` that offers nicely aligned and colorful (requires the `colorama package <https://pypi.org/project/colorama/>`_ if on Windows) console output.
If the `better-exceptions <https://github.com/Qix-/better-exceptions>`_ package is installed, it will also pretty-print exceptions with helpful contextual data.

.. figure:: _static/console_renderer.png
Expand Down
3 changes: 2 additions & 1 deletion docs/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ Here, ``structlog`` takes full advantage of its hopefully useful default setting
- All keywords are formatted using `structlog.dev.ConsoleRenderer`.
That in turn uses `repr` to serialize all values to strings.
Thus, it's easy to add support for logging of your own objects\ [*]_.
- If you have `colorama <https://pypi.org/project/colorama/>`_ installed, it's rendered in nice `colors <development>`.
- On Windows, if you have `colorama <https://pypi.org/project/colorama/>`_ installed, it's rendered in nice `colors <development>`.
Other OSes do not need colorama for nice colors.
- If you have `better-exceptions <https://github.com/qix-/better-exceptions>`_ installed, exceptions will be rendered in colors and with additional helpful information.

It should be noted that even in most complex logging setups the example would still look just like that thanks to `configuration`.
Expand Down
14 changes: 11 additions & 3 deletions docs/thread-local.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Thread Local-Context
Thread-Local Context
====================

.. testsetup:: *
Expand Down Expand Up @@ -50,6 +50,8 @@ The general flow of using these functions is:
>>> from structlog.threadlocal import (
... bind_threadlocal,
... clear_threadlocal,
... get_merged_threadlocal,
... get_threadlocal,
... merge_threadlocal,
... )
>>> from structlog import configure
Expand All @@ -61,15 +63,21 @@ The general flow of using these functions is:
... )
>>> log = structlog.get_logger()
>>> # At the top of your request handler (or, ideally, some general
>>> # middleware), clear the threadlocal context and bind some common
>>> # middleware), clear the thread-local context and bind some common
>>> # values:
>>> clear_threadlocal()
>>> bind_threadlocal(a=1)
>>> # Then use loggers as per normal
>>> # (perhaps by using structlog.get_logger() to create them).
>>> log.msg("hi")
a=1 event='hi'
>>> # And when we clear the threadlocal state again, it goes away.
>>> # You can access the current thread-local state.
>>> get_threadlocal()
{'a': 1}
>>> # Or get it merged with a bound logger.
>>> get_merged_threadlocal(log.bind(example=True))
{'a': 1, 'example': True}
>>> # And when we clear the thread-local state again, it goes away.
>>> clear_threadlocal()
>>> log.msg("hi there")
event='hi there'
Expand Down
4 changes: 2 additions & 2 deletions src/structlog/_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

from ._log_levels import make_filtering_bound_logger
from ._loggers import PrintLoggerFactory
from .dev import ConsoleRenderer, _has_colorama, set_exc_info
from .dev import ConsoleRenderer, _use_colors, set_exc_info
from .processors import StackInfoRenderer, TimeStamper, add_log_level
from .types import BindableLogger, Context, Processor, WrappedLogger

Expand All @@ -39,7 +39,7 @@
set_exc_info,
TimeStamper(fmt="%Y-%m-%d %H:%M.%S", utc=False),
ConsoleRenderer(
colors=_has_colorama and sys.stdout is not None and sys.stdout.isatty()
colors=_use_colors and sys.stdout is not None and sys.stdout.isatty()
),
]
_BUILTIN_DEFAULT_CONTEXT_CLASS = cast(Type[Context], dict)
Expand Down
75 changes: 41 additions & 34 deletions src/structlog/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ def _pad(s: str, length: int) -> str:


if colorama is not None:
_has_colorama = True

RESET_ALL = colorama.Style.RESET_ALL
BRIGHT = colorama.Style.BRIGHT
DIM = colorama.Style.DIM
Expand All @@ -60,11 +58,27 @@ def _pad(s: str, length: int) -> str:
GREEN = colorama.Fore.GREEN
RED_BACK = colorama.Back.RED
else:
_has_colorama = False

RESET_ALL = (
BRIGHT
) = DIM = RED = BLUE = CYAN = MAGENTA = YELLOW = GREEN = RED_BACK = ""
# These are the same values as the colorama color codes. Redefining them
# here allows users to specify that they want color without having to
# install colorama, which is only supposed to be necessary in Windows.
RESET_ALL = "\033[0m"
BRIGHT = "\033[1m"
DIM = "\033[2m"
RED = "\033[31m"
BLUE = "\033[34m"
CYAN = "\033[36m"
MAGENTA = "\033[35m"
YELLOW = "\033[33m"
GREEN = "\033[32m"
RED_BACK = "\033[41m"


if _IS_WINDOWS: # pragma: no cover
# On Windows, use colors by default only if colorama is installed.
_use_colors = colorama is not None
else:
# On other OSes, use colors by default.
_use_colors = True


class _Styles(Protocol):
Expand Down Expand Up @@ -174,34 +188,39 @@ class ConsoleRenderer:
`structlog.processors.format_exc_info` processor together with
`ConsoleRenderer` anymore! It will keep working, but you can't have
pretty exceptions and a warning will be raised if you ask for them.
.. versionchanged:: 21.3 The colors keyword now defaults to True on
non-Windows systems, and either True or False in Windows depending on
whether colorama is installed.
"""

def __init__(
self,
pad_event: int = _EVENT_WIDTH,
colors: bool = _has_colorama,
colors: bool = _use_colors,
force_colors: bool = False,
repr_native_str: bool = False,
level_styles: Optional[Styles] = None,
pretty_exceptions: bool = (better_exceptions is not None),
):
self._force_colors = self._init_colorama = False
styles: Styles
if colors is True:
if colorama is None:
raise SystemError(
_MISSING.format(
who=self.__class__.__name__ + " with `colors=True`",
package="colorama",
)
)

if colors:
if _IS_WINDOWS: # pragma: no cover
_init_colorama(self._force_colors)
else:
self._init_colorama = True
# On Windows, we can't do colorful output without colorama.
if colorama is None:
classname = self.__class__.__name__
raise SystemError(
_MISSING.format(
who=classname + " with `colors=True`",
package="colorama",
)
)
# Colorama must be init'd on Windows, but must NOT be
# init'd on other OSes, because it can break colors.
if force_colors:
self._force_colors = True
colorama.deinit()
colorama.init(strip=False)
else:
colorama.init()

styles = _ColorfulStyles
else:
Expand Down Expand Up @@ -241,10 +260,6 @@ def __call__(
self, logger: WrappedLogger, name: str, event_dict: EventDict
) -> str:

# Initialize lazily to prevent import side-effects.
if self._init_colorama:
_init_colorama(self._force_colors)
self._init_colorama = False
sio = StringIO()

ts = event_dict.pop("timestamp", None)
Expand Down Expand Up @@ -366,14 +381,6 @@ def get_default_level_styles(colors: bool = True) -> Any:
}


def _init_colorama(force: bool) -> None:
if force:
colorama.deinit()
colorama.init(strip=False)
else:
colorama.init()


_SENTINEL = object()


Expand Down
7 changes: 0 additions & 7 deletions src/structlog/stdlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,13 +367,6 @@ class AsyncBoundLogger:
the processor chain (e.g. JSON serialization) and I/O won't block your
whole application.
.. warning: Since the processor pipeline runs in a separate thread,
`structlog.contextvars.merge_contextvars` does **nothing** and should
be removed from you processor chain.
Instead it's merged within **this logger** before handing off log
processing to the thread.
Only available for Python 3.7 and later.
:ivar structlog.stdlib.BoundLogger sync_bl: The wrapped synchronous logger.
Expand Down
19 changes: 11 additions & 8 deletions tests/test_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def test_negative(self):

@pytest.fixture(name="cr")
def _cr():
return dev.ConsoleRenderer(colors=dev._has_colorama)
return dev.ConsoleRenderer(colors=dev._use_colors)


@pytest.fixture(name="styles")
Expand All @@ -47,11 +47,14 @@ def _unpadded(styles):


class TestConsoleRenderer:
@pytest.mark.skipif(dev._has_colorama, reason="Colorama must be missing.")
@pytest.mark.skipif(dev.colorama, reason="Colorama must be missing.")
@pytest.mark.skipif(
not dev._IS_WINDOWS, reason="Must be running on Windows."
)
def test_missing_colorama(self):
"""
ConsoleRenderer(colors=True) raises SystemError on initialization if
colorama is missing.
colorama is missing and _IS_WINDOWS is True.
"""
with pytest.raises(SystemError) as e:
dev.ConsoleRenderer(colors=True)
Expand Down Expand Up @@ -117,11 +120,11 @@ def test_init_accepts_overriding_levels(self, styles, padded):
Stdlib levels are rendered aligned, in brackets, and color coded.
"""
my_styles = dev.ConsoleRenderer.get_default_level_styles(
colors=dev._has_colorama
colors=dev._use_colors
)
my_styles["MY_OH_MY"] = my_styles["critical"]
cr = dev.ConsoleRenderer(
colors=dev._has_colorama, level_styles=my_styles
colors=dev._use_colors, level_styles=my_styles
)

# this would blow up if the level_styles override failed
Expand Down Expand Up @@ -234,7 +237,7 @@ def test_pad_event_param(self, styles):
"""
`pad_event` parameter works.
"""
rv = dev.ConsoleRenderer(42, dev._has_colorama)(
rv = dev.ConsoleRenderer(42, dev._use_colors)(
None, None, {"event": "test", "foo": "bar"}
)

Expand Down Expand Up @@ -350,7 +353,7 @@ def test_colorama_force_colors(self, styles, padded):
If force_colors is True, use colors even if the destination is non-tty.
"""
cr = dev.ConsoleRenderer(
colors=dev._has_colorama, force_colors=dev._has_colorama
colors=dev._use_colors, force_colors=dev._use_colors
)

rv = cr(
Expand All @@ -374,7 +377,7 @@ def test_colorama_force_colors(self, styles, padded):
+ styles.reset
) == rv

assert not dev._has_colorama or dev._ColorfulStyles is cr._styles
assert not dev._use_colors or dev._ColorfulStyles is cr._styles

@pytest.mark.parametrize("rns", [True, False])
def test_repr_native_str(self, rns):
Expand Down

0 comments on commit 892d90a

Please sign in to comment.