SKILL: stamp symbol parameters automatically in the new-part flow, never as an offer (by admin)
parent
474d5830ac
commit
3e5f756916
|
|
@ -2,16 +2,15 @@
|
|||
name: library-manager
|
||||
description: >-
|
||||
Manage Vecmocon's component library. Extract parameters from a component datasheet PDF into the
|
||||
per-typeid Excel template, check Gitea for a duplicate MPN_make, classify to a
|
||||
typeid, update that typeid's template (versioning, changelog, backfill), fill a per-part
|
||||
workbook, verify with a human, read the Altium symbol/footprint refs, and push a part folder to
|
||||
Gitea. Can UPDATE an existing part instead of hard-stopping on a duplicate. WRITES the mandatory
|
||||
SOP parameters (from the verified Excel) directly into the .SchLib symbol and COMPILES an Altium
|
||||
integrated library (.IntLib) bundling symbol + footprint, so every part folder holds five files
|
||||
(workbook, datasheet, .SchLib, .PcbLib, .IntLib). Every Description follows Vecmocon's strict
|
||||
Altium Description Format. Use whenever the user uploads a datasheet, builds/updates a library
|
||||
entry, adds a parameter, fills .SchLib parameters, builds an integrated library, or pushes to
|
||||
Gitea. ALWAYS trigger on "\datasheet", "\library", "\library-manager", or "\schlib".
|
||||
per-typeid Excel template. Checks Gitea for a duplicate MPN_make, classifies to a typeid, updates that typeid's template (versioning, changelog, backfill), fills
|
||||
a per-part workbook with human verification, reads the Altium symbol/footprint refs, assembles
|
||||
a part folder and pushes to Gitea. Can UPDATE an existing part instead of hard-stopping, and can
|
||||
WRITE the mandatory SOP parameters directly into a .SchLib symbol while stripping Ultra-Librarian
|
||||
defaults. On the .SchLib task it also fills that component's Excel (Description + all parameters)
|
||||
and pushes the updated symbol to Gitea, no verification loop. Descriptions
|
||||
follow Vecmocon's strict Altium Description Format. Use whenever the user uploads a datasheet,
|
||||
builds/updates a library entry, adds a template parameter, fills/updates .SchLib parameters, or
|
||||
pushes a part to Gitea. Always trigger on "\datasheet", "\library", "\library-manager", "\schlib".
|
||||
---
|
||||
|
||||
# Library Manager
|
||||
|
|
@ -42,6 +41,16 @@ own, without asking for confirmation**. Never add a "shall I push?" step — jus
|
|||
the user where it landed. (You still flag a genuine symbol/footprint mismatch, because that's a
|
||||
correctness issue, not a push confirmation.)
|
||||
|
||||
**Symbol parameters are a second exception — stamp them without asking, every time.** This
|
||||
holds in both directions. As a standalone task (the engineer hands over a `.SchLib`): fill that
|
||||
component's Excel (Description + all parameters) and push the updated symbol automatically,
|
||||
without pausing to confirm the values. And **inside the normal new-part flow**: once the symbol
|
||||
is uploaded at step 6, stamp the SOP + sheet parameters onto it and strip the Ultra-Librarian
|
||||
defaults as a matter of course — do **not** offer it as a follow-up, do **not** ask whether the
|
||||
engineer wants it, and never push a part folder whose symbol still carries UL defaults. See
|
||||
*Mandatory symbol parameters* for why this path skips the loop. Every other flow keeps the
|
||||
normal interactive asks below.
|
||||
|
||||
## Inputs
|
||||
|
||||
- **A datasheet PDF whose filename is the MPN** (e.g. `BAT46WJ.pdf`). If it's a series
|
||||
|
|
@ -75,16 +84,10 @@ library repo/
|
|||
<MPN>_<make>_<typeid>/ e.g. BAT46WJ_Nexperia_SCH
|
||||
<MPN>_<make>_<typeid>.xlsx this part's own one-row parameter sheet
|
||||
<MPN>_data.pdf the datasheet
|
||||
<symbol>.SchLib user-provided, with all parameters written in
|
||||
<symbol>.SchLib user-provided
|
||||
<footprint>.PcbLib user-provided
|
||||
<MPN>.IntLib integrated library (symbol + footprint, compiled by the skill)
|
||||
```
|
||||
|
||||
**Every part folder holds five files** — the workbook, the datasheet, the `.SchLib` (with the
|
||||
full parameter set written into it), the `.PcbLib`, and the compiled `.IntLib`. The `.SchLib`
|
||||
parameter fill and the `.IntLib` build are **not optional** — they run on every part before the
|
||||
push (see *Mandatory symbol parameters* and *Build the integrated library* below).
|
||||
|
||||
There is **no single master workbook** — each part carries its own sheet inside its folder.
|
||||
Connection + repo names live in `config/gitea.env` (`SKILL_REPO`, `LIBRARY_REPO`), so runs
|
||||
need no per-session token. If the host is unreachable, the git steps fail clearly and write
|
||||
|
|
@ -257,7 +260,9 @@ The part workbook has up to **two sheets**:
|
|||
Deliver the filled workbook to the user and ask them to verify it. If they report an error
|
||||
or say it isn't right, **go back to step 4, re-read the datasheet more carefully, re-fill,
|
||||
and hand it back.** Repeat until the user confirms it's verified. Nothing is pushed until
|
||||
this passes — the engineer is the ground truth for the numbers.
|
||||
this passes — the engineer is the ground truth for the numbers. (The standalone `.SchLib` task
|
||||
is the exception: it fills the Excel and pushes without this loop — see *Fill the component's
|
||||
Excel and push* under *Mandatory symbol parameters*.)
|
||||
|
||||
### 6. Symbol + footprint → the design columns
|
||||
|
||||
|
|
@ -292,23 +297,33 @@ python scripts/fill_templates.py part.json \
|
|||
--template assets/template/template.xlsx --dest <stage>/<tag>/ --design design.json
|
||||
```
|
||||
|
||||
Once you have the symbol and its Library Ref, **always** write the full parameter set into the
|
||||
`.SchLib` from the verified per-part Excel — see *Mandatory symbol parameters* below. **This is
|
||||
compulsory on every run; do not ask the engineer whether to do it — just do it.** It is how the
|
||||
verified workbook values (and the Description) land in the Altium symbol's properties, and the
|
||||
`.IntLib` is then built from this enriched symbol.
|
||||
Once you have the symbol and its Library Ref, **stamp the mandatory symbol parameters onto the
|
||||
`.SchLib` — always, automatically, without asking.** This is not an optional extra and it is not
|
||||
something to offer the engineer: a symbol that reaches Gitea carrying Ultra-Librarian defaults
|
||||
instead of the SOP set is an incomplete part. Do it in this same run, before step 7, so the
|
||||
folder is pushed complete the first time.
|
||||
|
||||
### 7. Assemble the part folder — build the `.IntLib`, then five files
|
||||
Build the parameter set from the datasheet values you already read for the workbook (they are the
|
||||
same values — Manufacturer, Manufacturer Part, Value, Tolerance, Operating Temperature, RoHS,
|
||||
Datasheet, Process, Vecmocon Part Code, …), **plus every engineering parameter from this typeid's
|
||||
sheet** and `Component Type` = the part's Class, then write them in and strip the UL defaults —
|
||||
see *Mandatory symbol parameters* below for the full set and the exact commands. Skip only the
|
||||
housekeeping columns (`MPN_make_type`, Skill/Template Version) and the four Library/Footprint
|
||||
Ref/Path columns — those are Altium's own model links, so duplicating them as parameters would
|
||||
create two sources of truth.
|
||||
|
||||
The staging folder `<tag>/` should hold the per-part `<tag>.xlsx`, the datasheet (name it
|
||||
`<MPN>_data.<ext>`), the enriched symbol (`.SchLib` with parameters written in, step 6), and the
|
||||
footprint (`.PcbLib`). Now **compile the integrated library** from the enriched symbol + footprint
|
||||
so the folder carries all **five** files — see *Build the integrated library* below:
|
||||
Don't stop to confirm the values here either; the engineer validates the symbol by opening it in
|
||||
Altium, which is the real check. Leave genuinely-unknown fields blank (the SOP hides blank
|
||||
parameters) and **note the gaps in your summary** rather than blocking on a question — the one
|
||||
field that is never on a datasheet is `Vecmocon Part Code`, so use it if the engineer supplied it
|
||||
and otherwise leave it blank and say so.
|
||||
|
||||
```bash
|
||||
python scripts/build_intlib.py --schlib <stage>/<tag>/<sym>.SchLib \
|
||||
--pcblib <stage>/<tag>/<fp>.PcbLib --out <stage>/<tag>/<MPN>.IntLib
|
||||
```
|
||||
### 7. Assemble the part folder
|
||||
|
||||
The staging folder `<tag>/` should now hold the four files: the per-part `<tag>.xlsx`, the
|
||||
datasheet (name it `<MPN>_data.<ext>`), the symbol (the **stamped** one from step 6, not the raw
|
||||
upload), and the footprint. If the engineer's upload carried extra files (a `.step` 3D model, a
|
||||
`.LibPkg`), ask whether to include them — the standard folder is these four.
|
||||
|
||||
### 8. Push to the library repo, under the part's Class
|
||||
|
||||
|
|
@ -324,11 +339,10 @@ user where it landed.
|
|||
## Mandatory symbol parameters (.SchLib)
|
||||
|
||||
The SOP (§5) requires every schematic symbol to carry a fixed parameter set in its Altium
|
||||
properties — `Manufacturer`, `Manufacturer Part`, `Value`, `Tolerance`, `Operating
|
||||
Temperature`, `ROHS`, `Datasheet`, `Process`, `Vecmocon Part Code`, and the two second-source
|
||||
fields — with the **Comment** set to the MPN. The skill stamps these onto the symbol from the
|
||||
verified workbook. **This step is compulsory on every part build — never ask whether to fill the
|
||||
`.SchLib` parameters; always do it** before assembling the folder and building the `.IntLib`.
|
||||
properties — `Component Type`, `Manufacturer`, `Manufacturer Part`, `Value`, `Tolerance`,
|
||||
`Operating Temperature`, `ROHS`, `Datasheet`, `Process`, `Vecmocon Part Code`, and the two
|
||||
second-source fields — with the **Comment** set to the MPN. The skill can stamp these onto the
|
||||
symbol from the datasheet.
|
||||
|
||||
This runs **as its own task too**, not only inside new-part creation: whenever the user hands
|
||||
over one or more `.SchLib` files and wants their parameters filled/updated (e.g. "\schlib", "add
|
||||
|
|
@ -337,9 +351,13 @@ build its `params.json`, and run `scripts/schlib_write.py` per file — same ste
|
|||
|
||||
The skill writes these **directly into the `.SchLib` in pure Python** with
|
||||
`scripts/schlib_write.py` (it rebuilds the OLE around the enlarged `Data` stream, preserving
|
||||
every other byte, and strips the Ultra-Librarian `Manufacturer_Name` / `Manufacturer_Part_Number`
|
||||
defaults that duplicate the SOP fields). Three kinds of value:
|
||||
every other byte, and strips the Ultra-Librarian defaults that shouldn't ship: `Manufacturer_Name`
|
||||
/ `Manufacturer_Part_Number` (they duplicate the SOP fields), the UL `Copyright` notice, and the
|
||||
UL `Component_Type` — replaced by Vecmocon's own spaced `Component Type`). Kinds of value:
|
||||
|
||||
- **Derived** — `Component Type` = the part's **Class** (`Resistor`, `Capacitor`, `Diode`,
|
||||
`Transistor`, `IC`, …), from `scripts/common.py:class_folder(typeid)` for this part's typeid.
|
||||
This is the same Class that names its library-repo folder, so the symbol carries it too.
|
||||
- **Read from the datasheet** (don't just echo given text — open the PDF and fill the real,
|
||||
verified values): `Value` = the **value only** in shorthand (e.g. `1u`, `12p`, `10k` — no
|
||||
package), plus `Manufacturer`, `Manufacturer Part`, `Operating Temperature`, `Tolerance`,
|
||||
|
|
@ -348,40 +366,21 @@ defaults that duplicate the SOP fields). Three kinds of value:
|
|||
populate these by default; they stay hidden in Altium until filled later. (An optional
|
||||
cross-reference search to find a second source is documented in
|
||||
`references/schlib_parameters.md` but is currently off — only do it if the engineer asks.)
|
||||
- **Ask the engineer** — only `Vecmocon Part Code` (internal, not derivable).
|
||||
- **Fill without pausing** — the `.SchLib` task is non-interactive, so don't stop to ask. The
|
||||
only genuinely non-derivable field is `Vecmocon Part Code` (internal): use it if the engineer
|
||||
already supplied it in the request, otherwise leave it blank (the SOP hides blank parameters)
|
||||
and note the gap in your summary rather than blocking on a question.
|
||||
|
||||
Leave any genuinely-unknown field blank — the SOP hides blank parameters, so a gap simply stays
|
||||
empty until filled. The full method for the second-source search is in
|
||||
`references/schlib_parameters.md`.
|
||||
|
||||
Write the **full parameter set** — the typeid template's engineering columns **plus** the SOP
|
||||
params above (see `references/schlib_parameters.md`) — and **source it from the verified per-part
|
||||
Excel** so the symbol and the workbook can never disagree. After the sheet is verified (step 5),
|
||||
pass that `<tag>.xlsx` to the writer with `--from-xlsx`: every engineering column **and the
|
||||
Description** are read straight out of it and written into the `.SchLib`. Then layer on the
|
||||
**SOP-only** fields that aren't template columns (the `Value` shorthand, `Manufacturer Part`,
|
||||
`Operating Temperature`, `ROHS`, `Datasheet`, `Process`, `Vecmocon Part Code`, and the blank
|
||||
second-source pair) via a small `params.json`; on any name collision the `params.json` value
|
||||
wins. Pass `--typeid` too, so any template column the datasheet left silent is still present
|
||||
(blank):
|
||||
Collect the values into a `params.json` and write them into the symbol:
|
||||
|
||||
```bash
|
||||
python scripts/schlib_write.py --schlib <in>.SchLib \
|
||||
--from-xlsx <stage>/<tag>/<tag>.xlsx --params params.json \
|
||||
--out <stage>/<tag>/<sym>.SchLib --typeid <TYPEID>
|
||||
python scripts/schlib_write.py --schlib <in>.SchLib --params params.json --out <stage>/<tag>/<sym>.SchLib
|
||||
```
|
||||
|
||||
(`--params` is optional if the Excel already carries everything you need; `--from-xlsx` is
|
||||
optional if you'd rather hand-build the whole set in `params.json` — give at least one.) The
|
||||
`Description` written onto the symbol (and into the component's ComponentDescription field) is
|
||||
the exact one from the Excel, which was built to `references/description_format.md`.
|
||||
|
||||
Passing `--typeid` also fills the symbol's **`Type`** parameter with the component type for that
|
||||
typeid — the taxonomy **Class** (e.g. `Resistor`, `Capacitor`, `Diode`, `Transistor`,
|
||||
`Relay / Contactor`, `Inductor / Magnetics`, `Integrated Circuit (IC)`) — so the symbol
|
||||
self-describes what kind of part it is. It's derived from the typeid (which came from the
|
||||
datasheet), so it's set automatically; only an explicit `Type` in the Excel/params overrides it.
|
||||
|
||||
Deliver the resulting `.SchLib`; the engineer opens it in Altium once to confirm it loads, then
|
||||
**Saves to Server** with a revision note. The full parameter set, each value's source, the
|
||||
`params.json` shape (incl. the `remove` list), and the mini-stream size caveat are in
|
||||
|
|
@ -390,39 +389,54 @@ round-trip, fall back to `scripts/altium_params.py` (emits an Altium DXP script
|
|||
parameters from inside Altium). Always have the engineer confirm the file opens in Altium — the
|
||||
skill writes Altium's own binary format, so Altium is the final validator.
|
||||
|
||||
## Build the integrated library (.IntLib)
|
||||
### Fill the component's Excel and push — automatically, no verification loop
|
||||
|
||||
Every part also gets a compiled **integrated library** — one file that bundles the schematic
|
||||
symbol (with the parameters written in) and its footprint, so the component resolves in Altium
|
||||
with no separate `.PcbLib` to locate. `scripts/build_intlib.py` compiles it in pure Python, no
|
||||
Altium needed, and it's the **fifth file** in every part folder.
|
||||
The datasheet values you just read for the symbol belong in that component's per-part Excel
|
||||
workbook too, so fill them in the **same pass and push the result without asking**. This is a
|
||||
deliberate exception to the skill's usual "verify before Gitea" rule: when the engineer hands
|
||||
over a symbol for the `.SchLib` task, they want the library entry brought fully up to date in
|
||||
one shot — the Description and every parameter written into the Excel, the updated symbol saved
|
||||
beside it, and the whole thing pushed — not a round of confirmation questions. The engineer is
|
||||
already reviewing the symbol in Altium, so a separate spreadsheet verification loop adds delay
|
||||
without adding safety. The one check that still stands is the symbol/footprint-vs-part match: if
|
||||
the symbol clearly isn't this component, stop and flag it rather than pushing the wrong part.
|
||||
|
||||
```bash
|
||||
python scripts/build_intlib.py --schlib <stage>/<tag>/<sym>.SchLib \
|
||||
--pcblib <stage>/<tag>/<fp>.PcbLib --out <stage>/<tag>/<MPN>.IntLib
|
||||
```
|
||||
1. **Fill the Excel automatically.** Reuse the values you already read for the symbol to build
|
||||
`part.json` — with `Description` built to `references/description_format.md` and every
|
||||
parameter the datasheet states — and fill the per-part sheet **directly, skipping the human
|
||||
verification loop (step 5)**. Do this inside a checkout of the library repo so it can be
|
||||
pushed; for a part already in Gitea, locate it with `find-part` exactly as in *Updating an
|
||||
existing part*, and re-derive the design columns from the symbol/footprint already in the
|
||||
folder so they carry through unchanged:
|
||||
|
||||
How it works and what it needs:
|
||||
```bash
|
||||
python scripts/gitea_components.py checkout --dest work/
|
||||
python scripts/gitea_components.py find-part --mpn <MPN> --make <make> --root work/ --json
|
||||
python scripts/altium_refs.py design \
|
||||
--symbol work/<Class>/<tag>/<sym>.SchLib \
|
||||
--footprint work/<Class>/<tag>/<footprint>.PcbLib > design.json
|
||||
python scripts/fill_templates.py part.json \
|
||||
--template assets/template/template.xlsx --dest work/<Class>/<tag>/ --design design.json
|
||||
```
|
||||
|
||||
- Feed it the **enriched `.SchLib`** (after `schlib_write.py` has written the parameters in) so the
|
||||
integrated symbol carries the full parameter set and the correct ComponentDescription.
|
||||
- The symbol **must contain a footprint model link** (an Altium RECORD=45 `ModelName` /
|
||||
`ModelType=PCBLIB` in its `Data` stream — Ultra-Librarian and Altium exports include this). The
|
||||
builder reads that link to know which footprint to bind, and errors clearly if it's absent — in
|
||||
that case the symbol has no footprint assigned, so fix the symbol (or re-export it) first.
|
||||
- It builds the `.IntLib` as an OLE compound file with five streams — the embedded `.schlib` and
|
||||
`.pcblib` (zlib-compressed at Altium's default level), plus `LibCrossRef.Txt`, `Parameters .bin`,
|
||||
and `Version.Txt` — reusing a bundled container skeleton
|
||||
(`assets/templates/intlib_container.IntLib`) for the exact directory layout Altium expects, and a
|
||||
**FAT-first** compound-file writer (`build_intlib.write_cfb`). Both the outer container and the
|
||||
embedded symbol are written FAT-first — this matters: a FAT-last layout re-opens fine in olefile
|
||||
and even standalone in Altium, but Altium's **IntLib extractor** throws "Stream read error" on it.
|
||||
The two embedded libraries are compressed at zlib's **default level** (`0x789c`); Altium's
|
||||
decompressor rejects other levels (e.g. level-9 `0x78da`).
|
||||
- The builder self-validates: it re-opens the output, decompresses both embedded libraries, and
|
||||
confirms they round-trip and that the cross-reference names the symbol + footprint. Even so,
|
||||
Altium is the final validator — have the engineer open the `.IntLib` once (or, as a guaranteed
|
||||
fallback, compile a `.LibPkg` in Altium from the same `.SchLib` + `.PcbLib`).
|
||||
(If `find-part` returns `NOT FOUND`, the part isn't in Gitea yet — assemble the folder as a
|
||||
new part per steps 4–7, still without the verification loop, then push with `push-part`.)
|
||||
|
||||
2. **Drop in the updated symbol and push — no confirmation.** Copy the `.SchLib` you wrote with
|
||||
`schlib_write.py` into the same part folder under its proper name, then push the updated part
|
||||
— the symbol and the freshly filled Excel together — automatically:
|
||||
|
||||
```bash
|
||||
cp <stage>/<tag>/<sym>.SchLib work/<Class>/<tag>/<sym>.SchLib
|
||||
python scripts/gitea_components.py commit-push --root work/ \
|
||||
--message "update <tag>: fill parameters + symbol (by <operator name>)" \
|
||||
--author "<operator name> <<operator email>>"
|
||||
```
|
||||
|
||||
Pushing without asking is consistent with the skill's standing rule that pushing is automatic;
|
||||
what's new here is that the Excel fill is automatic too. Tell the user which parameters you
|
||||
filled, that the symbol was updated, and where in Gitea it landed. (A part-data fill isn't a
|
||||
template change, so nothing version-bumps and the changelog is untouched.)
|
||||
|
||||
## Per-typeid versioning
|
||||
|
||||
|
|
@ -533,81 +547,4 @@ change: nothing is overwritten until the engineer has verified the new version.
|
|||
- **Symbol/footprint** → copy the new `.SchLib`/`.PcbLib` into the folder under their proper
|
||||
names (replacing the old ones), then re-derive against the **new** files and rebuild with
|
||||
`--design` exactly as above (this is step 6 of the add flow). Still flag a genuine
|
||||
symbol/footprint-vs-part mismatch — that's a correctness issue.
|
||||
- **Datasheet** → drop the newer PDF in as `<MPN>_data.<ext>`, replacing the old one. If the
|
||||
values should reflect it, also redo the values step above.
|
||||
|
||||
4. **Verify, then push.** Hand the rebuilt `<tag>.xlsx` back and run the same human
|
||||
verification loop (step 5) — the engineer is still the ground truth. Once confirmed, commit
|
||||
the checkout and push (attributed to the operator, with a message that says it's an update):
|
||||
|
||||
```bash
|
||||
python scripts/gitea_components.py commit-push --root work/ \
|
||||
--message "update <tag>: <what changed> (by <operator name>)" \
|
||||
--author "<operator name> <<operator email>>"
|
||||
```
|
||||
|
||||
The authored commit and message are the record of the revision (visible in `git log`, the
|
||||
Gitea commit view and `git blame`); the changelog stays reserved for template/version
|
||||
changes, not per-part data fixes. Tell the user what changed and where it landed.
|
||||
|
||||
## Pushing the skill repo
|
||||
|
||||
When skill files change (a new typeid template, a parameter add, a version/changelog bump),
|
||||
push the skill's own files to the skill repo with `push-skill` **automatically** (no
|
||||
confirmation):
|
||||
|
||||
```bash
|
||||
python scripts/gitea_components.py push-skill --author "<operator name> <<operator email>>" \
|
||||
--message "Sync skill files + changelog"
|
||||
```
|
||||
|
||||
`push-skill` clones the skill repo, copies the skill files in with the **`GIT_TOKEN` blanked
|
||||
out** (the real token never leaves the machine), and **merges** `CHANGELOG.xlsx` — appending
|
||||
this run's new rows onto the changelog already in Gitea so earlier entries are preserved — then
|
||||
writes the merged changelog back locally. (The older `push_to_gitea.sh` still exists for a
|
||||
plain flat push, but it does not merge the changelog or blank the token, so prefer
|
||||
`push-skill` for the skill repo.)
|
||||
|
||||
## Resources
|
||||
|
||||
- `assets/template/template.xlsx` — the master template: one sheet per **typeid** (125),
|
||||
source of every sheet's headers, styling and order. Columns A/B/C are always
|
||||
`MPN_make_type` / `Skill Version` / `Template Version`; `Library Ref/Path`,
|
||||
`Footprint Ref/Path` and `Manufacturer` sit near the end.
|
||||
- `assets/template/Type_ID.xlsx` + `references/taxonomy.md` — Class → Subclass → Type ID.
|
||||
- `references/description_format.md` — Vecmocon's Altium **Description Format** (the `_`-joined
|
||||
engineering string for each part's Description column). Defines a format for **every** type:
|
||||
the four SOP-defined ones (RES/CAP/Zener/TVS) are strict, the rest are the house extension on
|
||||
the same basis. Read it before filling any Description.
|
||||
- `references/schlib_parameters.md` — the SOP **mandatory symbol parameters** (§5) for the
|
||||
`.SchLib`: the parameter set, where each value comes from, and how the generated Altium script
|
||||
stamps them onto the symbol.
|
||||
- `assets/template/versions.json` — per-typeid `template_version` + `skill_version`.
|
||||
- `assets/CHANGELOG.xlsx` — global version/parameter changelog (created on first add;
|
||||
merged into the skill repo's copy in Gitea by `push-skill`).
|
||||
- `scripts/common.py` — taxonomy loader (`load_taxonomy`, `class_folder`), version store
|
||||
(`get_versions`, `version_labels`, `bump_versions`), and the tag helper (`part_tag`).
|
||||
- `scripts/fill_templates.py` — build one per-part `<tag>.xlsx` (version-stamped); reused for
|
||||
backfill.
|
||||
- `scripts/append_parameter.py` — append parameter(s) to a typeid, bump its versions, write
|
||||
the changelog.
|
||||
- `scripts/altium_refs.py` — read Library/Footprint Ref from `.SchLib`/`.PcbLib`.
|
||||
- `scripts/schlib_write.py` — write the SOP mandatory parameters **directly into a `.SchLib`**
|
||||
(pure-Python OLE rebuild; removes the Ultra-Librarian `Manufacturer_Name` /
|
||||
`Manufacturer_Part_Number` defaults). Primary path; see `references/schlib_parameters.md`.
|
||||
- `scripts/altium_params.py` — fallback: generate an Altium DelphiScript that stamps the same
|
||||
parameters onto a `.SchLib` from inside Altium (DXP → Run Script).
|
||||
- `scripts/build_intlib.py` — compile a component's `.SchLib` + `.PcbLib` into an Altium
|
||||
**integrated library** (`.IntLib`) in pure Python (FAT-first OLE writer + Altium-level zlib);
|
||||
the fifth file in every part folder. Needs the enriched `.SchLib` (parameters written) with a
|
||||
footprint model link. Uses `assets/templates/intlib_container.IntLib` as the container skeleton.
|
||||
- `assets/templates/intlib_container.IntLib` — a known-good single-component `.IntLib` reused
|
||||
purely as the OLE container skeleton by `build_intlib.py` (all its streams are overwritten).
|
||||
- `scripts/gitea_components.py` — `check-mpn`, `find-part` (locate an existing part to
|
||||
update), `checkout`, `list-type`, `place-part`, `commit-push`, `push-part` (library repo),
|
||||
and `push-skill` (skill repo: token-blanked push + append-only changelog merge).
|
||||
- `scripts/push_to_gitea.sh` — push a folder's contents to a Gitea repo (used for the skill
|
||||
repo).
|
||||
- `config/gitea.env` — host, user, token, and the `SKILL_REPO` / `LIBRARY_REPO` names
|
||||
(**secret** — do not push the token).
|
||||
symbol/footprint-vs-part misma
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -9,7 +9,9 @@ How the parameters get in: the skill writes them **directly into the `.SchLib` i
|
|||
via `scripts/schlib_write.py` — it rebuilds the OLE compound file around the enlarged component
|
||||
`Data` stream while preserving every other byte (all other streams, the directory tree, the
|
||||
Altium CLSIDs). It also **removes the Ultra-Librarian default params `Manufacturer_Name` and
|
||||
`Manufacturer_Part_Number`**, which just duplicate the SOP `Manufacturer` / `Manufacturer Part`.
|
||||
`Manufacturer_Part_Number`** (which duplicate the SOP `Manufacturer` / `Manufacturer Part`), the
|
||||
UL **`Copyright`** notice (Vecmocon symbols don't carry it), and the UL **`Component_Type`**
|
||||
(underscore) — replaced by Vecmocon's own spaced **`Component Type`** parameter (see below).
|
||||
The output is a ready `.SchLib`. Because this writes Altium's own format from outside Altium, the
|
||||
script self-checks that the result re-opens as a valid OLE with the params present — but **always
|
||||
open the result in Altium once to confirm it loads** before relying on it. (An older path,
|
||||
|
|
@ -20,10 +22,24 @@ inside Altium; keep it as a fallback if a particular file doesn't round-trip.)
|
|||
|
||||
Use these exact Altium parameter names (they must match the symbol, per the SOP screenshot).
|
||||
The **Comment** field is set to the MPN (SOP §4), and the **Description** field is the strict
|
||||
string from `references/description_format.md`.
|
||||
string from `references/description_format.md` — which **overwrites** whatever prose Ultra
|
||||
Librarian put in `Description` (UL's text is often wrong: a real 6N137 export read
|
||||
`SMD-8 CPLR SNGL 10MBD 100V/us -e3` when the datasheet CMR is 1000 V/µs).
|
||||
|
||||
Beyond this SOP set, also stamp on **every engineering parameter from the part's typeid sheet**
|
||||
(for an `ISO`: Isolator Type, Isolation Voltage, No. of Channels, Data Rate, Supply Voltage,
|
||||
Creepage, Package, Power, Max Output Current). Skip the housekeeping columns (`MPN_make_type`,
|
||||
Skill/Template Version) and the four Library/Footprint Ref/Path columns — Altium already holds
|
||||
those as the symbol's model links, so repeating them as parameters makes two sources of truth.
|
||||
|
||||
**Encoding gotcha:** Altium parameter records are **latin-1**, so a value containing `≥`, `≤`,
|
||||
`±`-beyond-latin1, `µ` (U+00B5 is fine, U+03BC is not) or similar will crash `schlib_write.py`
|
||||
with a `UnicodeEncodeError`. Rephrase into latin-1 (`≥ 7 mm` → `7 mm min.`) rather than dropping
|
||||
the value; `°` (U+00B0) is latin-1 and safe. The workbook keeps the original notation.
|
||||
|
||||
| Parameter | Source | Notes |
|
||||
|-----------|--------|-------|
|
||||
| `Component Type` | derived | the part's **Class** — `Resistor`, `Capacitor`, `Diode`, `Transistor`, `IC`, … — from the taxonomy row for its typeid (`scripts/common.py:class_folder(typeid)`) |
|
||||
| `Value` | datasheet | the component **value only** (no package), in shorthand — e.g. `1u`, `12p`, `100n`, `10k` |
|
||||
| `Manufacturer Part` | datasheet | the MPN; also the **Comment** field |
|
||||
| `Manufacturer` | datasheet | manufacturer name as printed, e.g. `YAGEO` |
|
||||
|
|
@ -41,7 +57,9 @@ handed to you.** Open the PDF, find each real value (`Value`, `Manufacturer Part
|
|||
`Manufacturer`, `Operating Temperature`, `Tolerance`, `Datasheet`, `ROHS`, and `Process` by
|
||||
inference from the package), and fill them verified. An honest blank beats a guess — the SOP
|
||||
hides blank parameters, so a gap just stays empty until someone fills it. Only **one** field is
|
||||
purely internal and must come from the engineer: `Vecmocon Part Code` — ask for it.
|
||||
purely internal and is never on a datasheet: `Vecmocon Part Code`. Use it if the engineer already
|
||||
supplied it; otherwise **leave it blank and note the gap in your summary — don't stop to ask**.
|
||||
Stamping the symbol is automatic and non-interactive (SKILL.md, step 6), so no field blocks it.
|
||||
|
||||
The second-source pair (`Manufacturer 2` / `Manufacturer Part 2`) is **left blank for now** —
|
||||
don't populate it by default. It simply stays hidden in Altium until someone fills it later.
|
||||
|
|
@ -78,6 +96,7 @@ symbol's Library Ref (from `altium_refs.py`); omit it to apply to every componen
|
|||
"component": "CC0402FRNPO9BN120",
|
||||
"comment": "CC0402FRNPO9BN120",
|
||||
"parameters": {
|
||||
"Component Type": "Capacitor",
|
||||
"Value": "12pF_0402",
|
||||
"Manufacturer Part": "CC0402FRNPO9BN120",
|
||||
"Manufacturer": "YAGEO",
|
||||
|
|
@ -93,41 +112,22 @@ symbol's Library Ref (from `altium_refs.py`); omit it to apply to every componen
|
|||
}
|
||||
```
|
||||
|
||||
## The full parameter set (template + SOP)
|
||||
|
||||
Every `.SchLib` should carry the **complete** parameter set for its part: the **typeid
|
||||
template's engineering columns** (all columns of that typeid's `template.xlsx` sheet except the
|
||||
internal bookkeeping ones — the tag `MPN_make_type`, `Skill Version`, `Template Version`, and the
|
||||
four `Library/Footprint Ref/Path` columns) **plus** the mandatory SOP params above. So a CER
|
||||
(ceramic MLCC) symbol gets `Capacitance(uF)`, `Tolerance`, `Voltage(V)`,
|
||||
`Dielectric(temp. Coefficient)`, `Operating Temp(°C)`, `Max operating temp(°C)`, `Package`,
|
||||
`Description`, `Manufacturer` from the template, alongside `Value`, `Manufacturer Part`,
|
||||
`Process`, `Vecmocon Part Code`, `ROHS`, `Datasheet`, and the second-source fields. Fill each
|
||||
from the datasheet; leave blank what the datasheet doesn't state.
|
||||
|
||||
## Writing them into the symbol
|
||||
|
||||
Write the parameters straight into the `.SchLib`, producing a new file. Pass `--typeid` so the
|
||||
writer guarantees the whole template column set is present (blank where you didn't supply a
|
||||
value) — this is what keeps every symbol's parameter set complete and consistent:
|
||||
Write the parameters straight into the `.SchLib`, producing a new file:
|
||||
|
||||
```bash
|
||||
python scripts/schlib_write.py --schlib <in>.SchLib --params params.json --out <out>.SchLib --typeid <TYPEID>
|
||||
python scripts/schlib_write.py --schlib <in>.SchLib --params params.json --out <out>.SchLib
|
||||
```
|
||||
|
||||
`params.json` carries your filled values (and may include a `"remove"` list — defaults to
|
||||
`["Manufacturer_Name", "Manufacturer_Part_Number"]`, the Ultra-Librarian duplicates that get
|
||||
stripped). The script targets the component named in `"component"` (its Library Ref / storage
|
||||
name), or every component if omitted, and self-checks the output re-opens as a valid OLE. It
|
||||
handles any parameter-set size — small sets stay in Altium's mini-stream, larger ones are written
|
||||
as a regular stream automatically. Deliver the resulting `.SchLib`; have the engineer open it in
|
||||
Altium once to confirm it loads, then Save to Server with a revision note per the SOP.
|
||||
`params.json` may carry a `"remove"` list (defaults to `["Manufacturer_Name",
|
||||
"Manufacturer_Part_Number", "Copyright", "Component_Type"]`); those Ultra-Librarian defaults are
|
||||
stripped and the SOP params — including the spaced `Component Type` = Class — added. Real UL
|
||||
exports also ship **placeholder** params whose Text is just the name back again (`Type` = `Type`,
|
||||
`RefDes` = `RefDes`, sometimes `TYPE`); add those to `remove` too — they're noise, not data. After
|
||||
writing, grep the output for `Ultra Librarian` / `Manufacturer_Name` and confirm the count is 0. The script targets the component named in `"component"` (its Library Ref / storage name),
|
||||
or every component if omitted, and self-checks the output re-opens as a valid OLE. Deliver the
|
||||
resulting `.SchLib`, and have the engineer open it in Altium once to confirm it loads, then Save
|
||||
to Server with a revision note per the SOP.
|
||||
|
||||
Fallback (apply from inside Altium):
|
||||
|
||||
```bash
|
||||
python scripts/altium_params.py script --params params.json --out apply_params.pas
|
||||
```
|
||||
|
||||
Then in Altium: open the `.SchLib`, **DXP → Run Script… → ApplyParameters**, review, **Save to
|
||||
Server**.
|
||||
Scope note: the d
|
||||
|
|
@ -12,39 +12,33 @@ move are recomputed.
|
|||
|
||||
What it does to the target component's Data stream:
|
||||
- removes the Ultra-Librarian default params ``Manufacturer_Name`` / ``Manufacturer_Part_Number``
|
||||
(they duplicate the SOP ``Manufacturer`` / ``Manufacturer Part`` — override with --keep or a
|
||||
"remove" list in params.json),
|
||||
(they duplicate the SOP ``Manufacturer`` / ``Manufacturer Part``), the UL ``Copyright`` notice,
|
||||
and the UL ``Component_Type`` (Vecmocon adds its own spaced ``Component Type`` = Class instead);
|
||||
override this default set with a "remove" list in params.json,
|
||||
- adds/updates the SOP parameters from params.json (see references/schlib_parameters.md),
|
||||
- leaves pins, graphics, the Comment and all other records exactly as they were.
|
||||
|
||||
Usage:
|
||||
# source parameters + Description from the verified per-part workbook (preferred):
|
||||
python schlib_write.py --schlib IN.SchLib --from-xlsx <tag>.xlsx \
|
||||
[--params sop.json] --typeid ELE --out OUT.SchLib
|
||||
# or from a params.json alone:
|
||||
python schlib_write.py --schlib IN.SchLib --params params.json --out OUT.SchLib
|
||||
|
||||
--from-xlsx reads the filled per-part `<tag>.xlsx` (the same workbook the engineer verified) and
|
||||
writes every engineering column + the Description into the symbol, so the .SchLib and the sheet
|
||||
never diverge. --params then layers on the SOP-only fields that aren't template columns
|
||||
(Value shorthand, Process, ROHS, Datasheet, Manufacturer Part, Vecmocon Part Code, ...); on a
|
||||
name collision the params.json value wins. Give either or both (at least one).
|
||||
|
||||
params.json (same shape altium_params.py uses):
|
||||
{"component":"JMK105BJ105KV-F", # LibRef / component-storage name; omit -> all comps
|
||||
"parameters":{"Value":"1u","Manufacturer":"Taiyo Yuden", ...},
|
||||
"remove":["Manufacturer_Name","Manufacturer_Part_Number"]} # optional; this is the default
|
||||
"parameters":{"Value":"1u","Manufacturer":"Taiyo Yuden","Component Type":"Capacitor", ...},
|
||||
"remove":["Manufacturer_Name","Manufacturer_Part_Number","Copyright","Component_Type"]} # optional; default
|
||||
|
||||
IMPORTANT: this writes Altium's own binary format from outside Altium. It is validated to
|
||||
re-open as a well-formed OLE with every other stream byte-identical, but ALWAYS open the result
|
||||
in Altium once to confirm it loads before relying on it.
|
||||
"""
|
||||
import argparse, json, os, struct, sys, hashlib
|
||||
import argparse, json, struct, sys, hashlib
|
||||
import olefile
|
||||
|
||||
FREESECT=0xFFFFFFFF; ENDOFCHAIN=0xFFFFFFFE; FATSECT=0xFFFFFFFD
|
||||
SEC=512; MINI=64; CUTOFF=4096
|
||||
DEFAULT_REMOVE=["Manufacturer_Name", "Manufacturer_Part_Number"]
|
||||
# Ultra-Librarian defaults we strip: the two that duplicate the SOP Manufacturer / Manufacturer
|
||||
# Part, the UL "Copyright" notice (Vecmocon symbols don't carry it), and the UL "Component_Type"
|
||||
# (underscore) — Vecmocon adds its own spaced "Component Type" = the part's Class instead.
|
||||
DEFAULT_REMOVE=["Manufacturer_Name", "Manufacturer_Part_Number", "Copyright", "Component_Type"]
|
||||
|
||||
|
||||
def le16(b,o): return struct.unpack('<H',b[o:o+2])[0]
|
||||
|
|
@ -52,62 +46,6 @@ def le32(b,o): return struct.unpack('<I',b[o:o+4])[0]
|
|||
def pad(b,n): return b+b'\x00'*((-len(b))%n)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------- typeid template columns
|
||||
|
||||
# Template columns that are internal library bookkeeping, NOT symbol parameters.
|
||||
NON_PARAM_COLS = {"MPN_make_type", "Skill Version", "Template Version",
|
||||
"Library Ref", "Library Path", "Footprint Ref", "Footprint Path"}
|
||||
|
||||
|
||||
def template_param_names(template_path, typeid):
|
||||
"""The symbol-parameter columns for a typeid = every column on that typeid's template sheet
|
||||
EXCEPT the internal bookkeeping ones (the tag, the two version columns, and the four design
|
||||
Ref/Path columns). These are the engineering parameters that belong on the symbol."""
|
||||
import openpyxl
|
||||
wb = openpyxl.load_workbook(template_path, read_only=True)
|
||||
if typeid not in wb.sheetnames:
|
||||
raise SystemExit(f"no template sheet for typeid '{typeid}'")
|
||||
ws = wb[typeid]
|
||||
return [ws.cell(1, c).value for c in range(1, ws.max_column + 1)
|
||||
if ws.cell(1, c).value and ws.cell(1, c).value not in NON_PARAM_COLS]
|
||||
|
||||
|
||||
def component_type_for(typeid):
|
||||
"""The human-readable component TYPE for a typeid (e.g. 'Resistor', 'Capacitor',
|
||||
'Relay / Contactor', 'Inductor / Magnetics', 'Integrated Circuit (IC)') taken from the library
|
||||
taxonomy's Class. Written into the symbol's `Type` parameter so the .SchLib self-describes what
|
||||
kind of part it is. Returns None if the taxonomy can't be loaded or the typeid is unknown."""
|
||||
if not typeid:
|
||||
return None
|
||||
try:
|
||||
import common
|
||||
return (common.load_taxonomy().get(typeid.upper()) or {}).get("class")
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def params_from_xlsx(xlsx_path, sheet=None):
|
||||
"""Read the filled parameter values out of a per-part workbook (`<tag>.xlsx`) — row 1 is the
|
||||
headers, row 2 is the single data row this skill writes. Returns {header: value} for every
|
||||
engineering column (i.e. NOT the bookkeeping/design columns in NON_PARAM_COLS), INCLUDING the
|
||||
Description column. This is what lets the .SchLib carry exactly the parameters + Description
|
||||
the engineer already verified in Excel — the two never diverge. Blank cells stay blank.
|
||||
|
||||
By default it reads the first sheet (the typeid parameter sheet). A `Version History` second
|
||||
sheet, if present, is skipped."""
|
||||
import openpyxl
|
||||
wb = openpyxl.load_workbook(xlsx_path, read_only=True, data_only=True)
|
||||
ws = wb[sheet] if sheet else wb[wb.sheetnames[0]]
|
||||
headers = [ws.cell(1, c).value for c in range(1, ws.max_column + 1)]
|
||||
values = [ws.cell(2, c).value for c in range(1, ws.max_column + 1)]
|
||||
out = {}
|
||||
for h, v in zip(headers, values):
|
||||
if not h or h in NON_PARAM_COLS:
|
||||
continue
|
||||
out[str(h)] = "" if v is None else str(v)
|
||||
return out
|
||||
|
||||
|
||||
# ----------------------------------------------------------------- read the container
|
||||
|
||||
def read_container(path):
|
||||
|
|
@ -159,7 +97,7 @@ def _uid(name):
|
|||
def _param_record(idx, name, value):
|
||||
s=(f"|RECORD=41|IndexInSheet={idx}|OwnerPartId=1|Justification=4|FontID=2|IsHidden=T"
|
||||
f"|Text={value}|Name={name}|UniqueID={_uid(name)}")
|
||||
payload=s.encode('utf-8')+b'\x00' # utf-8: handles Ω, µ, °, ± in names/values
|
||||
payload=s.encode('latin-1')+b'\x00'
|
||||
return struct.pack('<I',len(payload))+payload
|
||||
|
||||
|
||||
|
|
@ -180,38 +118,20 @@ def _leading_text_records(data):
|
|||
|
||||
|
||||
def _rec_name(block):
|
||||
t=block[4:-1].decode('utf-8','replace')
|
||||
t=block[4:-1].decode('latin-1')
|
||||
return t.split('|Name=')[1].split('|')[0] if '|Name=' in t else None
|
||||
|
||||
|
||||
def _patch_field(block, field, value):
|
||||
"""Replace |field=...| inside a length-prefixed text record, re-framing its 4-byte length.
|
||||
Used to set the component's ComponentDescription in the RECORD=1 header."""
|
||||
import re
|
||||
text = block[4:-1].decode('utf-8', 'replace')
|
||||
if f"|{field}=" in text:
|
||||
text = re.sub(rf"\|{re.escape(field)}=[^|]*", f"|{field}={value}", text, count=1)
|
||||
elif text.startswith("|RECORD="):
|
||||
text = text + f"|{field}={value}"
|
||||
payload = text.encode('utf-8') + b'\x00'
|
||||
return struct.pack('<I', len(payload)) + payload
|
||||
|
||||
|
||||
def edit_data(data, params, remove):
|
||||
"""Return a new Data stream: drop `remove` params, drop any SOP-name params (re-added
|
||||
fresh), keep everything else, then append the SOP params. Also mirror the `Description`
|
||||
parameter into the component's ComponentDescription field (the Altium 'Description' shown in
|
||||
the component properties). Pins/graphics/tail untouched."""
|
||||
fresh), keep everything else, then append the SOP params. Pins/graphics/tail untouched."""
|
||||
leading, tail = _leading_text_records(data)
|
||||
sop_names=set(params)
|
||||
desc = params.get("Description")
|
||||
kept=[]
|
||||
for blk in leading:
|
||||
nm=_rec_name(blk)
|
||||
if nm is not None and (nm in remove or nm in sop_names):
|
||||
continue # drop UL duplicates + stale SOP copies
|
||||
if desc is not None and blk[4:-1].startswith(b"|RECORD=1|"):
|
||||
blk = _patch_field(blk, "ComponentDescription", desc) # component Description field
|
||||
kept.append(blk)
|
||||
added=[_param_record(20+i, nm, val) for i,(nm,val) in enumerate(params.items())]
|
||||
return b''.join(kept)+b''.join(added)+tail
|
||||
|
|
@ -295,37 +215,10 @@ def rebuild(entries, content):
|
|||
|
||||
# ----------------------------------------------------------------- driver
|
||||
|
||||
def write_params(schlib, params_json, out, typeid=None, template=None, from_xlsx=None):
|
||||
params_json = params_json or {}
|
||||
def write_params(schlib, params_json, out):
|
||||
component=params_json.get("component") or None
|
||||
fields=params_json.get("parameters", {}) or {}
|
||||
remove=params_json.get("remove", DEFAULT_REMOVE)
|
||||
|
||||
# Base the parameter set on the verified per-part Excel when given (--from-xlsx): every
|
||||
# engineering column and the Description come straight from the workbook the engineer already
|
||||
# verified, so the symbol and the sheet can never disagree. Explicit params.json entries
|
||||
# (the SOP-only fields like Value/Process/ROHS/Datasheet/Vecmocon Part Code that aren't
|
||||
# template columns) are layered on top and win on any name collision.
|
||||
fields = {}
|
||||
if from_xlsx:
|
||||
fields.update(params_from_xlsx(from_xlsx))
|
||||
fields.update(params_json.get("parameters", {}) or {})
|
||||
|
||||
# If a typeid+template are given, guarantee the FULL template parameter set is written:
|
||||
# every engineering column for that typeid becomes a symbol parameter (value from the
|
||||
# params if provided, else blank). This is what makes every .SchLib carry the complete,
|
||||
# consistent parameter set the template defines — not just whatever was hand-listed.
|
||||
typeid = typeid or params_json.get("typeid")
|
||||
template = template or params_json.get("template")
|
||||
# Set the symbol's `Type` parameter to the component type for this typeid (Resistor, Capacitor,
|
||||
# Relay / Contactor, ...), from the taxonomy Class — unless one was explicitly provided. This
|
||||
# makes the symbol self-describe what kind of part it is.
|
||||
if typeid:
|
||||
ct = component_type_for(typeid)
|
||||
if ct:
|
||||
fields.setdefault("Type", ct)
|
||||
if typeid and template:
|
||||
for name in template_param_names(template, typeid):
|
||||
fields.setdefault(name, "")
|
||||
entries, paths, content = read_container(schlib)
|
||||
|
||||
# target Data stream sid(s): a stream named 'Data' whose parent storage == component (or all)
|
||||
|
|
@ -349,7 +242,7 @@ def write_params(schlib, params_json, out, typeid=None, template=None, from_xlsx
|
|||
ok=True
|
||||
for e in ole.listdir(streams=True):
|
||||
if e[-1].lower()=="data":
|
||||
t=ole.openstream(e).read().decode('utf-8','ignore')
|
||||
t=ole.openstream(e).read().decode('latin-1','ignore')
|
||||
for nm in fields:
|
||||
if f"|Name={nm}|" not in t and f"|Name={nm}\x00" not in t and f"Name={nm}" not in t:
|
||||
ok=False
|
||||
|
|
@ -362,26 +255,10 @@ def write_params(schlib, params_json, out, typeid=None, template=None, from_xlsx
|
|||
def main():
|
||||
ap=argparse.ArgumentParser()
|
||||
ap.add_argument("--schlib", required=True)
|
||||
ap.add_argument("--params", help="params.json with SOP fields (Value/Process/ROHS/Datasheet/"
|
||||
"Vecmocon Part Code/...) + optional 'component'/'remove'. "
|
||||
"Optional if --from-xlsx supplies the parameters.")
|
||||
ap.add_argument("--from-xlsx", dest="from_xlsx",
|
||||
help="the verified per-part <tag>.xlsx: every engineering column + the "
|
||||
"Description are written into the .SchLib straight from it, so the "
|
||||
"symbol matches the sheet. Layer SOP-only fields on with --params.")
|
||||
ap.add_argument("--params", required=True)
|
||||
ap.add_argument("--out", required=True)
|
||||
ap.add_argument("--typeid", help="component typeid; with --template, guarantees that typeid's "
|
||||
"full template parameter set is present (blank where absent)")
|
||||
ap.add_argument("--template", help="path to template.xlsx (defaults to the skill's)")
|
||||
a=ap.parse_args()
|
||||
if not a.params and not a.from_xlsx:
|
||||
ap.error("give --params and/or --from-xlsx (at least one source of parameters)")
|
||||
template = a.template
|
||||
if a.typeid and not template:
|
||||
template = os.path.join(os.path.dirname(__file__), "..", "assets", "template", "template.xlsx")
|
||||
params_json = json.load(open(a.params, encoding="utf-8")) if a.params else {}
|
||||
write_params(a.schlib, params_json, a.out,
|
||||
typeid=a.typeid, template=template, from_xlsx=a.from_xlsx)
|
||||
write_params(a.schlib, json.load(open(a.params, encoding="utf-8")), a.out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Reference in New Issue