agent0-sdk 0.2.0__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.
@@ -0,0 +1,103 @@
1
+ """
2
+ Test Endpoint Crawler with Real Public MCP and A2A Servers
3
+ Tests against actual public servers provided by the user.
4
+ """
5
+
6
+ import logging
7
+ import sys
8
+ import os
9
+
10
+ # Configure logging: root logger at WARNING to suppress noisy dependencies
11
+ logging.basicConfig(
12
+ level=logging.WARNING,
13
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
14
+ datefmt='%Y-%m-%d %H:%M:%S',
15
+ handlers=[logging.StreamHandler(sys.stdout)]
16
+ )
17
+
18
+ # Set debug level ONLY for agent0_sdk
19
+ logging.getLogger('agent0_sdk').setLevel(logging.DEBUG)
20
+ logging.getLogger('agent0_sdk.core').setLevel(logging.DEBUG)
21
+
22
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
23
+
24
+ from agent0_sdk.core.endpoint_crawler import EndpointCrawler
25
+ import json
26
+
27
+ def main():
28
+ print("๐Ÿงช Testing Endpoint Crawler with Real Public Servers")
29
+ print("=" * 70)
30
+
31
+ crawler = EndpointCrawler(timeout=10) # Longer timeout for real servers
32
+
33
+ # Real public endpoints
34
+ test_cases = [
35
+ {
36
+ "type": "A2A",
37
+ "endpoint": "https://hello-world-gxfr.onrender.com",
38
+ "description": "Real A2A Hello World Server"
39
+ },
40
+ {
41
+ "type": "MCP",
42
+ "endpoint": "https://mcp.atlassian.com/v1/forge/mcp",
43
+ "description": "Atlassian MCP Server (requires authentication, will fail gracefully)"
44
+ }
45
+ ]
46
+
47
+ successful_tests = []
48
+ failed_tests = []
49
+
50
+ for i, test_case in enumerate(test_cases, 1):
51
+ print(f"\n๐Ÿ“ Test {i}: {test_case['type']} Endpoint")
52
+ print("-" * 70)
53
+ print(f"URL: {test_case['endpoint']}")
54
+ print(f"Description: {test_case['description']}")
55
+ print()
56
+
57
+ if test_case['type'] == 'A2A':
58
+ capabilities = crawler.fetch_a2a_capabilities(test_case['endpoint'])
59
+ if capabilities:
60
+ print("โœ… SUCCESS! Fetched A2A capabilities:")
61
+ print(json.dumps(capabilities, indent=2))
62
+ successful_tests.append(test_case)
63
+ else:
64
+ print("โŒ Failed to fetch A2A capabilities")
65
+ failed_tests.append(test_case)
66
+
67
+ elif test_case['type'] == 'MCP':
68
+ capabilities = crawler.fetch_mcp_capabilities(test_case['endpoint'])
69
+ if capabilities:
70
+ print("โœ… SUCCESS! Fetched MCP capabilities:")
71
+ print(json.dumps(capabilities, indent=2))
72
+ successful_tests.append(test_case)
73
+ else:
74
+ print("โŒ Failed to fetch MCP capabilities")
75
+ failed_tests.append(test_case)
76
+
77
+ # Summary
78
+ print("\n" + "=" * 70)
79
+ print("๐Ÿ“Š Summary")
80
+ print("-" * 70)
81
+ print(f"โœ… Successful: {len(successful_tests)}")
82
+ print(f"โŒ Failed: {len(failed_tests)}")
83
+
84
+ if successful_tests:
85
+ print("\nโœ… Successfully tested endpoints:")
86
+ for test in successful_tests:
87
+ print(f" - {test['type']}: {test['endpoint']}")
88
+
89
+ if failed_tests:
90
+ print("\nโš ๏ธ Failed endpoints:")
91
+ for test in failed_tests:
92
+ print(f" - {test['type']}: {test['endpoint']}")
93
+
94
+ print("\n" + "=" * 70)
95
+ if successful_tests:
96
+ print("๐ŸŽ‰ Endpoint crawler is working with real public servers!")
97
+ else:
98
+ print("โš ๏ธ No capabilities fetched. Check endpoints or network connection.")
99
+ print("=" * 70)
100
+
101
+ if __name__ == "__main__":
102
+ main()
103
+
@@ -0,0 +1,267 @@
1
+ """
2
+ Test for Agent Registration with HTTP URI
3
+ Creates an agent, registers it with a mock HTTP URI, updates it, and verifies data integrity.
4
+
5
+ Flow:
6
+ 1. Register agent on-chain with mock URI (obtain agentId)
7
+ 2. Prepare registration file with obtained agentId
8
+ 3. Print registration file JSON for developer to host
9
+ 4. Update agent and verify consistency
10
+ """
11
+
12
+ import logging
13
+ import time
14
+ import random
15
+ import json
16
+ import sys
17
+
18
+ # Configure logging: root logger at WARNING to suppress noisy dependencies
19
+ logging.basicConfig(
20
+ level=logging.WARNING,
21
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
22
+ datefmt='%Y-%m-%d %H:%M:%S',
23
+ handlers=[logging.StreamHandler(sys.stdout)]
24
+ )
25
+
26
+ # Set debug level ONLY for agent0_sdk
27
+ logging.getLogger('agent0_sdk').setLevel(logging.DEBUG)
28
+ logging.getLogger('agent0_sdk.core').setLevel(logging.DEBUG)
29
+
30
+ from agent0_sdk import SDK
31
+ from config import CHAIN_ID, RPC_URL, AGENT_PRIVATE_KEY, print_config
32
+
33
+
34
+ def generateRandomData():
35
+ """Generate random test data for the agent."""
36
+ randomSuffix = random.randint(1000, 9999)
37
+ timestamp = int(time.time())
38
+
39
+ return {
40
+ 'name': f"Test Agent {randomSuffix}",
41
+ 'description': f"Created at {timestamp}",
42
+ 'image': f"https://example.com/image_{randomSuffix}.png",
43
+ 'mcpEndpoint': f"https://api.example.com/mcp/{randomSuffix}",
44
+ 'mcpVersion': f"2025-06-{random.randint(1, 28)}",
45
+ 'a2aEndpoint': f"https://api.example.com/a2a/{randomSuffix}.json",
46
+ 'a2aVersion': f"0.{random.randint(30, 35)}",
47
+ 'ensName': f"test{randomSuffix}.eth",
48
+ 'ensVersion': f"1.{random.randint(0, 9)}",
49
+ 'walletAddress': f"0x{'a' * 40}",
50
+ 'walletChainId': random.choice([1, 11155111, 8453, 137, 42161]),
51
+ 'active': True,
52
+ 'x402support': False,
53
+ 'reputation': random.choice([True, False]),
54
+ 'cryptoEconomic': random.choice([True, False]),
55
+ 'teeAttestation': random.choice([True, False])
56
+ }
57
+
58
+
59
+ def main():
60
+ print("๐Ÿงช Testing Agent Registration with HTTP URI")
61
+ print_config()
62
+
63
+ # SDK Configuration - no IPFS
64
+ sdkConfig = {
65
+ 'chainId': CHAIN_ID,
66
+ 'rpcUrl': RPC_URL
67
+ }
68
+
69
+ sdk = SDK(signer=AGENT_PRIVATE_KEY, **sdkConfig)
70
+ testData = generateRandomData()
71
+
72
+ # Step 1: Register agent on-chain with mock HTTP URI
73
+ print("\n๐Ÿ“ Step 1: Register Agent on-Chain with Mock URI")
74
+ print("-" * 60)
75
+
76
+ agent = sdk.createAgent(
77
+ name=testData['name'],
78
+ description=testData['description'],
79
+ image=testData['image']
80
+ )
81
+
82
+ # Register with mock URI to get agentId
83
+ mockUri = "https://example.com/agents/registration.json"
84
+ agent.register(mockUri)
85
+ agentId = agent.agentId
86
+ print(f"โœ… Registered: ID={agentId}")
87
+ print(f" Mock URI: {mockUri}")
88
+
89
+ # Step 2: Configure agent with all details
90
+ print("\n๐Ÿ“ Step 2: Configure Agent Details")
91
+ print("-" * 60)
92
+ print(f"โœ… Created: {testData['name']}")
93
+
94
+ agent.setMCP(testData['mcpEndpoint'], testData['mcpVersion'])
95
+ agent.setA2A(testData['a2aEndpoint'], testData['a2aVersion'])
96
+ agent.setENS(testData['ensName'], testData['ensVersion'])
97
+ agent.setAgentWallet(testData['walletAddress'], testData['walletChainId'])
98
+ agent.setActive(testData['active'])
99
+ agent.setX402Support(testData['x402support'])
100
+ agent.setTrust(
101
+ reputation=testData['reputation'],
102
+ cryptoEconomic=testData['cryptoEconomic'],
103
+ teeAttestation=testData['teeAttestation']
104
+ )
105
+
106
+ # Step 3: Get registration file and print it
107
+ print("\n๐Ÿ“ Step 3: Registration File for Hosting")
108
+ print("-" * 60)
109
+
110
+ registrationFile = agent.getRegistrationFile()
111
+ registrationJson = json.dumps(registrationFile.to_dict(), indent=2)
112
+
113
+ print("Registration file JSON (host this at the URL you specified):")
114
+ print("\n" + registrationJson)
115
+
116
+ # Save to file
117
+ filename = f"agent_registration_{agentId.replace(':', '_')}.json"
118
+ with open(filename, 'w') as f:
119
+ f.write(registrationJson)
120
+ print(f"\nโœ… Saved to: {filename}")
121
+
122
+ capturedState = {
123
+ 'agentId': agent.agentId,
124
+ 'agentURI': agent.agentURI,
125
+ 'name': agent.name,
126
+ 'description': agent.description,
127
+ 'image': agent.image,
128
+ 'walletAddress': agent.walletAddress,
129
+ 'walletChainId': agent.walletChainId,
130
+ 'active': agent.active,
131
+ 'x402support': agent.x402support,
132
+ 'mcpEndpoint': agent.mcpEndpoint,
133
+ 'a2aEndpoint': agent.a2aEndpoint,
134
+ 'ensEndpoint': agent.ensEndpoint,
135
+ 'metadata': agent.metadata.copy()
136
+ }
137
+
138
+ # Step 4: Update agent
139
+ print("\n๐Ÿ“ Step 4: Update Agent")
140
+ print("-" * 60)
141
+
142
+ agent.updateInfo(
143
+ name=testData['name'] + " UPDATED",
144
+ description=testData['description'] + " - UPDATED",
145
+ image=f"https://example.com/image_{random.randint(1000, 9999)}_updated.png"
146
+ )
147
+ agent.setMCP(f"https://api.example.com/mcp/{random.randint(10000, 99999)}", f"2025-06-{random.randint(1, 28)}")
148
+ agent.setA2A(f"https://api.example.com/a2a/{random.randint(10000, 99999)}.json", f"0.{random.randint(30, 35)}")
149
+ agent.setAgentWallet(f"0x{'b' * 40}", random.choice([1, 11155111, 8453, 137, 42161]))
150
+ agent.setENS(f"{testData['ensName']}.updated", f"1.{random.randint(0, 9)}")
151
+ agent.setActive(False)
152
+ agent.setX402Support(True)
153
+ agent.setTrust(
154
+ reputation=random.choice([True, False]),
155
+ cryptoEconomic=random.choice([True, False]),
156
+ teeAttestation=random.choice([True, False])
157
+ )
158
+ agent.setMetadata({
159
+ "testKey": "testValue",
160
+ "timestamp": int(time.time()),
161
+ "customField": "customValue",
162
+ "anotherField": "anotherValue",
163
+ "numericField": random.randint(1000, 9999)
164
+ })
165
+
166
+ # Update registration file and re-register
167
+ registrationFileUpdated = agent.getRegistrationFile()
168
+ registrationJsonUpdated = json.dumps(registrationFileUpdated.to_dict(), indent=2)
169
+
170
+ filenameUpdated = f"agent_registration_{agentId.replace(':', '_')}_updated.json"
171
+ with open(filenameUpdated, 'w') as f:
172
+ f.write(registrationJsonUpdated)
173
+
174
+ agent.register(mockUri)
175
+ print(f"โœ… Updated & re-registered")
176
+ print(f" Updated registration file: {filenameUpdated}")
177
+
178
+ # Capture updated state
179
+ updatedState = {
180
+ 'name': agent.name,
181
+ 'description': agent.description,
182
+ 'image': agent.image,
183
+ 'walletAddress': agent.walletAddress,
184
+ 'walletChainId': agent.walletChainId,
185
+ 'active': agent.active,
186
+ 'x402support': agent.x402support,
187
+ 'mcpEndpoint': agent.mcpEndpoint,
188
+ 'a2aEndpoint': agent.a2aEndpoint,
189
+ 'ensEndpoint': agent.ensEndpoint,
190
+ 'metadata': agent.metadata.copy()
191
+ }
192
+
193
+ # Step 5: Reload and verify
194
+ print("\n๐Ÿ“ Step 5: Reload and Verify")
195
+ print("-" * 60)
196
+
197
+ reloadedAgentId = agent.agentId
198
+ del agent
199
+ print("โณ Waiting for blockchain transaction to be mined (15 seconds)...")
200
+ time.sleep(15)
201
+ reloadedAgent = sdk.loadAgent(reloadedAgentId)
202
+ print(f"โœ… Reloaded from blockchain")
203
+
204
+ reloadedState = {
205
+ 'name': reloadedAgent.name,
206
+ 'description': reloadedAgent.description,
207
+ 'image': reloadedAgent.image,
208
+ 'walletAddress': reloadedAgent.walletAddress,
209
+ 'walletChainId': reloadedAgent.walletChainId,
210
+ 'active': reloadedAgent.active,
211
+ 'x402support': reloadedAgent.x402support,
212
+ 'mcpEndpoint': reloadedAgent.mcpEndpoint,
213
+ 'a2aEndpoint': reloadedAgent.a2aEndpoint,
214
+ 'ensEndpoint': reloadedAgent.ensEndpoint,
215
+ 'metadata': reloadedAgent.metadata.copy()
216
+ }
217
+
218
+ expectedState = updatedState
219
+ expectedState['walletAddress'] = f"0x{'b' * 40}"
220
+ expectedState['walletChainId'] = sdk.chainId
221
+
222
+ allMatch = True
223
+ for field, expected in expectedState.items():
224
+ actual = reloadedState.get(field)
225
+
226
+ # Handle type casting for metadata fields
227
+ if field == 'metadata' and isinstance(actual, dict) and isinstance(expected, dict):
228
+ normalized_actual = {}
229
+ for k, v in actual.items():
230
+ if k in expected:
231
+ expected_val = expected[k]
232
+ if isinstance(expected_val, int):
233
+ try:
234
+ normalized_actual[k] = int(v) if isinstance(v, str) else v
235
+ except (ValueError, TypeError):
236
+ normalized_actual[k] = v
237
+ elif isinstance(expected_val, float):
238
+ try:
239
+ normalized_actual[k] = float(v) if isinstance(v, str) else v
240
+ except (ValueError, TypeError):
241
+ normalized_actual[k] = v
242
+ else:
243
+ normalized_actual[k] = v
244
+ else:
245
+ normalized_actual[k] = v
246
+ actual = normalized_actual
247
+
248
+ if actual == expected:
249
+ print(f"โœ… {field}: {actual}")
250
+ else:
251
+ print(f"โŒ {field}: expected={expected}, got={actual}")
252
+ allMatch = False
253
+
254
+ if allMatch:
255
+ print("\nโœ… ALL CHECKS PASSED")
256
+ else:
257
+ print("\nโŒ SOME CHECKS FAILED")
258
+
259
+
260
+ if __name__ == "__main__":
261
+ try:
262
+ main()
263
+ except Exception as e:
264
+ print(f"\nโŒ Error: {e}")
265
+ import traceback
266
+ traceback.print_exc()
267
+ exit(1)
@@ -0,0 +1,227 @@
1
+ """
2
+ Real Test for Agent Registration with IPFS Pin (using Pinata)
3
+ Creates an agent, updates it on-chain, deletes it, reloads it, and verifies data integrity.
4
+ """
5
+
6
+ import logging
7
+ import time
8
+ import random
9
+ import sys
10
+
11
+ # Configure logging: root logger at WARNING to suppress noisy dependencies
12
+ logging.basicConfig(
13
+ level=logging.WARNING,
14
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
15
+ datefmt='%Y-%m-%d %H:%M:%S',
16
+ handlers=[logging.StreamHandler(sys.stdout)]
17
+ )
18
+
19
+ # Set debug level ONLY for agent0_sdk
20
+ logging.getLogger('agent0_sdk').setLevel(logging.DEBUG)
21
+ logging.getLogger('agent0_sdk.core').setLevel(logging.DEBUG)
22
+
23
+ from agent0_sdk import SDK
24
+ from config import CHAIN_ID, RPC_URL, AGENT_PRIVATE_KEY, PINATA_JWT, print_config
25
+
26
+
27
+ def generateRandomData():
28
+ """Generate random test data for the agent."""
29
+ randomSuffix = random.randint(1000, 9999)
30
+ timestamp = int(time.time())
31
+
32
+ return {
33
+ 'name': f"Test Agent {randomSuffix}",
34
+ 'description': f"Created at {timestamp}",
35
+ 'image': f"https://example.com/image_{randomSuffix}.png",
36
+ 'mcpEndpoint': f"https://api.example.com/mcp/{randomSuffix}",
37
+ 'mcpVersion': f"2025-06-{random.randint(1, 28)}",
38
+ 'a2aEndpoint': f"https://api.example.com/a2a/{randomSuffix}.json",
39
+ 'a2aVersion': f"0.{random.randint(30, 35)}",
40
+ 'ensName': f"test{randomSuffix}.eth",
41
+ 'ensVersion': f"1.{random.randint(0, 9)}",
42
+ 'walletAddress': f"0x{'a' * 40}",
43
+ 'walletChainId': random.choice([1, 11155111, 8453, 137, 42161]), # Mainnet, Sepolia, Base, Polygon, Arbitrum
44
+ 'active': True,
45
+ 'x402support': False,
46
+ 'reputation': random.choice([True, False]),
47
+ 'cryptoEconomic': random.choice([True, False]),
48
+ 'teeAttestation': random.choice([True, False])
49
+ }
50
+
51
+
52
+ def main():
53
+ print("๐Ÿงช Testing Agent Registration with IPFS Pin")
54
+ print_config()
55
+
56
+ # SDK Configuration with Pinata IPFS
57
+ sdkConfig = {
58
+ 'chainId': CHAIN_ID,
59
+ 'rpcUrl': RPC_URL,
60
+ 'ipfs': 'pinata',
61
+ 'pinataJwt': PINATA_JWT
62
+ }
63
+
64
+ sdk = SDK(signer=AGENT_PRIVATE_KEY, **sdkConfig)
65
+ testData = generateRandomData()
66
+
67
+ agent = sdk.createAgent(
68
+ name=testData['name'],
69
+ description=testData['description'],
70
+ image=testData['image']
71
+ )
72
+
73
+ agent.setMCP(testData['mcpEndpoint'], testData['mcpVersion'])
74
+ agent.setA2A(testData['a2aEndpoint'], testData['a2aVersion'])
75
+ agent.setENS(testData['ensName'], testData['ensVersion'])
76
+ agent.setAgentWallet(testData['walletAddress'], testData['walletChainId'])
77
+ agent.setActive(testData['active'])
78
+ agent.setX402Support(testData['x402support'])
79
+ agent.setTrust(
80
+ reputation=testData['reputation'],
81
+ cryptoEconomic=testData['cryptoEconomic'],
82
+ teeAttestation=testData['teeAttestation']
83
+ )
84
+
85
+ print(f"\nโœ… Created: {testData['name']}")
86
+
87
+ agent.registerIPFS()
88
+ agentId = agent.agentId
89
+ print(f"โœ… Registered: ID={agentId}")
90
+
91
+ capturedState = {
92
+ 'agentId': agent.agentId,
93
+ 'agentURI': agent.agentURI,
94
+ 'name': agent.name,
95
+ 'description': agent.description,
96
+ 'image': agent.image,
97
+ 'walletAddress': agent.walletAddress,
98
+ 'walletChainId': agent.walletChainId,
99
+ 'active': agent.active,
100
+ 'x402support': agent.x402support,
101
+ 'mcpEndpoint': agent.mcpEndpoint,
102
+ 'a2aEndpoint': agent.a2aEndpoint,
103
+ 'ensEndpoint': agent.ensEndpoint,
104
+ 'metadata': agent.metadata.copy()
105
+ }
106
+
107
+ agent.updateInfo(
108
+ name=testData['name'] + " UPDATED",
109
+ description=testData['description'] + " - UPDATED",
110
+ image=f"https://example.com/image_{random.randint(1000, 9999)}_updated.png"
111
+ )
112
+ agent.setMCP(f"https://api.example.com/mcp/{random.randint(10000, 99999)}", f"2025-06-{random.randint(1, 28)}")
113
+ agent.setA2A(f"https://api.example.com/a2a/{random.randint(10000, 99999)}.json", f"0.{random.randint(30, 35)}")
114
+ agent.setAgentWallet(f"0x{'b' * 40}", random.choice([1, 11155111, 8453, 137, 42161]))
115
+ agent.setENS(f"{testData['ensName']}.updated", f"1.{random.randint(0, 9)}")
116
+ agent.setActive(False)
117
+ agent.setX402Support(True)
118
+ agent.setTrust(
119
+ reputation=random.choice([True, False]),
120
+ cryptoEconomic=random.choice([True, False]),
121
+ teeAttestation=random.choice([True, False])
122
+ )
123
+ agent.setMetadata({
124
+ "testKey": "testValue",
125
+ "timestamp": int(time.time()),
126
+ "customField": "customValue",
127
+ "anotherField": "anotherValue",
128
+ "numericField": random.randint(1000, 9999)
129
+ })
130
+
131
+ agent.registerIPFS()
132
+ print(f"โœ… Updated & re-registered")
133
+
134
+ # Capture updated state before deletion
135
+ updatedState = {
136
+ 'name': agent.name,
137
+ 'description': agent.description,
138
+ 'image': agent.image,
139
+ 'walletAddress': agent.walletAddress,
140
+ 'walletChainId': agent.walletChainId,
141
+ 'active': agent.active,
142
+ 'x402support': agent.x402support,
143
+ 'mcpEndpoint': agent.mcpEndpoint,
144
+ 'a2aEndpoint': agent.a2aEndpoint,
145
+ 'ensEndpoint': agent.ensEndpoint,
146
+ 'metadata': agent.metadata.copy()
147
+ }
148
+
149
+ reloadedAgentId = agent.agentId
150
+ del agent
151
+ # Wait for blockchain transaction to be mined (Sepolia takes ~15 seconds)
152
+ print("โณ Waiting for blockchain transaction to be mined (15 seconds)...")
153
+ time.sleep(15)
154
+ reloadedAgent = sdk.loadAgent(reloadedAgentId)
155
+ print(f"โœ… Reloaded from blockchain")
156
+
157
+ reloadedState = {
158
+ 'name': reloadedAgent.name,
159
+ 'description': reloadedAgent.description,
160
+ 'image': reloadedAgent.image,
161
+ 'walletAddress': reloadedAgent.walletAddress,
162
+ 'walletChainId': reloadedAgent.walletChainId,
163
+ 'active': reloadedAgent.active,
164
+ 'x402support': reloadedAgent.x402support,
165
+ 'mcpEndpoint': reloadedAgent.mcpEndpoint,
166
+ 'a2aEndpoint': reloadedAgent.a2aEndpoint,
167
+ 'ensEndpoint': reloadedAgent.ensEndpoint,
168
+ 'metadata': reloadedAgent.metadata.copy()
169
+ }
170
+
171
+ expectedState = updatedState
172
+
173
+ # Override expected values for fields that should match the updated state
174
+ expectedState['walletAddress'] = f"0x{'b' * 40}"
175
+ # When wallet is set on-chain, walletChainId will be the current chain (where the update happened)
176
+ # This is different from the original registration file's chain ID
177
+ expectedState['walletChainId'] = sdk.chainId # Current chain where wallet was updated
178
+
179
+ allMatch = True
180
+ for field, expected in expectedState.items():
181
+ actual = reloadedState.get(field)
182
+
183
+ # Handle type casting for metadata fields (on-chain values are strings)
184
+ if field == 'metadata' and isinstance(actual, dict) and isinstance(expected, dict):
185
+ # Try to cast string values back to their original types
186
+ normalized_actual = {}
187
+ for k, v in actual.items():
188
+ if k in expected:
189
+ expected_val = expected[k]
190
+ # If expected is int or float, try to cast
191
+ if isinstance(expected_val, int):
192
+ try:
193
+ normalized_actual[k] = int(v) if isinstance(v, str) else v
194
+ except (ValueError, TypeError):
195
+ normalized_actual[k] = v
196
+ elif isinstance(expected_val, float):
197
+ try:
198
+ normalized_actual[k] = float(v) if isinstance(v, str) else v
199
+ except (ValueError, TypeError):
200
+ normalized_actual[k] = v
201
+ else:
202
+ normalized_actual[k] = v
203
+ else:
204
+ normalized_actual[k] = v
205
+ actual = normalized_actual
206
+
207
+ if actual == expected:
208
+ print(f"โœ… {field}: {actual}")
209
+ else:
210
+ print(f"โŒ {field}: expected={expected}, got={actual}")
211
+ allMatch = False
212
+
213
+ if allMatch:
214
+ print("\nโœ… ALL CHECKS PASSED")
215
+ else:
216
+ print("\nโŒ SOME CHECKS FAILED")
217
+
218
+
219
+ if __name__ == "__main__":
220
+ try:
221
+ main()
222
+ except Exception as e:
223
+ print(f"\nโŒ Error: {e}")
224
+ import traceback
225
+ traceback.print_exc()
226
+ exit(1)
227
+