ldbg 0.1.0__tar.gz

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.
ldbg-0.1.0/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+ tool_prompts.md
9
+ summarize_dict.py
10
+
11
+ # Virtual environments
12
+ .venv
@@ -0,0 +1 @@
1
+ 3.12
ldbg-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,117 @@
1
+ Metadata-Version: 2.4
2
+ Name: ldbg
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Author-email: Arthur Masson <arthur.masson@inria.fr>
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: openai>=1.107.3
8
+ Description-Content-Type: text/markdown
9
+
10
+ # llm-debug
11
+
12
+ ### A Minimal Python Library to debug with LLMs
13
+
14
+ Use natural-language prompts while debugging. Prompts are augmented with your current stack, variables, and source context.
15
+
16
+ DO NOT USE THIS LIBRARY
17
+
18
+ > “AI everywhere is rocket engines on a skateboard: a thrill that ends in wreckage. The planet pays in energy and emissions, and we pay in something subtler — the slow atrophy of our own intelligence, left idle while the machines do the heavy lifting.” ChatGPT
19
+
20
+ ## Features
21
+
22
+ - 🐍 Generate Python debug commands from natural-language instructions.
23
+ - 🔍 Context-aware: prompt auto-includes call stack, local/global variable previews, current function - source, and nearby code.
24
+ - ⚡ Works like an AI-augmented pdb: just ask what you want to inspect.
25
+ - 🤖 Supports OpenRouter
26
+
27
+ ## Installation
28
+
29
+ `pip install ldbg`
30
+
31
+ ## Quick Start
32
+
33
+ ### Example Session
34
+
35
+ ```python
36
+
37
+ >>> unknown_data = np.arange(9)
38
+ >>> example_dict = {"a": 1, "b": [1, 2, 3]}
39
+ >>> example_numbers = list(range(10))
40
+ >>> import ldbg
41
+ >>> ldbg.gc("describe unknown_data")
42
+ The model "gpt-5-mini-2025-08-07" says:
43
+
44
+ unknown_data is an numpy array which can be described with the following pandas code:
45
+
46
+ ```code block 1
47
+ pandas.DataFrame(unknown_data).describe()
48
+ ```
49
+
50
+ Note: you can use numpy.set_printoptions (or a library like numpyprint) to pretty print your array:
51
+
52
+ ```code block 2
53
+ with np.printoptions(precision=2, suppress=True, threshold=5):
54
+ unknown_data
55
+ ```
56
+
57
+ Would you like to execute the following code block:
58
+ pandas.DataFrame(unknown_data).describe()
59
+ (y/n)
60
+ ```
61
+
62
+ User enters y:
63
+ ```
64
+ 0
65
+ count 9.000000
66
+ mean 4.000000
67
+ std 2.738613
68
+ min 0.000000
69
+ 25% 2.000000
70
+ 50% 4.000000
71
+ 75% 6.000000
72
+ max 8.000000
73
+
74
+
75
+
76
+ Would you like to execute the following code block:
77
+ with np.printoptions(precision=2, suppress=True, threshold=5):
78
+ unknown_data
79
+ (y/n)
80
+ ```
81
+
82
+ User enters n and continues:
83
+
84
+ ```python
85
+ >>> ldbg.gc("plot example_numbers as a bar chart")
86
+ The model "gpt-5-mini-2025-08-07" says:
87
+
88
+ ```
89
+ import matplotlib.pyplot as plt
90
+ plt.bar(range(len(numbers)), numbers)
91
+ plt.show()
92
+ ```
93
+
94
+ Would you like to execute the following code block:
95
+ ...
96
+ ```
97
+
98
+ ### Example natural-language prompts
99
+
100
+ - "Describe my numpy arrays"
101
+ - "plot my_data['b'] as a histogram"
102
+ - "give me an example pandas dataframe about employees"
103
+ - "generate a 3x10x12 numpy array which will be used as an example image"
104
+ - "convert this Pillow image to grayscale"
105
+ - "open this 'image.ome.tiff' with bioio"
106
+
107
+ ## Configuration
108
+
109
+ By default, llm-debug uses the OpenAI client. So it reads the [OPENAI_API_KEY environment variable](https://platform.openai.com/docs/quickstart).
110
+
111
+ To use OpenRouter instead, define the `OPENROUTER_API_KEY` environment variable:
112
+
113
+ `export OPENROUTER_API_KEY="your_api_key_here"`
114
+
115
+ ## License
116
+
117
+ MIT License.
ldbg-0.1.0/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # llm-debug
2
+
3
+ ### A Minimal Python Library to debug with LLMs
4
+
5
+ Use natural-language prompts while debugging. Prompts are augmented with your current stack, variables, and source context.
6
+
7
+ DO NOT USE THIS LIBRARY
8
+
9
+ > “AI everywhere is rocket engines on a skateboard: a thrill that ends in wreckage. The planet pays in energy and emissions, and we pay in something subtler — the slow atrophy of our own intelligence, left idle while the machines do the heavy lifting.” ChatGPT
10
+
11
+ ## Features
12
+
13
+ - 🐍 Generate Python debug commands from natural-language instructions.
14
+ - 🔍 Context-aware: prompt auto-includes call stack, local/global variable previews, current function - source, and nearby code.
15
+ - ⚡ Works like an AI-augmented pdb: just ask what you want to inspect.
16
+ - 🤖 Supports OpenRouter
17
+
18
+ ## Installation
19
+
20
+ `pip install ldbg`
21
+
22
+ ## Quick Start
23
+
24
+ ### Example Session
25
+
26
+ ```python
27
+
28
+ >>> unknown_data = np.arange(9)
29
+ >>> example_dict = {"a": 1, "b": [1, 2, 3]}
30
+ >>> example_numbers = list(range(10))
31
+ >>> import ldbg
32
+ >>> ldbg.gc("describe unknown_data")
33
+ The model "gpt-5-mini-2025-08-07" says:
34
+
35
+ unknown_data is an numpy array which can be described with the following pandas code:
36
+
37
+ ```code block 1
38
+ pandas.DataFrame(unknown_data).describe()
39
+ ```
40
+
41
+ Note: you can use numpy.set_printoptions (or a library like numpyprint) to pretty print your array:
42
+
43
+ ```code block 2
44
+ with np.printoptions(precision=2, suppress=True, threshold=5):
45
+ unknown_data
46
+ ```
47
+
48
+ Would you like to execute the following code block:
49
+ pandas.DataFrame(unknown_data).describe()
50
+ (y/n)
51
+ ```
52
+
53
+ User enters y:
54
+ ```
55
+ 0
56
+ count 9.000000
57
+ mean 4.000000
58
+ std 2.738613
59
+ min 0.000000
60
+ 25% 2.000000
61
+ 50% 4.000000
62
+ 75% 6.000000
63
+ max 8.000000
64
+
65
+
66
+
67
+ Would you like to execute the following code block:
68
+ with np.printoptions(precision=2, suppress=True, threshold=5):
69
+ unknown_data
70
+ (y/n)
71
+ ```
72
+
73
+ User enters n and continues:
74
+
75
+ ```python
76
+ >>> ldbg.gc("plot example_numbers as a bar chart")
77
+ The model "gpt-5-mini-2025-08-07" says:
78
+
79
+ ```
80
+ import matplotlib.pyplot as plt
81
+ plt.bar(range(len(numbers)), numbers)
82
+ plt.show()
83
+ ```
84
+
85
+ Would you like to execute the following code block:
86
+ ...
87
+ ```
88
+
89
+ ### Example natural-language prompts
90
+
91
+ - "Describe my numpy arrays"
92
+ - "plot my_data['b'] as a histogram"
93
+ - "give me an example pandas dataframe about employees"
94
+ - "generate a 3x10x12 numpy array which will be used as an example image"
95
+ - "convert this Pillow image to grayscale"
96
+ - "open this 'image.ome.tiff' with bioio"
97
+
98
+ ## Configuration
99
+
100
+ By default, llm-debug uses the OpenAI client. So it reads the [OPENAI_API_KEY environment variable](https://platform.openai.com/docs/quickstart).
101
+
102
+ To use OpenRouter instead, define the `OPENROUTER_API_KEY` environment variable:
103
+
104
+ `export OPENROUTER_API_KEY="your_api_key_here"`
105
+
106
+ ## License
107
+
108
+ MIT License.
@@ -0,0 +1,23 @@
1
+ [project]
2
+ name = "ldbg"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Arthur Masson", email = "arthur.masson@inria.fr" }
8
+ ]
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "openai>=1.107.3",
12
+ ]
13
+
14
+ [build-system]
15
+ requires = ["hatchling"]
16
+ build-backend = "hatchling.build"
17
+
18
+ [dependency-groups]
19
+ dev = [
20
+ "ipython>=9.5.0",
21
+ "pytest>=8.4.2",
22
+ "ruff>=0.14.0",
23
+ ]
@@ -0,0 +1,3 @@
1
+ from .ldbg import generate_commands, gc
2
+
3
+ __all__ = ["generate_commands", "gc"]
@@ -0,0 +1,303 @@
1
+ import inspect
2
+ import re
3
+ import textwrap
4
+ import traceback
5
+ import linecache
6
+ import os
7
+ import pprint
8
+ from types import FrameType
9
+ from typing import cast
10
+
11
+ from openai import OpenAI
12
+
13
+ LENGTH_MAX = 10000
14
+ CODE_BLOCK_REGEX = r"```(?:[\w+-]*)\n(.*?)```"
15
+
16
+ if "OPENROUTER_API_KEY" in os.environ:
17
+ client = OpenAI(
18
+ base_url="https://openrouter.ai/api/v1",
19
+ api_key=os.environ["OPENROUTER_API_KEY"],
20
+ )
21
+ else:
22
+ client = OpenAI()
23
+
24
+
25
+ def extract_code_blocks(markdown_text: str):
26
+ pattern = re.compile(CODE_BLOCK_REGEX, re.DOTALL)
27
+ return pattern.findall(markdown_text)
28
+
29
+
30
+ def execute_code_block(code: str):
31
+ exec(code, {})
32
+
33
+
34
+ def execute_blocks(markdown_text: str | None) -> None:
35
+ """
36
+ Extract the code blocks in the markdown and ask user if he wants to execute them
37
+ """
38
+ if markdown_text is None:
39
+ return
40
+ blocks = extract_code_blocks(markdown_text)
41
+ for block in blocks:
42
+ print("Would you like to execute the following code block:")
43
+ print(textwrap.indent(block, " "))
44
+ confirm = input("(y/n)").lower()
45
+ if confirm.lower() in ["yes", "y"]:
46
+ execute_code_block(block)
47
+
48
+
49
+ def generate_commands(
50
+ prompt: str,
51
+ frame=None,
52
+ model="gpt-5-mini-2025-08-07",
53
+ print_prompt=True,
54
+ length_max=LENGTH_MAX,
55
+ context="",
56
+ ):
57
+ """
58
+ Generate Python debug help based on natural-language instructions.
59
+
60
+ Includes:
61
+ - Call stack / traceback
62
+ - Current function’s source
63
+ - Surrounding source lines (like ipdb 'll')
64
+
65
+ Example:
66
+
67
+ >>> import ldbg
68
+ >>> ldbg.generate_commands("describe unknown_data")
69
+ The model "gpt-5-mini-2025-08-07" answered:
70
+
71
+ unknown_data is an numpy array which can be described with the following pandas code:
72
+
73
+ ```
74
+ pandas.DataFrame(unknown_data).describe()
75
+ ```
76
+
77
+ Note: you can use numpy.set_printoptions (or a library like numpyprint) to pretty print your array:
78
+
79
+ ```
80
+ with np.printoptions(precision=2, suppress=True, threshold=5):
81
+ unknown_data
82
+ ```
83
+
84
+ Would you like to execute the following code block:
85
+ pandas.DataFrame(unknown_data).describe()
86
+ (y/n)?
87
+
88
+
89
+ <<< user enters y
90
+ 0
91
+ count 9.000000
92
+ mean 4.000000
93
+ std 2.738613
94
+ min 0.000000
95
+ 25% 2.000000
96
+ 50% 4.000000
97
+ 75% 6.000000
98
+ max 8.000000
99
+
100
+
101
+ Would you like to execute the following code block:
102
+ with np.printoptions(precision=2, suppress=True, threshold=5):
103
+ unknown_data
104
+ (y/n)?
105
+
106
+ <<< user enters n
107
+ """
108
+ if frame is None:
109
+ frame = cast(FrameType, inspect.currentframe().f_back) # type: ignore
110
+
111
+ # Locals & globals preview
112
+ locals_preview = pprint.pformat(frame.f_locals)[
113
+ :length_max
114
+ ] # {k: type(v).__name__ for k, v in frame.f_locals.items()}
115
+ globals_preview = pprint.pformat(frame.f_globals)[
116
+ :length_max
117
+ ] # {k: type(v).__name__ for k, v in frame.f_globals.items()}
118
+
119
+ # Traceback / call stack
120
+ stack_summary = traceback.format_stack(frame)
121
+ stack_text = "".join(stack_summary[-15:]) # limit to avoid overload
122
+
123
+ # Current function source
124
+ try:
125
+ source_lines, start_line = inspect.getsourcelines(frame)
126
+ func_source = "".join(source_lines)
127
+ except (OSError, TypeError):
128
+ func_source = "<source unavailable>"
129
+
130
+ # Context like ipdb 'll'
131
+ filename = frame.f_code.co_filename
132
+ lineno = frame.f_lineno
133
+ start_context = max(lineno - 10, 1)
134
+ context_lines = []
135
+ for i in range(start_context, lineno + 10):
136
+ line = linecache.getline(filename, i)
137
+ if line:
138
+ context_lines.append(f"{i:4d}: {line}")
139
+ context_text = "".join(context_lines)
140
+
141
+ # ldbg.generate_commands({prompt}, model={model}, code_only={code_only}, print_prompt={print_prompt}, print_answer={print_answer}, length_max={length_max})
142
+ context = textwrap.dedent(f"""
143
+ You are a Python debugging assistant.
144
+ The user is paused inside a Python script.
145
+
146
+ The user just ran `import ldbg; ldbg.gc({prompt}, model={model})` to ask you some help (gc stands for generate commands).
147
+
148
+ Local variables and their types (`locals = pprint.pformat(inspect.currentframe().f_locals)[:length_max]`):
149
+ {locals_preview}
150
+
151
+ Global variables and their types (`globals = pprint.pformat(inspect.currentframe().f_globals)[:length_max]`):
152
+ {globals_preview}
153
+
154
+ Current call stack (traceback):
155
+ {stack_text}
156
+
157
+ Current function source:
158
+ {func_source}
159
+
160
+ Nearby code (like ipdb 'll'):
161
+ {context_text}
162
+
163
+ Additional context:
164
+ {context}
165
+
166
+ If you need more context, a more detailed view of the local variables or the content of a source file,
167
+ tell the user the commands he should run to print the details you need.
168
+
169
+ For example, if you need to know more details about the local variables, tell him:
170
+
171
+ I need more context to help you.
172
+ Could you execute the following commands to give me more context? They will provide the details I need to help you.
173
+
174
+ ```
175
+ import inspect
176
+ frame = inspect.currentframe()
177
+ # Get frame.f_locals with a depth of 2
178
+ local_variables = pprint.pformat(frame.f_locals, depth=2)
179
+ ```
180
+
181
+ Then you can ask me again:
182
+ ```
183
+ ldbg.gc({prompt}, model={model}, context = f"local variables are: {{local_variables:.50000}}")
184
+ ```
185
+
186
+ Another example, if you need to know the content of some source files:
187
+
188
+ I need more context to help you.
189
+ Could you execute the following commands to give me more context? They will provide the details I need to help you.
190
+
191
+ ```
192
+ # Get the content of important.py
193
+ import_file_path = list(Path().glob('**/important.py'))[0]
194
+
195
+ with open(import_file_path) as f:
196
+ important_content = f.read()
197
+
198
+ # Find the lines surrounding the class ImportantClass in very_large_script.py
199
+ search = "class ImportantClass"
200
+ with open('path/to/important/very_large_script.py') as f:
201
+ lines = f.readlines()
202
+
203
+ # Find the 0-based index of the first matching line
204
+ idx = next(i for i, line in enumerate(lines) if search in line)
205
+
206
+ # Calculate start and end indices
207
+ start = max(0, idx - 10)
208
+ end = min(len(lines), idx + 10 + 1)
209
+
210
+ # Get the surrounding lines
211
+ script_content = []
212
+ for i, line in enumerate(lines[start:end]):
213
+ script_content.append(f"{{start + i + 1:04d}}: {{line.rstrip()}}")
214
+ ```
215
+
216
+ Then you can ask me again:
217
+ ```
218
+ ldbg.gc({prompt}, model={model}, context=f"important.py: {{important_content:.50000}}, very_large_script.py (lines {{start}} to {{end}}): {{script_content:.50000}}")
219
+ ```
220
+
221
+ You can also ask for help in multiple steps:
222
+
223
+ Could you execute the following commands to give me more context?
224
+ This will tell me all the source files in the current working directory.
225
+
226
+ ```
227
+ import pathlib
228
+ EXCLUDED = {{".venv", ".pixi"}}
229
+ python_files = [str(p) for p in pathlib.Path('.').rglob('*.py') if not any(part in EXCLUDED for part in p.parts)]
230
+ ```
231
+
232
+ Then you can ask me again:
233
+ ```
234
+ ldbg.gc({prompt}, model={model}, context=f"the python files are: {{python_files:.50000}}")
235
+ ```
236
+
237
+ And then I will know more about the project, and I might ask you to execute more commands
238
+ (for example to read some important files) to get all the context I need.
239
+
240
+ The length of your context window is limited and you perform better with focused questions and context.
241
+ Thus, when you ask the user to execute commands and send you more information,
242
+ always make sure to be precise so that you get a response of reasonable length.
243
+ For example, if you need some information in a huge file,
244
+ provide commands to extract exactly what you need instead of reading the entire file.
245
+ If you need a specific value deep in the locals values, get `frame.f_locals["deep_object"].deep_dict["deep_attribute"]["sub_attribute"]["etc"]`
246
+ instead of getting the entire locals with a large depth as in `local_variables = pprint.pformat(frame.f_locals, depth=10)`.
247
+
248
+ Cap the length of the responses to avoid reaching the maximum prompt length (which would result in a failure).
249
+
250
+ The user is a developer, you can also ask him details about the context in natural language.
251
+
252
+ If you have all the context you need, just provide a useful answer.
253
+ For example, if the user asks "describe unknown_data", you could answer:
254
+
255
+ `unknown_data` is an numpy array which can be described with the following pandas code:
256
+
257
+ ```
258
+ pandas.DataFrame(unknown_data).describe()
259
+ ```
260
+
261
+ You could also use numpy.set_printoptions (or a library like numpyprint) to pretty print your array:
262
+
263
+ ```
264
+ with np.printoptions(precision=2, suppress=True, threshold=5):
265
+ unknown_data
266
+ ```
267
+
268
+ Always put the code to execute in triple backticks code blocks.
269
+ Provide relatively short and concise answers.
270
+ """)
271
+
272
+ if print_prompt:
273
+ print("System prompt:")
274
+ print(context)
275
+ print("\nUser prompt:")
276
+ print(prompt)
277
+
278
+ resp = client.chat.completions.create(
279
+ model=model,
280
+ messages=[
281
+ {"role": "system", "content": context},
282
+ {"role": "user", "content": prompt},
283
+ ],
284
+ temperature=1,
285
+ )
286
+
287
+ response = resp.choices[0].message.content
288
+
289
+ if print_prompt:
290
+ print("\n\n\n")
291
+
292
+ if response is None:
293
+ return
294
+
295
+ print(f"Model {model} says:")
296
+ print(textwrap.indent(response, " "))
297
+
298
+ execute_blocks(response)
299
+
300
+ return
301
+
302
+
303
+ gc = generate_commands
File without changes
@@ -0,0 +1,140 @@
1
+ import inspect
2
+ import builtins
3
+ import types
4
+
5
+ import ldbg.ldbg as ldbg
6
+
7
+
8
+ def test_extract_code_blocks_single_block():
9
+ md = "Here is some text\n```python\nprint('hello')\n```\nmore text"
10
+ blocks = ldbg.extract_code_blocks(md)
11
+ assert blocks == ["print('hello')\n"]
12
+
13
+
14
+ def test_extract_code_blocks_multiple_blocks():
15
+ md = "```\na=1\n```\ntext\n```py\nb=2\n```"
16
+ blocks = ldbg.extract_code_blocks(md)
17
+ assert blocks == ["a=1\n", "b=2\n"]
18
+
19
+
20
+ def test_execute_code_block_prints_output(capsys):
21
+ # execute_code_block uses exec(..., {}) so it runs in an empty namespace.
22
+ ldbg.execute_code_block("print('hi from code block')")
23
+ captured = capsys.readouterr()
24
+ assert "hi from code block" in captured.out
25
+
26
+
27
+ def test_execute_blocks_none_does_nothing(capsys):
28
+ # Should not raise and should not print anything
29
+ ldbg.execute_blocks(None)
30
+ captured = capsys.readouterr()
31
+ assert captured.out == ""
32
+
33
+
34
+ def test_execute_blocks_user_confirms_exec(monkeypatch, capsys):
35
+ # Provide markdown with a single code block.
36
+ md = "Some text\n```\nprint('ran')\n```\n"
37
+ # Simulate user input 'y'
38
+ monkeypatch.setattr(builtins, "input", lambda prompt="": "y")
39
+ executed = {"called": False, "code": None}
40
+
41
+ def fake_exec_block(code):
42
+ executed["called"] = True
43
+ executed["code"] = code
44
+
45
+ monkeypatch.setattr(ldbg, "execute_code_block", fake_exec_block)
46
+
47
+ ldbg.execute_blocks(md)
48
+
49
+ captured = capsys.readouterr()
50
+ # We expect to have been prompted and the code executed
51
+ assert "Would you like to execute the following code block:" in captured.out
52
+ assert executed["called"] is True
53
+ assert "print('ran')" in executed["code"]
54
+
55
+
56
+ def test_execute_blocks_user_declines(monkeypatch, capsys):
57
+ md = "```\nprint('should_not_run')\n```"
58
+ # Simulate user input 'n'
59
+ monkeypatch.setattr(builtins, "input", lambda prompt="": "n")
60
+ executed = {"called": False}
61
+
62
+ monkeypatch.setattr(
63
+ ldbg, "execute_code_block", lambda code: executed.update(called=True)
64
+ )
65
+
66
+ ldbg.execute_blocks(md)
67
+ captured = capsys.readouterr()
68
+ assert "Would you like to execute the following code block:" in captured.out
69
+ assert executed.get("called") is not True
70
+
71
+
72
+ def test_generate_commands_calls_api_and_forwards_response(monkeypatch, capsys):
73
+ """
74
+ Ensure generate_commands:
75
+ - prints the system/user prompts when print_prompt=True
76
+ - calls the client.chat.completions.create API
77
+ - prints the model response and passes it to execute_blocks
78
+ """
79
+ # Create a fake response text that contains a code block
80
+ fake_response_text = (
81
+ "Here is a suggestion:\n\n```python\nprint('from model')\n```\n"
82
+ "And a closing line."
83
+ )
84
+
85
+ # Spy object to verify execute_blocks received the model response
86
+ called = {"create_called": False, "passed_response": None}
87
+
88
+ def fake_create(*args, **kwargs):
89
+ called["create_called"] = True
90
+ # Build an object with the expected shape: .choices[0].message.content
91
+ msg = types.SimpleNamespace(content=fake_response_text)
92
+ choice = types.SimpleNamespace(message=msg)
93
+ return types.SimpleNamespace(choices=[choice])
94
+
95
+ # Patch the chain client.chat.completions.create
96
+ monkeypatch.setattr(ldbg.client.chat.completions, "create", fake_create)
97
+
98
+ # Patch execute_blocks to capture what is passed
99
+ def fake_execute_blocks(resp_text):
100
+ called["passed_response"] = resp_text
101
+
102
+ monkeypatch.setattr(ldbg, "execute_blocks", fake_execute_blocks)
103
+
104
+ # Call generate_commands from a real frame (the test's current frame) to let it build context
105
+ frame = inspect.currentframe()
106
+ # Run function
107
+ ldbg.generate_commands("describe unknown_data", frame=frame, print_prompt=True)
108
+
109
+ captured = capsys.readouterr()
110
+ # Confirm we printed the System prompt and User prompt
111
+ assert "System prompt:" in captured.out
112
+ assert "User prompt:" in captured.out
113
+
114
+ # Confirm the API stub was called and execute_blocks got the model response
115
+ assert called["create_called"] is True
116
+ assert called["passed_response"] == fake_response_text
117
+
118
+
119
+ def test_generate_commands_handles_none_response(monkeypatch, capsys):
120
+ """
121
+ If the API returns a response object with None content, generate_commands should return gracefully.
122
+ """
123
+
124
+ def fake_create_none(*args, **kwargs):
125
+ msg = types.SimpleNamespace(content=None)
126
+ choice = types.SimpleNamespace(message=msg)
127
+ return types.SimpleNamespace(choices=[choice])
128
+
129
+ monkeypatch.setattr(ldbg.client.chat.completions, "create", fake_create_none)
130
+ # Patch execute_blocks to ensure it would not be called when response is None
131
+ monkeypatch.setattr(
132
+ ldbg,
133
+ "execute_blocks",
134
+ lambda t: (_ for _ in ()).throw(AssertionError("should not be called")),
135
+ )
136
+
137
+ # Call - should not raise
138
+ ldbg.generate_commands(
139
+ "any prompt", frame=inspect.currentframe(), print_prompt=False
140
+ )
ldbg-0.1.0/uv.lock ADDED
@@ -0,0 +1,535 @@
1
+ version = 1
2
+ revision = 3
3
+ requires-python = ">=3.12"
4
+
5
+ [[package]]
6
+ name = "annotated-types"
7
+ version = "0.7.0"
8
+ source = { registry = "https://pypi.org/simple" }
9
+ sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
10
+ wheels = [
11
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
12
+ ]
13
+
14
+ [[package]]
15
+ name = "anyio"
16
+ version = "4.11.0"
17
+ source = { registry = "https://pypi.org/simple" }
18
+ dependencies = [
19
+ { name = "idna" },
20
+ { name = "sniffio" },
21
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
22
+ ]
23
+ sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" }
24
+ wheels = [
25
+ { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" },
26
+ ]
27
+
28
+ [[package]]
29
+ name = "asttokens"
30
+ version = "3.0.0"
31
+ source = { registry = "https://pypi.org/simple" }
32
+ sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" }
33
+ wheels = [
34
+ { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" },
35
+ ]
36
+
37
+ [[package]]
38
+ name = "certifi"
39
+ version = "2025.10.5"
40
+ source = { registry = "https://pypi.org/simple" }
41
+ sdist = { url = "https://files.pythonhosted.org/packages/4c/5b/b6ce21586237c77ce67d01dc5507039d444b630dd76611bbca2d8e5dcd91/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", size = 164519, upload-time = "2025-10-05T04:12:15.808Z" }
42
+ wheels = [
43
+ { url = "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", size = 163286, upload-time = "2025-10-05T04:12:14.03Z" },
44
+ ]
45
+
46
+ [[package]]
47
+ name = "colorama"
48
+ version = "0.4.6"
49
+ source = { registry = "https://pypi.org/simple" }
50
+ sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
51
+ wheels = [
52
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
53
+ ]
54
+
55
+ [[package]]
56
+ name = "decorator"
57
+ version = "5.2.1"
58
+ source = { registry = "https://pypi.org/simple" }
59
+ sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" }
60
+ wheels = [
61
+ { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" },
62
+ ]
63
+
64
+ [[package]]
65
+ name = "distro"
66
+ version = "1.9.0"
67
+ source = { registry = "https://pypi.org/simple" }
68
+ sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" }
69
+ wheels = [
70
+ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" },
71
+ ]
72
+
73
+ [[package]]
74
+ name = "executing"
75
+ version = "2.2.1"
76
+ source = { registry = "https://pypi.org/simple" }
77
+ sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" }
78
+ wheels = [
79
+ { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" },
80
+ ]
81
+
82
+ [[package]]
83
+ name = "h11"
84
+ version = "0.16.0"
85
+ source = { registry = "https://pypi.org/simple" }
86
+ sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
87
+ wheels = [
88
+ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
89
+ ]
90
+
91
+ [[package]]
92
+ name = "httpcore"
93
+ version = "1.0.9"
94
+ source = { registry = "https://pypi.org/simple" }
95
+ dependencies = [
96
+ { name = "certifi" },
97
+ { name = "h11" },
98
+ ]
99
+ sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
100
+ wheels = [
101
+ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
102
+ ]
103
+
104
+ [[package]]
105
+ name = "httpx"
106
+ version = "0.28.1"
107
+ source = { registry = "https://pypi.org/simple" }
108
+ dependencies = [
109
+ { name = "anyio" },
110
+ { name = "certifi" },
111
+ { name = "httpcore" },
112
+ { name = "idna" },
113
+ ]
114
+ sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
115
+ wheels = [
116
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
117
+ ]
118
+
119
+ [[package]]
120
+ name = "idna"
121
+ version = "3.10"
122
+ source = { registry = "https://pypi.org/simple" }
123
+ sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
124
+ wheels = [
125
+ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
126
+ ]
127
+
128
+ [[package]]
129
+ name = "iniconfig"
130
+ version = "2.1.0"
131
+ source = { registry = "https://pypi.org/simple" }
132
+ sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" }
133
+ wheels = [
134
+ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" },
135
+ ]
136
+
137
+ [[package]]
138
+ name = "ipython"
139
+ version = "9.6.0"
140
+ source = { registry = "https://pypi.org/simple" }
141
+ dependencies = [
142
+ { name = "colorama", marker = "sys_platform == 'win32'" },
143
+ { name = "decorator" },
144
+ { name = "ipython-pygments-lexers" },
145
+ { name = "jedi" },
146
+ { name = "matplotlib-inline" },
147
+ { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
148
+ { name = "prompt-toolkit" },
149
+ { name = "pygments" },
150
+ { name = "stack-data" },
151
+ { name = "traitlets" },
152
+ ]
153
+ sdist = { url = "https://files.pythonhosted.org/packages/2a/34/29b18c62e39ee2f7a6a3bba7efd952729d8aadd45ca17efc34453b717665/ipython-9.6.0.tar.gz", hash = "sha256:5603d6d5d356378be5043e69441a072b50a5b33b4503428c77b04cb8ce7bc731", size = 4396932, upload-time = "2025-09-29T10:55:53.948Z" }
154
+ wheels = [
155
+ { url = "https://files.pythonhosted.org/packages/48/c5/d5e07995077e48220269c28a221e168c91123ad5ceee44d548f54a057fc0/ipython-9.6.0-py3-none-any.whl", hash = "sha256:5f77efafc886d2f023442479b8149e7d86547ad0a979e9da9f045d252f648196", size = 616170, upload-time = "2025-09-29T10:55:47.676Z" },
156
+ ]
157
+
158
+ [[package]]
159
+ name = "ipython-pygments-lexers"
160
+ version = "1.1.1"
161
+ source = { registry = "https://pypi.org/simple" }
162
+ dependencies = [
163
+ { name = "pygments" },
164
+ ]
165
+ sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" }
166
+ wheels = [
167
+ { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" },
168
+ ]
169
+
170
+ [[package]]
171
+ name = "jedi"
172
+ version = "0.19.2"
173
+ source = { registry = "https://pypi.org/simple" }
174
+ dependencies = [
175
+ { name = "parso" },
176
+ ]
177
+ sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" }
178
+ wheels = [
179
+ { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" },
180
+ ]
181
+
182
+ [[package]]
183
+ name = "jiter"
184
+ version = "0.11.0"
185
+ source = { registry = "https://pypi.org/simple" }
186
+ sdist = { url = "https://files.pythonhosted.org/packages/9d/c0/a3bb4cc13aced219dd18191ea66e874266bd8aa7b96744e495e1c733aa2d/jiter-0.11.0.tar.gz", hash = "sha256:1d9637eaf8c1d6a63d6562f2a6e5ab3af946c66037eb1b894e8fad75422266e4", size = 167094, upload-time = "2025-09-15T09:20:38.212Z" }
187
+ wheels = [
188
+ { url = "https://files.pythonhosted.org/packages/ba/b5/3009b112b8f673e568ef79af9863d8309a15f0a8cdcc06ed6092051f377e/jiter-0.11.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:2fb7b377688cc3850bbe5c192a6bd493562a0bc50cbc8b047316428fbae00ada", size = 305510, upload-time = "2025-09-15T09:19:25.893Z" },
189
+ { url = "https://files.pythonhosted.org/packages/fe/82/15514244e03b9e71e086bbe2a6de3e4616b48f07d5f834200c873956fb8c/jiter-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a1b7cbe3f25bd0d8abb468ba4302a5d45617ee61b2a7a638f63fee1dc086be99", size = 316521, upload-time = "2025-09-15T09:19:27.525Z" },
190
+ { url = "https://files.pythonhosted.org/packages/92/94/7a2e905f40ad2d6d660e00b68d818f9e29fb87ffe82774f06191e93cbe4a/jiter-0.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0a7f0ec81d5b7588c5cade1eb1925b91436ae6726dc2df2348524aeabad5de6", size = 338214, upload-time = "2025-09-15T09:19:28.727Z" },
191
+ { url = "https://files.pythonhosted.org/packages/a8/9c/5791ed5bdc76f12110158d3316a7a3ec0b1413d018b41c5ed399549d3ad5/jiter-0.11.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07630bb46ea2a6b9c6ed986c6e17e35b26148cce2c535454b26ee3f0e8dcaba1", size = 361280, upload-time = "2025-09-15T09:19:30.013Z" },
192
+ { url = "https://files.pythonhosted.org/packages/d4/7f/b7d82d77ff0d2cb06424141000176b53a9e6b16a1125525bb51ea4990c2e/jiter-0.11.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7764f27d28cd4a9cbc61704dfcd80c903ce3aad106a37902d3270cd6673d17f4", size = 487895, upload-time = "2025-09-15T09:19:31.424Z" },
193
+ { url = "https://files.pythonhosted.org/packages/42/44/10a1475d46f1fc1fd5cc2e82c58e7bca0ce5852208e0fa5df2f949353321/jiter-0.11.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d4a6c4a737d486f77f842aeb22807edecb4a9417e6700c7b981e16d34ba7c72", size = 378421, upload-time = "2025-09-15T09:19:32.746Z" },
194
+ { url = "https://files.pythonhosted.org/packages/9a/5f/0dc34563d8164d31d07bc09d141d3da08157a68dcd1f9b886fa4e917805b/jiter-0.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf408d2a0abd919b60de8c2e7bc5eeab72d4dafd18784152acc7c9adc3291591", size = 347932, upload-time = "2025-09-15T09:19:34.612Z" },
195
+ { url = "https://files.pythonhosted.org/packages/f7/de/b68f32a4fcb7b4a682b37c73a0e5dae32180140cd1caf11aef6ad40ddbf2/jiter-0.11.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cdef53eda7d18e799625023e1e250dbc18fbc275153039b873ec74d7e8883e09", size = 386959, upload-time = "2025-09-15T09:19:35.994Z" },
196
+ { url = "https://files.pythonhosted.org/packages/76/0a/c08c92e713b6e28972a846a81ce374883dac2f78ec6f39a0dad9f2339c3a/jiter-0.11.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:53933a38ef7b551dd9c7f1064f9d7bb235bb3168d0fa5f14f0798d1b7ea0d9c5", size = 517187, upload-time = "2025-09-15T09:19:37.426Z" },
197
+ { url = "https://files.pythonhosted.org/packages/89/b5/4a283bec43b15aad54fcae18d951f06a2ec3f78db5708d3b59a48e9c3fbd/jiter-0.11.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:11840d2324c9ab5162fc1abba23bc922124fedcff0d7b7f85fffa291e2f69206", size = 509461, upload-time = "2025-09-15T09:19:38.761Z" },
198
+ { url = "https://files.pythonhosted.org/packages/34/a5/f8bad793010534ea73c985caaeef8cc22dfb1fedb15220ecdf15c623c07a/jiter-0.11.0-cp312-cp312-win32.whl", hash = "sha256:4f01a744d24a5f2bb4a11657a1b27b61dc038ae2e674621a74020406e08f749b", size = 206664, upload-time = "2025-09-15T09:19:40.096Z" },
199
+ { url = "https://files.pythonhosted.org/packages/ed/42/5823ec2b1469395a160b4bf5f14326b4a098f3b6898fbd327366789fa5d3/jiter-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:29fff31190ab3a26de026da2f187814f4b9c6695361e20a9ac2123e4d4378a4c", size = 203520, upload-time = "2025-09-15T09:19:41.798Z" },
200
+ { url = "https://files.pythonhosted.org/packages/97/c4/d530e514d0f4f29b2b68145e7b389cbc7cac7f9c8c23df43b04d3d10fa3e/jiter-0.11.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:4441a91b80a80249f9a6452c14b2c24708f139f64de959943dfeaa6cb915e8eb", size = 305021, upload-time = "2025-09-15T09:19:43.523Z" },
201
+ { url = "https://files.pythonhosted.org/packages/7a/77/796a19c567c5734cbfc736a6f987affc0d5f240af8e12063c0fb93990ffa/jiter-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ff85fc6d2a431251ad82dbd1ea953affb5a60376b62e7d6809c5cd058bb39471", size = 314384, upload-time = "2025-09-15T09:19:44.849Z" },
202
+ { url = "https://files.pythonhosted.org/packages/14/9c/824334de0b037b91b6f3fa9fe5a191c83977c7ec4abe17795d3cb6d174cf/jiter-0.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5e86126d64706fd28dfc46f910d496923c6f95b395138c02d0e252947f452bd", size = 337389, upload-time = "2025-09-15T09:19:46.094Z" },
203
+ { url = "https://files.pythonhosted.org/packages/a2/95/ed4feab69e6cf9b2176ea29d4ef9d01a01db210a3a2c8a31a44ecdc68c38/jiter-0.11.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ad8bd82165961867a10f52010590ce0b7a8c53da5ddd8bbb62fef68c181b921", size = 360519, upload-time = "2025-09-15T09:19:47.494Z" },
204
+ { url = "https://files.pythonhosted.org/packages/b5/0c/2ad00f38d3e583caba3909d95b7da1c3a7cd82c0aa81ff4317a8016fb581/jiter-0.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b42c2cd74273455ce439fd9528db0c6e84b5623cb74572305bdd9f2f2961d3df", size = 487198, upload-time = "2025-09-15T09:19:49.116Z" },
205
+ { url = "https://files.pythonhosted.org/packages/ea/8b/919b64cf3499b79bdfba6036da7b0cac5d62d5c75a28fb45bad7819e22f0/jiter-0.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0062dab98172dd0599fcdbf90214d0dcde070b1ff38a00cc1b90e111f071982", size = 377835, upload-time = "2025-09-15T09:19:50.468Z" },
206
+ { url = "https://files.pythonhosted.org/packages/29/7f/8ebe15b6e0a8026b0d286c083b553779b4dd63db35b43a3f171b544de91d/jiter-0.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb948402821bc76d1f6ef0f9e19b816f9b09f8577844ba7140f0b6afe994bc64", size = 347655, upload-time = "2025-09-15T09:19:51.726Z" },
207
+ { url = "https://files.pythonhosted.org/packages/8e/64/332127cef7e94ac75719dda07b9a472af6158ba819088d87f17f3226a769/jiter-0.11.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:25a5b1110cca7329fd0daf5060faa1234be5c11e988948e4f1a1923b6a457fe1", size = 386135, upload-time = "2025-09-15T09:19:53.075Z" },
208
+ { url = "https://files.pythonhosted.org/packages/20/c8/557b63527442f84c14774159948262a9d4fabb0d61166f11568f22fc60d2/jiter-0.11.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:bf11807e802a214daf6c485037778843fadd3e2ec29377ae17e0706ec1a25758", size = 516063, upload-time = "2025-09-15T09:19:54.447Z" },
209
+ { url = "https://files.pythonhosted.org/packages/86/13/4164c819df4a43cdc8047f9a42880f0ceef5afeb22e8b9675c0528ebdccd/jiter-0.11.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:dbb57da40631c267861dd0090461222060960012d70fd6e4c799b0f62d0ba166", size = 508139, upload-time = "2025-09-15T09:19:55.764Z" },
210
+ { url = "https://files.pythonhosted.org/packages/fa/70/6e06929b401b331d41ddb4afb9f91cd1168218e3371972f0afa51c9f3c31/jiter-0.11.0-cp313-cp313-win32.whl", hash = "sha256:8e36924dad32c48d3c5e188d169e71dc6e84d6cb8dedefea089de5739d1d2f80", size = 206369, upload-time = "2025-09-15T09:19:57.048Z" },
211
+ { url = "https://files.pythonhosted.org/packages/f4/0d/8185b8e15de6dce24f6afae63380e16377dd75686d56007baa4f29723ea1/jiter-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:452d13e4fd59698408087235259cebe67d9d49173b4dacb3e8d35ce4acf385d6", size = 202538, upload-time = "2025-09-15T09:19:58.35Z" },
212
+ { url = "https://files.pythonhosted.org/packages/13/3a/d61707803260d59520721fa326babfae25e9573a88d8b7b9cb54c5423a59/jiter-0.11.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:089f9df9f69532d1339e83142438668f52c97cd22ee2d1195551c2b1a9e6cf33", size = 313737, upload-time = "2025-09-15T09:19:59.638Z" },
213
+ { url = "https://files.pythonhosted.org/packages/cd/cc/c9f0eec5d00f2a1da89f6bdfac12b8afdf8d5ad974184863c75060026457/jiter-0.11.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29ed1fe69a8c69bf0f2a962d8d706c7b89b50f1332cd6b9fbda014f60bd03a03", size = 346183, upload-time = "2025-09-15T09:20:01.442Z" },
214
+ { url = "https://files.pythonhosted.org/packages/a6/87/fc632776344e7aabbab05a95a0075476f418c5d29ab0f2eec672b7a1f0ac/jiter-0.11.0-cp313-cp313t-win_amd64.whl", hash = "sha256:a4d71d7ea6ea8786291423fe209acf6f8d398a0759d03e7f24094acb8ab686ba", size = 204225, upload-time = "2025-09-15T09:20:03.102Z" },
215
+ { url = "https://files.pythonhosted.org/packages/ee/3b/e7f45be7d3969bdf2e3cd4b816a7a1d272507cd0edd2d6dc4b07514f2d9a/jiter-0.11.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9a6dff27eca70930bdbe4cbb7c1a4ba8526e13b63dc808c0670083d2d51a4a72", size = 304414, upload-time = "2025-09-15T09:20:04.357Z" },
216
+ { url = "https://files.pythonhosted.org/packages/06/32/13e8e0d152631fcc1907ceb4943711471be70496d14888ec6e92034e2caf/jiter-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ae2a7593a62132c7d4c2abbee80bbbb94fdc6d157e2c6cc966250c564ef774", size = 314223, upload-time = "2025-09-15T09:20:05.631Z" },
217
+ { url = "https://files.pythonhosted.org/packages/0c/7e/abedd5b5a20ca083f778d96bba0d2366567fcecb0e6e34ff42640d5d7a18/jiter-0.11.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b13a431dba4b059e9e43019d3022346d009baf5066c24dcdea321a303cde9f0", size = 337306, upload-time = "2025-09-15T09:20:06.917Z" },
218
+ { url = "https://files.pythonhosted.org/packages/ac/e2/30d59bdc1204c86aa975ec72c48c482fee6633120ee9c3ab755e4dfefea8/jiter-0.11.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:af62e84ca3889604ebb645df3b0a3f3bcf6b92babbff642bd214616f57abb93a", size = 360565, upload-time = "2025-09-15T09:20:08.283Z" },
219
+ { url = "https://files.pythonhosted.org/packages/fe/88/567288e0d2ed9fa8f7a3b425fdaf2cb82b998633c24fe0d98f5417321aa8/jiter-0.11.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6f3b32bb723246e6b351aecace52aba78adb8eeb4b2391630322dc30ff6c773", size = 486465, upload-time = "2025-09-15T09:20:09.613Z" },
220
+ { url = "https://files.pythonhosted.org/packages/18/6e/7b72d09273214cadd15970e91dd5ed9634bee605176107db21e1e4205eb1/jiter-0.11.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:adcab442f4a099a358a7f562eaa54ed6456fb866e922c6545a717be51dbed7d7", size = 377581, upload-time = "2025-09-15T09:20:10.884Z" },
221
+ { url = "https://files.pythonhosted.org/packages/58/52/4db456319f9d14deed325f70102577492e9d7e87cf7097bda9769a1fcacb/jiter-0.11.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9967c2ab338ee2b2c0102fd379ec2693c496abf71ffd47e4d791d1f593b68e2", size = 347102, upload-time = "2025-09-15T09:20:12.175Z" },
222
+ { url = "https://files.pythonhosted.org/packages/ce/b4/433d5703c38b26083aec7a733eb5be96f9c6085d0e270a87ca6482cbf049/jiter-0.11.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e7d0bed3b187af8b47a981d9742ddfc1d9b252a7235471ad6078e7e4e5fe75c2", size = 386477, upload-time = "2025-09-15T09:20:13.428Z" },
223
+ { url = "https://files.pythonhosted.org/packages/c8/7a/a60bfd9c55b55b07c5c441c5085f06420b6d493ce9db28d069cc5b45d9f3/jiter-0.11.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:f6fe0283e903ebc55f1a6cc569b8c1f3bf4abd026fed85e3ff8598a9e6f982f0", size = 516004, upload-time = "2025-09-15T09:20:14.848Z" },
224
+ { url = "https://files.pythonhosted.org/packages/2e/46/f8363e5ecc179b4ed0ca6cb0a6d3bfc266078578c71ff30642ea2ce2f203/jiter-0.11.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:4ee5821e3d66606b29ae5b497230b304f1376f38137d69e35f8d2bd5f310ff73", size = 507855, upload-time = "2025-09-15T09:20:16.176Z" },
225
+ { url = "https://files.pythonhosted.org/packages/90/33/396083357d51d7ff0f9805852c288af47480d30dd31d8abc74909b020761/jiter-0.11.0-cp314-cp314-win32.whl", hash = "sha256:c2d13ba7567ca8799f17c76ed56b1d49be30df996eb7fa33e46b62800562a5e2", size = 205802, upload-time = "2025-09-15T09:20:17.661Z" },
226
+ { url = "https://files.pythonhosted.org/packages/e7/ab/eb06ca556b2551d41de7d03bf2ee24285fa3d0c58c5f8d95c64c9c3281b1/jiter-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fb4790497369d134a07fc763cc88888c46f734abdd66f9fdf7865038bf3a8f40", size = 313405, upload-time = "2025-09-15T09:20:18.918Z" },
227
+ { url = "https://files.pythonhosted.org/packages/af/22/7ab7b4ec3a1c1f03aef376af11d23b05abcca3fb31fbca1e7557053b1ba2/jiter-0.11.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e2bbf24f16ba5ad4441a9845e40e4ea0cb9eed00e76ba94050664ef53ef4406", size = 347102, upload-time = "2025-09-15T09:20:20.16Z" },
228
+ ]
229
+
230
+ [[package]]
231
+ name = "ldbg"
232
+ version = "0.1.0"
233
+ source = { editable = "." }
234
+ dependencies = [
235
+ { name = "openai" },
236
+ ]
237
+
238
+ [package.dev-dependencies]
239
+ dev = [
240
+ { name = "ipython" },
241
+ { name = "pytest" },
242
+ { name = "ruff" },
243
+ ]
244
+
245
+ [package.metadata]
246
+ requires-dist = [{ name = "openai", specifier = ">=1.107.3" }]
247
+
248
+ [package.metadata.requires-dev]
249
+ dev = [
250
+ { name = "ipython", specifier = ">=9.5.0" },
251
+ { name = "pytest", specifier = ">=8.4.2" },
252
+ { name = "ruff", specifier = ">=0.14.0" },
253
+ ]
254
+
255
+ [[package]]
256
+ name = "matplotlib-inline"
257
+ version = "0.1.7"
258
+ source = { registry = "https://pypi.org/simple" }
259
+ dependencies = [
260
+ { name = "traitlets" },
261
+ ]
262
+ sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159, upload-time = "2024-04-15T13:44:44.803Z" }
263
+ wheels = [
264
+ { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" },
265
+ ]
266
+
267
+ [[package]]
268
+ name = "openai"
269
+ version = "2.1.0"
270
+ source = { registry = "https://pypi.org/simple" }
271
+ dependencies = [
272
+ { name = "anyio" },
273
+ { name = "distro" },
274
+ { name = "httpx" },
275
+ { name = "jiter" },
276
+ { name = "pydantic" },
277
+ { name = "sniffio" },
278
+ { name = "tqdm" },
279
+ { name = "typing-extensions" },
280
+ ]
281
+ sdist = { url = "https://files.pythonhosted.org/packages/1a/dd/4d4d46a06943e37c95b6e388237e1e38d1e9aab264ff070f86345d60b7a4/openai-2.1.0.tar.gz", hash = "sha256:47f3463a5047340a989b4c0cd5378054acfca966ff61a96553b22f098e3270a2", size = 572998, upload-time = "2025-10-02T20:43:15.385Z" }
282
+ wheels = [
283
+ { url = "https://files.pythonhosted.org/packages/68/83/88f64fc8f037885efa8a629d1215f5bc1f037453bab4d4f823b5533319eb/openai-2.1.0-py3-none-any.whl", hash = "sha256:33172e8c06a4576144ba4137a493807a9ca427421dcabc54ad3aa656daf757d3", size = 964939, upload-time = "2025-10-02T20:43:13.568Z" },
284
+ ]
285
+
286
+ [[package]]
287
+ name = "packaging"
288
+ version = "25.0"
289
+ source = { registry = "https://pypi.org/simple" }
290
+ sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
291
+ wheels = [
292
+ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
293
+ ]
294
+
295
+ [[package]]
296
+ name = "parso"
297
+ version = "0.8.5"
298
+ source = { registry = "https://pypi.org/simple" }
299
+ sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" }
300
+ wheels = [
301
+ { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" },
302
+ ]
303
+
304
+ [[package]]
305
+ name = "pexpect"
306
+ version = "4.9.0"
307
+ source = { registry = "https://pypi.org/simple" }
308
+ dependencies = [
309
+ { name = "ptyprocess" },
310
+ ]
311
+ sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" }
312
+ wheels = [
313
+ { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" },
314
+ ]
315
+
316
+ [[package]]
317
+ name = "pluggy"
318
+ version = "1.6.0"
319
+ source = { registry = "https://pypi.org/simple" }
320
+ sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
321
+ wheels = [
322
+ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
323
+ ]
324
+
325
+ [[package]]
326
+ name = "prompt-toolkit"
327
+ version = "3.0.52"
328
+ source = { registry = "https://pypi.org/simple" }
329
+ dependencies = [
330
+ { name = "wcwidth" },
331
+ ]
332
+ sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" }
333
+ wheels = [
334
+ { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" },
335
+ ]
336
+
337
+ [[package]]
338
+ name = "ptyprocess"
339
+ version = "0.7.0"
340
+ source = { registry = "https://pypi.org/simple" }
341
+ sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" }
342
+ wheels = [
343
+ { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" },
344
+ ]
345
+
346
+ [[package]]
347
+ name = "pure-eval"
348
+ version = "0.2.3"
349
+ source = { registry = "https://pypi.org/simple" }
350
+ sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" }
351
+ wheels = [
352
+ { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" },
353
+ ]
354
+
355
+ [[package]]
356
+ name = "pydantic"
357
+ version = "2.11.10"
358
+ source = { registry = "https://pypi.org/simple" }
359
+ dependencies = [
360
+ { name = "annotated-types" },
361
+ { name = "pydantic-core" },
362
+ { name = "typing-extensions" },
363
+ { name = "typing-inspection" },
364
+ ]
365
+ sdist = { url = "https://files.pythonhosted.org/packages/ae/54/ecab642b3bed45f7d5f59b38443dcb36ef50f85af192e6ece103dbfe9587/pydantic-2.11.10.tar.gz", hash = "sha256:dc280f0982fbda6c38fada4e476dc0a4f3aeaf9c6ad4c28df68a666ec3c61423", size = 788494, upload-time = "2025-10-04T10:40:41.338Z" }
366
+ wheels = [
367
+ { url = "https://files.pythonhosted.org/packages/bd/1f/73c53fcbfb0b5a78f91176df41945ca466e71e9d9d836e5c522abda39ee7/pydantic-2.11.10-py3-none-any.whl", hash = "sha256:802a655709d49bd004c31e865ef37da30b540786a46bfce02333e0e24b5fe29a", size = 444823, upload-time = "2025-10-04T10:40:39.055Z" },
368
+ ]
369
+
370
+ [[package]]
371
+ name = "pydantic-core"
372
+ version = "2.33.2"
373
+ source = { registry = "https://pypi.org/simple" }
374
+ dependencies = [
375
+ { name = "typing-extensions" },
376
+ ]
377
+ sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" }
378
+ wheels = [
379
+ { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" },
380
+ { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" },
381
+ { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" },
382
+ { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" },
383
+ { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" },
384
+ { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" },
385
+ { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" },
386
+ { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" },
387
+ { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" },
388
+ { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" },
389
+ { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" },
390
+ { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" },
391
+ { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" },
392
+ { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" },
393
+ { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" },
394
+ { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" },
395
+ { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" },
396
+ { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" },
397
+ { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" },
398
+ { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" },
399
+ { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" },
400
+ { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" },
401
+ { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" },
402
+ { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" },
403
+ { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" },
404
+ { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" },
405
+ { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" },
406
+ { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" },
407
+ { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" },
408
+ { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" },
409
+ { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
410
+ ]
411
+
412
+ [[package]]
413
+ name = "pygments"
414
+ version = "2.19.2"
415
+ source = { registry = "https://pypi.org/simple" }
416
+ sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
417
+ wheels = [
418
+ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
419
+ ]
420
+
421
+ [[package]]
422
+ name = "pytest"
423
+ version = "8.4.2"
424
+ source = { registry = "https://pypi.org/simple" }
425
+ dependencies = [
426
+ { name = "colorama", marker = "sys_platform == 'win32'" },
427
+ { name = "iniconfig" },
428
+ { name = "packaging" },
429
+ { name = "pluggy" },
430
+ { name = "pygments" },
431
+ ]
432
+ sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" }
433
+ wheels = [
434
+ { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" },
435
+ ]
436
+
437
+ [[package]]
438
+ name = "ruff"
439
+ version = "0.14.0"
440
+ source = { registry = "https://pypi.org/simple" }
441
+ sdist = { url = "https://files.pythonhosted.org/packages/41/b9/9bd84453ed6dd04688de9b3f3a4146a1698e8faae2ceeccce4e14c67ae17/ruff-0.14.0.tar.gz", hash = "sha256:62ec8969b7510f77945df916de15da55311fade8d6050995ff7f680afe582c57", size = 5452071, upload-time = "2025-10-07T18:21:55.763Z" }
442
+ wheels = [
443
+ { url = "https://files.pythonhosted.org/packages/3a/4e/79d463a5f80654e93fa653ebfb98e0becc3f0e7cf6219c9ddedf1e197072/ruff-0.14.0-py3-none-linux_armv6l.whl", hash = "sha256:58e15bffa7054299becf4bab8a1187062c6f8cafbe9f6e39e0d5aface455d6b3", size = 12494532, upload-time = "2025-10-07T18:21:00.373Z" },
444
+ { url = "https://files.pythonhosted.org/packages/ee/40/e2392f445ed8e02aa6105d49db4bfff01957379064c30f4811c3bf38aece/ruff-0.14.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:838d1b065f4df676b7c9957992f2304e41ead7a50a568185efd404297d5701e8", size = 13160768, upload-time = "2025-10-07T18:21:04.73Z" },
445
+ { url = "https://files.pythonhosted.org/packages/75/da/2a656ea7c6b9bd14c7209918268dd40e1e6cea65f4bb9880eaaa43b055cd/ruff-0.14.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:703799d059ba50f745605b04638fa7e9682cc3da084b2092feee63500ff3d9b8", size = 12363376, upload-time = "2025-10-07T18:21:07.833Z" },
446
+ { url = "https://files.pythonhosted.org/packages/42/e2/1ffef5a1875add82416ff388fcb7ea8b22a53be67a638487937aea81af27/ruff-0.14.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ba9a8925e90f861502f7d974cc60e18ca29c72bb0ee8bfeabb6ade35a3abde7", size = 12608055, upload-time = "2025-10-07T18:21:10.72Z" },
447
+ { url = "https://files.pythonhosted.org/packages/4a/32/986725199d7cee510d9f1dfdf95bf1efc5fa9dd714d0d85c1fb1f6be3bc3/ruff-0.14.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e41f785498bd200ffc276eb9e1570c019c1d907b07cfb081092c8ad51975bbe7", size = 12318544, upload-time = "2025-10-07T18:21:13.741Z" },
448
+ { url = "https://files.pythonhosted.org/packages/9a/ed/4969cefd53315164c94eaf4da7cfba1f267dc275b0abdd593d11c90829a3/ruff-0.14.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30a58c087aef4584c193aebf2700f0fbcfc1e77b89c7385e3139956fa90434e2", size = 14001280, upload-time = "2025-10-07T18:21:16.411Z" },
449
+ { url = "https://files.pythonhosted.org/packages/ab/ad/96c1fc9f8854c37681c9613d825925c7f24ca1acfc62a4eb3896b50bacd2/ruff-0.14.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f8d07350bc7af0a5ce8812b7d5c1a7293cf02476752f23fdfc500d24b79b783c", size = 15027286, upload-time = "2025-10-07T18:21:19.577Z" },
450
+ { url = "https://files.pythonhosted.org/packages/b3/00/1426978f97df4fe331074baf69615f579dc4e7c37bb4c6f57c2aad80c87f/ruff-0.14.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eec3bbbf3a7d5482b5c1f42d5fc972774d71d107d447919fca620b0be3e3b75e", size = 14451506, upload-time = "2025-10-07T18:21:22.779Z" },
451
+ { url = "https://files.pythonhosted.org/packages/58/d5/9c1cea6e493c0cf0647674cca26b579ea9d2a213b74b5c195fbeb9678e15/ruff-0.14.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16b68e183a0e28e5c176d51004aaa40559e8f90065a10a559176713fcf435206", size = 13437384, upload-time = "2025-10-07T18:21:25.758Z" },
452
+ { url = "https://files.pythonhosted.org/packages/29/b4/4cd6a4331e999fc05d9d77729c95503f99eae3ba1160469f2b64866964e3/ruff-0.14.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb732d17db2e945cfcbbc52af0143eda1da36ca8ae25083dd4f66f1542fdf82e", size = 13447976, upload-time = "2025-10-07T18:21:28.83Z" },
453
+ { url = "https://files.pythonhosted.org/packages/3b/c0/ac42f546d07e4f49f62332576cb845d45c67cf5610d1851254e341d563b6/ruff-0.14.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:c958f66ab884b7873e72df38dcabee03d556a8f2ee1b8538ee1c2bbd619883dd", size = 13682850, upload-time = "2025-10-07T18:21:31.842Z" },
454
+ { url = "https://files.pythonhosted.org/packages/5f/c4/4b0c9bcadd45b4c29fe1af9c5d1dc0ca87b4021665dfbe1c4688d407aa20/ruff-0.14.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7eb0499a2e01f6e0c285afc5bac43ab380cbfc17cd43a2e1dd10ec97d6f2c42d", size = 12449825, upload-time = "2025-10-07T18:21:35.074Z" },
455
+ { url = "https://files.pythonhosted.org/packages/4b/a8/e2e76288e6c16540fa820d148d83e55f15e994d852485f221b9524514730/ruff-0.14.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4c63b2d99fafa05efca0ab198fd48fa6030d57e4423df3f18e03aa62518c565f", size = 12272599, upload-time = "2025-10-07T18:21:38.08Z" },
456
+ { url = "https://files.pythonhosted.org/packages/18/14/e2815d8eff847391af632b22422b8207704222ff575dec8d044f9ab779b2/ruff-0.14.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:668fce701b7a222f3f5327f86909db2bbe99c30877c8001ff934c5413812ac02", size = 13193828, upload-time = "2025-10-07T18:21:41.216Z" },
457
+ { url = "https://files.pythonhosted.org/packages/44/c6/61ccc2987cf0aecc588ff8f3212dea64840770e60d78f5606cd7dc34de32/ruff-0.14.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a86bf575e05cb68dcb34e4c7dfe1064d44d3f0c04bbc0491949092192b515296", size = 13628617, upload-time = "2025-10-07T18:21:44.04Z" },
458
+ { url = "https://files.pythonhosted.org/packages/73/e6/03b882225a1b0627e75339b420883dc3c90707a8917d2284abef7a58d317/ruff-0.14.0-py3-none-win32.whl", hash = "sha256:7450a243d7125d1c032cb4b93d9625dea46c8c42b4f06c6b709baac168e10543", size = 12367872, upload-time = "2025-10-07T18:21:46.67Z" },
459
+ { url = "https://files.pythonhosted.org/packages/41/77/56cf9cf01ea0bfcc662de72540812e5ba8e9563f33ef3d37ab2174892c47/ruff-0.14.0-py3-none-win_amd64.whl", hash = "sha256:ea95da28cd874c4d9c922b39381cbd69cb7e7b49c21b8152b014bd4f52acddc2", size = 13464628, upload-time = "2025-10-07T18:21:50.318Z" },
460
+ { url = "https://files.pythonhosted.org/packages/c6/2a/65880dfd0e13f7f13a775998f34703674a4554906167dce02daf7865b954/ruff-0.14.0-py3-none-win_arm64.whl", hash = "sha256:f42c9495f5c13ff841b1da4cb3c2a42075409592825dada7c5885c2c844ac730", size = 12565142, upload-time = "2025-10-07T18:21:53.577Z" },
461
+ ]
462
+
463
+ [[package]]
464
+ name = "sniffio"
465
+ version = "1.3.1"
466
+ source = { registry = "https://pypi.org/simple" }
467
+ sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
468
+ wheels = [
469
+ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
470
+ ]
471
+
472
+ [[package]]
473
+ name = "stack-data"
474
+ version = "0.6.3"
475
+ source = { registry = "https://pypi.org/simple" }
476
+ dependencies = [
477
+ { name = "asttokens" },
478
+ { name = "executing" },
479
+ { name = "pure-eval" },
480
+ ]
481
+ sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" }
482
+ wheels = [
483
+ { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" },
484
+ ]
485
+
486
+ [[package]]
487
+ name = "tqdm"
488
+ version = "4.67.1"
489
+ source = { registry = "https://pypi.org/simple" }
490
+ dependencies = [
491
+ { name = "colorama", marker = "sys_platform == 'win32'" },
492
+ ]
493
+ sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" }
494
+ wheels = [
495
+ { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" },
496
+ ]
497
+
498
+ [[package]]
499
+ name = "traitlets"
500
+ version = "5.14.3"
501
+ source = { registry = "https://pypi.org/simple" }
502
+ sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" }
503
+ wheels = [
504
+ { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" },
505
+ ]
506
+
507
+ [[package]]
508
+ name = "typing-extensions"
509
+ version = "4.15.0"
510
+ source = { registry = "https://pypi.org/simple" }
511
+ sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
512
+ wheels = [
513
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
514
+ ]
515
+
516
+ [[package]]
517
+ name = "typing-inspection"
518
+ version = "0.4.2"
519
+ source = { registry = "https://pypi.org/simple" }
520
+ dependencies = [
521
+ { name = "typing-extensions" },
522
+ ]
523
+ sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
524
+ wheels = [
525
+ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
526
+ ]
527
+
528
+ [[package]]
529
+ name = "wcwidth"
530
+ version = "0.2.14"
531
+ source = { registry = "https://pypi.org/simple" }
532
+ sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" }
533
+ wheels = [
534
+ { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" },
535
+ ]