Metadata-Version: 2.5
Name: part2kicad
Version: 0.2.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

From an LCSC number to a finished KiCad part with **traceable provenance** — symbol,
footprint and 3D model — straight into your own project.

What sets this apart from the existing tools is not convenience but traceability. Today
that means: every generated part carries its provenance as fields on the symbol —
source, fetch date and part number, and for parts taken from a search also price and
stock together with the date they were fetched. The report that shows, field by field,
where a value came from and which KLC rules it satisfies **does not exist yet** — it is
the goal and it arrives with phase 3.

## Status

Early development, but the path from the number to a wired-in part stands:
`part2kicad search` and `part2kicad add` create symbol, footprint and 3D model in the
KiCad project and register both library tables. What is still missing — multi-unit
parts, normalised field names, the quality report, the local cache — is listed in full
under [Known limits](#known-limits).

## Requirements

- Python 3.11 or newer
- **KiCad 10.0 or newer.** The tool invokes `kicad-cli` as a separate process. If
  `kicad-cli` is not on the search path — on Windows that is the normal case — it is
  looked for in the usual installation locations. Failing that, set the path explicitly:

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

## Installation

From PyPI:

```
uv pip install part2kicad
```

The package is a pure `py3-none-any` wheel; no compiler is needed on the target 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 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.

## Usage

```
part2kicad search rp2040          # search, pick, take it in — all in one invocation
part2kicad add C2040              # when the part number is already known
part2kicad add C2040 --force      # replace a part that is already present
```

The target project is looked up the way git does it: from the working directory upwards,
looking for a `.kicad_pro` file. `--project <path>` states it explicitly. If none is
found, the tool stops rather than writing somewhere arbitrary.

`--json` prints machine-readable output and asks nothing; `--verbose` writes one line per
fetch to stderr, with the address and the status code.

### Importing the same part a second time

If the part is already in the project library, `part2kicad` reports that together with
the date of the first fetch and **writes nothing**. Anyone who has touched up the 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
"Update Symbols from Library".

### What ends up on the generated part

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

Price and stock only appear in the search response. Whoever needs them on the part gets
it via `part2kicad search`; the fetch by part number does not bring them along, and
`part2kicad` does not invent a price. Every field except `Reference` and `Value` is
created hidden, so the schematic stays readable.

## 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.

### 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 |

Symbol and footprint come from **one** fetch; there is no second one for the footprint.
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 |

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 cap
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 **does not
  exist yet** — 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.

## Known limits

Honest rather than sounding complete:

- **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.
- **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. For macOS
  the search path to `kicad-cli` is on file as well, but nobody has run it there either.
- **Parts made of several units** are detected and explicitly refused, rather than
  filing a symbol with zero pins. Merging them comes later.
- **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.
- **The quality report does not exist yet.** Provenance and fetch date are on the part as
  fields; a report that shows the provenance field by field and lists the KLC rules
  checked together with their outcome arrives with phase 3. Until then, "checked" is the
  guarantee that every value comes from the source — not that a rule check has run.
- **A local cache does not exist yet.** Every fetch goes to the counterpart; a second
  `add … --force` fetches the same geometry again. The cache arrives with phase 5, see
  also the exclusion list above.
- **Price and stock are only available via `part2kicad search`**, see above.

## Tests

| 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).
