Ejemplo n.º 1
0
 def __init__(self, doc: "Drawing", entities: Iterable[Tags] = None):
     self.doc = doc
     self.entities: List[AcDsEntity] = []
     self.section_info = Tags()
     if entities is not None:
         self.load_tags(iter(entities))
Ejemplo n.º 2
0
 def add(self, appid: str, tags: Iterable) -> None:
     data = Tags(dxftag(code, value) for code, value in tags)
     if data[0] != (XDATA_MARKER, appid):
         data.insert(0, dxftag(XDATA_MARKER, appid))
     self._add(data)
Ejemplo n.º 3
0
def test_group_tags_poyline_with_xdata():
    tags = Tags.from_text(POLYLINE_WITH_INVALID_XDATA)
    assert len(tags) == 49
    tags2 = list(filter_invalid_xdata_group_codes(tags))
    assert len(tags2) == 41
Ejemplo n.º 4
0
 def test_emtpy_tags(self):
     tags = Tags()
     collected_tags = tags.collect_consecutive_tags([0, 1, 2, 3, 4])
     assert 0 == len(collected_tags)
Ejemplo n.º 5
0
 def __init__(self, type_, value, font='STANDARD'):
     self.type = type_
     self.value = value
     self.font = font
     self.tags = Tags()
Ejemplo n.º 6
0
 def test_find_first_value_error(self):
     tags = Tags.from_text(TESTFINDALL)
     with pytest.raises(DXFValueError):
         tags.tag_index(1)
Ejemplo n.º 7
0
 def test_strip_tags(self, tags):
     tags.remove_tags(codes=(0, ))
     result = Tags.strip(tags, codes=(0, ))
     assert 5 == len(result)
     assert isinstance(result, Tags)
Ejemplo n.º 8
0
def test_skip_empty_subclass(xtags3):
    xtags3.subclasses[1] = Tags()  # create empty subclass
    subclass2 = xtags3.get_subclass('AcDbText')
    assert (100, 'AcDbText') == subclass2[0]
Ejemplo n.º 9
0
 def export_entity(self, tagwriter: 'TagWriter') -> None:
     super().export_entity(tagwriter)
     tagwriter.write_tag2(SUBCLASS_MARKER, acdb_xrecord.name)
     tagwriter.write_tag2(280, self.dxf.cloning)
     tagwriter.write_tags(Tags(totags(self.tags)))
Ejemplo n.º 10
0
    def fast_load_dxfattribs(self,
                             dxf: DXFNamespace,
                             group_code_mapping: Dict[int, Union[str, List]],
                             subclass: Union[int, str, Tags],
                             *,
                             recover=False,
                             log=True) -> Tags:
        """ Load DXF attributes into the DXF namespace and returns the
        unprocessed tags without leading subclass marker(100, AcDb...).
        Bypasses the DXF attribute validity checks.

        Args:
            dxf: entity DXF namespace
            group_code_mapping: group code to DXF attribute name mapping,
                callback attributes have to be marked with a leading "*"
            subclass: subclass by index, by name or as Tags()
            recover: recover graphic attributes
            log: enable/disable logging of unprocessed tags

        """
        if self.r12:
            tags = self.subclasses[0]
        else:
            if isinstance(subclass, int):
                tags = self.subclass_by_index(subclass)
            elif isinstance(subclass, str):
                tags = self.find_subclass(subclass)
            else:
                tags = subclass

        unprocessed_tags = Tags()
        if tags is None or len(tags) == 0:
            return unprocessed_tags

        processed_names = set()
        # Localize attributes:
        get_attrib_name = group_code_mapping.get
        append_unprocessed_tag = unprocessed_tags.append
        unprotected_set_attrib = dxf.unprotected_set
        mark_attrib_as_processed = processed_names.add

        # Ignore (100, "AcDb...") or (0, "ENTITY") tag in case of DXF R12
        start = 1 if tags[0].code in (0, 100) else 0
        for tag in tags[start:]:
            name = get_attrib_name(tag.code)
            if isinstance(name, list):  # process group code duplicates:
                names = name
                # If all existing attrib names are used, treat this tag
                # like an unprocessed tag.
                name = None
                # The attribute names are processed in the order of their
                # definition:
                for name_ in names:
                    if name_ not in processed_names:
                        name = name_
                        mark_attrib_as_processed(name_)
                        break
            if name:
                # Ignore callback attributes and group codes explicit marked
                # as "*IGNORE":
                if name[0] != '*':
                    unprotected_set_attrib(name,
                                           cast_value(tag.code, tag.value))
            else:
                append_unprocessed_tag(tag)

        if self.r12:
            # R12 has always unprocessed tags, because there are all tags in one
            # subclass and one subclass definition never covers all tags e.g.
            # handle is processed in DXFEntity, so it is an unprocessed tag in
            # AcDbEntity.
            return unprocessed_tags

        # Only DXF R13+
        if recover and len(unprocessed_tags):
            unprocessed_tags = recover_graphic_attributes(
                unprocessed_tags, dxf)
        if len(unprocessed_tags) and log:
            # First tag is the subclass specifier (100, "AcDb...")
            name = tags[0].value
            self.log_unprocessed_tags(tags,
                                      subclass=name,
                                      handle=dxf.get('handle'))
        return unprocessed_tags
