Skip to content

Commit e310794

Browse files
author
Eugene Shershen
committed
init
1 parent 8f65dca commit e310794

File tree

8 files changed

+111
-79
lines changed

8 files changed

+111
-79
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
.idea
22
*.egg-info
3-
.venv
3+
.venv

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,4 +218,4 @@ This project is licensed under the MIT License - see the LICENSE file for detail
218218
- Connection string parsing
219219
- Basic SQL compilation support
220220
- Transaction support
221-
- SSL configuration support
221+
- SSL configuration support

psqlpy_sqlalchemy/connection.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
DBAPI-compatible connection and cursor wrappers for psqlpy
33
"""
44

5-
from typing import Any, List, Optional, Tuple, Union
5+
from typing import List, Optional, Tuple, Union
66

77
import psqlpy
88

@@ -31,7 +31,8 @@ def execute(
3131
# Convert parameters to psqlpy format if needed
3232
if isinstance(parameters, (list, tuple)):
3333
# Convert positional parameters to named parameters
34-
# This is a simplified conversion - in practice, you might need more sophisticated handling
34+
# This is a simplified conversion - in practice, you might need more
35+
# sophisticated handling
3536
param_dict = {f"param_{i}": val for i, val in enumerate(parameters)}
3637
query = self._convert_positional_to_named(query, len(parameters))
3738
self._result = self._psqlpy_connection.fetch(query, param_dict)
@@ -171,7 +172,8 @@ def commit(self):
171172
# If we're in a transaction, we need to commit it
172173
if self._in_transaction:
173174
try:
174-
# This is a simplified approach - in practice you'd track transactions better
175+
# This is a simplified approach - in practice you'd track
176+
# transactions better
175177
cursor = self.cursor()
176178
cursor.execute("COMMIT")
177179
self._in_transaction = False
@@ -196,7 +198,7 @@ def close(self):
196198
if not self._closed:
197199
try:
198200
self._psqlpy_connection.close()
199-
except:
201+
except Exception:
200202
pass # Ignore errors on close
201203
self._closed = True
202204

psqlpy_sqlalchemy/dbapi.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
DBAPI-compatible interface for psqlpy
33
"""
44

5-
from typing import Any, Optional
65

76
import psqlpy
87

psqlpy_sqlalchemy/dialect.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22
SQLAlchemy dialect for psqlpy
33
"""
44

5-
from typing import Any, Dict, List, Optional, Tuple, Union
6-
from urllib.parse import parse_qs, urlparse
5+
from typing import Any, Dict, List, Tuple
76

87
import psqlpy
9-
from sqlalchemy import pool, util
10-
from sqlalchemy.engine import default, interfaces
8+
from sqlalchemy.engine import default
119
from sqlalchemy.engine.url import URL
12-
from sqlalchemy.sql import sqltypes
1310

1411
from .connection import PsqlpyConnection
1512
from .dbapi import PsqlpyDBAPI
@@ -148,7 +145,7 @@ def get_isolation_level(self, dbapi_connection):
148145
if result:
149146
level = result[0].upper().replace(" ", "_")
150147
return level
151-
except:
148+
except Exception:
152149
pass
153150
return self.default_isolation_level
154151

@@ -171,7 +168,8 @@ def _handle_exception(self, e):
171168
"""Convert psqlpy exceptions to appropriate DBAPI exceptions"""
172169
if isinstance(e, psqlpy.Error):
173170
# For now, just re-raise as is
174-
# In a full implementation, we'd map to specific DBAPI exception types
171+
# In a full implementation, we'd map to specific DBAPI
172+
# exception types
175173
return e
176174
return e
177175

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,4 @@ ignore_errors = true
9292

9393
[[tool.mypy.overrides]]
9494
module = "tests.*"
95-
ignore_errors = true
95+
ignore_errors = true

tests/test_dbapi.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,26 @@ def test_dbapi_attributes(self):
2525
def test_exception_hierarchy(self):
2626
"""Test that all required DBAPI exceptions are available"""
2727
exceptions = [
28-
'Warning', 'Error', 'InterfaceError', 'DatabaseError',
29-
'DataError', 'OperationalError', 'IntegrityError',
30-
'InternalError', 'ProgrammingError', 'NotSupportedError'
28+
"Warning",
29+
"Error",
30+
"InterfaceError",
31+
"DatabaseError",
32+
"DataError",
33+
"OperationalError",
34+
"IntegrityError",
35+
"InternalError",
36+
"ProgrammingError",
37+
"NotSupportedError",
3138
]
32-
39+
3340
for exc_name in exceptions:
34-
self.assertTrue(hasattr(self.dbapi, exc_name),
35-
f"Missing DBAPI exception: {exc_name}")
41+
self.assertTrue(
42+
hasattr(self.dbapi, exc_name), f"Missing DBAPI exception: {exc_name}"
43+
)
3644
exc_class = getattr(self.dbapi, exc_name)
37-
self.assertTrue(callable(exc_class),
38-
f"Exception {exc_name} is not callable")
45+
self.assertTrue(
46+
callable(exc_class), f"Exception {exc_name} is not callable"
47+
)
3948

4049
def test_type_constructors(self):
4150
"""Test DBAPI type constructors"""
@@ -86,15 +95,15 @@ def test_tick_constructors(self):
8695

8796
# Get current timestamp
8897
current_time = time.time()
89-
98+
9099
# Test DateFromTicks
91100
date_from_ticks = self.dbapi.DateFromTicks(current_time)
92101
self.assertIsInstance(date_from_ticks, datetime.date)
93-
102+
94103
# Test TimeFromTicks
95104
time_from_ticks = self.dbapi.TimeFromTicks(current_time)
96105
self.assertIsInstance(time_from_ticks, datetime.time)
97-
106+
98107
# Test TimestampFromTicks
99108
timestamp_from_ticks = self.dbapi.TimestampFromTicks(current_time)
100109
self.assertIsInstance(timestamp_from_ticks, datetime.datetime)
@@ -109,9 +118,9 @@ def test_type_objects(self):
109118

110119
def test_connect_method_exists(self):
111120
"""Test that connect method exists"""
112-
self.assertTrue(hasattr(self.dbapi, 'connect'))
121+
self.assertTrue(hasattr(self.dbapi, "connect"))
113122
self.assertTrue(callable(self.dbapi.connect))
114123

115124

116-
if __name__ == '__main__':
117-
unittest.main()
125+
if __name__ == "__main__":
126+
unittest.main()

tests/test_dialect.py

Lines changed: 74 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import unittest
77

88
from sqlalchemy import Column, Integer, MetaData, String, Table, create_engine, text
9-
from sqlalchemy.orm import sessionmaker
109
from sqlalchemy.schema import CreateTable
1110

1211

@@ -25,7 +24,9 @@ def tearDown(self):
2524
def test_dialect_registration(self):
2625
"""Test that the dialect is properly registered"""
2726
try:
28-
self.engine = create_engine("postgresql+psqlpy://user:password@localhost/test")
27+
self.engine = create_engine(
28+
"postgresql+psqlpy://user:password@localhost/test"
29+
)
2930
self.assertIsNotNone(self.engine.dialect)
3031
self.assertEqual(self.engine.dialect.name, "postgresql")
3132
self.assertEqual(self.engine.dialect.driver, "psqlpy")
@@ -35,86 +36,107 @@ def test_dialect_registration(self):
3536
def test_connection_string_parsing(self):
3637
"""Test connection string parsing"""
3738
try:
38-
self.engine = create_engine("postgresql+psqlpy://testuser:testpass@localhost:5432/testdb?sslmode=require")
39-
39+
self.engine = create_engine(
40+
"postgresql+psqlpy://testuser:testpass@localhost:5432/testdb?sslmode=require"
41+
)
42+
4043
# Test create_connect_args
4144
args, kwargs = self.engine.dialect.create_connect_args(self.engine.url)
42-
45+
4346
self.assertIsInstance(args, list)
4447
self.assertIsInstance(kwargs, dict)
45-
48+
4649
# Check expected connection parameters
47-
expected_keys = ['host', 'port', 'db_name', 'username', 'password']
50+
expected_keys = ["host", "port", "db_name", "username", "password"]
4851
for key in expected_keys:
4952
self.assertIn(key, kwargs, f"Missing connection parameter: {key}")
50-
53+
5154
# Verify specific values
52-
self.assertEqual(kwargs['host'], 'localhost')
53-
self.assertEqual(kwargs['port'], 5432)
54-
self.assertEqual(kwargs['db_name'], 'testdb')
55-
self.assertEqual(kwargs['username'], 'testuser')
56-
self.assertEqual(kwargs['password'], 'testpass')
57-
55+
self.assertEqual(kwargs["host"], "localhost")
56+
self.assertEqual(kwargs["port"], 5432)
57+
self.assertEqual(kwargs["db_name"], "testdb")
58+
self.assertEqual(kwargs["username"], "testuser")
59+
self.assertEqual(kwargs["password"], "testpass")
60+
5861
except Exception as e:
5962
self.fail(f"Failed to parse connection string: {e}")
6063

6164
def test_basic_sql_compilation(self):
6265
"""Test basic SQL compilation"""
6366
try:
64-
self.engine = create_engine("postgresql+psqlpy://user:password@localhost/test")
65-
67+
self.engine = create_engine(
68+
"postgresql+psqlpy://user:password@localhost/test"
69+
)
70+
6671
# Test basic SQL compilation
6772
stmt = text("SELECT 1 as test_column")
6873
compiled = stmt.compile(self.engine)
6974
self.assertIsNotNone(compiled)
7075
self.assertIn("SELECT 1", str(compiled))
71-
76+
7277
# Test table creation SQL
7378
metadata = MetaData()
74-
test_table = Table('test_table', metadata,
75-
Column('id', Integer, primary_key=True),
76-
Column('name', String(50))
79+
test_table = Table(
80+
"test_table",
81+
metadata,
82+
Column("id", Integer, primary_key=True),
83+
Column("name", String(50)),
7784
)
78-
85+
7986
create_ddl = CreateTable(test_table)
8087
create_sql = str(create_ddl.compile(self.engine))
8188
self.assertIsNotNone(create_sql)
8289
self.assertIn("CREATE TABLE test_table", create_sql)
8390
self.assertIn("id", create_sql)
8491
self.assertIn("name", create_sql)
85-
92+
8693
except Exception as e:
8794
self.fail(f"Failed SQL compilation: {e}")
8895

8996
def test_dbapi_interface(self):
9097
"""Test DBAPI interface"""
9198
try:
92-
self.engine = create_engine("postgresql+psqlpy://user:password@localhost/test")
99+
self.engine = create_engine(
100+
"postgresql+psqlpy://user:password@localhost/test"
101+
)
93102
dbapi = self.engine.dialect.import_dbapi()
94-
103+
95104
self.assertIsNotNone(dbapi)
96-
105+
97106
# Test DBAPI attributes
98107
self.assertEqual(dbapi.apilevel, "2.0")
99108
self.assertEqual(dbapi.threadsafety, 2)
100109
self.assertEqual(dbapi.paramstyle, "pyformat")
101-
110+
102111
# Test exception hierarchy
103-
exceptions = ['Warning', 'Error', 'InterfaceError', 'DatabaseError',
104-
'DataError', 'OperationalError', 'IntegrityError',
105-
'InternalError', 'ProgrammingError', 'NotSupportedError']
106-
112+
exceptions = [
113+
"Warning",
114+
"Error",
115+
"InterfaceError",
116+
"DatabaseError",
117+
"DataError",
118+
"OperationalError",
119+
"IntegrityError",
120+
"InternalError",
121+
"ProgrammingError",
122+
"NotSupportedError",
123+
]
124+
107125
for exc_name in exceptions:
108-
self.assertTrue(hasattr(dbapi, exc_name), f"Missing DBAPI exception: {exc_name}")
109-
126+
self.assertTrue(
127+
hasattr(dbapi, exc_name), f"Missing DBAPI exception: {exc_name}"
128+
)
129+
110130
except Exception as e:
111131
self.fail(f"Failed DBAPI interface test: {e}")
112132

113133
def test_mock_connection(self):
114134
"""Test connection creation (without actual database)"""
115135
try:
116-
self.engine = create_engine("postgresql+psqlpy://user:password@localhost/test")
117-
136+
self.engine = create_engine(
137+
"postgresql+psqlpy://user:password@localhost/test"
138+
)
139+
118140
# This will fail because we don't have a real database,
119141
# but we can test that the connection creation process starts correctly
120142
try:
@@ -126,17 +148,19 @@ def test_mock_connection(self):
126148
# This is expected - we don't have a real database
127149
# The test passes if an exception is raised
128150
pass
129-
151+
130152
except Exception as e:
131153
# If we get here, it means the test setup itself failed
132154
self.fail(f"Unexpected error in connection test setup: {e}")
133155

134156
def test_dialect_capabilities(self):
135157
"""Test dialect capabilities and features"""
136158
try:
137-
self.engine = create_engine("postgresql+psqlpy://user:password@localhost/test")
159+
self.engine = create_engine(
160+
"postgresql+psqlpy://user:password@localhost/test"
161+
)
138162
dialect = self.engine.dialect
139-
163+
140164
# Test key dialect capabilities
141165
self.assertTrue(dialect.supports_statement_cache)
142166
self.assertTrue(dialect.supports_multivalues_insert)
@@ -147,7 +171,7 @@ def test_dialect_capabilities(self):
147171
self.assertTrue(dialect.supports_sequences)
148172
self.assertTrue(dialect.implicit_returning)
149173
self.assertTrue(dialect.full_returning)
150-
174+
151175
except Exception as e:
152176
self.fail(f"Failed dialect capabilities test: {e}")
153177

@@ -161,23 +185,23 @@ def test_connection_wrapper_creation(self):
161185

162186
# We can't create a real connection without a database,
163187
# but we can test the class exists and has required methods
164-
self.assertTrue(hasattr(PsqlpyConnection, 'cursor'))
165-
self.assertTrue(hasattr(PsqlpyConnection, 'commit'))
166-
self.assertTrue(hasattr(PsqlpyConnection, 'rollback'))
167-
self.assertTrue(hasattr(PsqlpyConnection, 'close'))
188+
self.assertTrue(hasattr(PsqlpyConnection, "cursor"))
189+
self.assertTrue(hasattr(PsqlpyConnection, "commit"))
190+
self.assertTrue(hasattr(PsqlpyConnection, "rollback"))
191+
self.assertTrue(hasattr(PsqlpyConnection, "close"))
168192

169193
def test_cursor_wrapper_creation(self):
170194
"""Test that cursor wrapper can be created"""
171195
from psqlpy_sqlalchemy.connection import PsqlpyCursor
172196

173197
# Test the class exists and has required methods
174-
self.assertTrue(hasattr(PsqlpyCursor, 'execute'))
175-
self.assertTrue(hasattr(PsqlpyCursor, 'executemany'))
176-
self.assertTrue(hasattr(PsqlpyCursor, 'fetchone'))
177-
self.assertTrue(hasattr(PsqlpyCursor, 'fetchmany'))
178-
self.assertTrue(hasattr(PsqlpyCursor, 'fetchall'))
179-
self.assertTrue(hasattr(PsqlpyCursor, 'close'))
198+
self.assertTrue(hasattr(PsqlpyCursor, "execute"))
199+
self.assertTrue(hasattr(PsqlpyCursor, "executemany"))
200+
self.assertTrue(hasattr(PsqlpyCursor, "fetchone"))
201+
self.assertTrue(hasattr(PsqlpyCursor, "fetchmany"))
202+
self.assertTrue(hasattr(PsqlpyCursor, "fetchall"))
203+
self.assertTrue(hasattr(PsqlpyCursor, "close"))
180204

181205

182-
if __name__ == '__main__':
183-
unittest.main()
206+
if __name__ == "__main__":
207+
unittest.main()

0 commit comments

Comments
 (0)