sqlsaber 0.4.1__tar.gz → 0.5.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.
Potentially problematic release.
This version of sqlsaber might be problematic. Click here for more details.
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/CHANGELOG.md +6 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/PKG-INFO +2 -1
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/pyproject.toml +2 -1
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/agents/anthropic.py +50 -1
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/agents/base.py +92 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/cli/display.py +30 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/cli/streaming.py +5 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/models/events.py +1 -1
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/uv.lock +25 -1
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/.github/workflows/publish.yml +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/.gitignore +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/.python-version +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/CLAUDE.md +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/LICENSE +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/README.md +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/pytest.ini +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/__main__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/agents/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/agents/mcp.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/agents/streaming.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/cli/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/cli/commands.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/cli/database.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/cli/interactive.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/cli/memory.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/cli/models.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/config/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/config/api_keys.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/config/database.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/config/settings.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/database/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/database/connection.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/database/schema.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/mcp/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/mcp/mcp.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/memory/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/memory/manager.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/memory/storage.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/models/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/src/sqlsaber/models/types.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/tests/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/tests/conftest.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/tests/test_cli/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/tests/test_cli/test_commands.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/tests/test_config/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/tests/test_config/test_database.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/tests/test_config/test_settings.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/tests/test_database/__init__.py +0 -0
- {sqlsaber-0.4.1 → sqlsaber-0.5.0}/tests/test_database/test_connection.py +0 -0
|
@@ -4,6 +4,12 @@ All notable changes to SQLSaber will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added support for plotting data from query results.
|
|
10
|
+
- The agent can decide if plotting will useful and create a plot with query results.
|
|
11
|
+
- Small updates to system prompt
|
|
12
|
+
|
|
7
13
|
## [0.4.1] - 2025-06-26
|
|
8
14
|
|
|
9
15
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlsaber
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: SQLSaber - Agentic SQL assistant like Claude Code
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -16,6 +16,7 @@ Requires-Dist: platformdirs>=4.0.0
|
|
|
16
16
|
Requires-Dist: questionary>=2.1.0
|
|
17
17
|
Requires-Dist: rich>=13.7.0
|
|
18
18
|
Requires-Dist: typer>=0.16.0
|
|
19
|
+
Requires-Dist: uniplot>=0.21.2
|
|
19
20
|
Description-Content-Type: text/markdown
|
|
20
21
|
|
|
21
22
|
# SQLSaber
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sqlsaber"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
4
4
|
description = "SQLSaber - Agentic SQL assistant like Claude Code"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -17,6 +17,7 @@ dependencies = [
|
|
|
17
17
|
"aiosqlite>=0.21.0",
|
|
18
18
|
"pandas>=2.0.0",
|
|
19
19
|
"fastmcp>=2.9.0",
|
|
20
|
+
"uniplot>=0.21.2",
|
|
20
21
|
]
|
|
21
22
|
|
|
22
23
|
[tool.uv]
|
|
@@ -82,6 +82,44 @@ class AnthropicSQLAgent(BaseSQLAgent):
|
|
|
82
82
|
"required": ["query"],
|
|
83
83
|
},
|
|
84
84
|
},
|
|
85
|
+
{
|
|
86
|
+
"name": "plot_data",
|
|
87
|
+
"description": "Create a plot of query results.",
|
|
88
|
+
"input_schema": {
|
|
89
|
+
"type": "object",
|
|
90
|
+
"properties": {
|
|
91
|
+
"y_values": {
|
|
92
|
+
"type": "array",
|
|
93
|
+
"items": {"type": ["number", "null"]},
|
|
94
|
+
"description": "Y-axis data points (required)",
|
|
95
|
+
},
|
|
96
|
+
"x_values": {
|
|
97
|
+
"type": "array",
|
|
98
|
+
"items": {"type": ["number", "null"]},
|
|
99
|
+
"description": "X-axis data points (optional, will use indices if not provided)",
|
|
100
|
+
},
|
|
101
|
+
"plot_type": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"enum": ["line", "scatter", "histogram"],
|
|
104
|
+
"description": "Type of plot to create (default: line)",
|
|
105
|
+
"default": "line",
|
|
106
|
+
},
|
|
107
|
+
"title": {
|
|
108
|
+
"type": "string",
|
|
109
|
+
"description": "Title for the plot",
|
|
110
|
+
},
|
|
111
|
+
"x_label": {
|
|
112
|
+
"type": "string",
|
|
113
|
+
"description": "Label for X-axis",
|
|
114
|
+
},
|
|
115
|
+
"y_label": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"description": "Label for Y-axis",
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
"required": ["y_values"],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
85
123
|
]
|
|
86
124
|
|
|
87
125
|
# Build system prompt with memories if available
|
|
@@ -96,13 +134,15 @@ Your responsibilities:
|
|
|
96
134
|
1. Understand user's natural language requests, think and convert them to SQL
|
|
97
135
|
2. Use the provided tools efficiently to explore database schema
|
|
98
136
|
3. Generate appropriate SQL queries
|
|
99
|
-
4. Execute queries safely
|
|
137
|
+
4. Execute queries safely - queries that modify the database are not allowed
|
|
100
138
|
5. Format and explain results clearly
|
|
139
|
+
6. Create visualizations when requested or when they would be helpful
|
|
101
140
|
|
|
102
141
|
IMPORTANT - Schema Discovery Strategy:
|
|
103
142
|
1. ALWAYS start with 'list_tables' to see available tables and row counts
|
|
104
143
|
2. Based on the user's query, identify which specific tables are relevant
|
|
105
144
|
3. Use 'introspect_schema' with a table_pattern to get details ONLY for relevant tables
|
|
145
|
+
4. Timestamp columns must be converted to text when you write queries
|
|
106
146
|
|
|
107
147
|
Guidelines:
|
|
108
148
|
- Use list_tables first, then introspect_schema for specific tables only
|
|
@@ -249,6 +289,15 @@ Guidelines:
|
|
|
249
289
|
"result": tool_result,
|
|
250
290
|
},
|
|
251
291
|
)
|
|
292
|
+
elif block["name"] == "plot_data":
|
|
293
|
+
yield StreamEvent(
|
|
294
|
+
"plot_result",
|
|
295
|
+
{
|
|
296
|
+
"tool_name": block["name"],
|
|
297
|
+
"input": block["input"],
|
|
298
|
+
"result": tool_result,
|
|
299
|
+
},
|
|
300
|
+
)
|
|
252
301
|
|
|
253
302
|
tool_results.append(build_tool_result_block(block["id"], tool_result))
|
|
254
303
|
|
|
@@ -4,6 +4,8 @@ import json
|
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
5
5
|
from typing import Any, AsyncIterator, Dict, List, Optional
|
|
6
6
|
|
|
7
|
+
from uniplot import histogram, plot
|
|
8
|
+
|
|
7
9
|
from sqlsaber.database.connection import (
|
|
8
10
|
BaseDatabaseConnection,
|
|
9
11
|
CSVConnection,
|
|
@@ -146,6 +148,15 @@ class BaseSQLAgent(ABC):
|
|
|
146
148
|
return await self.execute_sql(
|
|
147
149
|
tool_input["query"], tool_input.get("limit", 100)
|
|
148
150
|
)
|
|
151
|
+
elif tool_name == "plot_data":
|
|
152
|
+
return await self.plot_data(
|
|
153
|
+
y_values=tool_input["y_values"],
|
|
154
|
+
x_values=tool_input.get("x_values"),
|
|
155
|
+
plot_type=tool_input.get("plot_type", "line"),
|
|
156
|
+
title=tool_input.get("title"),
|
|
157
|
+
x_label=tool_input.get("x_label"),
|
|
158
|
+
y_label=tool_input.get("y_label"),
|
|
159
|
+
)
|
|
149
160
|
else:
|
|
150
161
|
return json.dumps({"error": f"Unknown tool: {tool_name}"})
|
|
151
162
|
|
|
@@ -182,3 +193,84 @@ class BaseSQLAgent(ABC):
|
|
|
182
193
|
if query_upper.startswith("SELECT") and "LIMIT" not in query_upper:
|
|
183
194
|
return f"{query.rstrip(';')} LIMIT {limit};"
|
|
184
195
|
return query
|
|
196
|
+
|
|
197
|
+
async def plot_data(
|
|
198
|
+
self,
|
|
199
|
+
y_values: List[float],
|
|
200
|
+
x_values: Optional[List[float]] = None,
|
|
201
|
+
plot_type: str = "line",
|
|
202
|
+
title: Optional[str] = None,
|
|
203
|
+
x_label: Optional[str] = None,
|
|
204
|
+
y_label: Optional[str] = None,
|
|
205
|
+
) -> str:
|
|
206
|
+
"""Create a terminal plot using uniplot.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
y_values: Y-axis data points
|
|
210
|
+
x_values: X-axis data points (optional)
|
|
211
|
+
plot_type: Type of plot - "line", "scatter", or "histogram"
|
|
212
|
+
title: Plot title
|
|
213
|
+
x_label: X-axis label
|
|
214
|
+
y_label: Y-axis label
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
JSON string with success status and plot details
|
|
218
|
+
"""
|
|
219
|
+
try:
|
|
220
|
+
# Validate inputs
|
|
221
|
+
if not y_values:
|
|
222
|
+
return json.dumps({"error": "No data provided for plotting"})
|
|
223
|
+
|
|
224
|
+
# Convert to floats if needed
|
|
225
|
+
try:
|
|
226
|
+
y_values = [float(v) if v is not None else None for v in y_values]
|
|
227
|
+
if x_values:
|
|
228
|
+
x_values = [float(v) if v is not None else None for v in x_values]
|
|
229
|
+
except (ValueError, TypeError) as e:
|
|
230
|
+
return json.dumps({"error": f"Invalid data format: {str(e)}"})
|
|
231
|
+
|
|
232
|
+
# Create the plot
|
|
233
|
+
if plot_type == "histogram":
|
|
234
|
+
# For histogram, we only need y_values
|
|
235
|
+
histogram(
|
|
236
|
+
y_values,
|
|
237
|
+
title=title,
|
|
238
|
+
bins=min(20, len(set(y_values))), # Adaptive bin count
|
|
239
|
+
)
|
|
240
|
+
plot_info = {
|
|
241
|
+
"type": "histogram",
|
|
242
|
+
"data_points": len(y_values),
|
|
243
|
+
"title": title or "Histogram",
|
|
244
|
+
}
|
|
245
|
+
elif plot_type in ["line", "scatter"]:
|
|
246
|
+
# For line/scatter plots
|
|
247
|
+
plot_kwargs = {
|
|
248
|
+
"ys": y_values,
|
|
249
|
+
"title": title,
|
|
250
|
+
"lines": plot_type == "line",
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if x_values:
|
|
254
|
+
plot_kwargs["xs"] = x_values
|
|
255
|
+
if x_label:
|
|
256
|
+
plot_kwargs["x_unit"] = x_label
|
|
257
|
+
if y_label:
|
|
258
|
+
plot_kwargs["y_unit"] = y_label
|
|
259
|
+
|
|
260
|
+
plot(**plot_kwargs)
|
|
261
|
+
|
|
262
|
+
plot_info = {
|
|
263
|
+
"type": plot_type,
|
|
264
|
+
"data_points": len(y_values),
|
|
265
|
+
"title": title or f"{plot_type.capitalize()} Plot",
|
|
266
|
+
"has_x_values": x_values is not None,
|
|
267
|
+
}
|
|
268
|
+
else:
|
|
269
|
+
return json.dumps({"error": f"Unsupported plot type: {plot_type}"})
|
|
270
|
+
|
|
271
|
+
return json.dumps(
|
|
272
|
+
{"success": True, "plot_rendered": True, "plot_info": plot_info}
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
except Exception as e:
|
|
276
|
+
return json.dumps({"error": f"Error creating plot: {str(e)}"})
|
|
@@ -205,3 +205,33 @@ class DisplayManager:
|
|
|
205
205
|
self.show_error("Failed to parse schema data")
|
|
206
206
|
except Exception as e:
|
|
207
207
|
self.show_error(f"Error displaying schema information: {str(e)}")
|
|
208
|
+
|
|
209
|
+
def show_plot(self, plot_data: dict):
|
|
210
|
+
"""Display plot information and status."""
|
|
211
|
+
try:
|
|
212
|
+
# Parse the result if it's a string
|
|
213
|
+
if isinstance(plot_data.get("result"), str):
|
|
214
|
+
result = json.loads(plot_data["result"])
|
|
215
|
+
else:
|
|
216
|
+
result = plot_data.get("result", {})
|
|
217
|
+
|
|
218
|
+
# Check if there was an error
|
|
219
|
+
if "error" in result:
|
|
220
|
+
self.show_error(f"Plot error: {result['error']}")
|
|
221
|
+
return
|
|
222
|
+
|
|
223
|
+
# If plot was successful, show plot info
|
|
224
|
+
if result.get("success") and result.get("plot_rendered"):
|
|
225
|
+
plot_info = result.get("plot_info", {})
|
|
226
|
+
self.console.print(
|
|
227
|
+
f"\n[bold green]✓ Plot rendered:[/bold green] {plot_info.get('title', 'Plot')}"
|
|
228
|
+
)
|
|
229
|
+
self.console.print(
|
|
230
|
+
f"[dim] Type: {plot_info.get('type', 'unknown')}, "
|
|
231
|
+
f"Data points: {plot_info.get('data_points', 0)}[/dim]"
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
except json.JSONDecodeError:
|
|
235
|
+
self.show_error("Failed to parse plot result")
|
|
236
|
+
except Exception as e:
|
|
237
|
+
self.show_error(f"Error displaying plot: {str(e)}")
|
|
@@ -63,6 +63,11 @@ class StreamingQueryHandler:
|
|
|
63
63
|
self.display.show_schema_info(event.data["result"])
|
|
64
64
|
has_content = True
|
|
65
65
|
|
|
66
|
+
elif event.type == "plot_result":
|
|
67
|
+
# Handle plot results
|
|
68
|
+
self.display.show_plot(event.data)
|
|
69
|
+
has_content = True
|
|
70
|
+
|
|
66
71
|
elif event.type == "processing":
|
|
67
72
|
# Show status when processing tool results
|
|
68
73
|
if explanation_started:
|
|
@@ -7,7 +7,7 @@ class StreamEvent:
|
|
|
7
7
|
"""Event emitted during streaming processing."""
|
|
8
8
|
|
|
9
9
|
def __init__(self, event_type: str, data: Any = None):
|
|
10
|
-
# 'tool_use', 'text', 'query_result', 'error', 'processing'
|
|
10
|
+
# 'tool_use', 'text', 'query_result', 'plot_result', 'error', 'processing'
|
|
11
11
|
self.type = event_type
|
|
12
12
|
self.data = data
|
|
13
13
|
|
|
@@ -774,6 +774,15 @@ wheels = [
|
|
|
774
774
|
{ url = "https://files.pythonhosted.org/packages/ad/3f/11dd4cd4f39e05128bfd20138faea57bec56f9ffba6185d276e3107ba5b2/questionary-2.1.0-py3-none-any.whl", hash = "sha256:44174d237b68bc828e4878c763a9ad6790ee61990e0ae72927694ead57bab8ec", size = 36747 },
|
|
775
775
|
]
|
|
776
776
|
|
|
777
|
+
[[package]]
|
|
778
|
+
name = "readchar"
|
|
779
|
+
version = "4.2.1"
|
|
780
|
+
source = { registry = "https://pypi.org/simple" }
|
|
781
|
+
sdist = { url = "https://files.pythonhosted.org/packages/dd/f8/8657b8cbb4ebeabfbdf991ac40eca8a1d1bd012011bd44ad1ed10f5cb494/readchar-4.2.1.tar.gz", hash = "sha256:91ce3faf07688de14d800592951e5575e9c7a3213738ed01d394dcc949b79adb", size = 9685 }
|
|
782
|
+
wheels = [
|
|
783
|
+
{ url = "https://files.pythonhosted.org/packages/a9/10/e4b1e0e5b6b6745c8098c275b69bc9d73e9542d5c7da4f137542b499ed44/readchar-4.2.1-py3-none-any.whl", hash = "sha256:a769305cd3994bb5fa2764aa4073452dc105a4ec39068ffe6efd3c20c60acc77", size = 9350 },
|
|
784
|
+
]
|
|
785
|
+
|
|
777
786
|
[[package]]
|
|
778
787
|
name = "rich"
|
|
779
788
|
version = "14.0.0"
|
|
@@ -854,7 +863,7 @@ wheels = [
|
|
|
854
863
|
|
|
855
864
|
[[package]]
|
|
856
865
|
name = "sqlsaber"
|
|
857
|
-
version = "0.
|
|
866
|
+
version = "0.5.0"
|
|
858
867
|
source = { editable = "." }
|
|
859
868
|
dependencies = [
|
|
860
869
|
{ name = "aiomysql" },
|
|
@@ -869,6 +878,7 @@ dependencies = [
|
|
|
869
878
|
{ name = "questionary" },
|
|
870
879
|
{ name = "rich" },
|
|
871
880
|
{ name = "typer" },
|
|
881
|
+
{ name = "uniplot" },
|
|
872
882
|
]
|
|
873
883
|
|
|
874
884
|
[package.dev-dependencies]
|
|
@@ -892,6 +902,7 @@ requires-dist = [
|
|
|
892
902
|
{ name = "questionary", specifier = ">=2.1.0" },
|
|
893
903
|
{ name = "rich", specifier = ">=13.7.0" },
|
|
894
904
|
{ name = "typer", specifier = ">=0.16.0" },
|
|
905
|
+
{ name = "uniplot", specifier = ">=0.21.2" },
|
|
895
906
|
]
|
|
896
907
|
|
|
897
908
|
[package.metadata.requires-dev]
|
|
@@ -971,6 +982,19 @@ wheels = [
|
|
|
971
982
|
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839 },
|
|
972
983
|
]
|
|
973
984
|
|
|
985
|
+
[[package]]
|
|
986
|
+
name = "uniplot"
|
|
987
|
+
version = "0.21.2"
|
|
988
|
+
source = { registry = "https://pypi.org/simple" }
|
|
989
|
+
dependencies = [
|
|
990
|
+
{ name = "numpy" },
|
|
991
|
+
{ name = "readchar" },
|
|
992
|
+
]
|
|
993
|
+
sdist = { url = "https://files.pythonhosted.org/packages/87/65/b9db385152a5283c88f955710123c6539a7c79436d2de377b3449995b041/uniplot-0.21.2.tar.gz", hash = "sha256:fc350d6e0f2352822747a3426fef7f521d1b3973585ad2e2967c702dfc6e8440", size = 33412 }
|
|
994
|
+
wheels = [
|
|
995
|
+
{ url = "https://files.pythonhosted.org/packages/3a/0e/0b2e41841eb18017e7e125bc8294180d2597a4ca049641068f55355bcc69/uniplot-0.21.2-py3-none-any.whl", hash = "sha256:cae5875eac0d06fd75cbb7076ea3fa49565ef1d71140f0b9a39f7be96085536b", size = 36419 },
|
|
996
|
+
]
|
|
997
|
+
|
|
974
998
|
[[package]]
|
|
975
999
|
name = "uvicorn"
|
|
976
1000
|
version = "0.34.3"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|