ducpy 3.3.7__tar.gz → 3.3.8__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.
- {ducpy-3.3.7 → ducpy-3.3.8}/Cargo.lock +1 -1
- {ducpy-3.3.7 → ducpy-3.3.8}/PKG-INFO +1 -1
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducpy/crate/Cargo.toml +1 -1
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducpy/crate/src/lib.rs +45 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/Cargo.toml +1 -3
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/build.rs +20 -16
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/db/bootstrap.rs +14 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/db/mod.rs +1 -1
- {ducpy-3.3.7 → ducpy-3.3.8}/pyproject.toml +0 -2
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/builders/sql_builder.py +16 -56
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/serialize.py +2 -55
- ducpy-3.3.8/src/ducpy_native/__init__.py +28 -0
- ducpy-3.3.7/src/ducpy/_version.py +0 -3
- ducpy-3.3.7/src/ducpy_native/__init__.py +0 -19
- {ducpy-3.3.7 → ducpy-3.3.8}/Cargo.toml +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/LICENSE +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/README.md +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/LICENSE +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/README.md +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8/packages/ducrs}/schema/duc.sql +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8/packages/ducrs}/schema/migrations/3000000_to_3000001.sql +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8/packages/ducrs}/schema/migrations/3000001_to_3000002.sql +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8/packages/ducrs}/schema/migrations/3000002_to_3000003.sql +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8/packages/ducrs}/schema/migrations/3000003_to_3000004.sql +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8/packages/ducrs}/schema/search.sql +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8/packages/ducrs}/schema/version_control.sql +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/api/document.rs +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/api/meta.rs +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/api/mod.rs +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/api/version_control.rs +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/db/native.rs +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/db/wasm.rs +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/lib.rs +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/parse.rs +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/serde_utils.rs +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/serialize.rs +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/packages/ducrs/src/types.rs +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/__init__.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/builders/__init__.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/builders/block_instance_builder.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/builders/block_utils.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/builders/element_builders.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/builders/mutate_builder.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/builders/state_builders.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/builders/style_builders.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/classes/DataStateClass.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/classes/ElementsClass.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/classes/__init__.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/enums.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/parse.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/search/__init__.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/search/search_elements.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/utils/__init__.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/utils/constants.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/utils/convert.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/utils/io.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/utils/mutate_utils.py +0 -0
- {ducpy-3.3.7 → ducpy-3.3.8}/src/ducpy/utils/rand_utils.py +0 -0
|
@@ -58,6 +58,45 @@ fn list_external_files(py: Python<'_>, buf: &[u8]) -> PyResult<PyObject> {
|
|
|
58
58
|
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("{e}")))
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/// Returns the current DUC schema version as a semver string (e.g. "3.0.0").
|
|
62
|
+
#[pyfunction]
|
|
63
|
+
fn get_schema_version() -> PyResult<String> {
|
|
64
|
+
Ok(duc::db::bootstrap::CURRENT_SCHEMA_VERSION_SEMVER.into())
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// Returns the raw integer schema version (e.g. 3000000).
|
|
68
|
+
#[pyfunction]
|
|
69
|
+
fn get_schema_version_int() -> PyResult<i64> {
|
|
70
|
+
Ok(duc::db::bootstrap::current_schema_version_int())
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/// Returns the canonical `duc.sql` schema string.
|
|
74
|
+
#[pyfunction]
|
|
75
|
+
fn get_duc_schema_sql() -> PyResult<String> {
|
|
76
|
+
Ok(duc::db::bootstrap::DUC_SCHEMA_SQL.into())
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// Returns the `version_control.sql` schema string.
|
|
80
|
+
#[pyfunction]
|
|
81
|
+
fn get_version_control_schema_sql() -> PyResult<String> {
|
|
82
|
+
Ok(duc::db::bootstrap::VERSION_CONTROL_SCHEMA_SQL.into())
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/// Returns the `search.sql` schema string.
|
|
86
|
+
#[pyfunction]
|
|
87
|
+
fn get_search_schema_sql() -> PyResult<String> {
|
|
88
|
+
Ok(duc::db::bootstrap::SEARCH_SCHEMA_SQL.into())
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/// Returns all migrations as a list of `(from_version, to_version, sql)` tuples.
|
|
92
|
+
#[pyfunction]
|
|
93
|
+
fn get_migrations(_py: Python<'_>) -> PyResult<Vec<(i64, i64, String)>> {
|
|
94
|
+
Ok(duc::db::bootstrap::MIGRATIONS
|
|
95
|
+
.iter()
|
|
96
|
+
.map(|(f, t, sql)| (*f, *t, sql.to_string()))
|
|
97
|
+
.collect())
|
|
98
|
+
}
|
|
99
|
+
|
|
61
100
|
/// Native duc file format operations.
|
|
62
101
|
#[pymodule]
|
|
63
102
|
fn ducpy_native(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
@@ -66,5 +105,11 @@ fn ducpy_native(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
|
66
105
|
m.add_function(wrap_pyfunction!(serialize_duc, m)?)?;
|
|
67
106
|
m.add_function(wrap_pyfunction!(get_external_file, m)?)?;
|
|
68
107
|
m.add_function(wrap_pyfunction!(list_external_files, m)?)?;
|
|
108
|
+
m.add_function(wrap_pyfunction!(get_schema_version, m)?)?;
|
|
109
|
+
m.add_function(wrap_pyfunction!(get_schema_version_int, m)?)?;
|
|
110
|
+
m.add_function(wrap_pyfunction!(get_duc_schema_sql, m)?)?;
|
|
111
|
+
m.add_function(wrap_pyfunction!(get_version_control_schema_sql, m)?)?;
|
|
112
|
+
m.add_function(wrap_pyfunction!(get_search_schema_sql, m)?)?;
|
|
113
|
+
m.add_function(wrap_pyfunction!(get_migrations, m)?)?;
|
|
69
114
|
Ok(())
|
|
70
115
|
}
|
|
@@ -25,6 +25,7 @@ fn decode_user_version_to_semver(user_version: u32) -> String {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
fn find_schema_dir(manifest_dir: &Path) -> Result<PathBuf, Box<dyn std::error::Error>> {
|
|
28
|
+
// 1. Explicit override.
|
|
28
29
|
if let Ok(path) = env::var("DUC_SCHEMA_DIR") {
|
|
29
30
|
let candidate = PathBuf::from(path);
|
|
30
31
|
if candidate.join("duc.sql").is_file() {
|
|
@@ -32,22 +33,25 @@ fn find_schema_dir(manifest_dir: &Path) -> Result<PathBuf, Box<dyn std::error::E
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if candidate.join("duc.sql").is_file() {
|
|
41
|
-
return Ok(candidate);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
36
|
+
// 2. Schema inside the crate directory (symlink in dev, real files after
|
|
37
|
+
// `cargo publish` dereferences the symlink into the tarball).
|
|
38
|
+
let bundled = manifest_dir.join("schema");
|
|
39
|
+
if bundled.join("duc.sql").is_file() {
|
|
40
|
+
return Ok(bundled);
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
// 3. Local workspace: walk up to the repo root `schema/`.
|
|
44
|
+
let source = manifest_dir
|
|
45
|
+
.ancestors()
|
|
46
|
+
.map(|a| a.join("schema"))
|
|
47
|
+
.find(|p| p.join("duc.sql").is_file())
|
|
48
|
+
.ok_or_else(|| {
|
|
49
|
+
format!(
|
|
50
|
+
"Could not locate schema/duc.sql from {}. Set DUC_SCHEMA_DIR to a directory containing duc.sql.",
|
|
51
|
+
manifest_dir.display()
|
|
52
|
+
)
|
|
53
|
+
})?;
|
|
54
|
+
Ok(source)
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
@@ -106,7 +110,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
106
110
|
let mut reg = String::from(
|
|
107
111
|
"// Auto-generated by build.rs — do not edit by hand.\n\
|
|
108
112
|
// Each entry: (from_version, to_version, sql).\n\
|
|
109
|
-
pub
|
|
113
|
+
pub static MIGRATIONS: &[(i64, i64, &str)] = &[\n",
|
|
110
114
|
);
|
|
111
115
|
for (from, to, sql) in &migrations {
|
|
112
116
|
reg.push_str(&format!(" ({from}i64, {to}i64, \""));
|
|
@@ -149,4 +153,4 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
149
153
|
println!("cargo:rerun-if-changed=build.rs");
|
|
150
154
|
|
|
151
155
|
Ok(())
|
|
152
|
-
}
|
|
156
|
+
}
|
|
@@ -32,10 +32,24 @@ const CURRENT_VERSION: i64 = {
|
|
|
32
32
|
val
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
/// Runtime accessor for the compile-time schema version integer.
|
|
36
|
+
pub fn current_schema_version_int() -> i64 {
|
|
37
|
+
CURRENT_VERSION
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
// Migration registry auto-generated by build.rs from `schema/migrations/*.sql`.
|
|
36
41
|
// Each entry is (from_version, to_version, sql). Sorted ascending by from_version.
|
|
37
42
|
include!(concat!(env!("OUT_DIR"), "/migrations_registry.rs"));
|
|
38
43
|
|
|
44
|
+
// ── Public re-exports for downstream crates ─────────────────────────────
|
|
45
|
+
|
|
46
|
+
/// Current schema version as a semver string (generated at build time).
|
|
47
|
+
pub const CURRENT_SCHEMA_VERSION_SEMVER: &str = env!("DUC_SCHEMA_VERSION");
|
|
48
|
+
|
|
49
|
+
pub const DUC_SCHEMA_SQL: &str = DUC_SCHEMA;
|
|
50
|
+
pub const VERSION_CONTROL_SCHEMA_SQL: &str = VERSION_CONTROL_SCHEMA;
|
|
51
|
+
pub const SEARCH_SCHEMA_SQL: &str = SEARCH_SCHEMA;
|
|
52
|
+
|
|
39
53
|
/// Per-connection PRAGMAs that must be re-applied on every open (they are
|
|
40
54
|
/// either ephemeral or take effect only after the first statement on the
|
|
41
55
|
/// connection).
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//! Call [`open_file`] or [`open_memory`] instead of calling `rusqlite::Connection`
|
|
4
4
|
//! directly. Internally they dispatch to the correct backend for each compile target.
|
|
5
5
|
|
|
6
|
-
mod bootstrap;
|
|
6
|
+
pub mod bootstrap;
|
|
7
7
|
|
|
8
8
|
#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
|
|
9
9
|
mod native;
|
|
@@ -34,8 +34,6 @@ python-packages = ["ducpy", "ducpy_native"]
|
|
|
34
34
|
module-name = "ducpy_native"
|
|
35
35
|
include = [
|
|
36
36
|
{ path = "LICENSE", format = "sdist" },
|
|
37
|
-
{ path = "schema/**/*", format = "sdist" },
|
|
38
|
-
{ path = "schema/**/*", format = "wheel" }
|
|
39
37
|
]
|
|
40
38
|
manifest-path = "packages/ducpy/crate/Cargo.toml"
|
|
41
39
|
python-source = "src"
|
|
@@ -29,67 +29,33 @@ Usage::
|
|
|
29
29
|
from __future__ import annotations
|
|
30
30
|
|
|
31
31
|
import os
|
|
32
|
-
import re
|
|
33
32
|
import sqlite3
|
|
34
33
|
import tempfile
|
|
35
34
|
from pathlib import Path
|
|
36
35
|
from typing import Any, List, Optional, Union
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
_MIGRATION_RE = re.compile(r"^(\d+)_to_(\d+)$")
|
|
37
|
+
import ducpy_native
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
def _find_schema_dir() -> Optional[Path]:
|
|
45
|
-
env_path = os.environ.get("DUC_SCHEMA_DIR")
|
|
46
|
-
if env_path:
|
|
47
|
-
candidate = Path(env_path)
|
|
48
|
-
if (candidate / "duc.sql").exists():
|
|
49
|
-
return candidate
|
|
50
|
-
|
|
51
|
-
current = Path(__file__).resolve()
|
|
52
|
-
for parent in current.parents:
|
|
53
|
-
candidate = parent / "schema"
|
|
54
|
-
if (candidate / "duc.sql").exists():
|
|
55
|
-
return candidate
|
|
56
|
-
return None
|
|
39
|
+
__all__ = ["DucSQL"]
|
|
57
40
|
|
|
58
41
|
|
|
59
42
|
def _get_current_schema_version() -> int:
|
|
60
|
-
"""
|
|
61
|
-
|
|
62
|
-
if schema_dir is None:
|
|
63
|
-
return 0
|
|
64
|
-
duc_sql = (schema_dir / "duc.sql").read_text(encoding="utf-8")
|
|
65
|
-
m = re.search(r"PRAGMA\s+user_version\s*=\s*(\d+)", duc_sql, re.IGNORECASE)
|
|
66
|
-
return int(m.group(1)) if m else 0
|
|
43
|
+
"""Current schema version integer (e.g. 3000000) — from the Rust crate."""
|
|
44
|
+
return ducpy_native.get_schema_version_int()
|
|
67
45
|
|
|
68
46
|
|
|
69
47
|
def _read_migrations() -> list[tuple[int, int, str]]:
|
|
70
|
-
"""
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
migrations_dir = schema_dir / "migrations"
|
|
75
|
-
if not migrations_dir.exists():
|
|
76
|
-
return []
|
|
77
|
-
result: list[tuple[int, int, str]] = []
|
|
78
|
-
for path in sorted(migrations_dir.glob("*.sql")):
|
|
79
|
-
m = _MIGRATION_RE.match(path.stem)
|
|
80
|
-
if m:
|
|
81
|
-
result.append((int(m.group(1)), int(m.group(2)), path.read_text(encoding="utf-8")))
|
|
82
|
-
result.sort(key=lambda x: x[0])
|
|
83
|
-
return result
|
|
48
|
+
"""All migrations as (from_version, to_version, sql) — from the Rust crate."""
|
|
49
|
+
raw = ducpy_native.get_migrations()
|
|
50
|
+
# get_migrations returns list of tuples with i64 values
|
|
51
|
+
return [(int(f), int(t), sql) for f, t, sql in raw]
|
|
84
52
|
|
|
85
53
|
|
|
86
54
|
def _apply_migrations(conn: sqlite3.Connection) -> None:
|
|
87
55
|
"""Walk the migration chain until user_version reaches the current schema version.
|
|
88
56
|
|
|
89
|
-
Mirrors the migration logic in Rust's ``bootstrap.rs
|
|
90
|
-
|
|
91
|
-
them until ``PRAGMA user_version`` matches the version declared in ``duc.sql``.
|
|
92
|
-
Safe to call on already-current or brand-new databases.
|
|
57
|
+
Mirrors the migration logic in Rust's ``bootstrap.rs``. Safe to call on
|
|
58
|
+
already-current or brand-new databases.
|
|
93
59
|
"""
|
|
94
60
|
user_version: int = conn.execute("PRAGMA user_version").fetchone()[0]
|
|
95
61
|
if user_version == 0:
|
|
@@ -112,18 +78,12 @@ def _apply_migrations(conn: sqlite3.Connection) -> None:
|
|
|
112
78
|
|
|
113
79
|
|
|
114
80
|
def _read_schema_sql() -> str:
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
parts: list[str] = []
|
|
122
|
-
for filename in ("duc.sql", "version_control.sql", "search.sql"):
|
|
123
|
-
path = schema_dir / filename
|
|
124
|
-
if path.exists():
|
|
125
|
-
parts.append(path.read_text(encoding="utf-8"))
|
|
126
|
-
return "\n".join(parts)
|
|
81
|
+
"""Concatenate the three schema SQL strings shipped by the Rust crate."""
|
|
82
|
+
return "\n".join([
|
|
83
|
+
ducpy_native.get_duc_schema_sql(),
|
|
84
|
+
ducpy_native.get_version_control_schema_sql(),
|
|
85
|
+
ducpy_native.get_search_schema_sql(),
|
|
86
|
+
])
|
|
127
87
|
|
|
128
88
|
|
|
129
89
|
def _apply_pragmas(conn: sqlite3.Connection) -> None:
|
|
@@ -29,61 +29,8 @@ class DucSerializationValidationError(ValueError):
|
|
|
29
29
|
super().__init__("Embedded code validation failed:\n" + "\n".join(f"- {failure}" for failure in failures))
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if env_path is not None:
|
|
35
|
-
candidate = env_path / "duc.sql"
|
|
36
|
-
if candidate.exists():
|
|
37
|
-
return candidate
|
|
38
|
-
|
|
39
|
-
current = Path(__file__).resolve()
|
|
40
|
-
for parent in current.parents:
|
|
41
|
-
candidate = parent / "schema" / "duc.sql"
|
|
42
|
-
if candidate.exists():
|
|
43
|
-
return candidate
|
|
44
|
-
|
|
45
|
-
return None
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def _decode_user_version_to_semver(user_version: int) -> str:
|
|
49
|
-
"""Decode sqlite-style schema user_version to semver.
|
|
50
|
-
|
|
51
|
-
Encoding convention:
|
|
52
|
-
major * 1_000_000 + minor * 1_000 + patch
|
|
53
|
-
"""
|
|
54
|
-
if user_version < 0:
|
|
55
|
-
return "0.0.0"
|
|
56
|
-
|
|
57
|
-
major = user_version // 1_000_000
|
|
58
|
-
minor = (user_version % 1_000_000) // 1_000
|
|
59
|
-
patch = user_version % 1_000
|
|
60
|
-
return f"{major}.{minor}.{patch}"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def _read_schema_version_fallback() -> str:
|
|
64
|
-
"""Resolve schema version directly from repository `schema/duc.sql`.
|
|
65
|
-
|
|
66
|
-
This is used when `ducpy._version` isn't available (for example, in clean
|
|
67
|
-
CI environments before setup-time generation has run).
|
|
68
|
-
"""
|
|
69
|
-
try:
|
|
70
|
-
schema_path = _find_schema_file()
|
|
71
|
-
if schema_path is None:
|
|
72
|
-
return "0.0.0"
|
|
73
|
-
content = schema_path.read_text(encoding="utf-8")
|
|
74
|
-
match = re.search(r"PRAGMA\s+user_version\s*=\s*(\d+)\s*;", content)
|
|
75
|
-
if match:
|
|
76
|
-
return _decode_user_version_to_semver(int(match.group(1)))
|
|
77
|
-
except Exception as exc: # pragma: no cover - defensive fallback for CI/runtime variance
|
|
78
|
-
logger.warning("Failed to resolve schema version fallback from duc.sql: %s", exc)
|
|
79
|
-
|
|
80
|
-
return "0.0.0"
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
try:
|
|
84
|
-
from ducpy._version import DUC_SCHEMA_VERSION
|
|
85
|
-
except ModuleNotFoundError:
|
|
86
|
-
DUC_SCHEMA_VERSION = _read_schema_version_fallback()
|
|
32
|
+
# Single source of truth for the schema version — comes from the Rust crate.
|
|
33
|
+
DUC_SCHEMA_VERSION = ducpy_native.get_schema_version()
|
|
87
34
|
|
|
88
35
|
# Map Python element class names → Rust serde type tag strings.
|
|
89
36
|
_ELEMENT_CLASS_TO_TYPE: Dict[str, str] = {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Python shim for the compiled :mod:`ducpy_native` extension.
|
|
2
|
+
|
|
3
|
+
When built with maturin (``module-name = "ducpy_native"`` and
|
|
4
|
+
``python-source = "src"``), the compiled extension is emitted as the
|
|
5
|
+
submodule ``ducpy_native.ducpy_native``. Re-export the extension symbols at the
|
|
6
|
+
package root so existing imports like ``import ducpy_native`` continue to work.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .ducpy_native import (get_external_file, # type: ignore[attr-defined]
|
|
10
|
+
list_external_files, parse_duc, parse_duc_lazy,
|
|
11
|
+
serialize_duc, get_schema_version,
|
|
12
|
+
get_schema_version_int, get_duc_schema_sql,
|
|
13
|
+
get_version_control_schema_sql,
|
|
14
|
+
get_search_schema_sql, get_migrations)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"parse_duc",
|
|
18
|
+
"parse_duc_lazy",
|
|
19
|
+
"serialize_duc",
|
|
20
|
+
"get_external_file",
|
|
21
|
+
"list_external_files",
|
|
22
|
+
"get_schema_version",
|
|
23
|
+
"get_schema_version_int",
|
|
24
|
+
"get_duc_schema_sql",
|
|
25
|
+
"get_version_control_schema_sql",
|
|
26
|
+
"get_search_schema_sql",
|
|
27
|
+
"get_migrations",
|
|
28
|
+
]
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"""Python shim for the compiled :mod:`ducpy_native` extension.
|
|
2
|
-
|
|
3
|
-
When built with maturin (``module-name = \"ducpy_native\"`` and
|
|
4
|
-
``python-source = \"src\"``), the compiled extension is emitted as the
|
|
5
|
-
submodule ``ducpy_native.ducpy_native``. Re-export the extension symbols at the
|
|
6
|
-
package root so existing imports like ``import ducpy_native`` continue to work.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from .ducpy_native import (get_external_file, # type: ignore[attr-defined]
|
|
10
|
-
list_external_files, parse_duc, parse_duc_lazy,
|
|
11
|
-
serialize_duc)
|
|
12
|
-
|
|
13
|
-
__all__ = [
|
|
14
|
-
"parse_duc",
|
|
15
|
-
"parse_duc_lazy",
|
|
16
|
-
"serialize_duc",
|
|
17
|
-
"get_external_file",
|
|
18
|
-
"list_external_files",
|
|
19
|
-
]
|
|
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
|