From e8056f62a70f99c1607c2766a2d808e499939c59 Mon Sep 17 00:00:00 2001 From: mozman Date: Sat, 27 Jan 2024 10:40:16 +0100 Subject: [PATCH] fix non-existing linetypes in layers #1018 --- notes/pages/CHANGELOG.md | 2 + src/ezdxf/entities/layer.py | 42 +++++++++++-------- .../test_424_audit.py | 9 +++- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/notes/pages/CHANGELOG.md b/notes/pages/CHANGELOG.md index 16fcbe39e..c926bfcf8 100644 --- a/notes/pages/CHANGELOG.md +++ b/notes/pages/CHANGELOG.md @@ -20,6 +20,8 @@ id:: 6588217b-c1d3-44c1-a0d7-e5ee465cc6de - {{pr 1004}} - the cache version number has been increased so that the fontmanger-cache is automatically rebuilt - NEW: `MeshBuilder.render_3dsolid()`, create [[3DSOLID]] entities from simple polyhedrons (experimental) + - NEW: `Auditor` fixes non-existing linetypes in layers, replaced by `Continuous` + - {{discussion 1018}} - CHANGE: renamed `Image.boundray_path_ocs()` to `Image.pixel_boundary_path()` - CHANGE: refactoring of the [[RecorderBackend]] - CHANGE: replaced `ezdxf.math.linspace` by `numpy.linspace` diff --git a/src/ezdxf/entities/layer.py b/src/ezdxf/entities/layer.py index 9cea7bbfe..effc0428a 100644 --- a/src/ezdxf/entities/layer.py +++ b/src/ezdxf/entities/layer.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2022, Manfred Moitzi +# Copyright (c) 2019-2024, Manfred Moitzi # License: MIT License from __future__ import annotations from typing import TYPE_CHECKING, Optional, cast, Any @@ -26,6 +26,7 @@ LINEWEIGHT_BYLAYER, LINEWEIGHT_DEFAULT, ) +from ezdxf.audit import AuditError from ezdxf.entities.dxfentity import base_class, SubclassProcessor, DXFEntity from .factory import register_entity @@ -34,6 +35,7 @@ from ezdxf.lldxf.tagwriter import AbstractTagWriter from ezdxf.entitydb import EntityDB from ezdxf import xref + from ezdxf.audit import Auditor __all__ = ["Layer", "acdb_symbol_table_record", "LayerOverrides"] @@ -109,9 +111,7 @@ def fix_layer_lineweight(lw: int) -> int: "unknown1": DXFAttr(348, dxfversion=DXF2007, optional=True), }, ) -acdb_layer_table_record_group_codes = group_code_mapping( - acdb_layer_table_record -) +acdb_layer_table_record_group_codes = group_code_mapping(acdb_layer_table_record) AcAecLayerStandard = "AcAecLayerStandard" AcCmTransparency = "AcCmTransparency" @@ -163,6 +163,7 @@ def export_entity(self, tagwriter: AbstractTagWriter) -> None: ) def set_required_attributes(self): + assert self.doc is not None, "valid DXF document required" if not self.dxf.hasattr("material_handle"): global_ = self.doc.materials["Global"] if isinstance(global_, DXFEntity): @@ -305,9 +306,7 @@ def transparency(self, value: float) -> None: self.doc.appids.new(AcCmTransparency) if 0 <= value <= 1: self.discard_xdata(AcCmTransparency) - self.set_xdata( - AcCmTransparency, [(1071, clr.float2transparency(value))] - ) + self.set_xdata(AcCmTransparency, [(1071, clr.float2transparency(value))]) else: raise ValueError("Value out of range [0, 1].") @@ -368,15 +367,13 @@ def _rename_layer_references(self, old_name: str, new_name: str) -> None: # todo: if LAYER_FILTER implemented, add support for # renaming layers logger.debug( - f'renaming layer "{old_name}" - document contains ' - f"LAYER_FILTER" + f'renaming layer "{old_name}" - document contains ' f"LAYER_FILTER" ) elif entity_type == "LAYER_INDEX": # todo: if LAYER_INDEX implemented, add support for # renaming layers logger.debug( - f'renaming layer "{old_name}" - document contains ' - f"LAYER_INDEX" + f'renaming layer "{old_name}" - document contains ' f"LAYER_INDEX" ) def get_vp_overrides(self) -> LayerOverrides: @@ -408,6 +405,19 @@ def map_resources(self, clone: DXFEntity, mapping: xref.ResourceMapper) -> None: # remove layer overrides clone.discard_extension_dict() + def audit(self, auditor: Auditor) -> None: + super().audit(auditor) + linetype = self.dxf.linetype + if auditor.doc.linetypes.has_entry(linetype): + return + self.dxf.linetype = "Continuous" + auditor.fixed_error( + code=AuditError.UNDEFINED_LINETYPE, + message=f"Replaced undefined linetype {linetype} in layer {self.dxf.name} by CONTINOUSE", + dxf_entity=self, + data=linetype, + ) + @dataclass class OverrideAttributes: @@ -622,9 +632,9 @@ def set_color(vp_handle: str, value: int): ovr = get_ovr(vp_handle) type_, data = clr.decode_raw_color(value) if type_ == clr.COLOR_TYPE_ACI: - ovr.aci = data + ovr.aci = data # type: ignore elif type_ == clr.COLOR_TYPE_RGB: - ovr.rgb = data + ovr.rgb = data # type: ignore def set_ltype(vp_handle: str, lt_handle: str): ltype = entitydb.get(lt_handle) @@ -699,9 +709,7 @@ def del_xdict_tags(key: str): xrec.destroy() xdict.discard(key) - def make_tags( - data: list[tuple[Any, str]], name: str, code: int - ) -> list[DXFTag]: + def make_tags(data: list[tuple[Any, str]], name: str, code: int) -> list[DXFTag]: tags: list[DXFTag] = [] for value, vp_handle in data: tags.extend( @@ -731,7 +739,7 @@ def collect_colors(): def collect_linetypes(): for vp_handle, ovr in vp_exist.items(): if ovr.linetype != default.linetype: - ltype = layer.doc.linetypes.get(ovr.linetype) + ltype = layer.doc.linetypes.get(ovr.linetype) # type: ignore if ltype is not None: yield ltype.dxf.handle, vp_handle diff --git a/tests/test_04_dxf_high_level_structs/test_424_audit.py b/tests/test_04_dxf_high_level_structs/test_424_audit.py index 5243d7d0f..dd97fabbc 100644 --- a/tests/test_04_dxf_high_level_structs/test_424_audit.py +++ b/tests/test_04_dxf_high_level_structs/test_424_audit.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2021 Manfred Moitzi +# Copyright (c) 2019-2024 Manfred Moitzi # License: MIT License import pytest import ezdxf @@ -64,6 +64,13 @@ def test_for_valid_layer_name(entity, auditor): assert len(auditor) == 1 assert auditor.errors[0].code == AuditError.INVALID_LAYER_NAME +def test_if_layer_linetype_exist(): + doc = ezdxf.new() + doc.layers.add("Layer0", linetype="DoesNotExist") + auditor = doc.audit() + assert len(auditor.fixes) == 1 + fix = auditor.fixes[0] + assert fix.code == AuditError.UNDEFINED_LINETYPE def test_for_existing_owner(entity, auditor): entity.dxf.owner = "FFFFFF"