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.
Files changed (80) hide show
  1. langroid/agent/md_tool_message_grammar.py +455 -0
  2. langroid/agent/tools/code_file_tool_parse.py +150 -0
  3. langroid/agent/tools/code_file_tool_pyparsing.py +194 -0
  4. langroid/agent/tools/code_file_tool_pyparsing2.py +199 -0
  5. langroid/agent/tools/formatted_model_custom.py +150 -0
  6. langroid/agent/tools/formatted_model_custom2.py +168 -0
  7. langroid/agent/tools/formatted_model_custom3.py +279 -0
  8. langroid/agent/tools/formatted_model_custom4.py +395 -0
  9. langroid/agent/tools/formatted_model_jinja.py +133 -0
  10. langroid/agent/tools/formatted_model_jinja.py-e +122 -0
  11. langroid/agent/tools/formatted_model_jinja2.py +145 -0
  12. langroid/agent/tools/formatted_model_jinja2.py-e +135 -0
  13. langroid/agent/tools/formatted_model_lark.py +0 -0
  14. langroid/agent/tools/formatted_model_lark2.py +168 -0
  15. langroid/agent/tools/formatted_model_parse.py +105 -0
  16. langroid/agent/tools/formatted_model_parse.py-e +98 -0
  17. langroid/agent/tools/formatted_model_parse2.py +113 -0
  18. langroid/agent/tools/formatted_model_parse2.py-e +109 -0
  19. langroid/agent/tools/formatted_model_parse3.py +114 -0
  20. langroid/agent/tools/formatted_model_parse3.py-e +110 -0
  21. langroid/agent/tools/formatted_model_parsimon.py +194 -0
  22. langroid/agent/tools/formatted_model_parsimon.py-e +186 -0
  23. langroid/agent/tools/formatted_model_pyparsing.py +169 -0
  24. langroid/agent/tools/formatted_model_pyparsing.py-e +149 -0
  25. langroid/agent/tools/formatted_model_pyparsing2.py +159 -0
  26. langroid/agent/tools/formatted_model_pyparsing2.py-e +143 -0
  27. langroid/agent/tools/formatted_model_pyparsing3.py +133 -0
  28. langroid/agent/tools/formatted_model_pyparsing3.py-e +121 -0
  29. langroid/agent/tools/formatted_model_pyparsing4.py +213 -0
  30. langroid/agent/tools/formatted_model_pyparsing4.py-e +176 -0
  31. langroid/agent/tools/formatted_model_pyparsing5.py +173 -0
  32. langroid/agent/tools/formatted_model_pyparsing5.py-e +142 -0
  33. langroid/agent/tools/formatted_model_regex.py +246 -0
  34. langroid/agent/tools/formatted_model_regex.py-e +248 -0
  35. langroid/agent/tools/formatted_model_regex2.py +250 -0
  36. langroid/agent/tools/formatted_model_regex2.py-e +253 -0
  37. langroid/agent/tools/formatted_model_tatsu.py +172 -0
  38. langroid/agent/tools/formatted_model_tatsu.py-e +160 -0
  39. langroid/agent/tools/formatted_model_template.py +217 -0
  40. langroid/agent/tools/formatted_model_template.py-e +200 -0
  41. langroid/agent/tools/formatted_model_xml.py +178 -0
  42. langroid/agent/tools/formatted_model_xml2.py +178 -0
  43. langroid/agent/tools/formatted_model_xml3.py +132 -0
  44. langroid/agent/tools/formatted_model_xml4.py +130 -0
  45. langroid/agent/tools/formatted_model_xml5.py +130 -0
  46. langroid/agent/tools/formatted_model_xml6.py +113 -0
  47. langroid/agent/tools/formatted_model_xml7.py +117 -0
  48. langroid/agent/tools/formatted_model_xml8.py +164 -0
  49. langroid/agent/tools/generic_tool.py +165 -0
  50. langroid/agent/tools/generic_tool_tatsu.py +275 -0
  51. langroid/agent/tools/grammar_based_model.py +132 -0
  52. langroid/agent/tools/grammar_based_model.py-e +128 -0
  53. langroid/agent/tools/grammar_based_model_lark.py +156 -0
  54. langroid/agent/tools/grammar_based_model_lark.py-e +153 -0
  55. langroid/agent/tools/grammar_based_model_parse.py +86 -0
  56. langroid/agent/tools/grammar_based_model_parse.py-e +80 -0
  57. langroid/agent/tools/grammar_based_model_parsimonious.py +129 -0
  58. langroid/agent/tools/grammar_based_model_parsimonious.py-e +120 -0
  59. langroid/agent/tools/grammar_based_model_pyparsing.py +105 -0
  60. langroid/agent/tools/grammar_based_model_pyparsing.py-e +103 -0
  61. langroid/agent/tools/grammar_based_model_regex.py +139 -0
  62. langroid/agent/tools/grammar_based_model_regex.py-e +130 -0
  63. langroid/agent/tools/grammar_based_model_regex2.py +124 -0
  64. langroid/agent/tools/grammar_based_model_regex2.py-e +116 -0
  65. langroid/agent/tools/grammar_based_model_tatsu.py +80 -0
  66. langroid/agent/tools/grammar_based_model_tatsu.py-e +77 -0
  67. langroid/agent/tools/lark_earley_example.py +135 -0
  68. langroid/agent/tools/lark_earley_example.py-e +117 -0
  69. langroid/agent/tools/lark_example.py +72 -0
  70. langroid/agent/tools/parse_example.py +76 -0
  71. langroid/agent/tools/parse_example2.py +87 -0
  72. langroid/agent/tools/parse_example3.py +42 -0
  73. langroid/agent/tools/parse_test.py +791 -0
  74. langroid/agent/xml_tool_message.py +106 -0
  75. langroid/language_models/openai_gpt.py +6 -1
  76. {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/METADATA +1 -1
  77. {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/RECORD +80 -6
  78. pyproject.toml +1 -1
  79. {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/LICENSE +0 -0
  80. {langroid-0.16.5.dist-info → langroid-0.16.7.dist-info}/WHEEL +0 -0
@@ -0,0 +1,77 @@
1
+ from typing import Dict, Type, ClassVar
2
+ from pydantic import BaseModel
3
+ from tatsu import compile as compile_grammar
4
+ from tatsu.model import ModelBuilder
5
+ from abc import ABC, abstractmethod
6
+
7
+ class GrammarBasedModel(BaseModel, ABC):
8
+ grammar: ClassVar[str]
9
+ start_token: ClassVar[str]
10
+ end_token: ClassVar[str]
11
+ field_mappings: ClassVar[Dict[str, str]]
12
+
13
+ @classmethod
14
+ @abstractmethod
15
+ def get_grammar(cls) -> str:
16
+ pass
17
+
18
+ @classmethod
19
+ def parse(cls, text: str) -> 'GrammarBasedModel':
20
+ parser = compile_grammar(cls.get_grammar())
21
+ ast = parser.parse(text, start='start')
22
+ model_dict = {field: getattr(ast, rule) for field, rule in cls.field_mappings.items()}
23
+ return cls(**model_dict)
24
+
25
+ def generate(self) -> str:
26
+ grammar = compile_grammar(self.get_grammar())
27
+ model_builder = ModelBuilder()
28
+ for field, rule in self.field_mappings.items():
29
+ setattr(model_builder, rule, getattr(self, field))
30
+ ast = model_builder.start()
31
+ return f"{self.start_token}\n{grammar.parse(str(ast), start='start')}\n{self.end_token}"
32
+
33
+ class PersonSpec(GrammarBasedModel):
34
+ name: str
35
+ age: int
36
+ city: str
37
+
38
+ grammar = """
39
+ start = name_line age_line city_line;
40
+ name_line = 'name:' /\s*/ name:/.+/ EOL;
41
+ age_line = 'age is' /\s*/ age:/\d+/ EOL;
42
+ city_line = 'lives in' /\s*/ city:/.+/ EOL;
43
+ EOL = /\r?\n/;
44
+ """
45
+ start_token = "<spec>"
46
+ end_token = "</spec>"
47
+ field_mappings = {
48
+ "name": "name",
49
+ "age": "age",
50
+ "city": "city"
51
+ }
52
+
53
+ @classmethod
54
+ def get_grammar(cls):
55
+ return cls.grammar
56
+
57
+ if __name__ == "__main__":
58
+ # Test parsing
59
+ input_str = """<spec>
60
+ name: John Doe
61
+ age is 30
62
+ lives in New York
63
+ </spec>"""
64
+ person = PersonSpec.parse(input_str)
65
+ print("Parsed person:", person)
66
+
67
+ # Test generation
68
+ generated_str = person.generate()
69
+ print("\nGenerated string:")
70
+ print(generated_str)
71
+
72
+ # Test round-trip
73
+ round_trip_person = PersonSpec.parse(generated_str)
74
+ print("\nRound-trip parsed person:", round_trip_person)
75
+
76
+ assert person == round_trip_person, "Round-trip parsing failed"
77
+ print("\nRound-trip test passed!")
@@ -0,0 +1,135 @@
1
+ import pytest
2
+ from lark import Lark, Transformer, Visitor
3
+
4
+ from langroid.pydantic_v1 import BaseModel
5
+
6
+
7
+ class Person(BaseModel):
8
+ name: str
9
+ age: int
10
+ city: str
11
+
12
+
13
+ grammar = """
14
+ person: "Name:" name "Age:" age "City:" city
15
+ name: WORD
16
+ age: NUMBER
17
+ city: WORD
18
+ WORD: /\w+/
19
+ NUMBER: /\d+/
20
+ %import common.WS
21
+ %ignore WS
22
+ """
23
+
24
+ parser = Lark(grammar, start="person", parser="earley")
25
+
26
+
27
+ class PersonTransformer(Transformer):
28
+ def person(self, items):
29
+ return Person(name=items[1], age=items[3], city=items[5])
30
+
31
+ def name(self, items):
32
+ return items[0].value
33
+
34
+ def age(self, items):
35
+ return int(items[0].value)
36
+
37
+ def city(self, items):
38
+ return items[0].value
39
+
40
+
41
+ class PersonToStringVisitor(Visitor):
42
+ def __init__(self):
43
+ self.result = []
44
+
45
+ def person(self, tree):
46
+ self.visit_children(tree)
47
+ return " ".join(self.result)
48
+
49
+ def name(self, tree):
50
+ self.result.extend(["Name:", str(tree.children[0])])
51
+
52
+ def age(self, tree):
53
+ self.result.extend(["Age:", str(tree.children[0])])
54
+
55
+ def city(self, tree):
56
+ self.result.extend(["City:", str(tree.children[0])])
57
+
58
+
59
+ transformer = PersonTransformer()
60
+ to_string_visitor = PersonToStringVisitor()
61
+
62
+
63
+ def from_string(cls, string):
64
+ tree = parser.parse(string)
65
+ return transformer.transform(tree)
66
+
67
+
68
+ def to_string(self):
69
+ from lark import Token
70
+
71
+ tree = parser.parse(
72
+ f"Name: {Token('WORD', self.name)} "
73
+ f"Age: {Token('NUMBER', str(self.age))} "
74
+ f"City: {Token('WORD', self.city)}"
75
+ )
76
+ return to_string_visitor.visit(tree)
77
+
78
+
79
+ Person.from_string = classmethod(from_string)
80
+ Person.to_string = to_string
81
+
82
+ # Test functions remain the same as in the previous version
83
+
84
+
85
+ # Test functions
86
+ def test_from_string():
87
+ person_str = "Name: John Age: 30 City: NewYork"
88
+ person = Person.from_string(person_str)
89
+ assert person.name == "John"
90
+ assert person.age == 30
91
+ assert person.city == "NewYork"
92
+
93
+
94
+ def test_to_string():
95
+ person = Person(name="Alice", age=25, city="London")
96
+ person_str = person.to_string()
97
+ assert person_str == "Name: Alice Age: 25 City: London"
98
+
99
+
100
+ def test_roundtrip():
101
+ original_str = "Name: Bob Age: 40 City: Paris"
102
+ person = Person.from_string(original_str)
103
+ regenerated_str = person.to_string()
104
+ assert original_str == regenerated_str
105
+
106
+
107
+ def test_different_values():
108
+ person = Person(name="Charlie", age=35, city="Berlin")
109
+ person_str = person.to_string()
110
+ assert person_str == "Name: Charlie Age: 35 City: Berlin"
111
+
112
+
113
+ def test_edge_cases():
114
+ # Test with minimum age
115
+ person = Person(name="Young", age=0, city="Baby")
116
+ person_str = person.to_string()
117
+ assert person_str == "Name: Young Age: 0 City: Baby"
118
+
119
+ # Test with very long name and city
120
+ long_name = "A" * 100
121
+ long_city = "B" * 100
122
+ person = Person(name=long_name, age=50, city=long_city)
123
+ person_str = person.to_string()
124
+ assert person_str == f"Name: {long_name} Age: 50 City: {long_city}"
125
+
126
+
127
+ def test_invalid_input():
128
+ with pytest.raises(
129
+ Exception
130
+ ): # The exact exception may vary based on Lark's implementation
131
+ Person.from_string("Invalid: Input")
132
+
133
+
134
+ if __name__ == "__main__":
135
+ pytest.main([__file__])
@@ -0,0 +1,117 @@
1
+ import pytest
2
+ from pydantic import BaseModel
3
+ from lark import Lark, Transformer, Visitor
4
+
5
+ class Person(BaseModel):
6
+ name: str
7
+ age: int
8
+ city: str
9
+
10
+ grammar = """
11
+ person: "Name:" name "Age:" age "City:" city
12
+ name: WORD
13
+ age: NUMBER
14
+ city: WORD
15
+ WORD: /\w+/
16
+ NUMBER: /\d+/
17
+ %import common.WS
18
+ %ignore WS
19
+ """
20
+
21
+ parser = Lark(grammar, start='person', parser='earley')
22
+
23
+ class PersonTransformer(Transformer):
24
+ def person(self, items):
25
+ return Person(name=items[1], age=items[3], city=items[5])
26
+
27
+ def name(self, items):
28
+ return items[0].value
29
+
30
+ def age(self, items):
31
+ return int(items[0].value)
32
+
33
+ def city(self, items):
34
+ return items[0].value
35
+
36
+ class PersonToStringVisitor(Visitor):
37
+ def __init__(self):
38
+ self.result = []
39
+
40
+ def person(self, tree):
41
+ self.visit_children(tree)
42
+ return " ".join(self.result)
43
+
44
+ def name(self, tree):
45
+ self.result.extend(["Name:", str(tree.children[0])])
46
+
47
+ def age(self, tree):
48
+ self.result.extend(["Age:", str(tree.children[0])])
49
+
50
+ def city(self, tree):
51
+ self.result.extend(["City:", str(tree.children[0])])
52
+
53
+ transformer = PersonTransformer()
54
+ to_string_visitor = PersonToStringVisitor()
55
+
56
+ def from_string(cls, string):
57
+ tree = parser.parse(string)
58
+ return transformer.transform(tree)
59
+
60
+ def to_string(self):
61
+ from lark import Token
62
+ tree = parser.parse(
63
+ f"Name: {Token('WORD', self.name)} "
64
+ f"Age: {Token('NUMBER', str(self.age))} "
65
+ f"City: {Token('WORD', self.city)}"
66
+ )
67
+ return to_string_visitor.visit(tree)
68
+
69
+ Person.from_string = classmethod(from_string)
70
+ Person.to_string = to_string
71
+
72
+ # Test functions remain the same as in the previous version
73
+
74
+ # Test functions
75
+ def test_from_string():
76
+ person_str = "Name: John Age: 30 City: NewYork"
77
+ person = Person.from_string(person_str)
78
+ assert person.name == "John"
79
+ assert person.age == 30
80
+ assert person.city == "NewYork"
81
+
82
+ def test_to_string():
83
+ person = Person(name="Alice", age=25, city="London")
84
+ person_str = person.to_string()
85
+ assert person_str == "Name: Alice Age: 25 City: London"
86
+
87
+ def test_roundtrip():
88
+ original_str = "Name: Bob Age: 40 City: Paris"
89
+ person = Person.from_string(original_str)
90
+ regenerated_str = person.to_string()
91
+ assert original_str == regenerated_str
92
+
93
+ def test_different_values():
94
+ person = Person(name="Charlie", age=35, city="Berlin")
95
+ person_str = person.to_string()
96
+ assert person_str == "Name: Charlie Age: 35 City: Berlin"
97
+
98
+ def test_edge_cases():
99
+ # Test with minimum age
100
+ person = Person(name="Young", age=0, city="Baby")
101
+ person_str = person.to_string()
102
+ assert person_str == "Name: Young Age: 0 City: Baby"
103
+
104
+ # Test with very long name and city
105
+ long_name = "A" * 100
106
+ long_city = "B" * 100
107
+ person = Person(name=long_name, age=50, city=long_city)
108
+ person_str = person.to_string()
109
+ assert person_str == f"Name: {long_name} Age: 50 City: {long_city}"
110
+
111
+ def test_invalid_input():
112
+ with pytest.raises(Exception): # The exact exception may vary based on Lark's implementation
113
+ Person.from_string("Invalid: Input")
114
+
115
+ if __name__ == "__main__":
116
+ pytest.main([__file__])
117
+
@@ -0,0 +1,72 @@
1
+ from typing import ClassVar
2
+
3
+ from lark import Lark, Transformer, Tree
4
+
5
+ from langroid.pydantic_v1 import BaseModel
6
+
7
+
8
+ class Person(BaseModel):
9
+ name: str
10
+ age: int
11
+ city: str
12
+
13
+ # Class variable to hold the grammar
14
+ grammar: ClassVar[
15
+ str
16
+ ] = """
17
+ start: "START Person" "\n" field ("---" "\n" field)* "END Person"
18
+ field: NAME "=" VALUE
19
+ NAME: "name" | "age" | "city"
20
+ VALUE: /[^\n]+/
21
+
22
+ %import common.WS
23
+ %ignore WS
24
+ """
25
+
26
+ @classmethod
27
+ def from_string(cls, string: str) -> "Person":
28
+ parser = Lark(cls.grammar, parser="lalr", transformer=PersonTransformer())
29
+ result = parser.parse(string)
30
+ return cls(**result)
31
+
32
+ def to_string(self) -> str:
33
+ parser = Lark(self.grammar, parser="lalr")
34
+ tree = Tree(
35
+ "start",
36
+ [
37
+ Tree("field", [Tree("NAME", [name]), Tree("VALUE", [str(value)])])
38
+ for name, value in self.dict().items()
39
+ ],
40
+ )
41
+ return parser.serialize(tree)
42
+
43
+
44
+ class PersonTransformer(Transformer):
45
+ def start(self, items):
46
+ return dict(items)
47
+
48
+ def field(self, items):
49
+ name, value = items
50
+ if name == "age":
51
+ value = int(value)
52
+ return name, value
53
+
54
+
55
+ # Example usage:
56
+ if __name__ == "__main__":
57
+ # Create a Person instance
58
+ p = Person(name="John Doe", age=30, city="New York")
59
+
60
+ # Convert to string
61
+ s = p.to_string()
62
+ print("To string:")
63
+ print(s)
64
+ print()
65
+
66
+ # Parse from string
67
+ p2 = Person.from_string(s)
68
+ print("Parsed from string:")
69
+ print(p2)
70
+
71
+ # Demonstrate that they're equal
72
+ print("\nAre equal:", p == p2)
@@ -0,0 +1,76 @@
1
+ from datetime import datetime
2
+
3
+ from parse import compile
4
+
5
+
6
+ class PersonFormatter:
7
+ # Define the grammar/template as a class attribute
8
+ GRAMMAR = """
9
+ Name: {name}
10
+ Age: {age:d}
11
+ Birthday: {birthday}
12
+ Hobbies: {hobbies}
13
+ """
14
+
15
+ @classmethod
16
+ def parse(cls, string):
17
+ parser = compile(cls.GRAMMAR)
18
+ result = parser.parse(string)
19
+ if result:
20
+ return {
21
+ "name": result["name"],
22
+ "age": result["age"],
23
+ "birthday": datetime.strptime(result["birthday"], "%Y-%m-%d").date(),
24
+ "hobbies": [hobby.strip() for hobby in result["hobbies"].split(",")],
25
+ }
26
+ return None
27
+
28
+ @classmethod
29
+ def format(cls, data):
30
+ hobbies_str = ", ".join(data["hobbies"])
31
+ return cls.GRAMMAR.format(
32
+ name=data["name"],
33
+ age=data["age"],
34
+ birthday=data["birthday"].strftime("%Y-%m-%d"),
35
+ hobbies=hobbies_str,
36
+ )
37
+
38
+
39
+ # Example usage
40
+ if __name__ == "__main__":
41
+ # Parsing
42
+ input_string = """
43
+ Name: John Doe
44
+ Age: 30
45
+ Birthday: 1993-05-15
46
+ Hobbies: reading, swimming, coding
47
+ """
48
+ parsed_data = PersonFormatter.parse(input_string)
49
+ print("Parsed data:", parsed_data)
50
+
51
+ # Formatting
52
+ person_data = {
53
+ "name": "Jane Smith",
54
+ "age": 25,
55
+ "birthday": datetime(1998, 8, 22).date(),
56
+ "hobbies": ["painting", "yoga", "traveling"],
57
+ }
58
+ formatted_string = PersonFormatter.format(person_data)
59
+ print("\nFormatted string:")
60
+ print(formatted_string)
61
+
62
+ # Demonstrating bidirectional conversion
63
+ print("\nBidirectional conversion:")
64
+ original_string = """
65
+ Name: Alice Johnson
66
+ Age: 35
67
+ Birthday: 1988-12-01
68
+ Hobbies: gardening, photography, cooking
69
+ """
70
+ print("Original:")
71
+ print(original_string)
72
+ parsed = PersonFormatter.parse(original_string)
73
+ print("Parsed:", parsed)
74
+ reformatted = PersonFormatter.format(parsed)
75
+ print("Reformatted:")
76
+ print(reformatted)
@@ -0,0 +1,87 @@
1
+ from parse import parse
2
+
3
+ # Define the format string
4
+ format_string = """
5
+ name:{:s}
6
+ {:d} is the age
7
+ lives in {:s}
8
+ """
9
+
10
+
11
+ def parse_person_info(input_string):
12
+ # Remove leading/trailing whitespace and split into lines
13
+ lines = input_string.strip().split("\n")
14
+
15
+ # Join the lines with a single newline
16
+ normalized_input = "\n".join(line.strip() for line in lines if line.strip())
17
+
18
+ # Parse the normalized input
19
+ result = parse(format_string, normalized_input)
20
+
21
+ if result:
22
+ name, age, city = result
23
+ return f"Name: {name.strip()}, Age: {age}, City: {city.strip()}"
24
+ else:
25
+ return "Parsing failed"
26
+
27
+
28
+ # Test cases and assertions
29
+ if __name__ == "__main__":
30
+ # Test case 1: Standard format
31
+ input1 = """
32
+ name: Beck
33
+ 30 is the age
34
+ lives in Tokyo
35
+ """
36
+ assert (
37
+ parse_person_info(input1) == "Name: Beck, Age: 30, City: Tokyo"
38
+ ), "Test case 1 failed"
39
+
40
+ # Test case 2: Extra whitespace
41
+ input2 = """
42
+ name: Beck
43
+ 30 is the age
44
+ lives in Tokyo
45
+ """
46
+ assert (
47
+ parse_person_info(input2) == "Name: Beck, Age: 30, City: Tokyo"
48
+ ), "Test case 2 failed"
49
+
50
+ # Test case 3: Extra newlines
51
+ input3 = """
52
+ name:Beck
53
+
54
+
55
+ 30 is the age
56
+
57
+ lives in Tokyo
58
+ """
59
+ assert (
60
+ parse_person_info(input3) == "Name: Beck, Age: 30, City: Tokyo"
61
+ ), "Test case 3 failed"
62
+
63
+ # Test case 4: Minimal whitespace
64
+ input4 = "name:John\n25 is the age\nlives in NewYork"
65
+ assert (
66
+ parse_person_info(input4) == "Name: John, Age: 25, City: NewYork"
67
+ ), "Test case 4 failed"
68
+
69
+ # Test case 5: Different name, age, city
70
+ input5 = """
71
+ name: Alice Johnson
72
+ 42 is the age
73
+ lives in San Francisco
74
+ """
75
+ assert (
76
+ parse_person_info(input5) == "Name: Alice Johnson, Age: 42, City: San Francisco"
77
+ ), "Test case 5 failed"
78
+
79
+ # Test case 6: Invalid format (should return "Parsing failed")
80
+ input6 = """
81
+ name: Invalid
82
+ not a number is the age
83
+ lives in Nowhere
84
+ """
85
+ assert parse_person_info(input6) == "Parsing failed", "Test case 6 failed"
86
+
87
+ print("All tests passed successfully!")
@@ -0,0 +1,42 @@
1
+ from parse import parse
2
+
3
+ # Define the parse specification
4
+ parse_spec = """
5
+ <format>
6
+ name{:s}{:>}{}\n
7
+ age{:s}{:>}{}\n
8
+ </format>
9
+ """
10
+
11
+
12
+ def parse_info(input_string):
13
+ print(f"Input string:\n{input_string}") # Debug print
14
+ result = parse(parse_spec, input_string, case_sensitive=False)
15
+ print(f"Parse result: {result}") # Debug print
16
+ if result:
17
+ name = result[1].strip() # The actual name value is in the second group
18
+ age = result[3].strip() # The actual age value is in the fourth group
19
+ return name, age
20
+ else:
21
+ return None
22
+
23
+
24
+ if __name__ == "__main__":
25
+ # Test case 1: Standard format
26
+ input_string1 = """
27
+ <format>
28
+ name beck
29
+ age 30
30
+ </format>
31
+ """
32
+ print("\nTest case 1:")
33
+ result1 = parse_info(input_string1)
34
+ print(f"Test 1 result: {result1}")
35
+ assert result1 == (
36
+ "beck",
37
+ "30",
38
+ ), f"Test 1 failed. Expected ('beck', '30'), got {result1}"
39
+
40
+ # Additional test cases...
41
+
42
+ print("All tests passed successfully!")