sqlsaber 0.3.0__py3-none-any.whl → 0.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of sqlsaber might be problematic. Click here for more details.
- sqlsaber/agents/mcp.py +21 -0
- sqlsaber/cli/commands.py +3 -0
- sqlsaber/cli/interactive.py +9 -6
- sqlsaber/database/schema.py +2 -2
- sqlsaber/mcp/__init__.py +5 -0
- sqlsaber/mcp/mcp.py +138 -0
- {sqlsaber-0.3.0.dist-info → sqlsaber-0.4.1.dist-info}/METADATA +72 -3
- {sqlsaber-0.3.0.dist-info → sqlsaber-0.4.1.dist-info}/RECORD +11 -8
- {sqlsaber-0.3.0.dist-info → sqlsaber-0.4.1.dist-info}/entry_points.txt +2 -0
- {sqlsaber-0.3.0.dist-info → sqlsaber-0.4.1.dist-info}/WHEEL +0 -0
- {sqlsaber-0.3.0.dist-info → sqlsaber-0.4.1.dist-info}/licenses/LICENSE +0 -0
sqlsaber/agents/mcp.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Generic SQL agent implementation for MCP tools."""
|
|
2
|
+
|
|
3
|
+
from typing import AsyncIterator
|
|
4
|
+
from sqlsaber.agents.base import BaseSQLAgent
|
|
5
|
+
from sqlsaber.database.connection import BaseDatabaseConnection
|
|
6
|
+
from sqlsaber.models.events import StreamEvent
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MCPSQLAgent(BaseSQLAgent):
|
|
10
|
+
"""MCP SQL Agent for MCP tool operations without LLM-specific logic."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, db_connection: BaseDatabaseConnection):
|
|
13
|
+
super().__init__(db_connection)
|
|
14
|
+
|
|
15
|
+
async def query_stream(
|
|
16
|
+
self, user_query: str, use_history: bool = True
|
|
17
|
+
) -> AsyncIterator[StreamEvent]:
|
|
18
|
+
"""Not implemented for generic agent as it's only used for tool operations."""
|
|
19
|
+
raise NotImplementedError(
|
|
20
|
+
"MCPSQLAgent does not support query streaming. Use specific agent implementations for conversation."
|
|
21
|
+
)
|
sqlsaber/cli/commands.py
CHANGED
|
@@ -117,6 +117,9 @@ def query(
|
|
|
117
117
|
if query_text:
|
|
118
118
|
# Single query mode with streaming
|
|
119
119
|
streaming_handler = StreamingQueryHandler(console)
|
|
120
|
+
console.print(
|
|
121
|
+
f"[bold blue]Connected to:[/bold blue] {db_name} {agent._get_database_type_name()}\n"
|
|
122
|
+
)
|
|
120
123
|
await streaming_handler.execute_streaming_query(query_text, agent)
|
|
121
124
|
else:
|
|
122
125
|
# Interactive mode
|
sqlsaber/cli/interactive.py
CHANGED
|
@@ -20,21 +20,24 @@ class InteractiveSession:
|
|
|
20
20
|
|
|
21
21
|
def show_welcome_message(self):
|
|
22
22
|
"""Display welcome message for interactive mode."""
|
|
23
|
+
# Show database information
|
|
24
|
+
db_name = getattr(self.agent, "database_name", None) or "Unknown"
|
|
25
|
+
db_type = self.agent._get_database_type_name()
|
|
26
|
+
|
|
23
27
|
self.console.print(
|
|
24
28
|
Panel.fit(
|
|
25
29
|
"[bold green]SQLSaber - Use the agent Luke![/bold green]\n\n"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
30
|
+
"[bold]Your agentic SQL assistant.[/bold]\n\n\n"
|
|
31
|
+
"[dim]Use 'clear' to reset conversation, 'exit' or 'quit' to leave.[/dim]\n\n"
|
|
32
|
+
"[dim]Start a message with '#' to add something to agent's memory for this database.[/dim]",
|
|
29
33
|
border_style="green",
|
|
30
34
|
)
|
|
31
35
|
)
|
|
32
|
-
|
|
33
36
|
self.console.print(
|
|
34
|
-
"[
|
|
37
|
+
f"[bold blue]Connected to:[/bold blue] {db_name} ({db_type})\n"
|
|
35
38
|
)
|
|
36
39
|
self.console.print(
|
|
37
|
-
"[dim]
|
|
40
|
+
"[dim]Press Esc-Enter or Meta-Enter to submit your query.[/dim]\n"
|
|
38
41
|
)
|
|
39
42
|
|
|
40
43
|
async def run(self):
|
sqlsaber/database/schema.py
CHANGED
|
@@ -201,8 +201,8 @@ class PostgreSQLSchemaIntrospector(BaseSchemaIntrospector):
|
|
|
201
201
|
t.table_type,
|
|
202
202
|
COALESCE(ts.approximate_row_count, 0) as row_count
|
|
203
203
|
FROM information_schema.tables t
|
|
204
|
-
LEFT JOIN table_stats ts
|
|
205
|
-
ON t.table_schema = ts.schemaname
|
|
204
|
+
LEFT JOIN table_stats ts
|
|
205
|
+
ON t.table_schema = ts.schemaname
|
|
206
206
|
AND t.table_name = ts.tablename
|
|
207
207
|
WHERE t.table_schema NOT IN ('pg_catalog', 'information_schema')
|
|
208
208
|
ORDER BY t.table_schema, t.table_name;
|
sqlsaber/mcp/__init__.py
ADDED
sqlsaber/mcp/mcp.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""FastMCP server implementation for SQLSaber."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from fastmcp import FastMCP
|
|
7
|
+
|
|
8
|
+
from sqlsaber.agents.mcp import MCPSQLAgent
|
|
9
|
+
from sqlsaber.config.database import DatabaseConfigManager
|
|
10
|
+
from sqlsaber.database.connection import DatabaseConnection
|
|
11
|
+
|
|
12
|
+
INSTRUCTIONS = """
|
|
13
|
+
This server provides helpful resources and tools that will help you address users queries on their database.
|
|
14
|
+
|
|
15
|
+
- Get all databases using `get_databases()`
|
|
16
|
+
- Call `list_tables()` to get a list of all tables in the database with row counts. Use this first to discover available tables.
|
|
17
|
+
- Call `introspect_schema()` to introspect database schema to understand table structures.
|
|
18
|
+
- Call `execute_sql()` to execute SQL queries against the database and retrieve results.
|
|
19
|
+
|
|
20
|
+
Guidelines:
|
|
21
|
+
- Use list_tables first, then introspect_schema for specific tables only
|
|
22
|
+
- Use table patterns like 'sample%' or '%experiment%' to filter related tables
|
|
23
|
+
- Use proper JOIN syntax and avoid cartesian products
|
|
24
|
+
- Include appropriate WHERE clauses to limit results
|
|
25
|
+
- Handle errors gracefully and suggest fixes
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
# Create the FastMCP server instance
|
|
29
|
+
mcp = FastMCP(name="SQL Assistant", instructions=INSTRUCTIONS)
|
|
30
|
+
|
|
31
|
+
# Initialize the database config manager
|
|
32
|
+
config_manager = DatabaseConfigManager()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def _create_agent_for_database(database_name: str) -> Optional[MCPSQLAgent]:
|
|
36
|
+
"""Create a MCPSQLAgent for the specified database."""
|
|
37
|
+
try:
|
|
38
|
+
# Look up configured database connection
|
|
39
|
+
db_config = config_manager.get_database(database_name)
|
|
40
|
+
if not db_config:
|
|
41
|
+
return None
|
|
42
|
+
connection_string = db_config.to_connection_string()
|
|
43
|
+
|
|
44
|
+
# Create database connection
|
|
45
|
+
db_conn = DatabaseConnection(connection_string)
|
|
46
|
+
|
|
47
|
+
# Create and return the agent
|
|
48
|
+
agent = MCPSQLAgent(db_conn)
|
|
49
|
+
return agent
|
|
50
|
+
|
|
51
|
+
except Exception:
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@mcp.tool
|
|
56
|
+
def get_databases() -> dict:
|
|
57
|
+
"""List all configured databases with their types."""
|
|
58
|
+
databases = []
|
|
59
|
+
for db_config in config_manager.list_databases():
|
|
60
|
+
databases.append(
|
|
61
|
+
{
|
|
62
|
+
"name": db_config.name,
|
|
63
|
+
"type": db_config.type,
|
|
64
|
+
"database": db_config.database,
|
|
65
|
+
"host": db_config.host,
|
|
66
|
+
"port": db_config.port,
|
|
67
|
+
"is_default": db_config.name == config_manager.get_default_name(),
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return {"databases": databases, "count": len(databases)}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@mcp.tool
|
|
75
|
+
async def list_tables(database: str) -> str:
|
|
76
|
+
"""
|
|
77
|
+
Get a list of all tables in the database with row counts. Use this first to discover available tables.
|
|
78
|
+
"""
|
|
79
|
+
try:
|
|
80
|
+
agent = await _create_agent_for_database(database)
|
|
81
|
+
if not agent:
|
|
82
|
+
return json.dumps(
|
|
83
|
+
{"error": f"Database '{database}' not found or could not connect"}
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
result = await agent.list_tables()
|
|
87
|
+
await agent.db.close()
|
|
88
|
+
return result
|
|
89
|
+
|
|
90
|
+
except Exception as e:
|
|
91
|
+
return json.dumps({"error": f"Error listing tables: {str(e)}"})
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@mcp.tool
|
|
95
|
+
async def introspect_schema(database: str, table_pattern: Optional[str] = None) -> str:
|
|
96
|
+
"""
|
|
97
|
+
Introspect database schema to understand table structures. Use optional pattern to filter tables (e.g., 'public.users', 'user%', '%order%').
|
|
98
|
+
"""
|
|
99
|
+
try:
|
|
100
|
+
agent = await _create_agent_for_database(database)
|
|
101
|
+
if not agent:
|
|
102
|
+
return json.dumps(
|
|
103
|
+
{"error": f"Database '{database}' not found or could not connect"}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
result = await agent.introspect_schema(table_pattern)
|
|
107
|
+
await agent.db.close()
|
|
108
|
+
return result
|
|
109
|
+
|
|
110
|
+
except Exception as e:
|
|
111
|
+
return json.dumps({"error": f"Error introspecting schema: {str(e)}"})
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@mcp.tool
|
|
115
|
+
async def execute_sql(database: str, query: str, limit: Optional[int] = 100) -> str:
|
|
116
|
+
"""Execute a SQL query against the specified database."""
|
|
117
|
+
try:
|
|
118
|
+
agent = await _create_agent_for_database(database)
|
|
119
|
+
if not agent:
|
|
120
|
+
return json.dumps(
|
|
121
|
+
{"error": f"Database '{database}' not found or could not connect"}
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
result = await agent.execute_sql(query, limit)
|
|
125
|
+
await agent.db.close()
|
|
126
|
+
return result
|
|
127
|
+
|
|
128
|
+
except Exception as e:
|
|
129
|
+
return json.dumps({"error": f"Error executing SQL: {str(e)}"})
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def main():
|
|
133
|
+
"""Entry point for the MCP server console script."""
|
|
134
|
+
mcp.run()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlsaber
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: SQLSaber - Agentic SQL assistant like Claude Code
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -8,6 +8,7 @@ Requires-Dist: aiomysql>=0.2.0
|
|
|
8
8
|
Requires-Dist: aiosqlite>=0.21.0
|
|
9
9
|
Requires-Dist: anthropic>=0.54.0
|
|
10
10
|
Requires-Dist: asyncpg>=0.30.0
|
|
11
|
+
Requires-Dist: fastmcp>=2.9.0
|
|
11
12
|
Requires-Dist: httpx>=0.28.1
|
|
12
13
|
Requires-Dist: keyring>=25.6.0
|
|
13
14
|
Requires-Dist: pandas>=2.0.0
|
|
@@ -23,7 +24,28 @@ Description-Content-Type: text/markdown
|
|
|
23
24
|
|
|
24
25
|
SQLSaber is an agentic SQL assistant. Think Claude Code but for SQL.
|
|
25
26
|
|
|
26
|
-
Ask your questions in natural language and it will gather the right context and answer your query by writing SQL and analyzing the results.
|
|
27
|
+
Ask your questions in natural language and it will gather the right context automatically and answer your query by writing SQL and analyzing the results.
|
|
28
|
+
|
|
29
|
+
## Table of Contents
|
|
30
|
+
|
|
31
|
+
- [Features](#features)
|
|
32
|
+
- [Installation](#installation)
|
|
33
|
+
- [Configuration](#configuration)
|
|
34
|
+
- [Database Connection](#database-connection)
|
|
35
|
+
- [AI Model Configuration](#ai-model-configuration)
|
|
36
|
+
- [Memory Management](#memory-management)
|
|
37
|
+
- [Usage](#usage)
|
|
38
|
+
- [Interactive Mode](#interactive-mode)
|
|
39
|
+
- [Single Query](#single-query)
|
|
40
|
+
- [Database Selection](#database-selection)
|
|
41
|
+
- [Examples](#examples)
|
|
42
|
+
- [MCP Server Integration](#mcp-server-integration)
|
|
43
|
+
- [Starting the MCP Server](#starting-the-mcp-server)
|
|
44
|
+
- [Configuring MCP Clients](#configuring-mcp-clients)
|
|
45
|
+
- [Available MCP Tools](#available-mcp-tools)
|
|
46
|
+
- [How It Works](#how-it-works)
|
|
47
|
+
- [Contributing](#contributing)
|
|
48
|
+
- [License](#license)
|
|
27
49
|
|
|
28
50
|
## Features
|
|
29
51
|
|
|
@@ -34,19 +56,29 @@ Ask your questions in natural language and it will gather the right context and
|
|
|
34
56
|
- 💬 Interactive REPL mode
|
|
35
57
|
- 🎨 Beautiful formatted output with syntax highlighting
|
|
36
58
|
- 🗄️ Support for PostgreSQL, SQLite, and MySQL
|
|
59
|
+
- 🔌 MCP (Model Context Protocol) server support
|
|
37
60
|
|
|
38
61
|
## Installation
|
|
39
62
|
|
|
63
|
+
### `uv`
|
|
64
|
+
|
|
40
65
|
```bash
|
|
41
66
|
uv tool install sqlsaber
|
|
42
67
|
```
|
|
43
68
|
|
|
44
|
-
|
|
69
|
+
### `pipx`
|
|
45
70
|
|
|
46
71
|
```bash
|
|
47
72
|
pipx install sqlsaber
|
|
48
73
|
```
|
|
49
74
|
|
|
75
|
+
### `brew`
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
brew install uv
|
|
79
|
+
uv tool install sqlsaber
|
|
80
|
+
```
|
|
81
|
+
|
|
50
82
|
## Configuration
|
|
51
83
|
|
|
52
84
|
### Database Connection
|
|
@@ -140,6 +172,43 @@ saber query "show me the distribution of customer ages"
|
|
|
140
172
|
saber query "which products had the highest sales growth last quarter?"
|
|
141
173
|
```
|
|
142
174
|
|
|
175
|
+
## MCP Server Integration
|
|
176
|
+
|
|
177
|
+
SQLSaber includes an MCP (Model Context Protocol) server that allows AI agents like Claude Code to directly leverage tools available in SQLSaber.
|
|
178
|
+
|
|
179
|
+
### Starting the MCP Server
|
|
180
|
+
|
|
181
|
+
Run the MCP server using uvx:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
uvx --from sqlsaber saber-mcp
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Configuring MCP Clients
|
|
188
|
+
|
|
189
|
+
#### Claude Code
|
|
190
|
+
|
|
191
|
+
Add SQLSaber as an MCP server in Claude Code:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
claude mcp add -- uvx --from sqlsaber saber-mcp
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### Other MCP Clients
|
|
198
|
+
|
|
199
|
+
For other MCP clients, configure them to run the command: `uvx --from sqlsaber saber-mcp`
|
|
200
|
+
|
|
201
|
+
### Available MCP Tools
|
|
202
|
+
|
|
203
|
+
Once connected, the MCP client will have access to these tools:
|
|
204
|
+
|
|
205
|
+
- `get_databases()` - Lists all configured databases
|
|
206
|
+
- `list_tables(database)` - Get all tables in a database with row counts
|
|
207
|
+
- `introspect_schema(database, table_pattern?)` - Get detailed schema information
|
|
208
|
+
- `execute_sql(database, query, limit?)` - Execute SQL queries (read-only)
|
|
209
|
+
|
|
210
|
+
The MCP server uses your existing SQLSaber database configurations, so make sure to set up your databases using `saber db add` first.
|
|
211
|
+
|
|
143
212
|
## How It Works
|
|
144
213
|
|
|
145
214
|
SQLSaber uses an intelligent three-step process optimized for minimal token usage:
|
|
@@ -3,12 +3,13 @@ sqlsaber/__main__.py,sha256=RIHxWeWh2QvLfah-2OkhI5IJxojWfy4fXpMnVEJYvxw,78
|
|
|
3
3
|
sqlsaber/agents/__init__.py,sha256=LWeSeEUE4BhkyAYFF3TE-fx8TtLud3oyEtyB8ojFJgo,167
|
|
4
4
|
sqlsaber/agents/anthropic.py,sha256=xAjKeQSnaut-P5VBeBISbQeqdP41epDjX6MJb2ZUXWg,14060
|
|
5
5
|
sqlsaber/agents/base.py,sha256=IuVyCaA7VsA92odfQS2_lYNzwIZwPxK55mL_xRewgwQ,6943
|
|
6
|
+
sqlsaber/agents/mcp.py,sha256=FKtXgDrPZ2-xqUYCw2baI5JzrWekXaC5fjkYW1_Mg50,827
|
|
6
7
|
sqlsaber/agents/streaming.py,sha256=_EO390-FHUrL1fRCNfibtE9QuJz3LGQygbwG3CB2ViY,533
|
|
7
8
|
sqlsaber/cli/__init__.py,sha256=qVSLVJLLJYzoC6aj6y9MFrzZvAwc4_OgxU9DlkQnZ4M,86
|
|
8
|
-
sqlsaber/cli/commands.py,sha256=
|
|
9
|
+
sqlsaber/cli/commands.py,sha256=Dw24W0jij-8t1lpk99C4PBTgzFSag6vU-FZcjAYGG54,5074
|
|
9
10
|
sqlsaber/cli/database.py,sha256=DUfyvNBDp47oFM_VAC_hXHQy_qyE7JbXtowflJpwwH8,12643
|
|
10
11
|
sqlsaber/cli/display.py,sha256=5J4AgJADmMwKi9Aq5u6_MKRO1TA6unS4F4RUfml_sfU,7651
|
|
11
|
-
sqlsaber/cli/interactive.py,sha256=
|
|
12
|
+
sqlsaber/cli/interactive.py,sha256=Kqe7kN9mhUiY_5z1Ki6apZ9ahs8uzhHp3xMZGiyTXpY,3912
|
|
12
13
|
sqlsaber/cli/memory.py,sha256=LW4ZF2V6Gw6hviUFGZ4ym9ostFCwucgBTIMZ3EANO-I,7671
|
|
13
14
|
sqlsaber/cli/models.py,sha256=3IcXeeU15IQvemSv-V-RQzVytJ3wuQ4YmWk89nTDcSE,7813
|
|
14
15
|
sqlsaber/cli/streaming.py,sha256=5QGAYTAvg9mzQLxDEVtdDH-TIbGfYYzMOLoOYPrHPu0,3788
|
|
@@ -18,15 +19,17 @@ sqlsaber/config/database.py,sha256=vKFOxPjVakjQhj1uoLcfzhS9ZFr6Z2F5b4MmYALQZoA,1
|
|
|
18
19
|
sqlsaber/config/settings.py,sha256=zjQ7nS3ybcCb88Ea0tmwJox5-q0ettChZw89ZqRVpX8,3975
|
|
19
20
|
sqlsaber/database/__init__.py,sha256=a_gtKRJnZVO8-fEZI7g3Z8YnGa6Nio-5Y50PgVp07ss,176
|
|
20
21
|
sqlsaber/database/connection.py,sha256=s8GSFZebB8be8sVUr-N0x88-20YfkfljJFRyfoB1gH0,15154
|
|
21
|
-
sqlsaber/database/schema.py,sha256=
|
|
22
|
+
sqlsaber/database/schema.py,sha256=9QoH-gADzWlepq-tGz3nPU3miSUU0koWmpDaoWvz8Q0,27951
|
|
23
|
+
sqlsaber/mcp/__init__.py,sha256=COdWq7wauPBp5Ew8tfZItFzbcLDSEkHBJSMhxzy8C9c,112
|
|
24
|
+
sqlsaber/mcp/mcp.py,sha256=ACm1P1TnicjOptQgeLNhXg5xgZf4MYq2kqdfVdj6wh0,4477
|
|
22
25
|
sqlsaber/memory/__init__.py,sha256=GiWkU6f6YYVV0EvvXDmFWe_CxarmDCql05t70MkTEWs,63
|
|
23
26
|
sqlsaber/memory/manager.py,sha256=ML2NEO5Z4Aw36sEI9eOvWVnjl-qT2VOTojViJAj7Seo,2777
|
|
24
27
|
sqlsaber/memory/storage.py,sha256=DvZBsSPaAfk_DqrNEn86uMD-TQsWUI6rQLfNw6PSCB8,5788
|
|
25
28
|
sqlsaber/models/__init__.py,sha256=RJ7p3WtuSwwpFQ1Iw4_DHV2zzCtHqIzsjJzxv8kUjUE,287
|
|
26
29
|
sqlsaber/models/events.py,sha256=55m41tDwMsFxnKKA5_VLJz8iV-V4Sq3LDfta4VoutJI,737
|
|
27
30
|
sqlsaber/models/types.py,sha256=3U_30n91EB3IglBTHipwiW4MqmmaA2qfshfraMZyPps,896
|
|
28
|
-
sqlsaber-0.
|
|
29
|
-
sqlsaber-0.
|
|
30
|
-
sqlsaber-0.
|
|
31
|
-
sqlsaber-0.
|
|
32
|
-
sqlsaber-0.
|
|
31
|
+
sqlsaber-0.4.1.dist-info/METADATA,sha256=Jf17BrqK-2LdClq-VdYzhQ5jCsIN44rqsAsQ9kU4ClM,5938
|
|
32
|
+
sqlsaber-0.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
33
|
+
sqlsaber-0.4.1.dist-info/entry_points.txt,sha256=jmFo96Ylm0zIKXJBwhv_P5wQ7SXP9qdaBcnTp8iCEe8,195
|
|
34
|
+
sqlsaber-0.4.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
35
|
+
sqlsaber-0.4.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|