ragaai-catalyst 2.0.7.2b1__py3-none-any.whl → 2.1__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 (29) hide show
  1. ragaai_catalyst/dataset.py +0 -3
  2. ragaai_catalyst/evaluation.py +1 -2
  3. ragaai_catalyst/tracers/__init__.py +1 -1
  4. ragaai_catalyst/tracers/agentic_tracing/agent_tracer.py +231 -74
  5. ragaai_catalyst/tracers/agentic_tracing/agentic_tracing.py +32 -42
  6. ragaai_catalyst/tracers/agentic_tracing/base.py +132 -30
  7. ragaai_catalyst/tracers/agentic_tracing/data_structure.py +91 -79
  8. ragaai_catalyst/tracers/agentic_tracing/examples/FinancialAnalysisSystem.ipynb +536 -0
  9. ragaai_catalyst/tracers/agentic_tracing/examples/GameActivityEventPlanner.ipynb +134 -0
  10. ragaai_catalyst/tracers/agentic_tracing/examples/TravelPlanner.ipynb +563 -0
  11. ragaai_catalyst/tracers/agentic_tracing/file_name_tracker.py +46 -0
  12. ragaai_catalyst/tracers/agentic_tracing/llm_tracer.py +262 -356
  13. ragaai_catalyst/tracers/agentic_tracing/tool_tracer.py +31 -19
  14. ragaai_catalyst/tracers/agentic_tracing/unique_decorator.py +61 -117
  15. ragaai_catalyst/tracers/agentic_tracing/upload_agentic_traces.py +187 -0
  16. ragaai_catalyst/tracers/agentic_tracing/upload_code.py +115 -0
  17. ragaai_catalyst/tracers/agentic_tracing/user_interaction_tracer.py +35 -59
  18. ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +0 -4
  19. ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json +2201 -324
  20. ragaai_catalyst/tracers/agentic_tracing/zip_list_of_unique_files.py +186 -0
  21. ragaai_catalyst/tracers/exporters/raga_exporter.py +1 -7
  22. ragaai_catalyst/tracers/llamaindex_callback.py +56 -60
  23. ragaai_catalyst/tracers/tracer.py +6 -2
  24. ragaai_catalyst/tracers/upload_traces.py +46 -57
  25. {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1.dist-info}/METADATA +8 -4
  26. {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1.dist-info}/RECORD +28 -22
  27. {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1.dist-info}/WHEEL +1 -1
  28. ragaai_catalyst/tracers/agentic_tracing/Untitled-1.json +0 -660
  29. {ragaai_catalyst-2.0.7.2b1.dist-info → ragaai_catalyst-2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,563 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Travel Agent Planner with AgentNeo Integration\n",
8
+ "\n",
9
+ "This Jupyter notebook demonstrates the integration of AgentNeo, a powerful tracing and monitoring tool, with a Travel Agent Planner system. AgentNeo provides seamless tracing capabilities for both function calls and AI model interactions, allowing for comprehensive analysis and debugging of complex systems."
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "markdown",
14
+ "metadata": {},
15
+ "source": [
16
+ "\n",
17
+ "# Setup and Imports\n",
18
+ "First, let's import the necessary libraries and set up our environment."
19
+ ]
20
+ },
21
+ {
22
+ "cell_type": "code",
23
+ "execution_count": 1,
24
+ "metadata": {},
25
+ "outputs": [],
26
+ "source": [
27
+ "import os\n",
28
+ "import requests\n",
29
+ "from dotenv import load_dotenv\n",
30
+ "from litellm import completion\n",
31
+ "import openai\n",
32
+ "from openai import OpenAI"
33
+ ]
34
+ },
35
+ {
36
+ "cell_type": "code",
37
+ "execution_count": 2,
38
+ "metadata": {},
39
+ "outputs": [],
40
+ "source": [
41
+ "# Load environment variables\n",
42
+ "load_dotenv(\"/Users/abs/Desktop/LLM/ragaai_catalyst/ragaai-catalyst/.env\")\n",
43
+ "\n",
44
+ "\n",
45
+ "# Initialize OpenAI API\n",
46
+ "openai.api_key = os.getenv(\"OPENAI_API_KEY\")\n",
47
+ "\n"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "code",
52
+ "execution_count": 3,
53
+ "metadata": {},
54
+ "outputs": [
55
+ {
56
+ "name": "stdout",
57
+ "output_type": "stream",
58
+ "text": [
59
+ "Project created successfully\n",
60
+ "Project 'ai_travel_agent_demo1' found.\n",
61
+ "Tracing Started.\n"
62
+ ]
63
+ }
64
+ ],
65
+ "source": [
66
+ "# Initialize AgentNeo Package\n",
67
+ "import os\n",
68
+ "os.chdir('..')\n",
69
+ "\n",
70
+ "from agentneo import AgentNeo, Tracer, Evaluation,launch_dashboard\n",
71
+ "# Initialize AgentNeo session\n",
72
+ "# Create project\n",
73
+ "neo_session = AgentNeo(session_name=\"test\")\n",
74
+ "\n",
75
+ "project_name = \"ai_travel_agent_demo1\"\n",
76
+ "\n",
77
+ "try:\n",
78
+ " neo_session.create_project(project_name=project_name)\n",
79
+ " print(\"Project created successfully\")\n",
80
+ "except:\n",
81
+ " neo_session.connect_project(project_name=project_name)\n",
82
+ " print(\"Project connected successfully\")\n",
83
+ "# Start tracing\n",
84
+ "tracer = Tracer(session=neo_session)\n",
85
+ "tracer.start()"
86
+ ]
87
+ },
88
+ {
89
+ "cell_type": "markdown",
90
+ "metadata": {},
91
+ "source": [
92
+ "# Travel Agent Tools\n",
93
+ "Now, let's define our Travel Agent Planner Tools with AgentNeo integration."
94
+ ]
95
+ },
96
+ {
97
+ "cell_type": "code",
98
+ "execution_count": 4,
99
+ "metadata": {},
100
+ "outputs": [],
101
+ "source": [
102
+ "@tracer.trace_llm(name=\"llm_call\")\n",
103
+ "def llm_call(prompt, max_tokens=512, model=\"gpt-3.5-turbo\"):\n",
104
+ " client = OpenAI(api_key=os.environ[\"OPENAI_API_KEY\"])\n",
105
+ "\n",
106
+ " response = client.chat.completions.create(\n",
107
+ " model=model,\n",
108
+ " messages=[{\"role\": \"user\", \"content\": prompt}],\n",
109
+ " max_tokens=max_tokens,\n",
110
+ " temperature=0.7,\n",
111
+ " )\n",
112
+ "\n",
113
+ " return response.choices[0].message.content.strip()\n",
114
+ "\n",
115
+ "\n",
116
+ "# Tools outside agents\n",
117
+ "@tracer.trace_tool(name=\"weather_tool\")\n",
118
+ "def weather_tool(destination):\n",
119
+ "\n",
120
+ " api_key = os.environ.get(\"OPENWEATHERMAP_API_KEY\")\n",
121
+ " base_url = \"http://api.openweathermap.org/data/2.5/weather\"\n",
122
+ "\n",
123
+ " params = {\"q\": destination, \"appid\": api_key, \"units\": \"metric\"}\n",
124
+ "\n",
125
+ " try:\n",
126
+ " response = requests.get(base_url, params=params)\n",
127
+ " response.raise_for_status()\n",
128
+ " data = response.json()\n",
129
+ "\n",
130
+ " weather_description = data[\"weather\"][0][\"description\"]\n",
131
+ " temperature = data[\"main\"][\"temp\"]\n",
132
+ "\n",
133
+ " return f\"{weather_description.capitalize()}, {temperature:.1f}°C\"\n",
134
+ " except requests.RequestException:\n",
135
+ " return \"Weather data not available.\"\n",
136
+ "\n",
137
+ "\n",
138
+ "@tracer.trace_tool(name=\"currency_converter_tool\")\n",
139
+ "def currency_converter_tool(amount, from_currency, to_currency):\n",
140
+ " api_key = os.environ.get(\"EXCHANGERATE_API_KEY\")\n",
141
+ " base_url = f\"https://v6.exchangerate-api.com/v6/{api_key}/pair/{from_currency}/{to_currency}\"\n",
142
+ "\n",
143
+ " try:\n",
144
+ " response = requests.get(base_url)\n",
145
+ " response.raise_for_status()\n",
146
+ " data = response.json()\n",
147
+ "\n",
148
+ " if data[\"result\"] == \"success\":\n",
149
+ " rate = data[\"conversion_rate\"]\n",
150
+ " return amount * rate\n",
151
+ " else:\n",
152
+ " return None\n",
153
+ " except requests.RequestException:\n",
154
+ " return None\n",
155
+ "\n",
156
+ "\n",
157
+ "@tracer.trace_tool(name=\"flight_price_estimator_tool\")\n",
158
+ "def flight_price_estimator_tool(origin, destination):\n",
159
+ " # This is a mock function. In a real scenario, you'd integrate with a flight API.\n",
160
+ " api_key = os.environ.get(\"FLIGHT_API_KEY\")\n",
161
+ " # Implement actual API call here\n",
162
+ " return f\"Estimated price from {origin} to {destination}: $500-$1000\"\n",
163
+ "\n",
164
+ "\n",
165
+ "# Agent with persona\n",
166
+ "@tracer.trace_agent(name=\"itinerary_agent\")\n",
167
+ "class ItineraryAgent:\n",
168
+ " def __init__(self, persona=\"Itinerary Agent\"):\n",
169
+ " self.persona = persona\n",
170
+ "\n",
171
+ " def plan_itinerary(self, user_preferences, duration=3):\n",
172
+ " itinerary_prompt = f\"\"\"\n",
173
+ "You are a travel expert named {self.persona}.\n",
174
+ "Based on the following user preferences, create a {duration}-day travel itinerary.\n",
175
+ "\n",
176
+ "User Preferences:\n",
177
+ "{user_preferences}\n",
178
+ "\n",
179
+ "Itinerary:\n",
180
+ "\"\"\"\n",
181
+ " return llm_call(itinerary_prompt, max_tokens=512)\n",
182
+ "\n",
183
+ "\n"
184
+ ]
185
+ },
186
+ {
187
+ "cell_type": "markdown",
188
+ "metadata": {},
189
+ "source": [
190
+ "\n",
191
+ "# Running the Analysis\n",
192
+ "Now let's create a main function for our Travel Agent Planner which recall all tools "
193
+ ]
194
+ },
195
+ {
196
+ "cell_type": "code",
197
+ "execution_count": 5,
198
+ "metadata": {},
199
+ "outputs": [],
200
+ "source": [
201
+ "# Main function\n",
202
+ "\n",
203
+ "@tracer.trace_agent(name=\"travel_agent\")\n",
204
+ "def travel_agent():\n",
205
+ " print(\"Welcome to the Personalized Travel Planner!\\n\")\n",
206
+ "\n",
207
+ " # Get user input\n",
208
+ " # user_input = input(\"Please describe your ideal vacation: \")\n",
209
+ " user_input = \"karela, 10 days, $100, nature\"\n",
210
+ "\n",
211
+ " # Extract preferences\n",
212
+ " preferences_prompt = f\"\"\"\n",
213
+ "Extract key travel preferences from the following user input:\n",
214
+ "\"{user_input}\"\n",
215
+ "\n",
216
+ "Please provide the extracted information in this format:\n",
217
+ "Destination:\n",
218
+ "Activities:\n",
219
+ "Budget:\n",
220
+ "Duration (in days):\n",
221
+ "\"\"\"\n",
222
+ " extracted_preferences = llm_call(preferences_prompt)\n",
223
+ " print(\"\\nExtracted Preferences:\")\n",
224
+ " print(extracted_preferences)\n",
225
+ "\n",
226
+ " # Parse extracted preferences\n",
227
+ " preferences = {}\n",
228
+ " for line in extracted_preferences.split(\"\\n\"):\n",
229
+ " if \":\" in line:\n",
230
+ " key, value = line.split(\":\", 1)\n",
231
+ " preferences[key.strip()] = value.strip()\n",
232
+ "\n",
233
+ " # Validate extracted preferences\n",
234
+ " required_keys = [\"Destination\", \"Activities\", \"Budget\", \"Duration (in days)\"]\n",
235
+ " if not all(key in preferences for key in required_keys):\n",
236
+ " print(\"\\nCould not extract all required preferences. Please try again.\")\n",
237
+ " return\n",
238
+ "\n",
239
+ " # Fetch additional information\n",
240
+ " weather = weather_tool(preferences[\"Destination\"])\n",
241
+ " print(f\"\\nWeather in {preferences['Destination']}: {weather}\")\n",
242
+ "\n",
243
+ " # origin = input(\"Please enter your departure city: \")\n",
244
+ " origin = \"delhi\"\n",
245
+ " flight_price = flight_price_estimator_tool(origin, preferences[\"Destination\"])\n",
246
+ " print(flight_price)\n",
247
+ "\n",
248
+ " # Plan itinerary\n",
249
+ " itinerary_agent = ItineraryAgent()\n",
250
+ " itinerary = itinerary_agent.plan_itinerary(\n",
251
+ " extracted_preferences, int(preferences[\"Duration (in days)\"])\n",
252
+ " )\n",
253
+ " print(\"\\nPlanned Itinerary:\")\n",
254
+ " print(itinerary)\n",
255
+ "\n",
256
+ " # Currency conversion\n",
257
+ " budget_amount = float(preferences[\"Budget\"].replace(\"$\", \"\").replace(\",\", \"\"))\n",
258
+ " converted_budget = currency_converter_tool(budget_amount, \"USD\", \"INR\")\n",
259
+ " if converted_budget:\n",
260
+ " print(f\"\\nBudget in INR: {converted_budget:.2f} INR\")\n",
261
+ " else:\n",
262
+ " print(\"\\nCurrency conversion not available.\")\n",
263
+ "\n",
264
+ " # Generate travel summary\n",
265
+ " summary_prompt = f\"\"\"\n",
266
+ "Summarize the following travel plan:\n",
267
+ "\n",
268
+ "Destination: {preferences['Destination']}\n",
269
+ "Activities: {preferences['Activities']}\n",
270
+ "Budget: {preferences['Budget']}\n",
271
+ "Duration: {preferences['Duration (in days)']} days\n",
272
+ "Itinerary: {itinerary}\n",
273
+ "Weather: {weather}\n",
274
+ "Flight Price: {flight_price}\n",
275
+ "\n",
276
+ "Travel Summary:\n",
277
+ "\"\"\"\n",
278
+ " travel_summary = llm_call(summary_prompt, max_tokens=2048)\n",
279
+ " print(\"\\nTravel Summary:\")\n",
280
+ " print(travel_summary)"
281
+ ]
282
+ },
283
+ {
284
+ "cell_type": "code",
285
+ "execution_count": 6,
286
+ "metadata": {},
287
+ "outputs": [
288
+ {
289
+ "name": "stdout",
290
+ "output_type": "stream",
291
+ "text": [
292
+ "Welcome to the Personalized Travel Planner!\n",
293
+ "\n"
294
+ ]
295
+ },
296
+ {
297
+ "name": "stderr",
298
+ "output_type": "stream",
299
+ "text": [
300
+ "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n"
301
+ ]
302
+ },
303
+ {
304
+ "name": "stdout",
305
+ "output_type": "stream",
306
+ "text": [
307
+ "\n",
308
+ "Extracted Preferences:\n",
309
+ "Destination: karela\n",
310
+ "Activities: nature\n",
311
+ "Budget: $100\n",
312
+ "Duration (in days): 10\n",
313
+ "\n",
314
+ "Weather in karela: Weather data not available.\n",
315
+ "Estimated price from goa to karela: $500-$1000\n"
316
+ ]
317
+ },
318
+ {
319
+ "name": "stderr",
320
+ "output_type": "stream",
321
+ "text": [
322
+ "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n"
323
+ ]
324
+ },
325
+ {
326
+ "name": "stdout",
327
+ "output_type": "stream",
328
+ "text": [
329
+ "\n",
330
+ "Planned Itinerary:\n",
331
+ "Day 1-2: Arrival in Karela\n",
332
+ "- Check into a budget-friendly accommodation\n",
333
+ "- Explore the natural beauty of Karela, including its lush forests and scenic views\n",
334
+ "- Visit local parks and hiking trails for a nature-filled day\n",
335
+ "\n",
336
+ "Day 3-4: Nature Excursions\n",
337
+ "- Take a guided nature walk through the Karela National Park\n",
338
+ "- Explore the nearby waterfalls and rivers for a refreshing experience\n",
339
+ "- Enjoy a picnic in the great outdoors\n",
340
+ "\n",
341
+ "Day 5-6: Cultural Discovery\n",
342
+ "- Visit local villages and learn about the traditional way of life in Karela\n",
343
+ "- Attend a cultural performance showcasing traditional music and dances\n",
344
+ "- Sample local cuisine and delicacies\n",
345
+ "\n",
346
+ "Day 7-8: Adventure Activities\n",
347
+ "- Try your hand at zip-lining through the forest canopy\n",
348
+ "- Go on a thrilling river rafting adventure\n",
349
+ "- Explore caves and gorges in the area\n",
350
+ "\n",
351
+ "Day 9-10: Relaxation and Reflection\n",
352
+ "- Spend your last days in Karela unwinding at a spa or wellness retreat\n",
353
+ "- Reflect on your nature-filled adventures and memories made during your trip\n",
354
+ "- Departure from Karela with a heart full of gratitude for the experience\n",
355
+ "\n",
356
+ "Overall, this itinerary offers a perfect blend of nature, culture, adventure, and relaxation within the user's budget constraints. Enjoy your 10-day trip to Karela!\n",
357
+ "\n",
358
+ "Currency conversion not available.\n"
359
+ ]
360
+ },
361
+ {
362
+ "name": "stderr",
363
+ "output_type": "stream",
364
+ "text": [
365
+ "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
366
+ "DEBUG:agentneo.tracing.agent_tracer:Successfully updated and committed AgentCallModel with id 2\n",
367
+ "DEBUG:agentneo.tracing.agent_tracer:Successfully updated and committed AgentCallModel with id 1\n"
368
+ ]
369
+ },
370
+ {
371
+ "name": "stdout",
372
+ "output_type": "stream",
373
+ "text": [
374
+ "\n",
375
+ "Travel Summary:\n",
376
+ "Destination: Karela\n",
377
+ "Activities: Nature exploration, cultural discovery, adventure activities, relaxation\n",
378
+ "Budget: $100\n",
379
+ "Duration: 10 days\n",
380
+ "Itinerary: Arrival and exploration of Karela's natural beauty, guided nature walks, cultural experiences, adventure activities like zip-lining and river rafting, relaxation at a spa or wellness retreat\n",
381
+ "Flight Price: Estimated at $500-$1000 from Goa to Karela\n",
382
+ "\n",
383
+ "Overall, the travel plan offers a diverse range of activities and experiences in Karela within the budget of $100 for a 10-day trip.\n",
384
+ "Tracing Completed.\n",
385
+ "Data saved to the database and JSON file.\n",
386
+ "\n"
387
+ ]
388
+ }
389
+ ],
390
+ "source": [
391
+ "# Main function to run the travel agent\n",
392
+ "def main():\n",
393
+ " travel_agent()\n",
394
+ "\n",
395
+ "# Ensure the script runs only when executed directly\n",
396
+ "if __name__ == \"__main__\":\n",
397
+ " main()\n",
398
+ " tracer.stop()\n"
399
+ ]
400
+ },
401
+ {
402
+ "cell_type": "markdown",
403
+ "metadata": {},
404
+ "source": [
405
+ "# Metrics Evaluation\n",
406
+ "Supported Metrics\n",
407
+ "Goal Decomposition Efficiency (goal_decomposition_efficiency)\n",
408
+ "Goal Fulfillment Rate (goal_fulfillment_rate)\n",
409
+ "Tool Call Correctness Rate (tool_call_correctness_rate)\n",
410
+ "Tool Call Success Rate (tool_call_success_rate)"
411
+ ]
412
+ },
413
+ {
414
+ "cell_type": "code",
415
+ "execution_count": 7,
416
+ "metadata": {},
417
+ "outputs": [],
418
+ "source": [
419
+ "# exe = Evaluation(session=neo_session, trace_id=tracer.trace_id)"
420
+ ]
421
+ },
422
+ {
423
+ "cell_type": "code",
424
+ "execution_count": 8,
425
+ "metadata": {},
426
+ "outputs": [],
427
+ "source": [
428
+ "# # run a single metric\n",
429
+ "# exe.evaluate(metric_list=['goal_decomposition_efficiency', \n",
430
+ "# 'goal_fulfillment_rate', \n",
431
+ "# 'tool_call_correctness_rate', \n",
432
+ "# 'tool_call_success_rate'])"
433
+ ]
434
+ },
435
+ {
436
+ "cell_type": "code",
437
+ "execution_count": 9,
438
+ "metadata": {},
439
+ "outputs": [],
440
+ "source": [
441
+ "# #print metric result\n",
442
+ "# metric_results = exe.get_results()\n",
443
+ "# metric_results"
444
+ ]
445
+ },
446
+ {
447
+ "cell_type": "code",
448
+ "execution_count": 10,
449
+ "metadata": {},
450
+ "outputs": [
451
+ {
452
+ "name": "stderr",
453
+ "output_type": "stream",
454
+ "text": [
455
+ "INFO:root:Port 3000 is busy. Finding an available port...\n",
456
+ "INFO:root:Using port 3028\n",
457
+ "INFO:root:Dashboard process started successfully\n",
458
+ "INFO:root:Dashboard launched successfully. Access it at: http://localhost:3028\n"
459
+ ]
460
+ }
461
+ ],
462
+ "source": [
463
+ "neo_session.launch_dashboard()"
464
+ ]
465
+ },
466
+ {
467
+ "cell_type": "markdown",
468
+ "metadata": {},
469
+ "source": [
470
+ "### get the trace data"
471
+ ]
472
+ },
473
+ {
474
+ "cell_type": "code",
475
+ "execution_count": 11,
476
+ "metadata": {},
477
+ "outputs": [
478
+ {
479
+ "ename": "ConnectionError",
480
+ "evalue": "HTTPConnectionPool(host='localhost', port=2020): Max retries exceeded with url: /api/analysis_traces/1 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x11a9bb4d0>: Failed to establish a new connection: [Errno 61] Connection refused'))",
481
+ "output_type": "error",
482
+ "traceback": [
483
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
484
+ "\u001b[0;31mConnectionRefusedError\u001b[0m Traceback (most recent call last)",
485
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/urllib3/connection.py:196\u001b[0m, in \u001b[0;36mHTTPConnection._new_conn\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 195\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 196\u001b[0m sock \u001b[38;5;241m=\u001b[39m \u001b[43mconnection\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_connection\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 197\u001b[0m \u001b[43m \u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_dns_host\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mport\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 198\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 199\u001b[0m \u001b[43m \u001b[49m\u001b[43msource_address\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msource_address\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 200\u001b[0m \u001b[43m \u001b[49m\u001b[43msocket_options\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msocket_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 201\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 202\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m socket\u001b[38;5;241m.\u001b[39mgaierror \u001b[38;5;28;01mas\u001b[39;00m e:\n",
486
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/urllib3/util/connection.py:85\u001b[0m, in \u001b[0;36mcreate_connection\u001b[0;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[1;32m 84\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 85\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m err\n\u001b[1;32m 86\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[1;32m 87\u001b[0m \u001b[38;5;66;03m# Break explicitly a reference cycle\u001b[39;00m\n",
487
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/urllib3/util/connection.py:73\u001b[0m, in \u001b[0;36mcreate_connection\u001b[0;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[1;32m 72\u001b[0m sock\u001b[38;5;241m.\u001b[39mbind(source_address)\n\u001b[0;32m---> 73\u001b[0m \u001b[43msock\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43msa\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 74\u001b[0m \u001b[38;5;66;03m# Break explicitly a reference cycle\u001b[39;00m\n",
488
+ "\u001b[0;31mConnectionRefusedError\u001b[0m: [Errno 61] Connection refused",
489
+ "\nThe above exception was the direct cause of the following exception:\n",
490
+ "\u001b[0;31mNewConnectionError\u001b[0m Traceback (most recent call last)",
491
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:789\u001b[0m, in \u001b[0;36mHTTPConnectionPool.urlopen\u001b[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001b[0m\n\u001b[1;32m 788\u001b[0m \u001b[38;5;66;03m# Make the request on the HTTPConnection object\u001b[39;00m\n\u001b[0;32m--> 789\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_make_request\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 790\u001b[0m \u001b[43m \u001b[49m\u001b[43mconn\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 791\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 792\u001b[0m \u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 793\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout_obj\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 794\u001b[0m \u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 795\u001b[0m \u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 796\u001b[0m \u001b[43m \u001b[49m\u001b[43mchunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchunked\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 797\u001b[0m \u001b[43m \u001b[49m\u001b[43mretries\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mretries\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 798\u001b[0m \u001b[43m \u001b[49m\u001b[43mresponse_conn\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mresponse_conn\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 799\u001b[0m \u001b[43m \u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpreload_content\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 800\u001b[0m \u001b[43m \u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdecode_content\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 801\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mresponse_kw\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 802\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 804\u001b[0m \u001b[38;5;66;03m# Everything went great!\u001b[39;00m\n",
492
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:495\u001b[0m, in \u001b[0;36mHTTPConnectionPool._make_request\u001b[0;34m(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 495\u001b[0m \u001b[43mconn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 496\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 497\u001b[0m \u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 498\u001b[0m \u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 499\u001b[0m \u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 500\u001b[0m \u001b[43m \u001b[49m\u001b[43mchunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchunked\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 501\u001b[0m \u001b[43m \u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpreload_content\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 502\u001b[0m \u001b[43m \u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdecode_content\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 503\u001b[0m \u001b[43m \u001b[49m\u001b[43menforce_content_length\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43menforce_content_length\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 504\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 506\u001b[0m \u001b[38;5;66;03m# We are swallowing BrokenPipeError (errno.EPIPE) since the server is\u001b[39;00m\n\u001b[1;32m 507\u001b[0m \u001b[38;5;66;03m# legitimately able to close the connection after sending a valid response.\u001b[39;00m\n\u001b[1;32m 508\u001b[0m \u001b[38;5;66;03m# With this behaviour, the received response is still readable.\u001b[39;00m\n",
493
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/urllib3/connection.py:398\u001b[0m, in \u001b[0;36mHTTPConnection.request\u001b[0;34m(self, method, url, body, headers, chunked, preload_content, decode_content, enforce_content_length)\u001b[0m\n\u001b[1;32m 397\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mputheader(header, value)\n\u001b[0;32m--> 398\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mendheaders\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 400\u001b[0m \u001b[38;5;66;03m# If we're given a body we start sending that in chunks.\u001b[39;00m\n",
494
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/http/client.py:1326\u001b[0m, in \u001b[0;36mHTTPConnection.endheaders\u001b[0;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[1;32m 1325\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m CannotSendHeader()\n\u001b[0;32m-> 1326\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_send_output\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessage_body\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencode_chunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencode_chunked\u001b[49m\u001b[43m)\u001b[49m\n",
495
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/http/client.py:1085\u001b[0m, in \u001b[0;36mHTTPConnection._send_output\u001b[0;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[1;32m 1084\u001b[0m \u001b[38;5;28;01mdel\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_buffer[:]\n\u001b[0;32m-> 1085\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmsg\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1087\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m message_body \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 1088\u001b[0m \n\u001b[1;32m 1089\u001b[0m \u001b[38;5;66;03m# create a consistent interface to message_body\u001b[39;00m\n",
496
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/http/client.py:1029\u001b[0m, in \u001b[0;36mHTTPConnection.send\u001b[0;34m(self, data)\u001b[0m\n\u001b[1;32m 1028\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mauto_open:\n\u001b[0;32m-> 1029\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1030\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n",
497
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/urllib3/connection.py:236\u001b[0m, in \u001b[0;36mHTTPConnection.connect\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 235\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mconnect\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 236\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msock \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_new_conn\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 237\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_tunnel_host:\n\u001b[1;32m 238\u001b[0m \u001b[38;5;66;03m# If we're tunneling it means we're connected to our proxy.\u001b[39;00m\n",
498
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/urllib3/connection.py:211\u001b[0m, in \u001b[0;36mHTTPConnection._new_conn\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 210\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mOSError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m--> 211\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m NewConnectionError(\n\u001b[1;32m 212\u001b[0m \u001b[38;5;28mself\u001b[39m, \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFailed to establish a new connection: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00me\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 213\u001b[0m ) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01me\u001b[39;00m\n\u001b[1;32m 215\u001b[0m \u001b[38;5;66;03m# Audit hooks are only available in Python 3.8+\u001b[39;00m\n",
499
+ "\u001b[0;31mNewConnectionError\u001b[0m: <urllib3.connection.HTTPConnection object at 0x11a9bb4d0>: Failed to establish a new connection: [Errno 61] Connection refused",
500
+ "\nThe above exception was the direct cause of the following exception:\n",
501
+ "\u001b[0;31mMaxRetryError\u001b[0m Traceback (most recent call last)",
502
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/requests/adapters.py:667\u001b[0m, in \u001b[0;36mHTTPAdapter.send\u001b[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[1;32m 666\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 667\u001b[0m resp \u001b[38;5;241m=\u001b[39m \u001b[43mconn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43murlopen\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 668\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 669\u001b[0m \u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 670\u001b[0m \u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 671\u001b[0m \u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 672\u001b[0m \u001b[43m \u001b[49m\u001b[43mredirect\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 673\u001b[0m \u001b[43m \u001b[49m\u001b[43massert_same_host\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 674\u001b[0m \u001b[43m \u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 675\u001b[0m \u001b[43m \u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 676\u001b[0m \u001b[43m \u001b[49m\u001b[43mretries\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmax_retries\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 677\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 678\u001b[0m \u001b[43m \u001b[49m\u001b[43mchunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchunked\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 679\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 681\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (ProtocolError, \u001b[38;5;167;01mOSError\u001b[39;00m) \u001b[38;5;28;01mas\u001b[39;00m err:\n",
503
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:843\u001b[0m, in \u001b[0;36mHTTPConnectionPool.urlopen\u001b[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001b[0m\n\u001b[1;32m 841\u001b[0m new_e \u001b[38;5;241m=\u001b[39m ProtocolError(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mConnection aborted.\u001b[39m\u001b[38;5;124m\"\u001b[39m, new_e)\n\u001b[0;32m--> 843\u001b[0m retries \u001b[38;5;241m=\u001b[39m \u001b[43mretries\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mincrement\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 844\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merror\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnew_e\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m_pool\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m_stacktrace\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msys\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexc_info\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m]\u001b[49m\n\u001b[1;32m 845\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 846\u001b[0m retries\u001b[38;5;241m.\u001b[39msleep()\n",
504
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/urllib3/util/retry.py:519\u001b[0m, in \u001b[0;36mRetry.increment\u001b[0;34m(self, method, url, response, error, _pool, _stacktrace)\u001b[0m\n\u001b[1;32m 518\u001b[0m reason \u001b[38;5;241m=\u001b[39m error \u001b[38;5;129;01mor\u001b[39;00m ResponseError(cause)\n\u001b[0;32m--> 519\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m MaxRetryError(_pool, url, reason) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mreason\u001b[39;00m \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[1;32m 521\u001b[0m log\u001b[38;5;241m.\u001b[39mdebug(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIncremented Retry for (url=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m): \u001b[39m\u001b[38;5;132;01m%r\u001b[39;00m\u001b[38;5;124m\"\u001b[39m, url, new_retry)\n",
505
+ "\u001b[0;31mMaxRetryError\u001b[0m: HTTPConnectionPool(host='localhost', port=2020): Max retries exceeded with url: /api/analysis_traces/1 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x11a9bb4d0>: Failed to establish a new connection: [Errno 61] Connection refused'))",
506
+ "\nDuring handling of the above exception, another exception occurred:\n",
507
+ "\u001b[0;31mConnectionError\u001b[0m Traceback (most recent call last)",
508
+ "Cell \u001b[0;32mIn[11], line 6\u001b[0m\n\u001b[1;32m 4\u001b[0m trace_id \u001b[38;5;241m=\u001b[39m tracer\u001b[38;5;241m.\u001b[39mtrace_id \n\u001b[1;32m 5\u001b[0m port \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m2020\u001b[39m \u001b[38;5;66;03m# port no of the falsk server\u001b[39;00m\n\u001b[0;32m----> 6\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[43mrequests\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43mf\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mhttp://localhost:\u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mport\u001b[49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[38;5;124;43m/api/analysis_traces/\u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mtrace_id\u001b[49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 8\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m response\u001b[38;5;241m.\u001b[39mstatus_code \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m200\u001b[39m:\n\u001b[1;32m 9\u001b[0m trace_data \u001b[38;5;241m=\u001b[39m response\u001b[38;5;241m.\u001b[39mjson()\n",
509
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/requests/api.py:73\u001b[0m, in \u001b[0;36mget\u001b[0;34m(url, params, **kwargs)\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mget\u001b[39m(url, params\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m 63\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124mr\u001b[39m\u001b[38;5;124;03m\"\"\"Sends a GET request.\u001b[39;00m\n\u001b[1;32m 64\u001b[0m \n\u001b[1;32m 65\u001b[0m \u001b[38;5;124;03m :param url: URL for the new :class:`Request` object.\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 70\u001b[0m \u001b[38;5;124;03m :rtype: requests.Response\u001b[39;00m\n\u001b[1;32m 71\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m---> 73\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mget\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparams\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
510
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/requests/api.py:59\u001b[0m, in \u001b[0;36mrequest\u001b[0;34m(method, url, **kwargs)\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[38;5;66;03m# By using the 'with' statement we are sure the session is closed, thus we\u001b[39;00m\n\u001b[1;32m 56\u001b[0m \u001b[38;5;66;03m# avoid leaving sockets open which can trigger a ResourceWarning in some\u001b[39;00m\n\u001b[1;32m 57\u001b[0m \u001b[38;5;66;03m# cases, and look like a memory leak in others.\u001b[39;00m\n\u001b[1;32m 58\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m sessions\u001b[38;5;241m.\u001b[39mSession() \u001b[38;5;28;01mas\u001b[39;00m session:\n\u001b[0;32m---> 59\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43msession\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
511
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/requests/sessions.py:589\u001b[0m, in \u001b[0;36mSession.request\u001b[0;34m(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)\u001b[0m\n\u001b[1;32m 584\u001b[0m send_kwargs \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 585\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtimeout\u001b[39m\u001b[38;5;124m\"\u001b[39m: timeout,\n\u001b[1;32m 586\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mallow_redirects\u001b[39m\u001b[38;5;124m\"\u001b[39m: allow_redirects,\n\u001b[1;32m 587\u001b[0m }\n\u001b[1;32m 588\u001b[0m send_kwargs\u001b[38;5;241m.\u001b[39mupdate(settings)\n\u001b[0;32m--> 589\u001b[0m resp \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprep\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43msend_kwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 591\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m resp\n",
512
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/requests/sessions.py:703\u001b[0m, in \u001b[0;36mSession.send\u001b[0;34m(self, request, **kwargs)\u001b[0m\n\u001b[1;32m 700\u001b[0m start \u001b[38;5;241m=\u001b[39m preferred_clock()\n\u001b[1;32m 702\u001b[0m \u001b[38;5;66;03m# Send the request\u001b[39;00m\n\u001b[0;32m--> 703\u001b[0m r \u001b[38;5;241m=\u001b[39m \u001b[43madapter\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mrequest\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 705\u001b[0m \u001b[38;5;66;03m# Total elapsed time of the request (approximately)\u001b[39;00m\n\u001b[1;32m 706\u001b[0m elapsed \u001b[38;5;241m=\u001b[39m preferred_clock() \u001b[38;5;241m-\u001b[39m start\n",
513
+ "File \u001b[0;32m~/miniconda3/lib/python3.12/site-packages/requests/adapters.py:700\u001b[0m, in \u001b[0;36mHTTPAdapter.send\u001b[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[1;32m 696\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(e\u001b[38;5;241m.\u001b[39mreason, _SSLError):\n\u001b[1;32m 697\u001b[0m \u001b[38;5;66;03m# This branch is for urllib3 v1.22 and later.\u001b[39;00m\n\u001b[1;32m 698\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m SSLError(e, request\u001b[38;5;241m=\u001b[39mrequest)\n\u001b[0;32m--> 700\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mConnectionError\u001b[39;00m(e, request\u001b[38;5;241m=\u001b[39mrequest)\n\u001b[1;32m 702\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m ClosedPoolError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 703\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mConnectionError\u001b[39;00m(e, request\u001b[38;5;241m=\u001b[39mrequest)\n",
514
+ "\u001b[0;31mConnectionError\u001b[0m: HTTPConnectionPool(host='localhost', port=2020): Max retries exceeded with url: /api/analysis_traces/1 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x11a9bb4d0>: Failed to establish a new connection: [Errno 61] Connection refused'))"
515
+ ]
516
+ }
517
+ ],
518
+ "source": [
519
+ "import requests\n",
520
+ "import json\n",
521
+ "\n",
522
+ "trace_id = tracer.trace_id \n",
523
+ "port = 2020 # port no of the falsk server\n",
524
+ "response = requests.get(f\"http://localhost:{port}/api/analysis_traces/{trace_id}\")\n",
525
+ "\n",
526
+ "if response.status_code == 200:\n",
527
+ " trace_data = response.json()\n",
528
+ " print(json.dumps(trace_data, indent=2))\n",
529
+ "else:\n",
530
+ " print(f\"Error: {response.status_code}\")\n",
531
+ " print(response.text)"
532
+ ]
533
+ },
534
+ {
535
+ "cell_type": "code",
536
+ "execution_count": null,
537
+ "metadata": {},
538
+ "outputs": [],
539
+ "source": []
540
+ }
541
+ ],
542
+ "metadata": {
543
+ "kernelspec": {
544
+ "display_name": "Python 3",
545
+ "language": "python",
546
+ "name": "python3"
547
+ },
548
+ "language_info": {
549
+ "codemirror_mode": {
550
+ "name": "ipython",
551
+ "version": 3
552
+ },
553
+ "file_extension": ".py",
554
+ "mimetype": "text/x-python",
555
+ "name": "python",
556
+ "nbconvert_exporter": "python",
557
+ "pygments_lexer": "ipython3",
558
+ "version": "3.11.11"
559
+ }
560
+ },
561
+ "nbformat": 4,
562
+ "nbformat_minor": 2
563
+ }
@@ -0,0 +1,46 @@
1
+ import inspect
2
+ from functools import wraps
3
+
4
+ class TrackName:
5
+ def __init__(self):
6
+ self.files = set() # To store unique filenames
7
+
8
+ def trace_decorator(self, func):
9
+ @wraps(func)
10
+ def wrapper(*args, **kwargs):
11
+ file_name = self._get_file_name()
12
+ self.files.add(file_name)
13
+
14
+ return func(*args, **kwargs)
15
+ return wrapper
16
+
17
+ def _get_file_name(self):
18
+ # Check if running in a Jupyter notebook
19
+ try:
20
+ from IPython import get_ipython
21
+ if 'IPKernelApp' in get_ipython().config:
22
+ return self._get_notebook_name()
23
+ except Exception:
24
+ pass
25
+
26
+ # Default to the filename from the stack
27
+ frame = inspect.stack()[2]
28
+ return frame.filename
29
+
30
+ def _get_notebook_name(self):
31
+ # Attempt to get the notebook name
32
+ try:
33
+ import ipynbname
34
+ return ipynbname.name() # This will return the notebook name
35
+ except ImportError:
36
+ return "Notebook name retrieval requires ipynbname package"
37
+ except Exception as e:
38
+ return f"Error retrieving notebook name: {e}"
39
+
40
+
41
+ def get_unique_files(self):
42
+ return list(self.files)
43
+
44
+ def reset(self):
45
+ """Reset the file tracker by clearing all tracked files."""
46
+ self.files.clear()