Metadata-Version: 2.5
Name: part2kicad
Version: 0.3.0
Summary: LCSC/EasyEDA parts as a KiCad library, with traceable provenance
Project-URL: Homepage, https://github.com/AltF4Quit/part2kicad
Project-URL: Issues, https://github.com/AltF4Quit/part2kicad/issues
Author: Emil Menzel
License-Expression: GPL-3.0-or-later
License-File: LICENSE
Keywords: easyeda,eda,footprint,jlcpcb,kicad,lcsc,pcb,symbol
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Manufacturing
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Requires-Dist: platformdirs>=4.0
Requires-Dist: sexpdata>=1.0.2
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Description-Content-Type: text/markdown

# part2kicad

Type an LCSC number, get a finished KiCad part in your project — symbol, footprint and
3D model, with a note on the symbol saying where every value came from.

```
cd my-kicad-project
part2kicad add C12594
```

```
TL074CDR (C12594) → my-kicad-project
  14 pins in 4 units
  Footprint SOIC-14_3.9x8.7mm_P1.27mm, 14 pads
  3D model TL074CDR.step
  Fetched on 2026-08-14
```

Open the schematic, press **A**, and the part is in the list. No download folder, no
manual library table, no copying files around.

## What you get

- **Symbol, footprint and 3D model in one go.** They land in your project's own library
  and both library tables are registered for you.
- **Multi-unit parts come out as one part.** A quad op-amp becomes one symbol with four
  units — `U1A` to `U1D` — not four separate parts.
- **Provenance on the part.** Source, part number and fetch date are fields on the
  symbol, so in six months you can still tell where it came from.
- **Nothing is overwritten by accident.** A part that is already in the library is
  reported, not replaced.
- **Search without leaving the terminal.** `part2kicad search rp2040` lists hits with
  price and stock, you pick one, it is taken in.

## Requirements

- **Python 3.11 or newer**
- **KiCad 10.0 or newer.** The tool calls `kicad-cli`, which ships with KiCad. On Windows
  that program is normally not on the search path, so `part2kicad` looks in the usual
  installation folders. If it still cannot find it, say where it is:

  ```
  set PART2KICAD_KICAD_CLI=C:\Program Files\KiCad\10.0\bin\kicad-cli.exe
  ```

  In PowerShell the same line reads:

  ```
  $env:PART2KICAD_KICAD_CLI = "C:\Program Files\KiCad\10.0\bin\kicad-cli.exe"
  ```

## Installation

```
uv pip install part2kicad
```

Plain `pip install part2kicad` works just as well. The package is a pure
`py3-none-any` wheel, so no compiler is needed on your machine.

Or from a wheel you build yourself, which is the route while working on the tool:

```
uv build
uv pip install dist/part2kicad-*.whl
```

Publishing to PyPI was a step of its own rather than a side effect of development,
because it cannot be taken back: it claims the name permanently and turns the command
layout (`search`, `add`) into a published interface that scripts and tutorials will
anchor themselves to. A released version can be yanked, but its number can never be
reused.

## Your first part

1. **Open a terminal in your KiCad project folder** — the one holding the `.kicad_pro`
   file. `part2kicad` finds the project the way git finds a repository: from the working
   directory upwards. If there is none, it stops instead of writing somewhere arbitrary.

2. **Take a part in.** If you know the LCSC number:

   ```
   part2kicad add C12594
   ```

   If you do not, search by manufacturer part number or by description:

   ```
   part2kicad search tl074
   ```

   You get a numbered list with package, price, stock and whether CAD data exists at all.
   Pick a number, and that part is taken in — search and import are one invocation.

3. **Open the schematic in KiCad** and press **A** to place a symbol. The library is
   named after your project and is already in the list; you do not have to add anything
   under *Preferences → Manage Symbol Libraries*.

4. **Check the 3D model.** Open the board, press **Alt+3**. The model is stored inside
   the project, so the folder still works on a machine that has never seen `part2kicad`.

If KiCad was already open while the part was written, use *Preferences → Manage Symbol
Libraries → OK* or restart it — KiCad reads the library tables once at start.

