langroid 0.16.5__py3-none-any.whl → 0.16.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- langroid/agent/md_tool_message_grammar.py +455 -0
- langroid/agent/tools/code_file_tool_parse.py +150 -0
- langroid/agent/tools/code_file_tool_pyparsing.py +194 -0
- langroid/agent/tools/code_file_tool_pyparsing2.py +199 -0
- langroid/agent/tools/formatted_model_custom.py +150 -0
- langroid/agent/tools/formatted_model_custom2.py +168 -0
- langroid/agent/tools/formatted_model_custom3.py +279 -0
- langroid/agent/tools/formatted_model_custom4.py +395 -0
- langroid/agent/tools/formatted_model_jinja.py +133 -0
- langroid/agent/tools/formatted_model_jinja.py-e +122 -0
- langroid/agent/tools/formatted_model_jinja2.py +145 -0
- langroid/agent/tools/formatted_model_jinja2.py-e +135 -0
- langroid/agent/tools/formatted_model_lark.py +0 -0
- langroid/agent/tools/formatted_model_lark2.py +168 -0
- langroid/agent/tools/formatted_model_parse.py +105 -0
- langroid/agent/tools/formatted_model_parse.py-e +98 -0
- langroid/agent/tools/formatted_model_parse2.py +113 -0
- langroid/agent/tools/formatted_model_parse2.py-e +109 -0
- langroid/agent/tools/formatted_model_parse3.py +114 -0
- langroid/agent/tools/formatted_model_parse3.py-e +110 -0
- langroid/agent/tools/formatted_model_parsimon.py +194 -0
- langroid/agent/tools/formatted_model_parsimon.py-e +186 -0
- langroid/agent/tools/formatted_model_pyparsing.py +169 -0
- langroid/agent/tools/formatted_model_pyparsing.py-e +149 -0
- langroid/agent/tools/formatted_model_pyparsing2.py +159 -0
- langroid/agent/tools/formatted_model_pyparsing2.py-e +143 -0
- langroid/agent/tools/formatted_model_pyparsing3.py +133 -0
- langroid/agent/tools/formatted_model_pyparsing3.py-e +121 -0
- langroid/agent/tools/formatted_model_pyparsing4.py +213 -0
- langroid/agent/tools/formatted_model_pyparsing4.py-e +176 -0
- langroid/agent/tools/formatted_model_pyparsing5.py +173 -0
- langroid/agent/tools/formatted_model_pyparsing5.py-e +142 -0
- langroid/agent/tools/formatted_model_regex.py +246 -0
- langroid/agent/tools/formatted_model_regex.py-e +248 -0
- langroid/agent/tools/formatted_model_regex2.py +250 -0
- langroid/agent/tools/formatted_model_regex2.py-e +253 -0
- langroid/agent/tools/formatted_model_tatsu.py +172 -0
- langroid/agent/tools/formatted_model_tatsu.py-e +160 -0
- langroid/agent/tools/formatted_model_template.py +217 -0
- langroid/agent/tools/formatted_model_template.py-e +200 -0
- langroid/agent/tools/formatted_model_xml.py +178 -0
- langroid/agent/tools/formatted_model_xml2.py +178 -0
- langroid/agent/tools/formatted_model_xml3.py +132 -0
- langroid/agent/tools/formatted_model_xml4.py +130 -0
- langroid/agent/tools/formatted_model_xml5.py +130 -0
- langroid/agent/tools/formatted_model_xml6.py +113 -0
- langroid/agent/tools/formatted_model_xml7.py +117 -0
- langroid/agent/tools/formatted_model_xml8.py +164 -0
- langroid/agent/tools/generic_tool.py +165 -0
- langroid/agent/tools/generic_tool_tatsu.py +275 -0
- langroid/agent/tools/grammar_based_model.py +132 -0
- langroid/agent/tools/grammar_based_model.py-e +128 -0
- langroid/agent/tools/grammar_based_model_lark.py +156 -0
- langroid/agent/tools/grammar_based_model_lark.py-e +153 -0
- langroid/agent/tools/grammar_based_model_parse.py +86 -0
- langroid/agent/tools/grammar_based_model_parse.py-e +80 -0
- langroid/agent/tools/grammar_based_model_parsimonious.py +129 -0
- langroid/agent/tools/grammar_based_model_parsimonious.py-e +120 -0
- langroid/agent/tools/grammar_based_model_pyparsing.py +105 -0
- langroid/agent/tools/grammar_based_model_pyparsing.py-e +103 -0
- langroid/agent/tools/grammar_based_model_regex.py +139 -0
- langroid/agent/tools/grammar_based_model_regex.py-e +130 -0
- langroid/agent/tools/grammar_based_model_regex2.py +124 -0
- langroid/agent/tools/grammar_based_model_regex2.py-e +116 -0
- langroid/agent/tools/grammar_based_model_tatsu.py +80 -0
- langroid/agent/tools/grammar_based_model_tatsu.py-e +77 -0
- langroid/agent/tools/lark_earley_example.py +135 -0
- langroid/agent/tools/lark_earley_example.py-e +117 -0
- langroid/agent/tools/lark_example.py +72 -0
- langroid/agent/tools/parse_example.py +76 -0
- langroid/agent/tools/parse_example2.py +87 -0
- langroid/agent/tools/parse_example3.py +42 -0
- langroid/agent/tools/parse_test.py +791 -0
- langroid/agent/xml_tool_message.py +106 -0
- langroid/language_models/openai_gpt.py +6 -1
- {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/METADATA +1 -1
- {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/RECORD +80 -6
- pyproject.toml +1 -1
- {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/LICENSE +0 -0
- {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/WHEEL +0 -0
@@ -0,0 +1,246 @@
|
|
1
|
+
import re
|
2
|
+
from abc import ABC, abstractmethod
|
3
|
+
from typing import Dict, Type, TypeVar
|
4
|
+
|
5
|
+
from langroid.pydantic_v1 import BaseModel
|
6
|
+
|
7
|
+
T = TypeVar("T", bound="FormattingModel")
|
8
|
+
|
9
|
+
|
10
|
+
class FormattingModel(BaseModel, ABC):
|
11
|
+
@classmethod
|
12
|
+
@abstractmethod
|
13
|
+
def format_spec(cls) -> str:
|
14
|
+
pass
|
15
|
+
|
16
|
+
@classmethod
|
17
|
+
@abstractmethod
|
18
|
+
def start_token(cls) -> str:
|
19
|
+
pass
|
20
|
+
|
21
|
+
@classmethod
|
22
|
+
@abstractmethod
|
23
|
+
def end_token(cls) -> str:
|
24
|
+
pass
|
25
|
+
|
26
|
+
@classmethod
|
27
|
+
@abstractmethod
|
28
|
+
def field_mappings(cls) -> Dict[str, str]:
|
29
|
+
pass
|
30
|
+
|
31
|
+
@classmethod
|
32
|
+
def parse(cls: Type[T], text: str) -> T:
|
33
|
+
# Remove start and end tokens
|
34
|
+
content = text.strip()[len(cls.start_token()) : -len(cls.end_token())].strip()
|
35
|
+
|
36
|
+
# Create regex pattern from format_spec
|
37
|
+
pattern = cls.format_spec()
|
38
|
+
for field, token in cls.field_mappings().items():
|
39
|
+
pattern = pattern.replace(token, f"(?P<{field}>.*?)")
|
40
|
+
|
41
|
+
# Extract data using regex
|
42
|
+
match = re.match(pattern, content, re.DOTALL)
|
43
|
+
if not match:
|
44
|
+
raise ValueError("Invalid format")
|
45
|
+
|
46
|
+
# Create instance with extracted data
|
47
|
+
data = {field: match.group(field).strip() for field in cls.field_mappings()}
|
48
|
+
return cls(**data)
|
49
|
+
|
50
|
+
def generate(self) -> str:
|
51
|
+
# Start with the format spec
|
52
|
+
result = self.format_spec()
|
53
|
+
|
54
|
+
# Replace tokens with actual values
|
55
|
+
for field, token in self.field_mappings().items():
|
56
|
+
value = getattr(self, field)
|
57
|
+
result = result.replace(token, str(value))
|
58
|
+
|
59
|
+
# Wrap with start and end tokens
|
60
|
+
return f"{self.start_token()}\n{result}\n{self.end_token()}"
|
61
|
+
|
62
|
+
|
63
|
+
class MyFormattedModel(FormattingModel):
|
64
|
+
name: str
|
65
|
+
age: int
|
66
|
+
city: str
|
67
|
+
|
68
|
+
@classmethod
|
69
|
+
def format_spec(cls) -> str:
|
70
|
+
return "name: {NAME}\n{AGE} is the age\nlives in {CITY}"
|
71
|
+
|
72
|
+
@classmethod
|
73
|
+
def start_token(cls) -> str:
|
74
|
+
return "<format>"
|
75
|
+
|
76
|
+
@classmethod
|
77
|
+
def end_token(cls) -> str:
|
78
|
+
return "</format>"
|
79
|
+
|
80
|
+
@classmethod
|
81
|
+
def field_mappings(cls) -> Dict[str, str]:
|
82
|
+
return {"name": "{NAME}", "age": "{AGE}", "city": "{CITY}"}
|
83
|
+
|
84
|
+
|
85
|
+
if __name__ == "__main__":
|
86
|
+
# Test object to string
|
87
|
+
model = MyFormattedModel(name="John", age=30, city="Tokyo")
|
88
|
+
generated = model.generate()
|
89
|
+
print("Generated string:")
|
90
|
+
print(generated)
|
91
|
+
print()
|
92
|
+
|
93
|
+
# Test string to object
|
94
|
+
parsed = MyFormattedModel.parse(generated)
|
95
|
+
print("Parsed object:")
|
96
|
+
print(parsed)
|
97
|
+
print()
|
98
|
+
|
99
|
+
# Test round-trip
|
100
|
+
print("Round-trip test:")
|
101
|
+
print("Original == Parsed:", model == parsed)
|
102
|
+
|
103
|
+
# Test with different values
|
104
|
+
another_model = MyFormattedModel(name="Alice", age=25, city="New York")
|
105
|
+
another_generated = another_model.generate()
|
106
|
+
print("\nAnother generated string:")
|
107
|
+
print(another_generated)
|
108
|
+
print()
|
109
|
+
|
110
|
+
another_parsed = MyFormattedModel.parse(another_generated)
|
111
|
+
print("Another parsed object:")
|
112
|
+
print(another_parsed)
|
113
|
+
print("Another Original == Another Parsed:", another_model == another_parsed)
|
114
|
+
|
115
|
+
# code file model
|
116
|
+
class CodeFileModel(FormattingModel):
|
117
|
+
language: str
|
118
|
+
file_path: str
|
119
|
+
code: str
|
120
|
+
|
121
|
+
@classmethod
|
122
|
+
def format_spec(cls) -> str:
|
123
|
+
return "code_file_model\nfile_path: {FILE_PATH}\n```{LANGUAGE}\n{CODE}\n```"
|
124
|
+
|
125
|
+
@classmethod
|
126
|
+
def start_token(cls) -> str:
|
127
|
+
return "<format>"
|
128
|
+
|
129
|
+
@classmethod
|
130
|
+
def end_token(cls) -> str:
|
131
|
+
return "</format>"
|
132
|
+
|
133
|
+
@classmethod
|
134
|
+
def field_mappings(cls) -> Dict[str, str]:
|
135
|
+
return {
|
136
|
+
"file_path": "{FILE_PATH}",
|
137
|
+
"language": "{LANGUAGE}",
|
138
|
+
"code": "{CODE}",
|
139
|
+
}
|
140
|
+
|
141
|
+
print("\nTesting CodeFileModel:")
|
142
|
+
code_model = CodeFileModel(
|
143
|
+
language="python",
|
144
|
+
file_path="src/main.py",
|
145
|
+
code='def hello():\n print("Hello, World!")',
|
146
|
+
)
|
147
|
+
code_generated = code_model.generate()
|
148
|
+
print("Generated CodeFileModel string:")
|
149
|
+
print(code_generated)
|
150
|
+
print()
|
151
|
+
|
152
|
+
code_parsed = CodeFileModel.parse(code_generated)
|
153
|
+
print("Parsed CodeFileModel object:")
|
154
|
+
print(code_parsed)
|
155
|
+
print()
|
156
|
+
|
157
|
+
print("CodeFileModel Round-trip test:")
|
158
|
+
print("Original == Parsed:", code_model == code_parsed)
|
159
|
+
|
160
|
+
# tolerant format
|
161
|
+
#
|
162
|
+
class CodeFileModel(FormattingModel):
|
163
|
+
language: str
|
164
|
+
file_path: str
|
165
|
+
code: str
|
166
|
+
|
167
|
+
@classmethod
|
168
|
+
def format_spec(cls) -> str:
|
169
|
+
return (
|
170
|
+
r"code_file_model\s*\n"
|
171
|
+
r"file_path:\s*{FILE_PATH}\s*\n"
|
172
|
+
r"```\s*{LANGUAGE}\s*\n"
|
173
|
+
r"{CODE}\s*"
|
174
|
+
r"```"
|
175
|
+
)
|
176
|
+
|
177
|
+
@classmethod
|
178
|
+
def start_token(cls) -> str:
|
179
|
+
return "<format>"
|
180
|
+
|
181
|
+
@classmethod
|
182
|
+
def end_token(cls) -> str:
|
183
|
+
return "</format>"
|
184
|
+
|
185
|
+
@classmethod
|
186
|
+
def field_mappings(cls) -> Dict[str, str]:
|
187
|
+
return {
|
188
|
+
"file_path": "{FILE_PATH}",
|
189
|
+
"language": "{LANGUAGE}",
|
190
|
+
"code": "{CODE}",
|
191
|
+
}
|
192
|
+
|
193
|
+
print("\nTesting CodeFileModel with various whitespace variations:")
|
194
|
+
|
195
|
+
test_strings = [
|
196
|
+
# Standard format
|
197
|
+
"""<format>
|
198
|
+
code_file_model
|
199
|
+
file_path: src/main.py
|
200
|
+
```python
|
201
|
+
def hello():
|
202
|
+
print("Hello, World!")
|
203
|
+
```
|
204
|
+
</format>""",
|
205
|
+
# Extra whitespace
|
206
|
+
"""<format>
|
207
|
+
code_file_model
|
208
|
+
file_path: src/main.py
|
209
|
+
``` python
|
210
|
+
def hello():
|
211
|
+
print("Hello, World!")
|
212
|
+
```
|
213
|
+
</format>""",
|
214
|
+
# Extra newlines
|
215
|
+
"""<format>
|
216
|
+
code_file_model
|
217
|
+
|
218
|
+
file_path: src/main.py
|
219
|
+
|
220
|
+
```python
|
221
|
+
|
222
|
+
def hello():
|
223
|
+
print("Hello, World!")
|
224
|
+
|
225
|
+
```
|
226
|
+
|
227
|
+
</format>""",
|
228
|
+
]
|
229
|
+
|
230
|
+
for i, test_string in enumerate(test_strings, 1):
|
231
|
+
print(f"\nTest {i}:")
|
232
|
+
print("Input string:")
|
233
|
+
print(test_string)
|
234
|
+
|
235
|
+
parsed = CodeFileModel.parse(test_string)
|
236
|
+
print("\nParsed object:")
|
237
|
+
print(parsed)
|
238
|
+
|
239
|
+
regenerated = parsed.generate()
|
240
|
+
print("\nRegenerated string:")
|
241
|
+
print(regenerated)
|
242
|
+
|
243
|
+
reparsed = CodeFileModel.parse(regenerated)
|
244
|
+
print("\nRound-trip test:")
|
245
|
+
print("Original parsed == Reparsed:", parsed == reparsed)
|
246
|
+
print("-" * 50)
|
@@ -0,0 +1,248 @@
|
|
1
|
+
from pydantic import BaseModel
|
2
|
+
from abc import ABC, abstractmethod
|
3
|
+
import re
|
4
|
+
from typing import Dict, Type, TypeVar
|
5
|
+
|
6
|
+
T = TypeVar('T', bound='FormattingModel')
|
7
|
+
|
8
|
+
class FormattingModel(BaseModel, ABC):
|
9
|
+
@classmethod
|
10
|
+
@abstractmethod
|
11
|
+
def format_spec(cls) -> str:
|
12
|
+
pass
|
13
|
+
|
14
|
+
@classmethod
|
15
|
+
@abstractmethod
|
16
|
+
def start_token(cls) -> str:
|
17
|
+
pass
|
18
|
+
|
19
|
+
@classmethod
|
20
|
+
@abstractmethod
|
21
|
+
def end_token(cls) -> str:
|
22
|
+
pass
|
23
|
+
|
24
|
+
@classmethod
|
25
|
+
@abstractmethod
|
26
|
+
def field_mappings(cls) -> Dict[str, str]:
|
27
|
+
pass
|
28
|
+
|
29
|
+
@classmethod
|
30
|
+
def parse(cls: Type[T], text: str) -> T:
|
31
|
+
# Remove start and end tokens
|
32
|
+
content = text.strip()[len(cls.start_token()):-len(cls.end_token())].strip()
|
33
|
+
|
34
|
+
# Create regex pattern from format_spec
|
35
|
+
pattern = cls.format_spec()
|
36
|
+
for field, token in cls.field_mappings().items():
|
37
|
+
pattern = pattern.replace(token, f"(?P<{field}>.*?)")
|
38
|
+
|
39
|
+
# Extract data using regex
|
40
|
+
match = re.match(pattern, content, re.DOTALL)
|
41
|
+
if not match:
|
42
|
+
raise ValueError("Invalid format")
|
43
|
+
|
44
|
+
# Create instance with extracted data
|
45
|
+
data = {field: match.group(field).strip() for field in cls.field_mappings()}
|
46
|
+
return cls(**data)
|
47
|
+
|
48
|
+
def generate(self) -> str:
|
49
|
+
# Start with the format spec
|
50
|
+
result = self.format_spec()
|
51
|
+
|
52
|
+
# Replace tokens with actual values
|
53
|
+
for field, token in self.field_mappings().items():
|
54
|
+
value = getattr(self, field)
|
55
|
+
result = result.replace(token, str(value))
|
56
|
+
|
57
|
+
# Wrap with start and end tokens
|
58
|
+
return f"{self.start_token()}\n{result}\n{self.end_token()}"
|
59
|
+
|
60
|
+
class MyFormattedModel(FormattingModel):
|
61
|
+
name: str
|
62
|
+
age: int
|
63
|
+
city: str
|
64
|
+
|
65
|
+
@classmethod
|
66
|
+
def format_spec(cls) -> str:
|
67
|
+
return "name: {NAME}\n{AGE} is the age\nlives in {CITY}"
|
68
|
+
|
69
|
+
@classmethod
|
70
|
+
def start_token(cls) -> str:
|
71
|
+
return "<format>"
|
72
|
+
|
73
|
+
@classmethod
|
74
|
+
def end_token(cls) -> str:
|
75
|
+
return "</format>"
|
76
|
+
|
77
|
+
@classmethod
|
78
|
+
def field_mappings(cls) -> Dict[str, str]:
|
79
|
+
return {
|
80
|
+
"name": "{NAME}",
|
81
|
+
"age": "{AGE}",
|
82
|
+
"city": "{CITY}"
|
83
|
+
}
|
84
|
+
|
85
|
+
if __name__ == "__main__":
|
86
|
+
# Test object to string
|
87
|
+
model = MyFormattedModel(name="John", age=30, city="Tokyo")
|
88
|
+
generated = model.generate()
|
89
|
+
print("Generated string:")
|
90
|
+
print(generated)
|
91
|
+
print()
|
92
|
+
|
93
|
+
# Test string to object
|
94
|
+
parsed = MyFormattedModel.parse(generated)
|
95
|
+
print("Parsed object:")
|
96
|
+
print(parsed)
|
97
|
+
print()
|
98
|
+
|
99
|
+
# Test round-trip
|
100
|
+
print("Round-trip test:")
|
101
|
+
print("Original == Parsed:", model == parsed)
|
102
|
+
|
103
|
+
# Test with different values
|
104
|
+
another_model = MyFormattedModel(name="Alice", age=25, city="New York")
|
105
|
+
another_generated = another_model.generate()
|
106
|
+
print("\nAnother generated string:")
|
107
|
+
print(another_generated)
|
108
|
+
print()
|
109
|
+
|
110
|
+
another_parsed = MyFormattedModel.parse(another_generated)
|
111
|
+
print("Another parsed object:")
|
112
|
+
print(another_parsed)
|
113
|
+
print("Another Original == Another Parsed:", another_model == another_parsed)
|
114
|
+
|
115
|
+
|
116
|
+
# code file model
|
117
|
+
class CodeFileModel(FormattingModel):
|
118
|
+
language: str
|
119
|
+
file_path: str
|
120
|
+
code: str
|
121
|
+
|
122
|
+
@classmethod
|
123
|
+
def format_spec(cls) -> str:
|
124
|
+
return "code_file_model\nfile_path: {FILE_PATH}\n```{LANGUAGE}\n{CODE}\n```"
|
125
|
+
|
126
|
+
@classmethod
|
127
|
+
def start_token(cls) -> str:
|
128
|
+
return "<format>"
|
129
|
+
|
130
|
+
@classmethod
|
131
|
+
def end_token(cls) -> str:
|
132
|
+
return "</format>"
|
133
|
+
|
134
|
+
@classmethod
|
135
|
+
def field_mappings(cls) -> Dict[str, str]:
|
136
|
+
return {
|
137
|
+
"file_path": "{FILE_PATH}",
|
138
|
+
"language": "{LANGUAGE}",
|
139
|
+
"code": "{CODE}"
|
140
|
+
}
|
141
|
+
|
142
|
+
|
143
|
+
print("\nTesting CodeFileModel:")
|
144
|
+
code_model = CodeFileModel(
|
145
|
+
language="python",
|
146
|
+
file_path="src/main.py",
|
147
|
+
code="def hello():\n print(\"Hello, World!\")"
|
148
|
+
)
|
149
|
+
code_generated = code_model.generate()
|
150
|
+
print("Generated CodeFileModel string:")
|
151
|
+
print(code_generated)
|
152
|
+
print()
|
153
|
+
|
154
|
+
code_parsed = CodeFileModel.parse(code_generated)
|
155
|
+
print("Parsed CodeFileModel object:")
|
156
|
+
print(code_parsed)
|
157
|
+
print()
|
158
|
+
|
159
|
+
print("CodeFileModel Round-trip test:")
|
160
|
+
print("Original == Parsed:", code_model == code_parsed)
|
161
|
+
|
162
|
+
# tolerant format
|
163
|
+
#
|
164
|
+
class CodeFileModel(FormattingModel):
|
165
|
+
language: str
|
166
|
+
file_path: str
|
167
|
+
code: str
|
168
|
+
|
169
|
+
@classmethod
|
170
|
+
def format_spec(cls) -> str:
|
171
|
+
return (
|
172
|
+
r"code_file_model\s*\n"
|
173
|
+
r"file_path:\s*{FILE_PATH}\s*\n"
|
174
|
+
r"```\s*{LANGUAGE}\s*\n"
|
175
|
+
r"{CODE}\s*"
|
176
|
+
r"```"
|
177
|
+
)
|
178
|
+
|
179
|
+
@classmethod
|
180
|
+
def start_token(cls) -> str:
|
181
|
+
return "<format>"
|
182
|
+
|
183
|
+
@classmethod
|
184
|
+
def end_token(cls) -> str:
|
185
|
+
return "</format>"
|
186
|
+
|
187
|
+
@classmethod
|
188
|
+
def field_mappings(cls) -> Dict[str, str]:
|
189
|
+
return {
|
190
|
+
"file_path": "{FILE_PATH}",
|
191
|
+
"language": "{LANGUAGE}",
|
192
|
+
"code": "{CODE}"
|
193
|
+
}
|
194
|
+
|
195
|
+
print("\nTesting CodeFileModel with various whitespace variations:")
|
196
|
+
|
197
|
+
test_strings = [
|
198
|
+
# Standard format
|
199
|
+
"""<format>
|
200
|
+
code_file_model
|
201
|
+
file_path: src/main.py
|
202
|
+
```python
|
203
|
+
def hello():
|
204
|
+
print("Hello, World!")
|
205
|
+
```
|
206
|
+
</format>""",
|
207
|
+
# Extra whitespace
|
208
|
+
"""<format>
|
209
|
+
code_file_model
|
210
|
+
file_path: src/main.py
|
211
|
+
``` python
|
212
|
+
def hello():
|
213
|
+
print("Hello, World!")
|
214
|
+
```
|
215
|
+
</format>""",
|
216
|
+
# Extra newlines
|
217
|
+
"""<format>
|
218
|
+
code_file_model
|
219
|
+
|
220
|
+
file_path: src/main.py
|
221
|
+
|
222
|
+
```python
|
223
|
+
|
224
|
+
def hello():
|
225
|
+
print("Hello, World!")
|
226
|
+
|
227
|
+
```
|
228
|
+
|
229
|
+
</format>"""
|
230
|
+
]
|
231
|
+
|
232
|
+
for i, test_string in enumerate(test_strings, 1):
|
233
|
+
print(f"\nTest {i}:")
|
234
|
+
print("Input string:")
|
235
|
+
print(test_string)
|
236
|
+
|
237
|
+
parsed = CodeFileModel.parse(test_string)
|
238
|
+
print("\nParsed object:")
|
239
|
+
print(parsed)
|
240
|
+
|
241
|
+
regenerated = parsed.generate()
|
242
|
+
print("\nRegenerated string:")
|
243
|
+
print(regenerated)
|
244
|
+
|
245
|
+
reparsed = CodeFileModel.parse(regenerated)
|
246
|
+
print("\nRound-trip test:")
|
247
|
+
print("Original parsed == Reparsed:", parsed == reparsed)
|
248
|
+
print("-" * 50)
|