Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ You can find our backwards-compatibility policy [here](https://github.com/hynek/
- Same for *sort_keys*.
[#756](https://github.com/hynek/structlog/pull/756)

- Same for *columns*.
[#757](https://github.com/hynek/structlog/pull/757)

- Added `structlog.dev.ConsoleRenderer.get_default_column_styles` for reuse the default column styles.
[#741](https://github.com/hynek/structlog/pull/741)

Expand Down
2 changes: 1 addition & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ API Reference
.. automodule:: structlog.dev

.. autoclass:: ConsoleRenderer
:members: get_default_level_styles, get_default_column_styles, exception_formatter, sort_keys
:members: get_default_level_styles, get_default_column_styles, exception_formatter, sort_keys, columns

.. autoclass:: ColumnStyles

Expand Down
9 changes: 5 additions & 4 deletions docs/console-output.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,14 @@ cr = structlog.dev.ConsoleRenderer(
structlog.configure(processors=structlog.get_config()["processors"][:-1]+[cr])
```

:::{hint}
You can replace only the last processor using:
You can also access and configure the columns of the active console renderer:

```python
structlog.configure(processors=structlog.get_config()["processors"][:-1]+[cr])
cr = structlog.dev.get_active_console_renderer()
cr.columns = [
...
]
```
:::


## Standard environment variables
Expand Down
55 changes: 44 additions & 11 deletions src/structlog/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,8 @@ class ConsoleRenderer:
.. versionadded:: 24.2.0 *pad_level*
"""

_default_column_formatter: ColumnFormatter

def __init__(
self,
pad_event: int = _EVENT_WIDTH,
Expand Down Expand Up @@ -636,16 +638,7 @@ def add_meaningless_arg(arg: str) -> None:
for w in to_warn:
warnings.warn(w, stacklevel=2)

defaults = [col for col in columns if col.key == ""]
if not defaults:
raise ValueError(
"Must pass a default column formatter (a column with `key=''`)."
)
if len(defaults) > 1:
raise ValueError("Only one default column formatter allowed.")

self._default_column_formatter = defaults[0].formatter
self._columns = [col for col in columns if col.key]
self.columns = columns

return

Expand Down Expand Up @@ -808,7 +801,7 @@ def __call__(

kvs = [
col.formatter(col.key, val)
for col in self._columns
for col in self.columns
if (val := event_dict.pop(col.key, _NOTHING)) is not _NOTHING
] + [
self._default_column_formatter(key, event_dict[key])
Expand Down Expand Up @@ -901,6 +894,46 @@ def sort_keys(self, value: bool) -> None:
"""
self._sort_keys = value

@property
def columns(self) -> list[Column]:
"""
The columns configuration for this console renderer.

Warning:
Just like with passing *columns* argument, many of the other
arguments you may have passed are ignored.

Args:
value:
A list of `Column` objects defining both the order and format
of the key-value pairs in the output.

**Must** contain a column with ``key=''`` that defines the
default formatter.

Raises:
ValueError: If there's not exactly one default column formatter.

.. versionadded:: 25.5.0
"""
return [Column("", self._default_column_formatter), *self._columns]

@columns.setter
def columns(self, value: list[Column]) -> None:
"""
.. versionadded:: 25.5.0
"""
defaults = [col for col in value if col.key == ""]
if not defaults:
raise ValueError(
"Must pass a default column formatter (a column with `key=''`)."
)
if len(defaults) > 1:
raise ValueError("Only one default column formatter allowed.")

self._default_column_formatter = defaults[0].formatter
self._columns = [col for col in value if col.key]


_SENTINEL = object()

Expand Down
15 changes: 15 additions & 0 deletions tests/test_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,21 @@ def test_sort_keys_property(self, cr):
assert cr.sort_keys is True
assert cr._sort_keys is True

def test_columns_property(self, cr):
"""
The columns property can be set and retrieved without re-instantiating
ConsoleRenderer.

The property also fakes the default column formatter.
"""
cols = [dev.Column("", lambda k, v: "")]

cr.columns = cols

assert cols == cr.columns
assert [] == cr._columns
assert cols[0].formatter == cr._default_column_formatter


class TestSetExcInfo:
def test_wrong_name(self):
Expand Down