## Everyday use

```
part2kicad add C2040                 # take a part in by number
part2kicad search rp2040             # search, pick, take it in — one invocation
part2kicad add C2040 --force         # replace a part that is already there
part2kicad add C2040 --project ../my-board   # name the project explicitly
part2kicad add C2040 --json          # machine-readable output, asks nothing
part2kicad add C2040 --verbose       # one line per fetch on stderr
```

### Taking the same part in twice

If the part is already in the project library, `part2kicad` says so along with the date
of the first fetch and **writes nothing**. Anyone who has touched up a part by hand does
not lose that work to a careless second invocation.

`--force` replaces it. A symbol already placed in the schematic then has to be brought up
to date there, via *Tools → Update Symbols from Library*.

### What ends up on the part

| Group | Fields |
|---|---|
| Provenance | `Supplier Part`, `Manufacturer`, `Manufacturer Part`, `Datasheet`, `Source`, `Fetch Date` |
| Commercial data | `Price` and `Stock`, each with the date it was fetched |
| Technical parameters | whatever the source delivers, under its **unchanged** field names |
| Assembly | `JLCPCB Part Class` (Basic/Extended) — it decides the assembly cost |

Every field except `Reference` and `Value` is created hidden, so the schematic stays
readable. Price and stock only come with `part2kicad search`; the fetch by part number
does not carry them, and `part2kicad` does not invent a price.

The `Datasheet` link is checked before it is written: one HEAD request asks the server
what it would actually deliver. Many links that end in `.pdf` return a web page, and the
field says so rather than pretending.

## When something goes wrong

| What you see | What it means | What to do |
|---|---|---|
| `kicad-cli not found` | KiCad is not installed, or not where the tool looked | Set `PART2KICAD_KICAD_CLI` to the full path, see [Requirements](#requirements) |
| `no KiCad project found` | You are not inside a project folder | `cd` into the folder holding the `.kicad_pro` file, or pass `--project` |
| `this part has no CAD data` | The supplier has the part but no symbol or footprint for it | The message names the part and links its datasheet; draw it by hand or pick another part |
| `already in the library` | The part was taken in before | That is the safeguard, not an error. `--force` replaces it |
| The library does not show in KiCad | KiCad read its library tables at start | *Preferences → Manage Symbol Libraries → OK*, or restart KiCad |
| Everything hangs for two minutes | The supplier is throttling you | Leave it running; it waits and retries. **Ctrl-C** stops it cleanly at any time |

## What it cannot do yet

Honest rather than sounding complete:

- **The report does not exist yet.** Provenance and fetch date are on the part as fields;
  a report that shows field by field where each value came from, and which KLC rules were
  checked with what outcome, arrives with phase 3. Until then, "traceable" means every
  value comes from the source — not that a rule check has run.
- **A local result store does not exist yet**, so a second `add … --force` fetches the
  same geometry again. It arrives with phase 5.
- **The field names of the technical parameters stay as the source delivers them** — so,
  inconsistent. Unifying them is a step of its own and has not been taken yet.
- **macOS is untested, and nobody has run this on Linux yet.** Development and testing
  happen on Windows. For Linux the platform assumptions are pinned down statically — no
  hard-wired path, no shell invocation, no file access without a stated encoding,
  configuration folder from `platformdirs` — but a run is still outstanding.
- **Two concurrent invocations on the same library can lose a symbol.** The swap of the
  finished file is atomic; the read-modify-write before it is not. For an interactive
  single-workstation tool, a file lock has deliberately not been built in.
- **Price and stock are only available via `part2kicad search`**, see above.

## How this tool treats the data sources

`part2kicad` queries foreign servers that have no contract with us to serve it. What it
does while doing so is written out here in full, because a user is entitled to know what
runs in their name.

### Endpoints used

All the addresses live in `src/part2kicad/recipe.toml` and **not** in the program code.
If the counterpart changes, the repair is an edit there — not a program update.

| Purpose | Address | When |
|---|---|---|
| Search | `https://pro.easyeda.com/api/eda/product/search` | once per `search` invocation |
| Geometry (symbol **and** footprint) | `https://easyeda.com/api/products/{lcsc}/components` | once per part taken in |
| 3D model (STEP) | `https://modules.easyeda.com/…/{uuid}` | once per part taken in, if one is on file |
| Datasheet check | whichever address the response names — measured, `atta.`, `item.` and `so.szlcsc.com` | one HEAD request per part taken in |

Symbol and footprint come from **one** fetch; there is no second one for the footprint.
The datasheet check is a HEAD request: it asks what the server would deliver and reads no
body. If a part is already in the library, no fetch happens at all without `--force`.

### Identification

`part2kicad` identifies itself as

```
part2kicad/<version> (+https://pypi.org/project/part2kicad/)
```

An honest identification that names the product. Explicitly **not**: a faked browser
user agent, or bending name resolution to get around a block. This is not decoration —
measured, the honest route gets through, and the dishonest one would not be acceptable
even if it were necessary.

The identification can be changed without touching the program: your own `recipe.toml`
in the platform's configuration folder (Windows `%LOCALAPPDATA%\part2kicad\`, Linux
`~/.config/part2kicad/`) overrides individual values **selectively**:

```toml
[identity]
user_agent = "my-identification/1.0 (+https://example.example)"
```

### Minimum intervals and behaviour when blocked

Every endpoint has its **own** time budget — the block we measured is tied to the path,
and a shared budget would slow the search down as soon as a geometry fetch is due.

| Endpoint | Minimum interval | Maximum attempts |
|---|---|---|
| Search | 2.5 s | 3 |
| Geometry | 3.0 s | 3 |
| 3D model | 1.0 s | 3 |
| Datasheet check | 1.0 s | 3 |

The counterpart starts blocking after roughly 45 fetches within a few minutes —
cumulatively, not by peak rate. It then answers with a bare **HTTP 403**, without
`Retry-After` and without HTTP 429; the block therefore cannot be predicted, only
recognised. It clears by itself after about two minutes.

In that case `part2kicad` waits, starting at 120 seconds and doubling per attempt, for at
most three attempts — 120 + 240 = **six minutes** in total. More would be out of
proportion: measured, the block clears after around two minutes, and if it is still there
after three times that, it is not the ordinary rate limit; waiting longer is then no
better a bet than telling the user. The wait is shown as a status line — two minutes of
silence could not be told apart from a crash — and **Ctrl-C** ends it at any time with a
message instead of a stack trace. If the counterpart still will not let up, the
invocation stops with a message saying that it is not your machine's fault. Nothing is
written along the way: as long as not all the pieces are together, the library stays
untouched.

The numbers all live in `recipe.toml` and can be changed in your own user file — a limit
hard-coded in the program would take that option away.

### The counterpart's exclusion list

`easyeda.com/robots.txt` disallows `//api/` paths — and with them the geometry endpoint.
That is named openly here rather than passed over:

- The route is used **deliberately**, because there is no other one that would yield a
  part's CAD data.
- It is **minimised**: one fetch per part, never a full catalogue, and none at all for a
  part that is already present.
- A result store that would also spare the *repeated* fetch of the same part is **still
  missing** — it arrives with phase 5. So a second `part2kicad add C2040 --force` fetches
  the geometry a second time. This is stated here because a disclosure that lists a
  measure not yet taken is not a disclosure.
- The **search traffic** — that is, the volume — goes to `pro.easyeda.com`, whose own
  exclusion list names only `/login` and a set of named SEO bots, not `/api/`.

Anyone who judges this differently can leave `part2kicad add` alone and use the tool for
searching only.

## Development

```
git clone https://github.com/AltF4Quit/part2kicad
uv sync
```

| Run | Command |
|---|---|
| Fast lane, without KiCad | `pytest -m "not kicad and not live"` |
| Full run (default) | `pytest -m "not live"` |
| Live tests against the real counterpart | `pytest -m live --live` |

Live tests **never** run by accident: they need both the marker and the `--live` switch.
Tests that need an installed KiCad skip themselves with a visible reason when none is
found.

## License

GPL-3.0-or-later, see [LICENSE](LICENSE).