Ejemplo n.º 11
0
def test_init_with_tags():
    tags = Tags.from_text(XTAGS1)
    xtags = ExtendedTags(tags)
    assert 3 == len(xtags.subclasses)
    assert 1 == len(xtags.xdata)
Ejemplo n.º 12
0
 def get_handle(tags: Tags):
     try:
         return tags.get_handle()
     except ValueError:
         return "0"
Ejemplo n.º 13
0
 def test_replace_handle_5(self):
     tags = Tags.from_text(TESTHANDLE5)
     tags.replace_handle("AA")
     assert "AA" == tags.get_handle()
Ejemplo n.º 14
0
 def test_get_handle_5(self):
     tags = Tags.from_text(TESTHANDLE5)
     assert "F5" == tags.get_handle()
Ejemplo n.º 15
0
 def test_find_all(self):
     tags = Tags.from_text(TESTFINDALL)
     assert 3 == len(tags.find_all(0))
Ejemplo n.º 16
0
 def _copy_data(self, entity: 'VBAProject') -> None:
     entity.tags = Tags(entity.tags)
Ejemplo n.º 17
0
 def test_tag_index(self):
     tags = Tags.from_text(TESTFINDALL)
     index = tags.tag_index(0)
     assert 0 == index
     index = tags.tag_index(0, index + 1)
     assert 1 == index
Ejemplo n.º 18
0
 def __init__(self):
     super().__init__()
     self.tags = Tags()
Ejemplo n.º 19
0
 def test_replace_handle_105(self):
     tags = Tags.from_text(TESTHANDLE105)
     tags.replace_handle('AA')
     assert 'AA' == tags.get_handle()
Ejemplo n.º 20
0
 def _copy_data(self, entity: 'XRecord') -> None:
     entity.tags = Tags(entity.tags)
Ejemplo n.º 21
0
 def tags(self):
     return Tags.from_text(COLLECT_1)
Ejemplo n.º 22
0
class HeaderSection:
    MIN_HEADER_TAGS = Tags.from_text(MIN_HEADER_TEXT)
    name = 'HEADER'

    def __init__(self):
        self.hdrvars: Dict[str, 'HeaderVar'] = OrderedDict()
        self.custom_vars = CustomVars()

    @classmethod
    def load(cls, tags: Iterator[DXFTag] = None) -> 'HeaderSection':
        """ Constructor to generate header variables loaded from DXF files
        (untrusted environment).

        Args:
            tags: DXF tags as Tags() or ExtendedTags()

        (internal API)
        """
        if tags is None:  # create default header
            # files without a header have the default version: R12
            return cls.new(dxfversion=const.DXF12)
        section = cls()
        section.load_tags(iter(tags))
        return section

    @classmethod
    def new(cls, dxfversion=const.LATEST_DXF_VERSION) -> 'HeaderSection':
        section = HeaderSection()
        section.hdrvars = default_vars()
        section['$ACADVER'] = dxfversion
        return section

    def load_tags(self, tags: Iterator[DXFTag]) -> None:
        """ Constructor to generate header variables loaded from DXF files
        (untrusted environment).

        Args:
            tags: DXF tags as Tags() or ExtendedTags()

        """
        tags = tags or self.MIN_HEADER_TAGS
        section_tag = next(tags)
        name_tag = next(tags)

        if section_tag != (0, 'SECTION') or name_tag != (2, 'HEADER'):
            raise const.DXFStructureError(
                "Critical structure error in HEADER section.")

        groups = group_tags(header_validator(tags), splitcode=9)
        custom_property_stack = []  # collect $CUSTOMPROPERTY/TAG
        for group in groups:
            name = group[0].value
            value = group[1]
            if name in ('$CUSTOMPROPERTYTAG', '$CUSTOMPROPERTY'):
                custom_property_stack.append(value.value)
            else:
                self.hdrvars[name] = HeaderVar(value)

        custom_property_stack.reverse()
        while len(custom_property_stack):
            try:
                self.custom_vars.append(tag=custom_property_stack.pop(),
                                        value=custom_property_stack.pop())
            except IndexError:  # internal exception
                break

    @classmethod
    def from_text(cls, text: str) -> 'HeaderSection':
        """ Load constructor from text for testing """
        return cls.load(Tags.from_text(text))

    def _headervar_factory(self, key: str, value: Any) -> DXFTag:
        if key in HEADER_VAR_MAP:
            factory = HEADER_VAR_MAP[key].factory
            return factory(value)
        else:
            raise const.DXFKeyError(f"Invalid header variable {key}.")

    def __len__(self) -> int:
        """ Returns count of header variables. """
        return len(self.hdrvars)

    def __contains__(self, key) -> bool:
        """ Returns ``True`` if header variable `key` exist. """
        return key in self.hdrvars

    def varnames(self) -> KeysView:
        """ Returns an iterable of all header variable names. """
        return self.hdrvars.keys()

    def export_dxf(self, tagwriter: 'TagWriter') -> None:
        """ Exports header section as DXF tags. (internal API) """
        def _write(name: str, value: Any) -> None:
            if value.value is None:
                logger.info(f"did not write header var {name}, value is None.")
                return
            tagwriter.write_tag2(9, name)
            group_code = version_specific_group_code(name, dxfversion)
            # fix invalid group codes
            if group_code != value.code:
                value = HeaderVar((group_code, value.value))
            tagwriter.write_str(str(value))

        dxfversion = tagwriter.dxfversion
        write_handles = tagwriter.write_handles

        tagwriter.write_str("  0\nSECTION\n  2\nHEADER\n")
        save = self['$ACADVER']
        self['$ACADVER'] = dxfversion
        for name, value in header_vars_by_priority(self.hdrvars, dxfversion):
            if not write_handles and name == '$HANDSEED':
                continue  # skip $HANDSEED
            _write(name, value)
            if name == '$LASTSAVEDBY':  # ugly hack, but necessary for AutoCAD
                self.custom_vars.write(tagwriter)
        self['$ACADVER'] = save
        tagwriter.write_str("  0\nENDSEC\n")

    def get(self, key: str, default: Any = None) -> Any:
        """ Returns value of header variable `key` if exist, else the `default`
        value.

        """
        if key in self.hdrvars:
            return self.__getitem__(key)
        else:
            return default

    def __getitem__(self, key: str) -> Any:
        """ Get header variable `key` by index operator like:
        :code:`drawing.header['$ACADVER']`

        """
        try:
            return self.hdrvars[key].value
        except KeyError:  # map exception
            raise const.DXFKeyError(str(key))

    def __setitem__(self, key: str, value: Any) -> None:
        """ Set header variable `key` to `value` by index operator like:
        :code:`drawing.header['$ANGDIR'] = 1`

        """
        try:
            tags = self._headervar_factory(key, value)
        except (IndexError, ValueError):
            raise const.DXFValueError(str(value))
        self.hdrvars[key] = HeaderVar(tags)

    def __delitem__(self, key: str) -> None:
        """ Delete header variable `key` by index operator like:
        :code:`del drawing.header['$ANGDIR']`

        """
        try:
            del self.hdrvars[key]
        except KeyError:  # map exception
            raise const.DXFKeyError(str(key))
Ejemplo n.º 23
0
 def tags(self):
     return Tags.from_text(TEST_TAGREADER)
Ejemplo n.º 24
0
 def from_text(cls, text: str) -> 'HeaderSection':
     """ Load constructor from text for testing """
     return cls.load(Tags.from_text(text))
Ejemplo n.º 25
0
 def _set_path_tags(self, vertices: Iterable['Vertex']):
     boundary = [DXFVertex(11, value) for value in vertices]
     subclasstags = Tags(tag for tag in self.tags.subclasses[2]
                         if tag.code != 11)  # filter out existing path tags
     subclasstags.extend(boundary)
     self.tags.subclasses[2] = subclasstags
Ejemplo n.º 26
0
 def test_point_count_management(self):
     mline = MLine()
     mline.load_vertices(Tags.from_text(VTX_2))
     assert len(mline.vertices) == 2
     assert len(mline) == 2
     assert mline.dxf.count == 2, 'should be a callback to __len__()'
Ejemplo n.º 27
0
 def __init__(self, doc: 'Drawing' = None):
     super().__init__(doc)
     # todo: MLEADER implementation
     self.tags = Tags()
Ejemplo n.º 28
0
 def test_get_handle_105(self):
     tags = Tags.from_text(TESTHANDLE105)
     assert 'F105' == tags.get_handle()
Ejemplo n.º 29
0
def test_invalid_group_code_raises_value_error():
    tags = Tags.from_text("5\ninvalid\n")
    with pytest.raises(const.DXFValueError):
        parse_items(tags)
Ejemplo n.º 30
0
 def _write_header(self, tagwriter: "TagWriter") -> None:
     tagwriter.write_tags(Tags([self._dxftype, self.flags]))