def test_package() -> None:
    package = Package(
        '009e35ef-1f50-4bf3-ab58-11eb85bf5503',
        Name('Soldered Wire Connector 1x19 ⌀1.0mm'),
        Description(
            'A 1x19 soldered wire connector with 2.54mm pin spacing and 1.0mm drill holes.\n\nGenerated with librepcb-parts-generator (generate_connectors.py)'
        ), Keywords('connector, 1x19, d1.0, connector, soldering, generic'),
        Author('Danilo B.'), Version('0.1'), Created('2018-10-17T19:13:41Z'),
        Deprecated(False), Category('56a5773f-eeb4-4b39-8cb9-274f3da26f4f'))

    package.add_pad(
        PackagePad('5c4d39d3-35cc-4836-a082-693143ee9135', Name('1')))
    package.add_pad(
        PackagePad('6100dd55-d3b3-4139-9085-d5a75e783c37', Name('2')))

    package.add_footprint(create_footprint())
    assert str(
        package) == """(librepcb_package 009e35ef-1f50-4bf3-ab58-11eb85bf5503
Exemple #2
0
def generate_pkg(
    dirpath: str,
    diameter: float,
    height: float,
    pitch: float,
    lead_width: float,
    author: str,
    version: str,
    create_date: Optional[str],
) -> None:
    # Name according IPC-7351 "Capacitor, Polarized Radial Diameter":
    # CAPPRD + Lead Spacing + W Lead Width + D Body Diameter + H Body Height
    name = 'CAPPRD{}W{}D{}H{}'.format(format_ipc_dimension(pitch),
                                      format_ipc_dimension(lead_width),
                                      format_ipc_dimension(diameter),
                                      format_ipc_dimension(height))
    variant = get_variant(diameter, height, pitch, lead_width)

    def _pkg_uuid(identifier: str) -> str:
        return uuid('pkg', variant, identifier)

    def _create_footprint(footprint_identifier: str, name: str) -> Footprint:
        def _fpt_uuid(identifier: str) -> str:
            return _pkg_uuid(footprint_identifier + '-' + identifier)

        drill = LEAD_WIDTH_TO_DRILL[lead_width]
        restring = min(
            (0.4 if diameter >= 6.0 else 0.3),  # preferred restring
            (pitch - drill - 0.25) / 2)  # minimum required restring
        pad_diameter = drill + (2 * restring)  # outer diameter of pad
        courtyard_diameter = diameter + (1.0 if diameter >= 10.0 else 0.8)

        def _generate_fill_polygon(identifier: str, layer: str) -> Polygon:
            polygon = Polygon(
                uuid=_fpt_uuid(identifier),
                layer=Layer(layer),
                width=Width(0.0),
                fill=Fill(True),
                grab_area=GrabArea(False),
            )
            if ((pitch - pad_diameter) < 0.6):
                # not enough space, use a simplified polygon
                vertices = [
                    (0.0, (diameter / 2) - 0.2, 0.0),
                    (0.0, (pad_diameter / 2) + 0.2, 0.0),
                    (pitch / 2, (pad_diameter / 2) + 0.2, -180.0),
                    (pitch / 2, -(pad_diameter / 2) - 0.2, 0.0),
                    (0.0, -(pad_diameter / 2) - 0.2, 0.0),
                    (0.0, -(diameter / 2) + 0.2, 180.0),
                    (0.0, (diameter / 2) - 0.2, 0.0),
                ]
            else:
                vertices = [
                    (0.0, (diameter / 2) - 0.2, 0.0),
                    (0.0, 0.0, 0.0),
                    ((pitch / 2) - (pad_diameter / 2) - 0.2, 0.0, -180.0),
                    ((pitch / 2) + (pad_diameter / 2) + 0.2, 0.0, -180.0),
                    ((pitch / 2) - (pad_diameter / 2) - 0.2, 0.0, 0.0),
                    (0.0, 0.0, 0.0),
                    (0.0, -(diameter / 2) + 0.2, 180.0),
                    (0.0, (diameter / 2) - 0.2, 0.0),
                ]
            for vertex in vertices:
                polygon.add_vertex(
                    Vertex(Position(vertex[0], vertex[1]), Angle(vertex[2])))
            return polygon

        footprint = Footprint(
            uuid=_fpt_uuid('footprint'),
            name=Name(name),
            description=Description(''),
        )
        footprint.add_pad(
            FootprintPad(
                uuid=_pkg_uuid('pad-plus'),
                side=Side.THT,
                shape=Shape.RECT,
                position=Position(-pitch / 2, 0),
                rotation=Rotation(0),
                size=Size(pad_diameter, pad_diameter),
                drill=Drill(drill),
            ))
        footprint.add_pad(
            FootprintPad(
                uuid=_pkg_uuid('pad-minus'),
                side=Side.THT,
                shape=Shape.ROUND,
                position=Position(pitch / 2, 0),
                rotation=Rotation(0),
                size=Size(pad_diameter, pad_diameter),
                drill=Drill(drill),
            ))

        # placement
        footprint.add_circle(
            Circle(
                uuid=_fpt_uuid('circle-placement'),
                layer=Layer('top_placement'),
                width=Width(0.2),
                fill=Fill(False),
                grab_area=GrabArea(False),
                diameter=Diameter(diameter + 0.2),
                position=Position(0.0, 0.0),
            ))
        footprint.add_polygon(
            _generate_fill_polygon(
                identifier='polygon-placement-fill',
                layer='top_placement',
            ))

        # documentation
        footprint.add_circle(
            Circle(
                uuid=_fpt_uuid('circle-documentation'),
                layer=Layer('top_documentation'),
                width=Width(0.2),
                fill=Fill(False),
                grab_area=GrabArea(False),
                diameter=Diameter(diameter - 0.2),
                position=Position(0.0, 0.0),
            ))
        footprint.add_polygon(
            _generate_fill_polygon(
                identifier='polygon-documentation-fill',
                layer='top_documentation',
            ))

        # courtyard
        footprint.add_circle(
            Circle(
                uuid=_fpt_uuid('circle-courtyard'),
                layer=Layer('top_courtyard'),
                width=Width(0.2),
                fill=Fill(False),
                grab_area=GrabArea(False),
                diameter=Diameter(courtyard_diameter),
                position=Position(0.0, 0.0),
            ))

        # texts
        footprint.add_text(
            StrokeText(
                uuid=_fpt_uuid('text-name'),
                layer=Layer('top_names'),
                height=Height(1.0),
                stroke_width=StrokeWidth(0.2),
                letter_spacing=LetterSpacing.AUTO,
                line_spacing=LineSpacing.AUTO,
                align=Align('center bottom'),
                position=Position(0.0, (diameter / 2) + 0.8),
                rotation=Rotation(0.0),
                auto_rotate=AutoRotate(True),
                mirror=Mirror(False),
                value=Value('{{NAME}}'),
            ))
        footprint.add_text(
            StrokeText(
                uuid=_fpt_uuid('text-value'),
                layer=Layer('top_values'),
                height=Height(1.0),
                stroke_width=StrokeWidth(0.2),
                letter_spacing=LetterSpacing.AUTO,
                line_spacing=LineSpacing.AUTO,
                align=Align('center top'),
                position=Position(0.0, -(diameter / 2) - 0.8),
                rotation=Rotation(0.0),
                auto_rotate=AutoRotate(True),
                mirror=Mirror(False),
                value=Value('{{VALUE}}'),
            ))
        return footprint

    # package
    package = Package(
        uuid=_pkg_uuid('pkg'),
        name=Name(name),
        description=Description(
            'Polarized radial electrolytic capacitor.\\n\\n' +
            'Diameter: {} mm\\n'.format(diameter) +
            'Height: {} mm\\n'.format(height) +
            'Lead Spacing: {} mm\\n'.format(pitch) +
            'Max. Lead Diameter: {} mm\\n\\n'.format(lead_width) +
            'Generated with {}'.format(generator)),
        keywords=Keywords(
            'electrolytic,capacitor,polarized,radial,c,cap,cpol'),
        author=Author(author),
        version=Version(version),
        created=Created(create_date or now()),
        deprecated=Deprecated(False),
        category=Category('ee75e31d-f231-41d9-8a3b-bea5114f41e3'),
    )
    package.add_pad(PackagePad(uuid=_pkg_uuid('pad-plus'), name=Name('+')))
    package.add_pad(PackagePad(uuid=_pkg_uuid('pad-minus'), name=Name('-')))
    package.add_footprint(
        _create_footprint(
            footprint_identifier='default',
            name='default',
        ))

    # write files
    pkg_dir_path = path.join(dirpath, package.uuid)
    if not (path.exists(pkg_dir_path) and path.isdir(pkg_dir_path)):
        makedirs(pkg_dir_path)
    with open(path.join(pkg_dir_path, '.librepcb-pkg'), 'w') as f:
        f.write('0.1\n')
    with open(path.join(pkg_dir_path, 'package.lp'), 'w') as f:
        f.write(str(package))
        f.write('\n')
    print('Wrote package {}'.format(name))