git fixec null symbol
This commit is contained in:
@@ -8,11 +8,22 @@ from pathlib import Path
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_text(value: str | None) -> str:
|
||||||
|
"""Remove NUL bytes — PostgreSQL text fields reject them; SchDoc may contain them."""
|
||||||
|
if not value:
|
||||||
|
return ""
|
||||||
|
return value.replace("\x00", "")
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ComponentProperty:
|
class ComponentProperty:
|
||||||
name: str
|
name: str
|
||||||
text: str
|
text: str
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
self.name = sanitize_text(self.name)
|
||||||
|
self.text = sanitize_text(self.text)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DielProperty:
|
class DielProperty:
|
||||||
@@ -22,6 +33,10 @@ class DielProperty:
|
|||||||
diel_type: int
|
diel_type: int
|
||||||
layer_number: int
|
layer_number: int
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
self.name = sanitize_text(self.name)
|
||||||
|
self.value = sanitize_text(self.value)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ProjectData:
|
class ProjectData:
|
||||||
@@ -342,6 +357,7 @@ class AltiumParser:
|
|||||||
|
|
||||||
|
|
||||||
def make_complex_string(text: str, props: list[ComponentProperty]) -> str:
|
def make_complex_string(text: str, props: list[ComponentProperty]) -> str:
|
||||||
|
text = sanitize_text(text)
|
||||||
if not text.startswith("="):
|
if not text.startswith("="):
|
||||||
return text
|
return text
|
||||||
expr = text[1:]
|
expr = text[1:]
|
||||||
@@ -351,7 +367,7 @@ def make_complex_string(text: str, props: list[ComponentProperty]) -> str:
|
|||||||
key = m.group(1)
|
key = m.group(1)
|
||||||
return mapping.get(key, "")
|
return mapping.get(key, "")
|
||||||
|
|
||||||
return re.sub(r"['\"]([^'\"]+)['\"]", repl, expr)
|
return sanitize_text(re.sub(r"['\"]([^'\"]+)['\"]", repl, expr))
|
||||||
|
|
||||||
|
|
||||||
def find_prjpcb(extract_dir: Path) -> Optional[Path]:
|
def find_prjpcb(extract_dir: Path) -> Optional[Path]:
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from app.models import (
|
|||||||
Variant,
|
Variant,
|
||||||
VariantProperty,
|
VariantProperty,
|
||||||
)
|
)
|
||||||
from app.services.altium_parser import AltiumParser, ProjectData, find_prjpcb, make_complex_string
|
from app.services.altium_parser import AltiumParser, ProjectData, find_prjpcb, make_complex_string, sanitize_text
|
||||||
from app.services.designators import DEFAULT_MAPPINGS
|
from app.services.designators import DEFAULT_MAPPINGS
|
||||||
|
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ def ensure_default_mappings(db: Session, project: Project) -> None:
|
|||||||
def save_project_data(db: Session, project: Project, data: ProjectData) -> None:
|
def save_project_data(db: Session, project: Project, data: ProjectData) -> None:
|
||||||
variant_objs: list[Variant] = []
|
variant_objs: list[Variant] = []
|
||||||
for name in data.variant_names:
|
for name in data.variant_names:
|
||||||
v = Variant(project_id=project.id, name=name)
|
v = Variant(project_id=project.id, name=sanitize_text(name))
|
||||||
db.add(v)
|
db.add(v)
|
||||||
variant_objs.append(v)
|
variant_objs.append(v)
|
||||||
db.flush()
|
db.flush()
|
||||||
@@ -95,7 +95,7 @@ def save_project_data(db: Session, project: Project, data: ProjectData) -> None:
|
|||||||
designator = ""
|
designator = ""
|
||||||
for p in comp_props:
|
for p in comp_props:
|
||||||
if p.name.lower() == "designator":
|
if p.name.lower() == "designator":
|
||||||
designator = p.text
|
designator = sanitize_text(p.text)
|
||||||
break
|
break
|
||||||
if not designator:
|
if not designator:
|
||||||
continue
|
continue
|
||||||
@@ -105,7 +105,13 @@ def save_project_data(db: Session, project: Project, data: ProjectData) -> None:
|
|||||||
db.add(comp)
|
db.add(comp)
|
||||||
db.flush()
|
db.flush()
|
||||||
for p in comp_props:
|
for p in comp_props:
|
||||||
db.add(ComponentProperty(component_id=comp.id, key=p.name, value=p.text))
|
db.add(
|
||||||
|
ComponentProperty(
|
||||||
|
component_id=comp.id,
|
||||||
|
key=sanitize_text(p.name),
|
||||||
|
value=sanitize_text(p.text),
|
||||||
|
)
|
||||||
|
)
|
||||||
designator_to_component[designator] = comp
|
designator_to_component[designator] = comp
|
||||||
# link to all variants as fitted by default
|
# link to all variants as fitted by default
|
||||||
for v in variant_objs:
|
for v in variant_objs:
|
||||||
@@ -126,7 +132,7 @@ def save_project_data(db: Session, project: Project, data: ProjectData) -> None:
|
|||||||
designator = ""
|
designator = ""
|
||||||
for p in comp_props:
|
for p in comp_props:
|
||||||
if p.name == "Designator":
|
if p.name == "Designator":
|
||||||
designator = p.text
|
designator = sanitize_text(p.text)
|
||||||
break
|
break
|
||||||
if not designator:
|
if not designator:
|
||||||
continue
|
continue
|
||||||
@@ -149,8 +155,8 @@ def save_project_data(db: Session, project: Project, data: ProjectData) -> None:
|
|||||||
VariantProperty(
|
VariantProperty(
|
||||||
component_id=comp.id,
|
component_id=comp.id,
|
||||||
variant_id=variant.id,
|
variant_id=variant.id,
|
||||||
key=p.name,
|
key=sanitize_text(p.name),
|
||||||
value=p.text,
|
value=sanitize_text(p.text),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -159,16 +165,18 @@ def save_project_data(db: Session, project: Project, data: ProjectData) -> None:
|
|||||||
for item in params:
|
for item in params:
|
||||||
if len(item) < 2:
|
if len(item) < 2:
|
||||||
continue
|
continue
|
||||||
name, value = item[0], item[1]
|
name, value = sanitize_text(item[0]), sanitize_text(item[1])
|
||||||
value = make_complex_string(value, flat_props)
|
value = sanitize_text(make_complex_string(value, flat_props))
|
||||||
db.add(
|
db.add(
|
||||||
ProjectParam(
|
ProjectParam(
|
||||||
project_id=project.id,
|
project_id=project.id,
|
||||||
name=name,
|
name=name,
|
||||||
value=value,
|
value=value,
|
||||||
variant_name=data.variant_names[variant_idx]
|
variant_name=sanitize_text(
|
||||||
if variant_idx < len(data.variant_names)
|
data.variant_names[variant_idx]
|
||||||
else "",
|
if variant_idx < len(data.variant_names)
|
||||||
|
else ""
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -181,15 +189,16 @@ def save_project_data(db: Session, project: Project, data: ProjectData) -> None:
|
|||||||
db.add(
|
db.add(
|
||||||
DielMaterial(
|
DielMaterial(
|
||||||
pcb_data_id=pcb.id,
|
pcb_data_id=pcb.id,
|
||||||
name=m.name,
|
name=sanitize_text(m.name),
|
||||||
value=m.value,
|
value=sanitize_text(m.value),
|
||||||
height=m.height,
|
height=m.height,
|
||||||
diel_type=m.diel_type,
|
diel_type=m.diel_type,
|
||||||
layer_number=m.layer_number,
|
layer_number=m.layer_number,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
project.pcb_doc_name = Path(data.pcb_doc_file_name).name if data.pcb_doc_file_name else None
|
pcb_name = sanitize_text(Path(data.pcb_doc_file_name).name if data.pcb_doc_file_name else "")
|
||||||
|
project.pcb_doc_name = pcb_name or None
|
||||||
if "No Variations" in data.variant_names:
|
if "No Variations" in data.variant_names:
|
||||||
project.current_variant = "No Variations"
|
project.current_variant = "No Variations"
|
||||||
elif data.variant_names:
|
elif data.variant_names:
|
||||||
@@ -247,10 +256,13 @@ def ingest_zip(
|
|||||||
db.refresh(project)
|
db.refresh(project)
|
||||||
return project
|
return project
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
project.status = "error"
|
db.rollback()
|
||||||
project.error_message = str(e)
|
proj = db.get(Project, project.id)
|
||||||
db.commit()
|
if proj:
|
||||||
raise
|
proj.status = "error"
|
||||||
|
proj.error_message = str(e)[:2000]
|
||||||
|
db.commit()
|
||||||
|
raise ValueError(str(e)) from e
|
||||||
|
|
||||||
|
|
||||||
def get_project_full(db: Session, project_id: int) -> Project | None:
|
def get_project_full(db: Session, project_id: int) -> Project | None:
|
||||||
|
|||||||
Reference in New Issue
Block a user