diff --git a/src/styx/backend/python/pycodegen/core.py b/src/styx/backend/python/pycodegen/core.py index 755356c..514efcb 100644 --- a/src/styx/backend/python/pycodegen/core.py +++ b/src/styx/backend/python/pycodegen/core.py @@ -3,7 +3,7 @@ from abc import ABC from dataclasses import dataclass, field -from styx.backend.python.pycodegen.utils import enquote, ensure_endswith, linebreak_paragraph +from styx.backend.python.pycodegen.utils import enquote, ensure_endswith, escape_backslash, linebreak_paragraph LineBuffer = list[str] INDENT = " " @@ -110,7 +110,7 @@ def generate(self) -> LineBuffer: if arg.name == "self": continue arg_docstr = linebreak_paragraph( - f"{arg.name}: {arg.docstring if arg.docstring else ''}", + f"{arg.name}: {escape_backslash(arg.docstring) if arg.docstring else ''}", width=80 - (4 * 3) - 1, first_line_width=80 - (4 * 2) - 1, ) @@ -121,7 +121,7 @@ def generate(self) -> LineBuffer: # Add docstring (Google style) if self.docstring_body: - docstring_linebroken = linebreak_paragraph(self.docstring_body, width=80 - 4) + docstring_linebroken = linebreak_paragraph(escape_backslash(self.docstring_body), width=80 - 4) else: docstring_linebroken = [""] @@ -132,7 +132,7 @@ def generate(self) -> LineBuffer: "", "Args:", *indent(arg_docstr_buf), - *(["Returns:", *indent([f"{self.return_descr}"])] if self.return_descr else []), + *(["Returns:", *indent([f"{escape_backslash(self.return_descr)}"])] if self.return_descr else []), '"""', ]) ) @@ -162,7 +162,9 @@ def generate(self) -> LineBuffer: def _arg_docstring(arg: PyArg) -> LineBuffer: if not arg.docstring: return [] - return linebreak_paragraph(f'"""{arg.docstring}"""', width=80 - 4, first_line_width=80 - 4) + return linebreak_paragraph( + f'"""{escape_backslash(arg.docstring)}"""', width=80 - 4, first_line_width=80 - 4 + ) args = concat([[f.declaration(), *_arg_docstring(f)] for f in self.fields]) methods = concat([method.generate() for method in self.methods], [""]) @@ -173,7 +175,13 @@ def _arg_docstring(arg: PyArg) -> LineBuffer: f"class {self.name}:", *indent([ *( - ['"""', *linebreak_paragraph(self.docstring, width=80 - 4, first_line_width=80 - 4), '"""'] + [ + '"""', + *linebreak_paragraph( + escape_backslash(self.docstring), width=80 - 4, first_line_width=80 - 4 + ), + '"""', + ] if self.docstring else [] ), @@ -184,14 +192,17 @@ def _arg_docstring(arg: PyArg) -> LineBuffer: else: buf = [ f"class {self.name}(typing.NamedTuple):", - *indent([ - '"""', - f"{self.docstring}", - '"""', - *args, - *blank_before(methods), - ]), ] + if self.docstring: + buf.extend( + indent([ + '"""', + f"{escape_backslash(self.docstring)}", + '"""', + *args, + *blank_before(methods), + ]) + ) return buf @@ -219,7 +230,7 @@ def generate(self) -> LineBuffer: ) return blank_after([ - *(['"""', *linebreak_paragraph(self.docstr), '"""'] if self.docstr else []), + *(['"""', *linebreak_paragraph(escape_backslash(self.docstr)), '"""'] if self.docstr else []), *comment([ "This file was auto generated by Styx.", "Do not edit this file directly.", diff --git a/src/styx/backend/python/pycodegen/utils.py b/src/styx/backend/python/pycodegen/utils.py index 47ff0c0..bc4784a 100644 --- a/src/styx/backend/python/pycodegen/utils.py +++ b/src/styx/backend/python/pycodegen/utils.py @@ -154,3 +154,8 @@ def linebreak_paragraph(text: str, width: int = 80, first_line_width: int = 80) def ensure_endswith(text: str, suffix: str) -> str: """Ensure that a string ends with a specific suffix.""" return text if text.endswith(suffix) else f"{text}{suffix}" + + +def escape_backslash(s: str) -> str: + """Escape backslashes with double backslash.""" + return s.replace("\\", "\\\\")