def raw_pretty_print(filename, nocompile=True, legacy_mode=False): try: info = dxf_file_info(str(filename)) except IOError: print("Unable to read DXF file '{}'.".format(filename)) sys.exit(1) except DXFError as e: print(str(e)) sys.exit(2) with io.open(filename, mode='rt', encoding=info.encoding, errors='ignore') as dxf: tagger = low_level_tagger(dxf) if legacy_mode: tagger = tag_reorder_layer(tagger) if nocompile is False: tagger = tag_compiler(tagger) html_filename = filename.parent / (filename.stem + '.html') try: with io.open(html_filename, mode='wt', encoding='utf-8') as html: html.write(rawpp(tagger, str(filename))) except IOError: print("IOError: can not write file '{}'.".format(html_filename)) except DXFStructureError as e: print("DXFStructureError: {}".format(str(e))) return html_filename
def _iter_objects_section(self): if self._fp_objects_section is None: self._fp_objects_section = self._seek_to_section('OBJECTS') self.file.seek(self._fp_objects_section) for tag in low_level_tagger(self.file): if tag != DXFTag(0, 'ENDSEC'): yield tag else: yield tag break
def _seek_to_section(self, name: str) -> int: prev_tag = (0, None) self.file.seek(0) find = DXFTag(2, name) section = DXFTag(0, 'SECTION') for tag in low_level_tagger(self.file): if tag == find and prev_tag == section: break prev_tag = tag return self.file.tell()
def test_fix_line_coordinate_order(): tags = list(low_level_tagger(StringIO(TEST_LINE1))) ordered_tags = list(fix_coordinate_order(tags, codes=(10, 11))) assert ordered_tags[0] == (0, 'LINE') assert ordered_tags[-6] == (10, '1000.') assert ordered_tags[-5] == (20, '2000.') assert ordered_tags[-4] == (11, '1100.') assert ordered_tags[-3] == (21, '2100.') assert ordered_tags[-2] == (1000, 'ExtData') assert ordered_tags[-1] == (0, 'EOF')
def _iter_until_entities_section(self) -> DXFTag: prev_tag = (0, None) self.file.seek(0) for tag in low_level_tagger(self.file): if tag != (2, 'ENTITIES'): yield tag else: if prev_tag == (0, 'SECTION'): yield tag # write (0, 'ENTITIES') break prev_tag = tag self._fp_entities_section = self.file.tell()
def from_stream(stream: TextIO, codes: Set[int] = None) -> Iterable['DXFTag']: """ Yields comment tags from text `stream` as :class:`~ezdxf.lldxf.types.DXFTag` objects. Args: stream: input text stream codes: set of group codes to yield additional DXF tags e.g. {5, 0} to also yield handle and structure tags """ codes = codes or set() codes.add(999) return (tag for tag in low_level_tagger(stream, skip_comments=False) if tag.code in codes)
def modelspace(filename: str, types: Iterable[str] = None) -> Iterable[DXFGraphic]: """ Iterate over all modelspace entities as :class:`DXFGraphic` objects of a seekable file. Use this function to 'quick' iterate over modelspace entities of a DXF file, filtering DXF types may speed up things if many entity types will be skipped. Args: filename: filename of a seekable DXF file types: DXF types like ``['LINE', '3DFACE']`` which should be returned, ``None`` returns all supported types. """ info = dxf_file_info(filename) prev_code: int = -1 prev_value: str = '' entities = False requested_types = _requested_types(types) with open(filename, mode='rt', encoding=info.encoding) as fp: tagger = low_level_tagger(fp) queued: Optional[DXFEntity] = None tags: List[DXFTag] = [] factory = EntityFactory() linked_entity = entity_linker() for tag in tag_compiler(tagger): code = tag.code value = tag.value if entities: if code == 0 and value == 'ENDSEC': if queued: yield queued return if code == 0: if len(tags) and tags[0].value in requested_types: entity = factory.entity(ExtendedTags(tags)) if not linked_entity( entity) and entity.dxf.paperspace == 0: if queued: # queue one entity for collecting linked entities (VERTEX, ATTRIB) yield queued queued = entity tags = [tag] else: tags.append(tag) continue # if entities - nothing else matters elif code == 2 and prev_code == 0 and prev_value == 'SECTION': entities = (value == 'ENTITIES') prev_code = code prev_value = value
def readfile(filename: str, legacy_mode: bool = False, compile_tags=True) -> Iterable[DXFTag]: from ezdxf.lldxf.validator import is_dxf_file if not is_dxf_file(filename): raise IOError("File '{}' is not a DXF file.".format(filename)) info = dxf_file_info(filename) fp = open(filename, mode='rt', encoding=info.encoding, errors='ignore') tagger = low_level_tagger(fp) if legacy_mode: tagger = tag_reorder_layer(tagger) if compile_tags: tagger = tag_compiler(tagger) return tagger
def modelspace(self) -> Iterable[DXFGraphic]: """ Returns an iterator for all supported DXF entities in the modelspace. These entities are regular :class:`~ezdxf.entities.DXFGraphic` objects but without a valid document assigned. It is **not** possible to add these entities to other `ezdxf` documents. It is only possible to recreate the objects by factory functions base on attributes of the source entity. For MESH, POLYMESH and POLYFACE it is possible to use the :class:`~ezdxf.render.MeshTransformer` class to render (recreate) this objects as new entities in another document. """ if self._fp_entities_section is None: self._fp_entities_section = self._seek_to_section('ENTITIES') self.file.seek(self._fp_entities_section) tags = [] factory = EntityFactory() polyline: Optional[Polyline] = None for tag in tag_compiler(low_level_tagger(self.file)): if tag.code == 0: # start new entity if len(tags): xtags = ExtendedTags(tags) dxftype = xtags.dxftype() if dxftype in SUPPORTED_DXF_TYPES: entity = factory.entity(xtags) if dxftype == 'SEQEND': if polyline is not None: polyline.seqend = entity yield polyline polyline = None # suppress all other SEQEND entities -> ATTRIB elif dxftype == 'VERTEX' and polyline is not None: # vertices without POLYLINE are DXF structure errors, but here just ignore it. polyline.vertices.append(entity) elif dxftype == 'POLYLINE': polyline = entity else: # POLYLINE without SEQEND is a DXF structure error, but here just ignore it. # By using this add-on be sure to get valid DXF files. polyline = None yield entity if tag == (0, 'ENDSEC'): break tags = [tag] else: tags.append(tag)
def test_write_R12_without_handles(filename, tmpdir): dwg = ezdxf.readfile(filename) dwg.header['$HANDLING'] = 0 export_path = str(tmpdir.join("dxf_r12_without_handles.dxf")) dwg.saveas(export_path) # can't check with ezdxf.readfile(), because handles automatically enabled with open(export_path) as f: tagger = low_level_tagger(f) sections = load_dxf_structure(tagger) for entity in sections['ENTITIES']: with pytest.raises(ezdxf.DXFValueError): # has no handles entity.get_handle() for entity in sections['TABLES']: if entity[0] != (0, 'DIMSTYLE'): with pytest.raises(ezdxf.DXFValueError): # has no handles entity.get_handle() else: # special DIMSTYLE entity assert len(entity.find_all(105)) == 0, 'remove handle group code 105' assert len(entity.find_all(5)) == 1, 'do not remove group code 5'
def test_polyline_with_xdata(): tags = list(tag_compiler(low_level_tagger(StringIO(POLYLINE_WITH_XDATA)))) assert len(tags) == 49
def test_low_level_tagger_skip_comments(): tags = list(low_level_tagger(StringIO('999\ncomment\n0\nEOF\n'))) assert (0, 'EOF') == tags[0] assert len(tags) == 1
def string_reorder_tagger(s): return tag_reorder_layer(low_level_tagger(StringIO(s)))
def test_low_level_tagger(): tags = list(low_level_tagger(StringIO(TEST_LINE1))) assert len(tags) == 14
def read(stream): """ Open an existing drawing. """ from ezdxf.lldxf.tagger import low_level_tagger, tag_compiler tagger = list(low_level_tagger(stream)) return tag_compiler(iter(tagger))
def test_low_level_tagger_not_skip_comments(): tags = list(low_level_tagger(StringIO('999\ncomment\n0\nEOF\n'), skip_comments=False)) assert (999, 'comment') == tags[0] assert (0, 'EOF') == tags[1] assert len(tags) == 2
def external_tag_compiler(text): return tag_compiler(low_level_tagger(StringIO(text)))
def tags(request): stream = finder.getstream(request.param) return low_level_tagger(stream)