Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit eb91431

Browse files
authored
Added typing stub file (#48)
This adds a stub file, adding type hints in Python. This added the `connect` function as well as the `Connection` and `Cursor` classes. Everything is in the `libsql_experimental.pyi` file. According to [this](https://pyo3.rs/v0.21.0-beta.0/python-typing-hints#if-you-do-not-have-other-python-files) PyO3 documentation, as long as there is no other Python files (excluding examples) Maturin will automatically install this file correctly, adding `__init__.pyi` and `py.typed` to site-packages. Below is a before and after example for the `connect` function. If there is anything I missed or misunderstood, let me know and ill fix it :) ![before](https://github.com/tursodatabase/libsql-experimental-python/assets/42066957/e890f7c7-1f06-4980-8d89-1e3ee604190f) ![image](https://github.com/tursodatabase/libsql-experimental-python/assets/42066957/b4c6c23e-df29-4c0b-96de-8d2cc72caed6)
2 parents 8e342c0 + 7fa1884 commit eb91431

File tree

3 files changed

+93
-1
lines changed

3 files changed

+93
-1
lines changed

‎.github/workflows/pr-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,6 @@ jobs:
3636
run: |
3737
python3 -m venv .env # maturin requires a virtualenv
3838
source .env/bin/activate
39-
pip3 install maturin pytest
39+
pip3 install maturin pytest mypy
4040
maturin develop
4141
pytest

‎libsql_experimental.pyi

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""libSQL's experimental Python implementation"""
2+
3+
from typing import Any, Self, final
4+
5+
6+
paramstyle = "qmark"
7+
sqlite_version_info = (3, 42, 0)
8+
Error = Exception
9+
LEGACY_TRANSACTION_CONTROL: int = -1
10+
11+
12+
@final
13+
class Cursor:
14+
"""libSQL database cursor.
15+
16+
Implements a superset of the [DB-API 2.0 (PEP249)](https://peps.python.org/pep-0249/) Cursor object protocol.""" # noqa: E501
17+
arraysize: int
18+
19+
@property
20+
def description(self) -> tuple[tuple[Any, ...], ...] | None: ...
21+
22+
@property
23+
def rowcount(self) -> int: ...
24+
25+
@property
26+
def lastrowid(self) -> int | None: ...
27+
28+
def close(self) -> None: ...
29+
def execute(self, sql: str, parameters: tuple[Any, ...] = ...) -> Self: ...
30+
def executemany(self, sql: str, parameters: list[tuple[Any, ...]] = ...) -> Self: ... # noqa: E501
31+
def executescript(self, script: str) -> Self: ...
32+
def fetchone(self) -> tuple[Any, ...] | None: ...
33+
def fetchmany(self, size: int = ...) -> list[tuple[Any, ...]]: ... # noqa: E501
34+
def fetchall(self) -> list[tuple[Any, ...]]: ...
35+
36+
37+
@final
38+
class Connection:
39+
"""libSQL database connection.
40+
41+
Implements a superset of the [DB-API 2.0 (PEP249)](https://peps.python.org/pep-0249/) Connection object protocol.""" # noqa: E501
42+
@property
43+
def isolation_level(self) -> str | None: ...
44+
45+
@property
46+
def in_transaction(self) -> bool: ...
47+
48+
def commit(self) -> None: ...
49+
def cursor(self) -> Cursor: ...
50+
def sync(self) -> None: ...
51+
def rollback(self) -> None: ...
52+
def execute(self, sql: str, parameters: tuple[Any, ...] = ...) -> Cursor: ... # noqa: E501
53+
def executemany(self, sql: str, parameters: list[tuple[Any, ...]] = ...) -> Cursor: ... # noqa: E501
54+
def executescript(self, script: str) -> None: ...
55+
56+
57+
def connect(database: str,
58+
isolation_level: str | None = ...,
59+
check_same_thread: bool = True,
60+
uri: bool = False,
61+
sync_url: str = ...,
62+
sync_interval: float = ...,
63+
auth_token: str = ...,
64+
encryption_key: str = ...) -> Connection:
65+
"""Open a new libSQL connection, return a Connection object."""

‎tests/test_suite.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,33 @@ def test_int64(provider):
298298
res = cur.execute("SELECT * FROM data")
299299
assert [(1, 1099511627776)] == res.fetchall()
300300

301+
def test_type_adherence(capsys):
302+
try:
303+
from mypy.stubtest import test_stubs, parse_options
304+
except (ImportError, ModuleNotFoundError):
305+
# skip test if mypy not installed
306+
pytest.skip("Cant test type stubs without mypy installed")
307+
308+
# run mypy stubtest tool. Equivalent to running the following the terminal
309+
"""
310+
stubtest --concise libsql_experimental | \
311+
grep -v 'which is incompatible with stub argument type'
312+
"""
313+
test_stubs(parse_options(["--concise", "libsql_experimental"]))
314+
cap = capsys.readouterr()
315+
316+
# this is part of error reported if is default parameter is ellipsis
317+
# `arg: type = ...` which is a nicer way to hide implementation from user
318+
# than having the more "correct" `arg: type | None = None` everywhere
319+
ellipsis_err = "which is incompatible with stub argument type"
320+
321+
lines = cap.out.split("\n")
322+
lines = filter(lambda x: ellipsis_err not in x, lines) # filter false positives from ellipsis
323+
lines = filter(lambda x: len(x) != 0, lines) # filter empty lines
324+
325+
# there will always be one error which i dont know how to get rid of
326+
# `libsql_experimental.libsql_experimental failed to find stubs`
327+
assert len(list(lines)) == 1
301328

302329
def connect(provider, database, isolation_level="DEFERRED", autocommit=-1):
303330
if provider == "libsql-remote":

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /