def test_bounds_all_elts(self):
        '''bounds() with all the elements competing'''
        net = Net('foo')
        mkbounds(net, 3, 3, -1, -2)
        self.des.add_net(net)

        annot = Annotation('foo', 3, 3, 0, True)
        mkbounds(annot, 3, 3, 3, 5)
        self.des.design_attributes.add_annotation(annot)

        libcomp = Component('bar')
        libcomp.add_symbol(Symbol())
        libcomp.symbols[0].add_body(Body())
        mkbounds(libcomp.symbols[0].bodies[0], 0, 0, 3, 3)
        self.des.add_component('foo', libcomp)

        compinst = ComponentInstance('bar', 'foo', 0)
        compinst.add_symbol_attribute(SymbolAttribute(3, 0, 0))
        self.des.add_component_instance(compinst)

        top_left, btm_right = self.des.bounds()
        self.assertEqual(top_left.x, -1)
        self.assertEqual(top_left.y, -2)
        self.assertEqual(btm_right.x, 6)
        self.assertEqual(btm_right.y, 5)
    def parse_component_instance(self, f):
        """ Parse a component instance from a $Comp block """
        # pylint: disable=R0914

        # name & reference
        prefix, name, reference = f.readline().split()
        assert prefix == 'L'

        # unit & convert
        prefix, unit, convert, _ = f.readline().split(None, 3)
        unit, convert = int(unit), int(convert)
        assert prefix == 'U'

        # position
        prefix, compx, compy = f.readline().split()
        assert prefix == 'P'
        compx, compy = int(compx), int(compy)

        line = f.readline()
        rotation = 0
        annotations = []

        while line.strip() not in ("$EndComp", ''):
            if line.startswith('F '):
                parts = line.split('"', 2)
                value = parts[1].decode('utf-8', errors='replace')
                parts = parts[2].strip().split()
                annotations.append(
                    Annotation(value,
                               make_length(int(parts[1]) - compx),
                               -make_length(int(parts[2]) - compy),
                               0 if parts[0] == 'H' else 1, 'true'))
            elif line.startswith('\t'):
                parts = line.strip().split()
                if len(parts) == 4:
                    rotation = MATRIX2ROTATION.get(
                        tuple(int(i) for i in parts), 0)
            line = f.readline()

        inst = ComponentInstance(reference, name, convert - 1)
        symbattr = SymbolAttribute(make_length(compx), -make_length(compy),
                                   rotation)
        for ann in annotations:
            symbattr.add_annotation(ann)
        inst.add_symbol_attribute(symbattr)

        return inst
    def test_bounds_parts(self):
        '''test bounds() with just components in the design'''
        libcomp = Component('bar')
        libcomp.add_symbol(Symbol())
        libcomp.symbols[0].add_body(Body())
        mkbounds(libcomp.symbols[0].bodies[0], 0, 0, 10, 10)
        self.des.add_component('foo', libcomp)
        for (x, y) in ((1, 3), (3, 2), (5, 3), (3, 7)):
            compinst = ComponentInstance(str((x, y)), 'foo', 0)
            compinst.add_symbol_attribute(SymbolAttribute(x, y, 0))
            self.des.add_component_instance(compinst)

        top_left, btm_right = self.des.bounds()
        self.assertEqual(top_left.x, 1)
        self.assertEqual(top_left.y, 2)
        self.assertEqual(btm_right.x, 15)
        self.assertEqual(btm_right.y, 17)
    def test_write_instance(self):
        """
        The write_instance method serializes a component instance
        correctly.
        """

        inst = ComponentInstance('id', 'libid', 1)
        inst.add_symbol_attribute(SymbolAttribute(3, 4, 0.5))
        writer = KiCAD()
        buf = StringIO()
        writer.write_instance(buf, inst)
        self.assertEqual(buf.getvalue(), '''\
$Comp
L libid id
U 1 1 00000000
P 33 -44
\t1    33 -44
\t0    1    1    0
$EndComp
''')
    def parse_component_instances(self, component_instances):
        """ Extract the component instances. """
        for instance in component_instances:
            # Get instance_id, library_id and symbol_index
            instance_id = instance.get('instance_id')
            library_id = instance.get('library_id')
            symbol_index = int(instance.get('symbol_index'))
            # Make the ComponentInstance()
            inst = ComponentInstance(instance_id, library_id, symbol_index)

            # Get the SymbolAttributes
            for symbol_attribute in instance.get('symbol_attributes'):
                attr = self.parse_symbol_attribute(symbol_attribute)
                inst.add_symbol_attribute(attr)

            # Get the Attributes
            for key, value in instance.get('attributes').items():
                inst.add_attribute(key, value)

            # Add the ComponentInstance
            self.design.add_component_instance(inst)
    def parse_inst(self, args):
        """ Returns a parsed component instance. """
        inst, libname, libnum, x, y, rot, _scale, _b = args.split()
        # scale is a floating point scaling constant. Also, evil.
        thisinst = ComponentInstance(inst, self.lookup(libname, libnum), 0)
        if int(rot) > 3:
            # part is flipped around y-axis. When applying transforms, flip it
            # first, then rotate it.
            rot = str(int(rot) - 4)
            # flip = True

        thisinst.add_symbol_attribute(SymbolAttribute(int(x), int(y),
                                                      float(rot) / 2))
        subdata = defaultdict(list)
        for phrase in self.stream:
            cmd, _sep, args = phrase.partition(' ')
            if cmd not in ('|R', 'A', 'C'):
                self.stream.push(phrase)
                break
            k, v = self.parsenode(cmd)(args)
            subdata[k].append(v)
        for annot in subdata['annot']:
            thisinst.symbol_attributes[0].add_annotation(annot)
            if '=' in annot.value:
                thisinst.add_attribute(*(annot.value.split('=', 1)))

        # Turns out C can reference a net before it's been created via
        # the N command. Really don't like passing stuff inband like this. Ugh.
        thisinst.conns = subdata['conn']
        return ('inst', thisinst)
    def parse_component_instance(self, inst):
        """ Parse a Fritzing non-wire instance into a ComponentInstance """

        view = inst.find('views/schematicView')

        if view is None:
            return

        if view.get('layer') == 'breadboardbreadboard':
            return

        cpt = self.ensure_component(inst)

        if cpt is None:
            return

        index = inst.get('modelIndex')
        idref = inst.get('moduleIdRef')
        title = inst.find('title').text
        geom = view.find('geometry')
        xform = geom.find('transform')

        x, y = float(geom.get('x', 0)), float(geom.get('y', 0))

        if xform is None:
            rotation = 0.0
        else:
            matrix = tuple(int(float(xform.get(key, 0)))
                           for key in ('m11', 'm12', 'm21', 'm22'))
            x, y = rotate_component(cpt, matrix, x, y)
            rotation = MATRIX2ROTATION.get(matrix, 0.0)

        compinst = ComponentInstance(title, idref, 0)

        compinst.add_symbol_attribute(
            SymbolAttribute(make_x(x), make_y(y), rotation))

        self.component_instances[index] = compinst
    def parse_component(self, stream, params):
        """ Creates a component instance according to the component *params*.
            If the component is not known in the library, a the component 
            will be created according to its description in the embedded
            environment ``[]`` or a symbol file. The component is added
            to the library automatically if necessary. 
            An instance of this component will be created and added to 
            the design. 
            A GEDAError is raised when either the component file
            is invalid or the referenced symbol file cannot be found 
            in the known directories.

            Returns a tuple of Component and ComponentInstance objects.
        """
        basename, dummy = os.path.splitext(params['basename'])

        component_name = basename
        if params['mirror']:
            component_name += '_MIRRORED'

        if component_name in self.design.components.components:
            component = self.design.components.components[component_name]

            ## skipping embedded data might be required
            self.skip_embedded_section(stream)

        else:
            ##check if sym file is embedded or referenced 
            if basename.startswith('EMBEDDED'):
                ## embedded only has to be processed when NOT in symbol lookup
                if basename not in self.known_symbols:
                    component = self.parse_component_data(stream, params)
            else:
                if basename not in self.known_symbols:
                    log.warn("referenced symbol file '%s' unknown" % basename)
                    ## parse optional attached environment before continuing
                    self._parse_environment(stream)
                    return None, None

                ## requires parsing of referenced symbol file
                f_in = open(self.known_symbols[basename], "rU")
                self._check_version(f_in)

                component = self.parse_component_data(f_in, params) 

                f_in.close()
                        
            self.design.add_component(component_name, component)

        ## get all attributes assigned to component instance
        attributes = self._parse_environment(stream)

        ## refdes attribute is name of component (mandatory as of gEDA doc)
        ## examples if gaf repo have components without refdes, use part of
        ## basename
        if attributes is not None:
            instance = ComponentInstance(
                attributes.get('_refdes', component.name),
                component.name, 
                0
            )
            for key, value in attributes.items():
                instance.add_attribute(key, value)

        else:
            instance = ComponentInstance(
                component.name, 
                component.name, 
                0
            )

        ## generate a component instance using attributes
        self.design.add_component_instance(instance)

        symbol = SymbolAttribute(
            self.x_to_px(params['x']), 
            self.y_to_px(params['y']), 
            self.conv_angle(params['angle'])
        )
        instance.add_symbol_attribute(symbol)

        ## add annotation for special attributes 
        for idx, attribute_key in enumerate(['_refdes', 'device']):
            if attribute_key in component.attributes \
               or attribute_key in instance.attributes:

                symbol.add_annotation(
                    Annotation(
                        '{{%s}}' % attribute_key, 
                        0, 0+idx*10, 0.0, 'true'
                    )
                )

        return component, instance
    def parse(self, filename, library_filename=None):
        """ Parse a kicad file into a design """

        # Rough'n'dirty parsing, assume nothing useful comes before
        # the description
        circuit = Design()
        segments = set()  # each wire segment
        junctions = set()  # wire junction point (connects all wires under it)

        if library_filename is None:
            library_filename = splitext(filename)[0] + '-cache.lib'
            if exists(library_filename):
                self.parse_library(library_filename, circuit)

        f = open(filename)

        # Read until the end of the description
        while f.readline().strip() != "$EndDescr":
            pass

        # Now parse wires and components, ignore connections, we get
        # connectivity from wire segments

        line = f.readline()
        while line:
            element = line.split()[0]  # whats next on the list
            if element == "Wire":  # Wire Segment, coords on 2nd line
                x1, y1, x2, y2 = [int(i) for i in f.readline().split()]
                if not (x1 == x2 and y1 == y2):  # ignore zero-length segments
                    segments.add(((x1, y1), (x2, y2)))
            elif element == "Connection":  # Store these to apply later
                x, y = [int(i) for i in line.split()[2:4]]
                junctions.add((x, y))
            elif element == "$Comp":  # Component Instance
                # name & reference
                prefix, name, reference = f.readline().split()
                assert prefix == 'L'

                # timestamp
                prefix, _ = f.readline().split(None, 1)
                assert prefix == 'U'

                # position
                prefix, compx, compy = f.readline().split()
                assert prefix == 'P'
                compx, compy = int(compx), int(compy)

                # TODO(ajray): ignore all the fields for now, probably
                # could make these annotations

                while f.readline().strip() not in ("$EndComp", ''):
                    pass

                # TODO: calculate rotation
                inst = ComponentInstance(reference, name, 0)
                inst.add_symbol_attribute(SymbolAttribute(compx, compy, 0))

                circuit.add_component_instance(inst)

            line = f.readline()

        f.close()

        segments = self.divide(segments, junctions)
        circuit.nets = self.calc_nets(segments)

        return circuit
    def parse(self, filename, library_filename=None):
        """ Parse a kicad file into a design """

        # Rough'n'dirty parsing, assume nothing useful comes before
        # the description
        circuit = Design()
        segments = set()  # each wire segment
        junctions = set()  # wire junction point (connects all wires under it)

        if library_filename is None:
            library_filename = splitext(filename)[0] + "-cache.lib"
            if exists(library_filename):
                self.parse_library(library_filename, circuit)

        f = open(filename)

        # Read until the end of the description
        while f.readline().strip() != "$EndDescr":
            pass

        # Now parse wires and components, ignore connections, we get
        # connectivity from wire segments

        line = f.readline()
        while line:
            element = line.split()[0]  # whats next on the list
            if element == "Wire":  # Wire Segment, coords on 2nd line
                x1, y1, x2, y2 = [int(i) for i in f.readline().split()]
                if not (x1 == x2 and y1 == y2):  # ignore zero-length segments
                    segments.add(((x1, y1), (x2, y2)))
            elif element == "Connection":  # Store these to apply later
                x, y = [int(i) for i in line.split()[2:4]]
                junctions.add((x, y))
            elif element == "$Comp":  # Component Instance
                # name & reference
                prefix, name, reference = f.readline().split()
                assert prefix == "L"

                # timestamp
                prefix, _ = f.readline().split(None, 1)
                assert prefix == "U"

                # position
                prefix, compx, compy = f.readline().split()
                assert prefix == "P"
                compx, compy = int(compx), int(compy)

                # TODO(ajray): ignore all the fields for now, probably
                # could make these annotations

                while f.readline().strip() not in ("$EndComp", ""):
                    pass

                # TODO: calculate rotation
                inst = ComponentInstance(reference, name, 0)
                inst.add_symbol_attribute(SymbolAttribute(compx, compy, 0))

                circuit.add_component_instance(inst)

            line = f.readline()

        f.close()

        segments = self.divide(segments, junctions)
        circuit.nets = self.calc_nets(segments)

        return circuit