def audit(self, auditor: 'Auditor'): """ Restore database integrity: - restore database entries with modified handles (key != entity.dxf.handle) - remove entities with invalid handles - empty trashcan - destroy all entities in the trashcan - removes destroyed database entries (purge) """ assert self.locked is False, 'Database is locked!' add_entities = [] with self.trashcan() as trash: for handle, entity in self.items(): # Destroyed entities are already filtered! if not is_valid_handle(handle): auditor.fixed_error( code=AuditError.INVALID_ENTITY_HANDLE, message= f'Removed entity {entity.dxftype()} with invalid ' f'handle "{handle}" from entity database.', ) trash.add(handle) if handle != entity.dxf.get('handle'): # database handle != stored entity handle # prevent entity from being destroyed: self._database[handle] = None trash.add(handle) add_entities.append(entity) # Remove all destroyed entities from database: self.purge() for entity in add_entities: handle = entity.dxf.get('handle') if handle is None: auditor.fixed_error( code=AuditError.INVALID_ENTITY_HANDLE, message=f'Removed entity {entity.dxftype()} without handle ' f'from entity database.', ) continue if not is_valid_handle(handle) or handle == '0': auditor.fixed_error( code=AuditError.INVALID_ENTITY_HANDLE, message=f'Removed entity {entity.dxftype()} with invalid ' f'handle "{handle}" from entity database.', ) continue self[handle] = entity
def add(self, key: str, value: 'DXFEntity') -> None: """ Add entry ``(key, value)``. """ if isinstance(value, str): if not is_valid_handle(value): raise DXFValueError( f'Invalid entity handle #{value} for key {key}') self._data[key] = value
def __setitem__(self, handle: str, entity: DXFEntity) -> None: """ Set `entity` for `handle`. """ assert isinstance(handle, str), type(handle) assert isinstance(entity, DXFEntity), type(entity) if handle == '0' or not is_valid_handle(handle): raise ValueError(f'Invalid handle {handle}.') self._database[handle] = entity
def add(self, key: str, entity: DXFObject) -> None: """Add entry ``(key, value)``. Raises: DXFValueError: invalid entity handle DXFTypeError: invalid DXF type """ if isinstance(entity, str): if not is_valid_handle(entity): raise DXFValueError( f"Invalid entity handle #{entity} for key {key}") elif isinstance(entity, DXFGraphic): if self.doc is not None and self.doc.is_loading: # AutoCAD add-ons can store graphical entities in DICTIONARIES # in the OBJECTS section and AutoCAD does not complain - so just # preserve them! # Example "ZJMC-288.dxf" in issue #585, add-on: "acdgnlsdraw.crx"? logger.warning(f"Invalid entity {str(entity)} in {str(self)}") else: # Do not allow ezdxf users to add graphical entities to a # DICTIONARY object! raise DXFTypeError( f"Graphic entities not allowed: {entity.dxftype()}") self._data[key] = entity
def audit(self, auditor: 'Auditor'): """ Restore database integrity: - removes deleted database entries (purge) - restore database entries with modified handles (key != entity.dxf.handle) - remove entities with invalid handles """ db = self._database remove_handles = [] add_entities = [] for handle, entity in db.items(): if not is_valid_handle(handle): auditor.fixed_error( code=AuditError.INVALID_ENTITY_HANDLE, message= f'Removed entity {entity.dxftype()} with invalid handle "{handle}" from entity database.', ) remove_handles.append(handle) if not entity.is_alive: remove_handles.append(handle) elif handle != entity.dxf.get('handle'): remove_handles.append(handle) add_entities.append(entity) for handle in remove_handles: del db[handle] for entity in add_entities: handle = entity.dxf.get('handle') if handle is None: auditor.fixed_error( code=AuditError.INVALID_ENTITY_HANDLE, message= f'Removed entity {entity.dxftype()} without handle from entity database.', ) continue if not is_valid_handle(handle) or handle == '0': auditor.fixed_error( code=AuditError.INVALID_ENTITY_HANDLE, message= f'Removed entity {entity.dxftype()} with invalid handle "{handle}" from entity database.', ) continue self[handle] = entity
def audit(self, auditor: 'Auditor'): """ Restore database integrity: - removes deleted database entries (purge) - restore database entries with modified handles (key != entity.dxf.handle) - remove entities with invalid handles """ assert self.locked is False, 'Database is locked!' db = self._database add_entities = [] for handle, entity in db.items(): if not is_valid_handle(handle): auditor.fixed_error( code=AuditError.INVALID_ENTITY_HANDLE, message=f'Removed entity {entity.dxftype()} with invalid handle "{handle}" from entity database.', ) self.trash(handle) if not entity.is_alive: self.trash(handle) elif handle != entity.dxf.get('handle'): # database handle != stored entity handle # prevent entity from being destroyed: self._database[handle] = None self.trash(handle) add_entities.append(entity) self.empty_trashcan() for entity in add_entities: handle = entity.dxf.get('handle') if handle is None: auditor.fixed_error( code=AuditError.INVALID_ENTITY_HANDLE, message=f'Removed entity {entity.dxftype()} without handle from entity database.', ) continue if not is_valid_handle(handle) or handle == '0': auditor.fixed_error( code=AuditError.INVALID_ENTITY_HANDLE, message=f'Removed entity {entity.dxftype()} with invalid handle "{handle}" from entity database.', ) continue self[handle] = entity
def __setitem__(self, handle: str, entity: DXFEntity) -> None: """ Set `entity` for `handle`. """ assert isinstance(handle, str), type(handle) assert isinstance(entity, DXFEntity), type(entity) assert entity.is_alive, 'Can not store destroyed entity.' if self.locked: raise DXFInternalEzdxfError('Locked entity database.') if handle == '0' or not is_valid_handle(handle): raise ValueError(f'Invalid handle {handle}.') self._database[handle] = entity
def safe_handle(handle: Optional[str], doc: Optional["Drawing"] = None) -> str: if handle is None: return "0" assert isinstance(handle, str), "invalid type" if doc is not None: if handle not in doc.entitydb: return "0" return handle if not is_valid_handle(handle): return "0" return handle.upper()
def test_is_valid_handle(): assert is_valid_handle( '0' ) is True, '0 is a valid handle, but not allowed aa key in the entity database' assert is_valid_handle('ABBA') is True assert is_valid_handle('FEFE') is True assert is_valid_handle(None) is False, 'None is not a valid handle' assert is_valid_handle('X') is False, 'Not a valid hex value' assert is_valid_handle(1) is False, 'Integer is not a valid handle' assert is_valid_handle(1.0) is False, 'Float is not a valid handle'
def test_is_valid_handle(): assert ( is_valid_handle("0") is True ), "0 is a valid handle, but not allowed aa key in the entity database" assert is_valid_handle("ABBA") is True assert is_valid_handle("FEFE") is True assert is_valid_handle(None) is False, "None is not a valid handle" assert is_valid_handle("X") is False, "Not a valid hex value" assert is_valid_handle(1) is False, "Integer is not a valid handle" assert is_valid_handle(1.0) is False, "Float is not a valid handle"