Skip to content

Commit b25b140

Browse files
committed
feat(dbapi2): compatibility specs
1 parent b7ff349 commit b25b140

File tree

5 files changed

+156
-20
lines changed

5 files changed

+156
-20
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
build/
33
experiments/
44
sdk/
5-
venv*/
5+
.venv*/
66
main.dSYM/
77
.env
88
*.pyc

src/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
placeholder

src/sqlitecloud/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# the classes and functions from the dbapi2 module.
33
# eg: sqlite3.connect() -> sqlitecloud.connect()
44
#
5+
56
from .dbapi2 import (
67
PARSE_COLNAMES,
78
PARSE_DECLTYPES,
@@ -28,5 +29,3 @@
2829
"converters",
2930
"Row",
3031
]
31-
32-
VERSION = "0.0.79"

src/sqlitecloud/datatypes.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,6 @@ def _parse_connection_string(self, connection_string) -> None:
228228
) from e
229229

230230

231-
class SQLiteCloudException(Exception):
232-
def __init__(self, message: str, code: int = -1, xerrcode: int = 0) -> None:
233-
super().__init__(message)
234-
self.errmsg = str(message)
235-
self.errcode = code
236-
self.xerrcode = xerrcode
237-
238-
239231
class SQLiteCloudNumber:
240232
"""
241233
Represents the parsed number or the error code.
@@ -256,3 +248,34 @@ def __init__(self) -> None:
256248
self.value: Optional[SQLiteCloudDataTypes] = None
257249
self.len: int = 0
258250
self.cellsize: int = 0
251+
252+
253+
class SQLiteCloudWarning(Exception):
254+
def __init__(self, message: str, code: int = -1, xerrcode: int = 0) -> None:
255+
super().__init__(message)
256+
self.errmsg = str(message)
257+
self.errcode = code
258+
self.xerrcode = xerrcode
259+
260+
261+
class SQLiteCloudError(Exception):
262+
def __init__(self, message: str, code: int = -1, xerrcode: int = 0) -> None:
263+
super().__init__(message)
264+
self.errmsg = str(message)
265+
self.errcode = code
266+
self.xerrcode = xerrcode
267+
268+
269+
# class SQLiteCloudInterfaceError(SQLiteCloudError):
270+
# def __init__(self, message: str, code: int = -1, xerrcode: int = 0) -> None:
271+
# super().__init__(message, code, xerrcode)
272+
273+
274+
# class SQLiteCloudDatabaseError(SQLiteCloudError):
275+
# def __init__(self, message: str, code: int = -1, xerrcode: int = 0) -> None:
276+
# super().__init__(message, code, xerrcode)
277+
278+
279+
class SQLiteCloudException(SQLiteCloudError):
280+
def __init__(self, message: str, code: int = -1, xerrcode: int = 0) -> None:
281+
super().__init__(message, code, xerrcode)

src/sqlitecloud/dbapi2.py

Lines changed: 122 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
# PEP 249 – Python Database API Specification v2.0
44
# https://peps.python.org/pep-0249/
55
#
6+
import collections
7+
import datetime
68
import logging
79
import re
810
import sys
9-
from datetime import date, datetime
11+
import time
1012
from typing import (
1113
Any,
1214
Callable,
@@ -25,7 +27,9 @@
2527
SQLiteCloudAccount,
2628
SQLiteCloudConfig,
2729
SQLiteCloudConnect,
30+
SQLiteCloudError,
2831
SQLiteCloudException,
32+
SQLiteCloudWarning,
2933
SQLiteDataTypes,
3034
)
3135
from sqlitecloud.driver import Driver
@@ -36,6 +40,36 @@
3640
SQLiteCloudResult,
3741
)
3842

43+
version = "0.1.0"
44+
version_info = (0, 1, 0)
45+
46+
# version from sqlite3 in py3.6
47+
sqlite_version = "3.34.1"
48+
sqlite_version_info = (3, 34, 1)
49+
50+
Binary = bytes
51+
Date = datetime.date
52+
Time = datetime.time
53+
Timestamp = datetime.datetime
54+
55+
Warning = SQLiteCloudWarning
56+
Error = SQLiteCloudError
57+
InterfaceError = SQLiteCloudException
58+
DatabaseError = SQLiteCloudException
59+
DataError = SQLiteCloudException
60+
OperationalError = SQLiteCloudException
61+
IntegrityError = SQLiteCloudException
62+
InternalError = SQLiteCloudException
63+
ProgrammingError = SQLiteCloudException
64+
NotSupportedError = SQLiteCloudException
65+
66+
# Map for types for SQLite
67+
STRING = "TEXT"
68+
BINARY = "BINARY"
69+
NUMBER = "INTEGER"
70+
DATETIME = "TIMESTAMP"
71+
ROWID = "INTEGER PRIMARY KEY"
72+
3973
# SQLite supported types
4074
SQLiteTypes = Union[int, float, str, bytes, None]
4175

@@ -193,6 +227,7 @@ def __init__(
193227
self, sqlitecloud_connection: SQLiteCloudConnect, detect_types: int = 0
194228
) -> None:
195229
self._driver = Driver()
230+
self._autocommit = True
196231
self.sqlitecloud_connection = sqlitecloud_connection
197232

198233
self.row_factory: Optional[Callable[["Cursor", Tuple], object]] = None
@@ -212,6 +247,17 @@ def sqlcloud_connection(self) -> SQLiteCloudConnect:
212247
"""
213248
return self.sqlitecloud_connection
214249

