diff --git a/CHANGELOG.md b/CHANGELOG.md index 61dc143a..7b08f6ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## \[Unreleased\] -- Nothing yet. +### Fixed + +- `heredocs_to_strings` writes the heredoc's value rather than its own text. It was quoting the source -- markers and all -- so `< LarkRule: if isinstance(value, str): if value.startswith('"') and value.endswith('"'): - if not self.options.heredocs_to_strings and value.startswith('"<<-'): - match = HEREDOC_TRIM_PATTERN.match(value[1:-1]) - if match: + if value.startswith('"<<-') and HEREDOC_TRIM_PATTERN.match(value[1:-1]): + if not self.options.heredocs_to_strings: return self._deserialize_heredoc(value[1:-1], True) + return self._deserialize_string(self._heredoc_as_quoted(value[1:-1], True)) - if not self.options.heredocs_to_strings and value.startswith('"<<'): - match = HEREDOC_PATTERN.match(value[1:-1]) - if match: + if value.startswith('"<<') and HEREDOC_PATTERN.match(value[1:-1]): + if not self.options.heredocs_to_strings: return self._deserialize_heredoc(value[1:-1], False) + return self._deserialize_string(self._heredoc_as_quoted(value[1:-1], False)) if self.options.strings_to_heredocs: inner = value[1:-1] @@ -252,6 +252,24 @@ def _deserialize_string_part(self, value: str) -> StringPartRule: return StringPartRule([STRING_CHARS(value)]) + def _heredoc_as_quoted(self, heredoc: str, trim: bool) -> str: + """Return the quoted-string source for *heredoc*'s value. + + Not by quoting the heredoc's own text: that is what this option used to + do, and it produced `"< Union[HeredocTemplateRule, HeredocTrimTemplateRule]: diff --git a/test/unit/test_heredocs_to_strings.py b/test/unit/test_heredocs_to_strings.py new file mode 100644 index 00000000..0b7ce646 --- /dev/null +++ b/test/unit/test_heredocs_to_strings.py @@ -0,0 +1,71 @@ +# pylint: disable=C0103,C0114,C0115,C0116 +r"""`heredocs_to_strings` writes a value, not the heredoc's own text (GH #337). + +The option converts a heredoc into a quoted string. It was quoting the +heredoc's *source* -- markers and all -- across as many physical lines as the +original occupied: + + a = "< str: + return dumps(loads(source), deserializer_options=STRINGS) + + def test_a_plain_heredoc(self): + self.assertEqual(self._convert("a = <