Skip to content

Commit 54fb12a

Browse files
Declare __all__ on base and requirements modules
Every public sqlalchemydqlite module now lists its public surface in a module-level ``__all__``. ``base.py`` exposes only ``DqliteDialect``; ``requirements.py`` exposes only ``Requirements`` (the bare class name is intentional — SQLAlchemy's test suite looks it up under that exact name). Private helpers (``_DqliteDateTime``, ``_DqliteDate``, ``_parse_url_bool``) remain omitted. New ``tests/test_public_api.py`` pins each module's ``__all__`` set and verifies ``from ... import *`` does not leak private names. Also pick up the matching ``requires-dist`` / ``provides-extras`` entries in uv.lock for the editable dqlite-wire install. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5a25c10 commit 54fb12a

4 files changed

Lines changed: 63 additions & 7 deletions

File tree

src/sqlalchemydqlite/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import dqlitedbapi.exceptions as _dbapi_exc
1919
from dqlitewire import LEADER_ERROR_CODES as _LEADER_CHANGE_CODES
2020

21+
__all__ = ["DqliteDialect"]
22+
2123
_TRUE_TOKENS = frozenset({"1", "true", "yes", "on"})
2224
_FALSE_TOKENS = frozenset({"0", "false", "no", "off"})
2325

src/sqlalchemydqlite/requirements.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from sqlalchemy.testing import exclusions
88
from sqlalchemy.testing.requirements import SuiteRequirements
99

10+
__all__ = ["Requirements"]
11+
1012

1113
class Requirements(SuiteRequirements):
1214
"""Test suite requirements for dqlite dialect.

tests/test_public_api.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""Pin the public surface of each sqlalchemydqlite module.
2+
3+
Every public module declares ``__all__`` listing its public names.
4+
These tests guard against accidental leakage of private helpers and
5+
against drift in the public-class set. See ISSUE-112 / 131 / 180
6+
precedents for the policy.
7+
"""
8+
9+
import sqlalchemydqlite
10+
import sqlalchemydqlite.aio
11+
import sqlalchemydqlite.base
12+
import sqlalchemydqlite.requirements
13+
14+
15+
def test_package_all_is_minimal() -> None:
16+
assert set(sqlalchemydqlite.__all__) == {"DqliteDialect"}
17+
18+
19+
def test_base_all_is_minimal() -> None:
20+
assert set(sqlalchemydqlite.base.__all__) == {"DqliteDialect"}
21+
22+
23+
def test_requirements_all_is_minimal() -> None:
24+
assert set(sqlalchemydqlite.requirements.__all__) == {"Requirements"}
25+
26+
27+
def test_aio_all_contains_public_adapter_classes() -> None:
28+
assert {"AsyncAdaptedConnection", "AsyncAdaptedCursor", "DqliteDialect_aio"}.issubset(
29+
set(sqlalchemydqlite.aio.__all__)
30+
)
31+
32+
33+
def test_star_import_base_does_not_leak_private() -> None:
34+
"""``from sqlalchemydqlite.base import *`` must not expose private helpers.
35+
36+
``_DqliteDateTime``, ``_DqliteDate``, ``_parse_url_bool`` are
37+
private module-level symbols. A bare ``__all__ = ["DqliteDialect"]``
38+
guarantees ``import *`` omits them.
39+
"""
40+
namespace: dict[str, object] = {}
41+
exec("from sqlalchemydqlite.base import *", namespace) # noqa: S102
42+
assert "DqliteDialect" in namespace
43+
assert "_DqliteDateTime" not in namespace
44+
assert "_DqliteDate" not in namespace
45+
assert "_parse_url_bool" not in namespace
46+
47+
48+
def test_star_import_requirements_does_not_leak_private() -> None:
49+
namespace: dict[str, object] = {}
50+
exec("from sqlalchemydqlite.requirements import *", namespace) # noqa: S102
51+
assert "Requirements" in namespace
52+
# Defensive: confirm no SuiteRequirements leakage from the import alias path.
53+
assert "SuiteRequirements" not in namespace

uv.lock

Lines changed: 6 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)