250+
@property
251+
def autocommit(self) -> bool:
252+
"""Autocommit enabled is the only currently supported option in SQLite Cloud."""
253+
return self._autocommit
254+
255+
@autocommit.setter
256+
def autocommit(self, value: bool) -> None:
257+
# TODO: raise NotSupportedError
258+
if not value:
259+
raise SQLiteCloudException("Disable Autocommit is not supported.")
260+
215261
def execute(
216262
self,
217263
sql: str,
@@ -253,6 +299,50 @@ def executemany(
253299
cursor = self.cursor()
254300
return cursor.executemany(sql, seq_of_parameters)
255301

302+
def executescript(self, sql_script: str):
303+
# TODO: raise NotSupportedError
304+
raise SQLiteCloudException("executescript() is not supported.")
305+
306+
def create_function(self, name, num_params, func):
307+
# TODO: raise NotSupportedError
308+
raise SQLiteCloudException("create_function() is not supported.")
309+
310+
def create_aggregate(self, name, num_params, aggregate_class):
311+
# TODO: raise NotSupportedError
312+
raise SQLiteCloudException("create_aggregate() is not supported.")
313+
314+
def create_collation(self, name, func):
315+
# TODO: raise NotSupportedError
316+
raise SQLiteCloudException("create_collation() is not supported.")
317+
318+
def interrupt(self):
319+
# TODO: raise NotSupportedError
320+
raise SQLiteCloudException("interrupt() is not supported.")
321+
322+
def set_authorizer(self, authorizer):
323+
# TODO: raise NotSupportedError
324+
raise SQLiteCloudException("set_authorizer() is not supported.")
325+
326+
def set_progress_handler(self, handler, n):
327+
# TODO: raise NotSupportedError
328+
raise SQLiteCloudException("set_progress_handler() is not supported.")
329+
330+
def set_trace_callback(self, trace_callback):
331+
# TODO: raise NotSupportedError
332+
raise SQLiteCloudException("set_trace_callback() is not supported.")
333+
334+
def enable_load_extension(self, enable):
335+
# TODO: raise NotSupportedError
336+
raise SQLiteCloudException("enable_load_extension() is not supported.")
337+
338+
def load_extension(path):
339+
# TODO: raise NotSupportedError
340+
raise SQLiteCloudException("load_extension() is not supported.")
341+
342+
def iterdump(self):
343+
# TODO: raise NotSupportedError
344+
raise SQLiteCloudException("iterdump() is not supported.")
345+
256346
def close(self):
257347
"""
258348
Closes the database connection.
@@ -277,7 +367,7 @@ def commit(self):
277367
and "no transaction is active" in e.errmsg
278368
):
279369
# compliance to sqlite3
280-
logging.warning(e)
370+
logging.debug(e)
281371

282372
def rollback(self):
283373
"""
@@ -297,7 +387,7 @@ def rollback(self):
297387
and "no transaction is active" in e.errmsg
298388
):
299389
# compliance to sqlite3
300-
logging.warning(e)
390+
logging.debug(e)
301391

302392
def cursor(self):
303393
"""
@@ -606,10 +696,20 @@ def fetchall(self) -> List[Any]:
606696
return self.fetchmany(self.rowcount)
607697

608698
def setinputsizes(self, sizes) -> None:
609-
pass
699+
# TODO: raise NotSupportedError
700+
raise SQLiteCloudException("setinputsizes() is not supported.")
610701

611702
def setoutputsize(self, size, column=None) -> None:
612-
pass
703+
# TODO: raise NotSupportedError
704+
raise SQLiteCloudException("setoutputsize() is not supported.")
705+
706+
def scroll(value, mode="relative"):
707+
# TODO: raise NotSupportedError
708+
raise SQLiteCloudException("scroll() is not supported.")
709+
710+
def messages(self):
711+
# TODO: raise NotSupportedError
712+
raise SQLiteCloudException("messages() is not supported.")
613713

614714
def _call_row_factory(self, row: Tuple) -> object:
615715
if self.row_factory is None:
@@ -842,6 +942,18 @@ def __init__(self, message: str) -> None:
842942
self.message = message
843943

844944

945+
def DateFromTicks(ticks):
946+
return Date(*time.localtime(ticks)[:3])
947+
948+
949+
def TimeFromTicks(ticks):
950+
return Time(*time.localtime(ticks)[3:6])
951+
952+
953+
def TimestampFromTicks(ticks):
954+
return Timestamp(*time.localtime(ticks)[:6])
955+
956+
845957
def register_adapters_and_converters():
846958
"""
847959
sqlite3 default adapters and converters.
@@ -858,7 +970,7 @@ def adapt_datetime(val):
858970
return val.isoformat(" ")
859971

860972
def convert_date(val):
861-
return date(*map(int, val.split(b"-")))
973+
return datetime.date(*map(int, val.split(b"-")))
862974

863975
def convert_timestamp(val):
864976
datepart, timepart = val.split(b" ")
@@ -870,13 +982,14 @@ def convert_timestamp(val):
870982
else:
871983
microseconds = 0
872984

873-
val = datetime(year, month, day, hours, minutes, seconds, microseconds)
985+
val = datetime.datetime(year, month, day, hours, minutes, seconds, microseconds)
874986
return val
875987

876-
register_adapter(date, adapt_date)
877-
register_adapter(datetime, adapt_datetime)
988+
register_adapter(datetime.date, adapt_date)
989+
register_adapter(datetime.datetime, adapt_datetime)
878990
register_converter("date", convert_date)
879991
register_converter("timestamp", convert_timestamp)
880992

881993

882994
register_adapters_and_converters()
995+
collections.abc.Sequence.register(Row)

0 commit comments

Comments
 (0)