ducpy 3.3.5__tar.gz → 3.3.7__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.5 → ducpy-3.3.7}/Cargo.lock +1 -1
- {ducpy-3.3.5 → ducpy-3.3.7}/PKG-INFO +1 -1
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducpy/crate/Cargo.toml +1 -1
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/Cargo.toml +11 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/parse.rs +34 -5
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/serialize.rs +22 -8
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/types.rs +2 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/pyproject.toml +4 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/schema/duc.sql +12 -2
- ducpy-3.3.7/schema/migrations/3000003_to_3000004.sql +41 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/__init__.py +1 -1
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/builders/element_builders.py +54 -44
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/builders/state_builders.py +3 -3
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/classes/ElementsClass.py +8 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/serialize.py +244 -19
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/utils/__init__.py +2 -1
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/utils/convert.py +58 -6
- ducpy-3.3.5/packages/ducrs/.gitignore +0 -21
- ducpy-3.3.5/packages/ducrs/package.json +0 -13
- ducpy-3.3.5/packages/ducrs/release.config.cjs +0 -31
- ducpy-3.3.5/packages/ducrs/sst-env.d.ts +0 -10
- ducpy-3.3.5/packages/ducrs/tests/.gitignore +0 -2
- ducpy-3.3.5/packages/ducrs/tests/common/mod.rs +0 -1008
- ducpy-3.3.5/packages/ducrs/tests/parser_assets.rs +0 -227
- ducpy-3.3.5/packages/ducrs/tests/synthetic_roundtrip.rs +0 -25
- ducpy-3.3.5/schema/migrations/3000003_to_3000004.sql +0 -20
- {ducpy-3.3.5 → ducpy-3.3.7}/Cargo.toml +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/LICENSE +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/README.md +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducpy/crate/src/lib.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/LICENSE +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/README.md +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/build.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/api/document.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/api/meta.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/api/mod.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/api/version_control.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/db/bootstrap.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/db/mod.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/db/native.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/db/wasm.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/lib.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/packages/ducrs/src/serde_utils.rs +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/schema/migrations/3000000_to_3000001.sql +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/schema/migrations/3000001_to_3000002.sql +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/schema/migrations/3000002_to_3000003.sql +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/schema/search.sql +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/schema/version_control.sql +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/_version.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/builders/__init__.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/builders/block_instance_builder.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/builders/block_utils.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/builders/mutate_builder.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/builders/sql_builder.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/builders/style_builders.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/classes/DataStateClass.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/classes/__init__.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/enums.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/parse.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/search/__init__.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/search/search_elements.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/utils/constants.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/utils/io.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/utils/mutate_utils.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy/utils/rand_utils.py +0 -0
- {ducpy-3.3.5 → ducpy-3.3.7}/src/ducpy_native/__init__.py +0 -0
|
@@ -7,6 +7,17 @@ license = "MIT"
|
|
|
7
7
|
authors = ["Ducflair support@ducflair.com"]
|
|
8
8
|
repository = "https://github.com/ducflair/duc/tree/main/packages/ducrs"
|
|
9
9
|
readme = "README.md"
|
|
10
|
+
include = [
|
|
11
|
+
"src/**",
|
|
12
|
+
"build.rs",
|
|
13
|
+
"Cargo.toml",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"schema/duc.sql",
|
|
17
|
+
"schema/version_control.sql",
|
|
18
|
+
"schema/search.sql",
|
|
19
|
+
"schema/migrations/*.sql",
|
|
20
|
+
]
|
|
10
21
|
|
|
11
22
|
[dependencies]
|
|
12
23
|
base64 = "0.21.5"
|
|
@@ -1460,17 +1460,20 @@ fn read_pdf_element(conn: &Connection, base: DucElementBase) -> ParseResult<DucE
|
|
|
1460
1460
|
}
|
|
1461
1461
|
|
|
1462
1462
|
fn read_doc_element(conn: &Connection, base: DucElementBase) -> ParseResult<DucElementEnum> {
|
|
1463
|
+
let id = base.id.clone();
|
|
1463
1464
|
let (file_id, grid_config) = read_document_grid_config(conn, &base.id)?;
|
|
1464
1465
|
let mut stmt = conn.prepare_cached(
|
|
1465
1466
|
"SELECT text FROM element_doc WHERE element_id = ?1"
|
|
1466
1467
|
)?;
|
|
1467
1468
|
let text: String = stmt.query_row(params![base.id], |row| row.get(0))?;
|
|
1469
|
+
let referenced_file_ids = read_doc_referenced_file_ids(conn, &id)?;
|
|
1468
1470
|
Ok(DucElementEnum::DucDocElement(DucDocElement {
|
|
1469
1471
|
base,
|
|
1470
1472
|
style: DucDocStyle {},
|
|
1471
1473
|
text,
|
|
1472
1474
|
grid_config,
|
|
1473
1475
|
file_id,
|
|
1476
|
+
referenced_file_ids,
|
|
1474
1477
|
}))
|
|
1475
1478
|
}
|
|
1476
1479
|
|
|
@@ -1512,11 +1515,7 @@ fn read_model_element(conn: &Connection, base: DucElementBase) -> ParseResult<Du
|
|
|
1512
1515
|
Ok((row.get::<_, Option<String>>(0)?, row.get::<_, Option<String>>(1)?, row.get::<_, Option<Vec<u8>>>(2)?))
|
|
1513
1516
|
})?;
|
|
1514
1517
|
|
|
1515
|
-
let
|
|
1516
|
-
"SELECT file_id FROM model_element_files WHERE element_id = ?1 ORDER BY sort_order"
|
|
1517
|
-
)?;
|
|
1518
|
-
let file_ids: Vec<String> = f_stmt.query_map(params![id], |row| row.get(0))?
|
|
1519
|
-
.collect::<Result<Vec<_>, _>>()?;
|
|
1518
|
+
let file_ids = read_element_file_ids(conn, &id)?;
|
|
1520
1519
|
|
|
1521
1520
|
let viewer_state = read_model_viewer_state(conn, &id)?;
|
|
1522
1521
|
|
|
@@ -1525,6 +1524,36 @@ fn read_model_element(conn: &Connection, base: DucElementBase) -> ParseResult<Du
|
|
|
1525
1524
|
}))
|
|
1526
1525
|
}
|
|
1527
1526
|
|
|
1527
|
+
fn read_element_file_ids(conn: &Connection, element_id: &str) -> ParseResult<Vec<String>> {
|
|
1528
|
+
let mut stmt = conn.prepare_cached(
|
|
1529
|
+
"SELECT file_id FROM model_element_files WHERE element_id = ?1 ORDER BY sort_order"
|
|
1530
|
+
)?;
|
|
1531
|
+
let file_ids = stmt.query_map(params![element_id], |row| row.get(0))?
|
|
1532
|
+
.collect::<Result<Vec<_>, _>>()?;
|
|
1533
|
+
Ok(file_ids)
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
fn read_doc_referenced_file_ids(conn: &Connection, element_id: &str) -> ParseResult<Vec<String>> {
|
|
1537
|
+
if !table_exists(conn, "doc_element_referenced_files")? {
|
|
1538
|
+
return Ok(Vec::new());
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
let mut stmt = conn.prepare_cached(
|
|
1542
|
+
"SELECT file_id FROM doc_element_referenced_files WHERE element_id = ?1 ORDER BY sort_order"
|
|
1543
|
+
)?;
|
|
1544
|
+
let file_ids = stmt.query_map(params![element_id], |row| row.get(0))?
|
|
1545
|
+
.collect::<Result<Vec<_>, _>>()?;
|
|
1546
|
+
Ok(file_ids)
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
fn table_exists(conn: &Connection, table_name: &str) -> ParseResult<bool> {
|
|
1550
|
+
Ok(conn.query_row(
|
|
1551
|
+
"SELECT EXISTS(SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?1)",
|
|
1552
|
+
params![table_name],
|
|
1553
|
+
|row| row.get::<_, i64>(0),
|
|
1554
|
+
)? != 0)
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1528
1557
|
fn read_model_viewer_state(conn: &Connection, element_id: &str) -> ParseResult<Option<Viewer3DState>> {
|
|
1529
1558
|
let mut stmt = conn.prepare_cached(
|
|
1530
1559
|
"SELECT
|
|
@@ -456,6 +456,7 @@ fn write_element_wrapper(tx: &Transaction, wrapper: &ElementWrapper) -> Serializ
|
|
|
456
456
|
"INSERT INTO element_doc (element_id, text) VALUES (?1, ?2)",
|
|
457
457
|
params![e.base.id, e.text],
|
|
458
458
|
)?;
|
|
459
|
+
write_doc_referenced_file_ids(tx, &e.base.id, &e.referenced_file_ids)?;
|
|
459
460
|
}
|
|
460
461
|
DucElementEnum::DucTableElement(e) => {
|
|
461
462
|
write_base_element(tx, "table", &e.base)?;
|
|
@@ -834,14 +835,7 @@ fn write_model_element(tx: &Transaction, e: &DucModelElement) -> SerializeResult
|
|
|
834
835
|
params![e.base.id, e.model_type, e.code, e.thumbnail],
|
|
835
836
|
)?;
|
|
836
837
|
|
|
837
|
-
|
|
838
|
-
let mut stmt = tx.prepare_cached(
|
|
839
|
-
"INSERT INTO model_element_files (element_id, file_id, sort_order) VALUES (?1, ?2, ?3)"
|
|
840
|
-
)?;
|
|
841
|
-
for (i, fid) in e.file_ids.iter().enumerate() {
|
|
842
|
-
stmt.execute(params![e.base.id, fid, i as i32])?;
|
|
843
|
-
}
|
|
844
|
-
}
|
|
838
|
+
write_element_file_ids(tx, &e.base.id, &e.file_ids)?;
|
|
845
839
|
|
|
846
840
|
if let Some(ref vs) = e.viewer_state {
|
|
847
841
|
write_model_viewer_state(tx, &e.base.id, vs)?;
|
|
@@ -850,6 +844,26 @@ fn write_model_element(tx: &Transaction, e: &DucModelElement) -> SerializeResult
|
|
|
850
844
|
Ok(())
|
|
851
845
|
}
|
|
852
846
|
|
|
847
|
+
fn write_element_file_ids(tx: &Transaction, element_id: &str, file_ids: &[String]) -> SerializeResult<()> {
|
|
848
|
+
let mut stmt = tx.prepare_cached(
|
|
849
|
+
"INSERT INTO model_element_files (element_id, file_id, sort_order) VALUES (?1, ?2, ?3)"
|
|
850
|
+
)?;
|
|
851
|
+
for (i, fid) in file_ids.iter().enumerate() {
|
|
852
|
+
stmt.execute(params![element_id, fid, i as i32])?;
|
|
853
|
+
}
|
|
854
|
+
Ok(())
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
fn write_doc_referenced_file_ids(tx: &Transaction, element_id: &str, file_ids: &[String]) -> SerializeResult<()> {
|
|
858
|
+
let mut stmt = tx.prepare_cached(
|
|
859
|
+
"INSERT INTO doc_element_referenced_files (element_id, file_id, sort_order) VALUES (?1, ?2, ?3)"
|
|
860
|
+
)?;
|
|
861
|
+
for (i, fid) in file_ids.iter().enumerate() {
|
|
862
|
+
stmt.execute(params![element_id, fid, i as i32])?;
|
|
863
|
+
}
|
|
864
|
+
Ok(())
|
|
865
|
+
}
|
|
866
|
+
|
|
853
867
|
fn write_model_viewer_state(tx: &Transaction, element_id: &str, vs: &Viewer3DState) -> SerializeResult<()> {
|
|
854
868
|
let cam = &vs.camera;
|
|
855
869
|
let disp = &vs.display;
|
|
@@ -1045,6 +1045,8 @@ pub struct DucDocElement {
|
|
|
1045
1045
|
pub text: String,
|
|
1046
1046
|
pub grid_config: DocumentGridConfig,
|
|
1047
1047
|
pub file_id: Option<String>,
|
|
1048
|
+
#[serde(default)]
|
|
1049
|
+
pub referenced_file_ids: Vec<String>,
|
|
1048
1050
|
}
|
|
1049
1051
|
|
|
1050
1052
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
-- "DUC_" in ASCII
|
|
2
2
|
-- Apply in order: duc.sql → version_control.sql → search.sql
|
|
3
3
|
PRAGMA application_id = 1146569567;
|
|
4
|
-
PRAGMA user_version =
|
|
4
|
+
PRAGMA user_version = 3000004;
|
|
5
5
|
PRAGMA journal_mode = WAL;
|
|
6
6
|
PRAGMA foreign_keys = ON;
|
|
7
7
|
PRAGMA synchronous = NORMAL;
|
|
@@ -702,6 +702,16 @@ CREATE TABLE element_doc (
|
|
|
702
702
|
text TEXT NOT NULL DEFAULT ''
|
|
703
703
|
); -- no WITHOUT ROWID: implicit integer rowid needed for FTS5 content sync
|
|
704
704
|
|
|
705
|
+
-- External files referenced by a doc element's Typst source (images, data files, etc.).
|
|
706
|
+
CREATE TABLE doc_element_referenced_files (
|
|
707
|
+
element_id TEXT NOT NULL REFERENCES element_doc(element_id) ON DELETE CASCADE,
|
|
708
|
+
file_id TEXT NOT NULL,
|
|
709
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
710
|
+
PRIMARY KEY (element_id, file_id)
|
|
711
|
+
) WITHOUT ROWID;
|
|
712
|
+
|
|
713
|
+
CREATE INDEX idx_doc_referenced_files_file ON doc_element_referenced_files(file_id);
|
|
714
|
+
|
|
705
715
|
-- Table element. Source of truth is the linked xlsx file.
|
|
706
716
|
CREATE TABLE element_table (
|
|
707
717
|
element_id TEXT PRIMARY KEY REFERENCES elements(id) ON DELETE CASCADE,
|
|
@@ -844,4 +854,4 @@ CREATE INDEX idx_external_file_revisions_file ON external_file_revisions(file_id
|
|
|
844
854
|
CREATE TABLE external_file_revision_data (
|
|
845
855
|
revision_id TEXT PRIMARY KEY REFERENCES external_file_revisions(id) ON DELETE CASCADE,
|
|
846
856
|
data BLOB NOT NULL
|
|
847
|
-
) WITHOUT ROWID;
|
|
857
|
+
) WITHOUT ROWID;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
-- Migration: 3000003 → 3000004
|
|
2
|
+
-- Rename element_model.svg_path (TEXT) to thumbnail (BLOB), and add dedicated
|
|
3
|
+
-- references for external files used by doc element Typst source.
|
|
4
|
+
|
|
5
|
+
CREATE TABLE element_model_new (
|
|
6
|
+
element_id TEXT PRIMARY KEY REFERENCES elements(id) ON DELETE CASCADE,
|
|
7
|
+
model_type TEXT,
|
|
8
|
+
code TEXT,
|
|
9
|
+
thumbnail BLOB
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
INSERT INTO element_model_new (element_id, model_type, code, thumbnail)
|
|
13
|
+
SELECT element_id, model_type, code, CAST(svg_path AS BLOB)
|
|
14
|
+
FROM element_model;
|
|
15
|
+
|
|
16
|
+
DROP TABLE element_model;
|
|
17
|
+
|
|
18
|
+
ALTER TABLE element_model_new RENAME TO element_model;
|
|
19
|
+
|
|
20
|
+
CREATE INDEX idx_element_model_type ON element_model(model_type);
|
|
21
|
+
|
|
22
|
+
CREATE TABLE IF NOT EXISTS doc_element_referenced_files (
|
|
23
|
+
element_id TEXT NOT NULL REFERENCES element_doc(element_id) ON DELETE CASCADE,
|
|
24
|
+
file_id TEXT NOT NULL,
|
|
25
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
26
|
+
PRIMARY KEY (element_id, file_id)
|
|
27
|
+
) WITHOUT ROWID;
|
|
28
|
+
|
|
29
|
+
CREATE INDEX IF NOT EXISTS idx_doc_referenced_files_file ON doc_element_referenced_files(file_id);
|
|
30
|
+
|
|
31
|
+
-- Defensive cleanup for prerelease files that may have stored doc references in
|
|
32
|
+
-- model_element_files before this dedicated table existed.
|
|
33
|
+
INSERT OR IGNORE INTO doc_element_referenced_files (element_id, file_id, sort_order)
|
|
34
|
+
SELECT mf.element_id, mf.file_id, mf.sort_order
|
|
35
|
+
FROM model_element_files mf
|
|
36
|
+
INNER JOIN element_doc d ON d.element_id = mf.element_id;
|
|
37
|
+
|
|
38
|
+
DELETE FROM model_element_files
|
|
39
|
+
WHERE element_id IN (SELECT element_id FROM element_doc);
|
|
40
|
+
|
|
41
|
+
PRAGMA user_version = 3000004;
|
|
@@ -27,6 +27,6 @@ from .classes import *
|
|
|
27
27
|
from .enums import *
|
|
28
28
|
from .parse import (DucData, get_external_file, list_external_files, parse_duc,
|
|
29
29
|
parse_duc_lazy)
|
|
30
|
-
from .serialize import DUC_SCHEMA_VERSION, serialize_duc
|
|
30
|
+
from .serialize import DUC_SCHEMA_VERSION, DucSerializationValidationError, serialize_duc
|
|
31
31
|
from .search import *
|
|
32
32
|
from .utils import *
|
|
@@ -55,45 +55,46 @@ def _create_element_wrapper(element_class, base_params, element_params, explicit
|
|
|
55
55
|
base_params.setdefault('region_ids', [])
|
|
56
56
|
base_params.setdefault('instance_id', None)
|
|
57
57
|
|
|
58
|
-
base_params.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
58
|
+
if base_params.get('styles') is None:
|
|
59
|
+
base_params['styles'] = DucElementStylesBase(
|
|
60
|
+
roundness=0.0,
|
|
61
|
+
stroke=[ElementStroke(
|
|
62
|
+
content=ElementContentBase(
|
|
63
|
+
preference=None,
|
|
64
|
+
src="",
|
|
65
|
+
visible=True,
|
|
66
|
+
opacity=1.0,
|
|
67
|
+
tiling=None,
|
|
68
|
+
hatch=None,
|
|
69
|
+
image_filter=DucImageFilter(brightness=1.0, contrast=1.0)
|
|
70
|
+
),
|
|
71
|
+
width=DEFAULT_STROKE_WIDTH,
|
|
72
|
+
style=StrokeStyle(
|
|
73
|
+
preference=STROKE_PREFERENCE.SOLID,
|
|
74
|
+
dash=None,
|
|
75
|
+
dash_line_override=None,
|
|
76
|
+
cap=None,
|
|
77
|
+
join=None,
|
|
78
|
+
dash_cap=None,
|
|
79
|
+
miter_limit=None
|
|
80
|
+
),
|
|
81
|
+
placement=STROKE_PLACEMENT.CENTER,
|
|
82
|
+
stroke_sides=None
|
|
83
|
+
)],
|
|
84
|
+
background=[ElementBackground(
|
|
85
|
+
content=ElementContentBase(
|
|
86
|
+
preference=None,
|
|
87
|
+
src="",
|
|
88
|
+
visible=True,
|
|
89
|
+
opacity=1.0,
|
|
90
|
+
tiling=None,
|
|
91
|
+
hatch=None,
|
|
92
|
+
image_filter=DucImageFilter(brightness=1.0, contrast=1.0)
|
|
93
|
+
)
|
|
94
|
+
)],
|
|
95
|
+
opacity=1.0,
|
|
96
|
+
blending=None
|
|
97
|
+
)
|
|
97
98
|
|
|
98
99
|
base_element = DucElementBase(**base_params)
|
|
99
100
|
|
|
@@ -168,8 +169,9 @@ def _create_element_wrapper(element_class, base_params, element_params, explicit
|
|
|
168
169
|
base=base_element,
|
|
169
170
|
style=element_params.get('style') or DucDocStyle(),
|
|
170
171
|
text=element_params.get('text', ""),
|
|
171
|
-
grid_config=element_params.get('grid_config'
|
|
172
|
+
grid_config=element_params.get('grid_config') or default_grid_config,
|
|
172
173
|
file_id=element_params.get('file_id'),
|
|
174
|
+
referenced_file_ids=element_params.get('referenced_file_ids') or [],
|
|
173
175
|
)
|
|
174
176
|
elif element_class == DucFrameElement:
|
|
175
177
|
stack_base = element_params.get('stack_base')
|
|
@@ -698,6 +700,8 @@ class DocElementBuilder(ElementSpecificBuilder):
|
|
|
698
700
|
self.extra["style"] = style; return self
|
|
699
701
|
def with_file_id(self, file_id: str):
|
|
700
702
|
self.extra["file_id"] = file_id; return self
|
|
703
|
+
def with_referenced_file_ids(self, referenced_file_ids: List[str]):
|
|
704
|
+
self.extra["referenced_file_ids"] = referenced_file_ids; return self
|
|
701
705
|
def with_grid_config(self, grid_config: DocumentGridConfig):
|
|
702
706
|
self.extra["grid_config"] = grid_config; return self
|
|
703
707
|
|
|
@@ -707,6 +711,7 @@ class DocElementBuilder(ElementSpecificBuilder):
|
|
|
707
711
|
"style": self.extra.get('style'),
|
|
708
712
|
"text": self.extra.get('text', ""),
|
|
709
713
|
"file_id": self.extra.get('file_id'),
|
|
714
|
+
"referenced_file_ids": self.extra.get('referenced_file_ids', []),
|
|
710
715
|
"grid_config": self.extra.get('grid_config'),
|
|
711
716
|
}
|
|
712
717
|
return _create_element_wrapper(DucDocElement, base_params, element_params,
|
|
@@ -727,11 +732,12 @@ class EmbeddableElementBuilder(ElementSpecificBuilder):
|
|
|
727
732
|
|
|
728
733
|
class ModelElementBuilder(ElementSpecificBuilder):
|
|
729
734
|
def with_model_type(self, model_type: str):
|
|
735
|
+
valid_types = {"python", "ifc", "dxf", "dwg", "step", "stl"}
|
|
736
|
+
if model_type not in valid_types:
|
|
737
|
+
raise ValueError(f"Invalid model_type: {model_type}. Allowed types: {sorted(list(valid_types))}")
|
|
730
738
|
self.extra["model_type"] = model_type; return self
|
|
731
739
|
def with_code(self, code: str):
|
|
732
740
|
self.extra["code"] = code; return self
|
|
733
|
-
def with_svg_path(self, svg_path: str):
|
|
734
|
-
self.extra["svg_path"] = svg_path; return self
|
|
735
741
|
def with_file_ids(self, file_ids: List[str]):
|
|
736
742
|
self.extra["file_ids"] = file_ids; return self
|
|
737
743
|
def with_viewer_state(self, viewer_state):
|
|
@@ -739,11 +745,15 @@ class ModelElementBuilder(ElementSpecificBuilder):
|
|
|
739
745
|
|
|
740
746
|
def build(self) -> ElementWrapper:
|
|
741
747
|
base_params = self.base.__dict__.copy()
|
|
748
|
+
model_type = self.extra.get('model_type', 'python')
|
|
749
|
+
valid_types = {"python", "ifc", "dxf", "dwg", "step", "stl"}
|
|
750
|
+
if model_type not in valid_types:
|
|
751
|
+
raise ValueError(f"Invalid model_type: {model_type}. Allowed types: {sorted(list(valid_types))}")
|
|
752
|
+
|
|
742
753
|
element_params = {
|
|
743
754
|
"file_ids": self.extra.get('file_ids', []),
|
|
744
|
-
"model_type":
|
|
755
|
+
"model_type": model_type,
|
|
745
756
|
"code": self.extra.get('code'),
|
|
746
|
-
"svg_path": self.extra.get('svg_path'),
|
|
747
757
|
"viewer_state": self.extra.get('viewer_state'),
|
|
748
758
|
}
|
|
749
759
|
return _create_element_wrapper(DucModelElement, base_params, element_params,
|
|
@@ -446,9 +446,9 @@ def create_local_state_from_base(base: BaseStateParams, **kwargs) -> DucLocalSta
|
|
|
446
446
|
current_item_stroke=kwargs.get('current_item_stroke', None),
|
|
447
447
|
current_item_background=kwargs.get('current_item_background', None),
|
|
448
448
|
current_item_opacity=kwargs.get('current_item_opacity', 1.0),
|
|
449
|
-
current_item_font_family=kwargs.get('current_item_font_family', "
|
|
449
|
+
current_item_font_family=kwargs.get('current_item_font_family', "Roboto Mono"),
|
|
450
450
|
current_item_font_size=kwargs.get('current_item_font_size', 20.0),
|
|
451
|
-
current_item_text_align=kwargs.get('current_item_text_align',
|
|
451
|
+
current_item_text_align=kwargs.get('current_item_text_align', TEXT_ALIGN.LEFT),
|
|
452
452
|
current_item_roundness=kwargs.get('current_item_roundness', 0.0),
|
|
453
453
|
current_item_start_line_head=kwargs.get('current_item_start_line_head', None),
|
|
454
454
|
current_item_end_line_head=kwargs.get('current_item_end_line_head', None),
|
|
@@ -457,7 +457,7 @@ def create_local_state_from_base(base: BaseStateParams, **kwargs) -> DucLocalSta
|
|
|
457
457
|
objects_snap_mode_enabled=kwargs.get('objects_snap_mode_enabled', True),
|
|
458
458
|
grid_mode_enabled=kwargs.get('grid_mode_enabled', True),
|
|
459
459
|
outline_mode_enabled=kwargs.get('outline_mode_enabled', False),
|
|
460
|
-
manual_save_mode=kwargs.get('manual_save_mode',
|
|
460
|
+
manual_save_mode=kwargs.get('manual_save_mode', False),
|
|
461
461
|
decimal_places=kwargs.get('decimal_places', 2),
|
|
462
462
|
)
|
|
463
463
|
|
|
@@ -393,6 +393,7 @@ class DucDocElement:
|
|
|
393
393
|
text: str
|
|
394
394
|
grid_config: DocumentGridConfig
|
|
395
395
|
file_id: Optional[str] = None
|
|
396
|
+
referenced_file_ids: Optional[List[str]] = None
|
|
396
397
|
|
|
397
398
|
@dataclass
|
|
398
399
|
class DucTableElement:
|
|
@@ -482,6 +483,13 @@ class DucModelElement:
|
|
|
482
483
|
thumbnail: Optional[bytes] = None
|
|
483
484
|
viewer_state: Optional[Viewer3DState] = None
|
|
484
485
|
|
|
486
|
+
def __post_init__(self):
|
|
487
|
+
valid_types = {"python", "ifc", "dxf", "dwg", "step", "stl"}
|
|
488
|
+
if self.model_type is None:
|
|
489
|
+
self.model_type = "python"
|
|
490
|
+
if self.model_type not in valid_types:
|
|
491
|
+
raise ValueError(f"Invalid model_type: {self.model_type}. Allowed types: {sorted(list(valid_types))}")
|
|
492
|
+
|
|
485
493
|
|
|
486
494
|
# =============== BLOCK DEFINITIONS ===============
|
|
487
495
|
|