Skip to content

Commit 05f5566

Browse files
authored
Fix off-by-one issue in pretty-formatter (#1665)
The pretty-format methods have a `max_line_length` that is used to keep the formatted output within the given number of columns when possible. The argument is supposed to be >0, but in some cases, `max(0, ...)` was used, resulting in errors when the limit was hit. This PR updates those calls to `max(1, ...)`. This PR includes some commits to better organize the tests - please view by commit.
1 parent bfd1952 commit 05f5566

File tree

5 files changed

+100
-81
lines changed

5 files changed

+100
-81
lines changed

metricflow-semantics/metricflow_semantics/mf_logging/pretty_print.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def _handle_sequence_obj(
9393
# Convert each item to a pretty string.
9494
items_as_str = tuple(
9595
self._handle_any_obj(
96-
list_item, remaining_line_width=max(0, remaining_line_width - len(self._indent_prefix))
96+
list_item, remaining_line_width=max(1, remaining_line_width - len(self._indent_prefix))
9797
)
9898
for list_item in list_like_obj
9999
)
@@ -216,7 +216,7 @@ def _handle_indented_key_value_item( # type: ignore[misc]
216216
# ]
217217

218218
# See if the value fits in the previous line.
219-
remaining_width_for_value = max(0, remaining_line_width - len(result_lines[-1]))
219+
remaining_width_for_value = max(1, remaining_line_width - len(result_lines[-1]))
220220
value_str = self._handle_any_obj(value, remaining_line_width=remaining_width_for_value)
221221
value_lines = value_str.splitlines()
222222

@@ -456,7 +456,7 @@ def mf_pformat_dict( # type: ignore
456456
else:
457457
value_str = mf_pformat(
458458
obj=value,
459-
max_line_length=max(0, max_line_length - len(indent_prefix)),
459+
max_line_length=max(1, max_line_length - len(indent_prefix)),
460460
indent_prefix=indent_prefix,
461461
include_object_field_names=include_object_field_names,
462462
include_none_object_fields=include_none_object_fields,

metricflow-semantics/tests_metricflow_semantics/mf_logging/__init__.py

Whitespace-only changes.

metricflow-semantics/tests_metricflow_semantics/mf_logging/test_lazy_format.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
from metricflow_semantics.formatting.formatting_helpers import mf_dedent
66
from metricflow_semantics.mf_logging.lazy_formattable import LazyFormat
7-
from tests_metricflow_semantics.mf_logging.recorded_logging_context import RecordingLogHandler, recorded_logging_context
87
from typing_extensions import override
98

9+
from tests_metricflow_semantics.mf_logging.recorded_logging_context import RecordingLogHandler, recorded_logging_context
10+
1011
logger = logging.getLogger(__name__)
1112

1213

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
from __future__ import annotations
2+
3+
import logging
4+
import textwrap
5+
6+
from metricflow_semantics.formatting.formatting_helpers import mf_dedent
7+
from metricflow_semantics.mf_logging.pretty_print import mf_pformat_dict
8+
9+
logger = logging.getLogger(__name__)
10+
11+
12+
def test_pformat_many() -> None: # noqa: D103
13+
result = mf_pformat_dict("Example description:", obj_dict={"object_0": (1, 2, 3), "object_1": {4: 5}})
14+
15+
assert (
16+
textwrap.dedent(
17+
"""\
18+
Example description:
19+
object_0: (1, 2, 3)
20+
object_1: {4: 5}
21+
"""
22+
).rstrip()
23+
== result
24+
)
25+
26+
27+
def test_pformat_many_with_raw_strings() -> None: # noqa: D103
28+
result = mf_pformat_dict("Example description:", obj_dict={"object_0": "foo\nbar"}, preserve_raw_strings=True)
29+
30+
assert (
31+
textwrap.dedent(
32+
"""\
33+
Example description:
34+
object_0:
35+
foo
36+
bar
37+
"""
38+
).rstrip()
39+
== result
40+
)
41+
42+
43+
def test_pformat_dict_with_empty_message() -> None:
44+
"""Test `mf_pformat_dict` without a description."""
45+
result = mf_pformat_dict(obj_dict={"object_0": (1, 2, 3), "object_1": {4: 5}})
46+
47+
assert (
48+
mf_dedent(
49+
"""
50+
object_0: (1, 2, 3)
51+
object_1: {4: 5}
52+
"""
53+
)
54+
== result
55+
)
56+
57+
58+
def test_pformat_dict_with_pad_sections_with_newline() -> None:
59+
"""Test `mf_pformat_dict` with new lines between sections."""
60+
result = mf_pformat_dict(obj_dict={"object_0": (1, 2, 3), "object_1": {4: 5}}, pad_items_with_newlines=True)
61+
62+
assert (
63+
mf_dedent(
64+
"""
65+
object_0: (1, 2, 3)
66+
67+
object_1: {4: 5}
68+
"""
69+
)
70+
== result
71+
)
72+
73+
74+
def test_pformat_many_with_strings() -> None: # noqa: D103
75+
result = mf_pformat_dict("Example description:", obj_dict={"object_0": "foo\nbar"})
76+
assert (
77+
textwrap.dedent(
78+
"""\
79+
Example description:
80+
object_0: 'foo\\nbar'
81+
"""
82+
).rstrip()
83+
== result
84+
)
85+
86+
87+
def test_minimal_length() -> None:
88+
"""Test where the max_line_length is the minimal length."""
89+
assert mf_pformat_dict("Example output", {"foo": "bar"}, max_line_length=1) == mf_dedent(
90+
"""
91+
Example output
92+
foo: 'bar'
93+
"""
94+
)

metricflow-semantics/tests_metricflow_semantics/collection_helpers/test_pretty_print.py renamed to metricflow-semantics/tests_metricflow_semantics/mf_logging/test_pretty_print.py

Lines changed: 1 addition & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77

88
from dbt_semantic_interfaces.implementations.elements.dimension import PydanticDimension
99
from dbt_semantic_interfaces.type_enums import DimensionType
10-
from metricflow_semantics.formatting.formatting_helpers import mf_dedent
1110
from metricflow_semantics.mf_logging.formatting import indent
1211
from metricflow_semantics.mf_logging.pretty_formattable import MetricFlowPrettyFormattable
13-
from metricflow_semantics.mf_logging.pretty_print import mf_pformat, mf_pformat_dict
12+
from metricflow_semantics.mf_logging.pretty_print import mf_pformat
1413
from metricflow_semantics.test_helpers.metric_time_dimension import MTD_SPEC_DAY
1514
from typing_extensions import override
1615

@@ -146,50 +145,6 @@ def test_pydantic_model() -> None: # noqa: D103
146145
)
147146

148147

149-
def test_pformat_many() -> None: # noqa: D103
150-
result = mf_pformat_dict("Example description:", obj_dict={"object_0": (1, 2, 3), "object_1": {4: 5}})
151-
152-
assert (
153-
textwrap.dedent(
154-
"""\
155-
Example description:
156-
object_0: (1, 2, 3)
157-
object_1: {4: 5}
158-
"""
159-
).rstrip()
160-
== result
161-
)
162-
163-
164-
def test_pformat_many_with_raw_strings() -> None: # noqa: D103
165-
result = mf_pformat_dict("Example description:", obj_dict={"object_0": "foo\nbar"}, preserve_raw_strings=True)
166-
167-
assert (
168-
textwrap.dedent(
169-
"""\
170-
Example description:
171-
object_0:
172-
foo
173-
bar
174-
"""
175-
).rstrip()
176-
== result
177-
)
178-
179-
180-
def test_pformat_many_with_strings() -> None: # noqa: D103
181-
result = mf_pformat_dict("Example description:", obj_dict={"object_0": "foo\nbar"})
182-
assert (
183-
textwrap.dedent(
184-
"""\
185-
Example description:
186-
object_0: 'foo\\nbar'
187-
"""
188-
).rstrip()
189-
== result
190-
)
191-
192-
193148
def test_custom_pretty_print() -> None:
194149
"""Check that `MetricFlowPrettyFormattable` can be used to override the result when using MF's pretty-printer."""
195150

@@ -204,34 +159,3 @@ def pretty_format(self) -> Optional[str]:
204159
return f"{self.__class__.__name__}({self.field_0:.2f})"
205160

206161
assert mf_pformat(_ExampleDataclass(1.2345)) == f"{_ExampleDataclass.__name__}(1.23)"
207-
208-
209-
def test_pformat_dict_with_empty_message() -> None:
210-
"""Test `mf_pformat_dict` without a description."""
211-
result = mf_pformat_dict(obj_dict={"object_0": (1, 2, 3), "object_1": {4: 5}})
212-
213-
assert (
214-
mf_dedent(
215-
"""
216-
object_0: (1, 2, 3)
217-
object_1: {4: 5}
218-
"""
219-
)
220-
== result
221-
)
222-
223-
224-
def test_pformat_dict_with_pad_sections_with_newline() -> None:
225-
"""Test `mf_pformat_dict` with new lines between sections."""
226-
result = mf_pformat_dict(obj_dict={"object_0": (1, 2, 3), "object_1": {4: 5}}, pad_items_with_newlines=True)
227-
228-
assert (
229-
mf_dedent(
230-
"""
231-
object_0: (1, 2, 3)
232-
233-
object_1: {4: 5}
234-
"""
235-
)
236-
== result
237-
)

0 commit comments

Comments
 (0)