dbression 0.1.2__tar.gz → 0.2.0__tar.gz
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.
- {dbression-0.1.2 → dbression-0.2.0}/CHANGELOG.md +14 -1
- {dbression-0.1.2 → dbression-0.2.0}/PKG-INFO +10 -4
- {dbression-0.1.2 → dbression-0.2.0}/README.md +8 -2
- dbression-0.2.0/docs/dbression_head.png +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/pyproject.toml +2 -1
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/db/engine.py +27 -0
- dbression-0.2.0/tests/test_sqlite_engine.py +60 -0
- {dbression-0.1.2 → dbression-0.2.0}/uv.lock +1 -1
- {dbression-0.1.2 → dbression-0.2.0}/.github/workflows/ci.yml +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/.github/workflows/publish.yml +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/.gitignore +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/.python-version +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/LICENSE +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/01-hello/HelloSql.test.md +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/01-hello/_root.wiki +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/01-hello/connection.properties +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/02-stored-procedure/BumpCounterTest.test.md +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/02-stored-procedure/SuiteSetUp.test.md +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/02-stored-procedure/SuiteTearDown.test.md +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/02-stored-procedure/_root.wiki +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/02-stored-procedure/connection.properties +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/03-schema-drift/SchemaSnapshotTest.test.md +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/03-schema-drift/SuiteSetUp.test.md +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/03-schema-drift/SuiteTearDown.test.md +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/03-schema-drift/_root.wiki +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/03-schema-drift/connection.properties +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/examples/README.md +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/__init__.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/cli.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/db/__init__.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/db/connection.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/db/errors.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/fixtures/__init__.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/fixtures/base.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/fixtures/basic.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/fixtures/inspect_and_store.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/fixtures/plugins.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/fixtures/suite_fixtures.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/parser/__init__.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/parser/ast.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/parser/markdown.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/parser/markdown_writer.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/parser/tokenizer.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/parser/wiki.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/report/__init__.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/report/console.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/report/json_report.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/report/junit.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/runner.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/src/dbression/symbols.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/conftest.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_connection.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_markdown_parser.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_markdown_roundtrip.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_parser.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_phase2_fixtures.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_plugins.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_postgres_live.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_report_junit.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_smoke.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_symbols.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_tokenizer.py +0 -0
- {dbression-0.1.2 → dbression-0.2.0}/tests/test_update_fixture.py +0 -0
|
@@ -7,6 +7,18 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.0] — 2026-06-01
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **SQLite as a `DatabaseEnvironment`.** Use `DatabaseEnvironment | sqlite` (alias
|
|
15
|
+
`sqlite3`) with `service=:memory:` or `service=<path-to-db-file>` in
|
|
16
|
+
`connection.properties`. No native deps — uses the Python stdlib `sqlite3`
|
|
17
|
+
driver via SQLAlchemy. `Execute Procedure` does not apply (SQLite has no
|
|
18
|
+
stored procedures); everything else (`Query`, `Execute`, `Insert`, `Delete`,
|
|
19
|
+
`Inspect *`, `Update`, captures, substitutions) works the same as on the
|
|
20
|
+
other backends.
|
|
21
|
+
|
|
10
22
|
## [0.1.2] — 2026-06-01
|
|
11
23
|
|
|
12
24
|
SQL Server live-verification release. A real-world MSSQL DBFit suite (WD-Gehsteig
|
|
@@ -120,7 +132,8 @@ with code paths in place for SQL Server and Oracle.
|
|
|
120
132
|
reject `python-oracledb` thin-mode authentication. Configuration is via
|
|
121
133
|
`DBRESSION_ORACLE_CLIENT_LIB_DIR`.
|
|
122
134
|
|
|
123
|
-
[Unreleased]: https://github.com/angrydat/dbression/compare/v0.
|
|
135
|
+
[Unreleased]: https://github.com/angrydat/dbression/compare/v0.2.0...HEAD
|
|
136
|
+
[0.2.0]: https://github.com/angrydat/dbression/releases/tag/v0.2.0
|
|
124
137
|
[0.1.2]: https://github.com/angrydat/dbression/releases/tag/v0.1.2
|
|
125
138
|
[0.1.1]: https://github.com/angrydat/dbression/releases/tag/v0.1.1
|
|
126
139
|
[0.1.0]: https://github.com/angrydat/dbression/releases/tag/v0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dbression
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Rage-quit your flaky DB regressions — modern, lightweight, multi-DB regression testing.
|
|
5
5
|
Project-URL: Homepage, https://angrydata.info/dbression
|
|
6
6
|
Project-URL: Repository, https://github.com/angrydat/dbression
|
|
@@ -9,7 +9,7 @@ Project-URL: Changelog, https://github.com/angrydat/dbression/blob/main/CHANGELO
|
|
|
9
9
|
Author-email: Jürgen Zornig <info@angrydata.info>
|
|
10
10
|
License: MIT
|
|
11
11
|
License-File: LICENSE
|
|
12
|
-
Keywords: database,dbfit,fitnesse,markdown,oracle,postgres,regression,sql,sqlserver,testing
|
|
12
|
+
Keywords: database,dbfit,fitnesse,markdown,oracle,postgres,regression,sql,sqlite,sqlserver,testing
|
|
13
13
|
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Environment :: Console
|
|
15
15
|
Classifier: Intended Audience :: Developers
|
|
@@ -35,6 +35,10 @@ Requires-Dist: sqlalchemy>=2.0
|
|
|
35
35
|
Requires-Dist: typer>=0.12
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
|
|
38
|
+
<p align="center">
|
|
39
|
+
<img src="https://raw.githubusercontent.com/angrydat/dbression/main/docs/dbression_head.png" alt="dbression — database regression testing for schema changes, migrations, and critical queries" width="820">
|
|
40
|
+
</p>
|
|
41
|
+
|
|
38
42
|
# dbression
|
|
39
43
|
|
|
40
44
|
> ### Rage-quit your flaky DB regressions.
|
|
@@ -48,7 +52,7 @@ anywhere. `dbression` is a Python re-implementation in the spirit of the fantast
|
|
|
48
52
|
|
|
49
53
|
```text
|
|
50
54
|
$ dbression run tests/
|
|
51
|
-
dbression 0.
|
|
55
|
+
dbression 0.2.0 — Suite: tests @ postgresql+psycopg://wlk:***@db01/wlk
|
|
52
56
|
|
|
53
57
|
✓ HelloSql 0.004s
|
|
54
58
|
CommonSuite/
|
|
@@ -92,7 +96,8 @@ the model gets every detail it needs to suggest a fix, no screenshots, no contex
|
|
|
92
96
|
|
|
93
97
|
```bash
|
|
94
98
|
# install (we use uv, but pip works too)
|
|
95
|
-
uv tool install
|
|
99
|
+
uv tool install dbression # or: pipx install dbression
|
|
100
|
+
# or: pip install dbression
|
|
96
101
|
|
|
97
102
|
# run
|
|
98
103
|
dbression run tests/
|
|
@@ -328,6 +333,7 @@ Postgres, Oracle and SQL Server. Honest state of the parts:
|
|
|
328
333
|
| PostgreSQL | ✅ verified against a real-world suite |
|
|
329
334
|
| Oracle | ✅ verified against a real-world 19c suite via `oracledb` (thin) |
|
|
330
335
|
| SQL Server | ✅ verified against a real-world suite via `pymssql` |
|
|
336
|
+
| SQLite | ✅ via stdlib `sqlite3` — no procedures (the DB has none) |
|
|
331
337
|
| JUnit XML + JSON output | ✅ |
|
|
332
338
|
| `.test.md` native Markdown format + `dbression convert` | ✅ |
|
|
333
339
|
| Plugin entry-points for custom fixtures | ✅ |
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/angrydat/dbression/main/docs/dbression_head.png" alt="dbression — database regression testing for schema changes, migrations, and critical queries" width="820">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# dbression
|
|
2
6
|
|
|
3
7
|
> ### Rage-quit your flaky DB regressions.
|
|
@@ -11,7 +15,7 @@ anywhere. `dbression` is a Python re-implementation in the spirit of the fantast
|
|
|
11
15
|
|
|
12
16
|
```text
|
|
13
17
|
$ dbression run tests/
|
|
14
|
-
dbression 0.
|
|
18
|
+
dbression 0.2.0 — Suite: tests @ postgresql+psycopg://wlk:***@db01/wlk
|
|
15
19
|
|
|
16
20
|
✓ HelloSql 0.004s
|
|
17
21
|
CommonSuite/
|
|
@@ -55,7 +59,8 @@ the model gets every detail it needs to suggest a fix, no screenshots, no contex
|
|
|
55
59
|
|
|
56
60
|
```bash
|
|
57
61
|
# install (we use uv, but pip works too)
|
|
58
|
-
uv tool install
|
|
62
|
+
uv tool install dbression # or: pipx install dbression
|
|
63
|
+
# or: pip install dbression
|
|
59
64
|
|
|
60
65
|
# run
|
|
61
66
|
dbression run tests/
|
|
@@ -291,6 +296,7 @@ Postgres, Oracle and SQL Server. Honest state of the parts:
|
|
|
291
296
|
| PostgreSQL | ✅ verified against a real-world suite |
|
|
292
297
|
| Oracle | ✅ verified against a real-world 19c suite via `oracledb` (thin) |
|
|
293
298
|
| SQL Server | ✅ verified against a real-world suite via `pymssql` |
|
|
299
|
+
| SQLite | ✅ via stdlib `sqlite3` — no procedures (the DB has none) |
|
|
294
300
|
| JUnit XML + JSON output | ✅ |
|
|
295
301
|
| `.test.md` native Markdown format + `dbression convert` | ✅ |
|
|
296
302
|
| Plugin entry-points for custom fixtures | ✅ |
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dbression"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "Rage-quit your flaky DB regressions — modern, lightweight, multi-DB regression testing."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -16,6 +16,7 @@ keywords = [
|
|
|
16
16
|
"postgres",
|
|
17
17
|
"oracle",
|
|
18
18
|
"sqlserver",
|
|
19
|
+
"sqlite",
|
|
19
20
|
"sql",
|
|
20
21
|
"markdown",
|
|
21
22
|
"fitnesse",
|
|
@@ -41,6 +41,7 @@ def _maybe_init_oracle_thick() -> None:
|
|
|
41
41
|
_POSTGRES_ALIASES = {"postgres", "postgresql", "pg"}
|
|
42
42
|
_ORACLE_ALIASES = {"oracle"}
|
|
43
43
|
_MSSQL_ALIASES = {"sqlserver", "mssql", "ms-sql"}
|
|
44
|
+
_SQLITE_ALIASES = {"sqlite", "sqlite3"}
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
def make_engine(environment: str, config: ConnectionConfig) -> Engine:
|
|
@@ -55,6 +56,8 @@ def make_engine(environment: str, config: ConnectionConfig) -> Engine:
|
|
|
55
56
|
url = _build_oracle_url(config, extra)
|
|
56
57
|
elif env in _MSSQL_ALIASES:
|
|
57
58
|
url = _build_mssql_url(config, extra)
|
|
59
|
+
elif env in _SQLITE_ALIASES:
|
|
60
|
+
url = _build_sqlite_url(config, extra)
|
|
58
61
|
else:
|
|
59
62
|
raise ValueError(f"Unknown DatabaseEnvironment: {environment!r}")
|
|
60
63
|
|
|
@@ -116,6 +119,30 @@ def _build_mssql_url(cfg: ConnectionConfig, extra: dict[str, str]) -> URL | str:
|
|
|
116
119
|
)
|
|
117
120
|
|
|
118
121
|
|
|
122
|
+
def _build_sqlite_url(cfg: ConnectionConfig, extra: dict[str, str]) -> URL | str:
|
|
123
|
+
"""SQLite via the Python stdlib ``sqlite3`` driver. No native deps.
|
|
124
|
+
|
|
125
|
+
Path source order:
|
|
126
|
+
|
|
127
|
+
* ``connection-string=sqlite:///…`` — taken verbatim
|
|
128
|
+
* ``service=:memory:`` — in-memory DB
|
|
129
|
+
* ``service=<file-path>`` — file-backed DB (absolute or relative)
|
|
130
|
+
* ``database=<file-path>`` (extras) — fallback alias
|
|
131
|
+
|
|
132
|
+
SQLite has no auth — ``username`` / ``password`` in connection.properties are
|
|
133
|
+
ignored. Stored procedures and `Execute Procedure` won't work (SQLite has none).
|
|
134
|
+
"""
|
|
135
|
+
if cfg.connection_string:
|
|
136
|
+
return cfg.connection_string
|
|
137
|
+
path = cfg.service or extra.get("database") or ":memory:"
|
|
138
|
+
# SQLAlchemy SQLite URLs:
|
|
139
|
+
# sqlite:///:memory: — in-memory
|
|
140
|
+
# sqlite:///relative.db — relative to cwd (3 slashes)
|
|
141
|
+
# sqlite:////abs/path.db — absolute (4 slashes; the leading `/` of the path
|
|
142
|
+
# concatenates with the 3-slash prefix)
|
|
143
|
+
return f"sqlite:///{path}"
|
|
144
|
+
|
|
145
|
+
|
|
119
146
|
def _split_host_port(service: str | None) -> tuple[str | None, int | None]:
|
|
120
147
|
if not service:
|
|
121
148
|
return None, None
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""SQLite engine smoke test — confirm the DatabaseEnvironment dispatch and end-to-end
|
|
2
|
+
Query / Execute against an in-memory SQLite DB."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from sqlalchemy import text
|
|
6
|
+
|
|
7
|
+
from dbression.db.connection import ConnectionConfig
|
|
8
|
+
from dbression.db.engine import make_engine
|
|
9
|
+
from dbression.fixtures import resolve_fixture
|
|
10
|
+
from dbression.fixtures.base import FixtureContext
|
|
11
|
+
from dbression.parser.ast import Table
|
|
12
|
+
from dbression.symbols import SymbolTable
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _ctx(conn):
|
|
16
|
+
return FixtureContext(conn=conn, symbols=SymbolTable(), stored={})
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_sqlite_memory_via_database_environment():
|
|
20
|
+
cfg = ConnectionConfig(service=":memory:")
|
|
21
|
+
eng = make_engine("sqlite", cfg)
|
|
22
|
+
with eng.connect() as c:
|
|
23
|
+
assert c.execute(text("select 1")).scalar() == 1
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_sqlite_file_path_url_shape(tmp_path):
|
|
27
|
+
db = tmp_path / "x.db"
|
|
28
|
+
cfg = ConnectionConfig(service=str(db))
|
|
29
|
+
eng = make_engine("sqlite", cfg)
|
|
30
|
+
# Absolute path → 4 slashes
|
|
31
|
+
assert str(eng.url).startswith("sqlite:////")
|
|
32
|
+
with eng.connect() as c:
|
|
33
|
+
c.execute(text("create table t (a int)"))
|
|
34
|
+
c.execute(text("insert into t values (42)"))
|
|
35
|
+
assert c.execute(text("select a from t")).scalar() == 42
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_sqlite_runs_query_fixture():
|
|
39
|
+
cfg = ConnectionConfig(service=":memory:")
|
|
40
|
+
eng = make_engine("sqlite", cfg)
|
|
41
|
+
with eng.begin() as conn:
|
|
42
|
+
conn.execute(text("create table t (n int, name text)"))
|
|
43
|
+
conn.execute(text("insert into t values (1, 'a'), (2, 'b')"))
|
|
44
|
+
with eng.connect() as conn:
|
|
45
|
+
cls = resolve_fixture("Query")
|
|
46
|
+
tbl = Table(
|
|
47
|
+
name="Query",
|
|
48
|
+
header_args=["select n, name from t order by n"],
|
|
49
|
+
headers=["n", "name"],
|
|
50
|
+
rows=[["1", "a"], ["2", "b"]],
|
|
51
|
+
)
|
|
52
|
+
res = cls().run(tbl, _ctx(conn))
|
|
53
|
+
assert res.passed, res.message
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_sqlite_alias_sqlite3_also_works():
|
|
57
|
+
cfg = ConnectionConfig(service=":memory:")
|
|
58
|
+
eng = make_engine("sqlite3", cfg)
|
|
59
|
+
with eng.connect() as c:
|
|
60
|
+
assert c.execute(text("select 1")).scalar() == 1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|