ecadlib 0.3.0__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ecadlib-0.3.0 → ecadlib-0.3.1}/CHANGELOG.md +35 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/PKG-INFO +66 -23
- {ecadlib-0.3.0 → ecadlib-0.3.1}/README.md +65 -22
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/__init__.py +1 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/altium365.py +5 -4
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/altium_dblib_sync.py +152 -16
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/altium_export.py +45 -5
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/altium_forms.py +5 -2
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/altium_lib.py +83 -9
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/altium_menu.py +151 -37
- ecadlib-0.3.1/ecadlib/altium_native.py +1293 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/altium_pkg.py +119 -20
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/altium_project.py +18 -10
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/app.py +32 -6
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/assets/kicad_action_plugin.py +14 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/assets/kicad_reread.py +20 -2
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/bom_triage.py +47 -18
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/cli.py +12 -4
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/clihelp.py +4 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/datasheet.py +53 -9
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/doctor.py +22 -5
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eagle_export.py +20 -9
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/easy_setup.py +3 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/easyeda_convert.py +3 -2
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/easyeda_pro_export.py +1 -4
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/baselines/kicad-v1.json +6 -5
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/golden/demo.txt +6 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/golden/specs.txt +96 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/golden/testpack.txt +6 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/firstrun.py +31 -5
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/footprint_adv.py +4 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/footprint_rules.py +8 -0
- ecadlib-0.3.1/ecadlib/fp_edit.py +194 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/house_style.py +22 -9
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/httpcache.py +3 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/hub.py +8 -2
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/hub_copy.py +24 -2
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/kicad_dblib.py +19 -4
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/kicad_export.py +112 -22
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/kicad_import.py +4 -3
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/kicad_menu.py +2 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/launcher.py +3 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/librarian.py +38 -6
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/lifecycle.py +7 -40
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/llm/openai_compat.py +3 -3
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/llm/rails.py +18 -4
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/llm/run.py +16 -5
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/mcp_server.py +3 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/messages.py +23 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/parity.py +17 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/plugins.py +5 -0
- ecadlib-0.3.1/ecadlib/providers.py +374 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/release_check.py +16 -4
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/rules.py +4 -2
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/rules_infer.py +114 -28
- ecadlib-0.3.1/ecadlib/sources_check.py +162 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/sourcing.py +58 -14
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/stdparts.py +21 -2
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/step_gen.py +167 -5
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/symbol_layout.py +5 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/team.py +2 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/term.py +11 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/ui/server.py +22 -4
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/ui/static/index.html +5 -5
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/upkeep.py +8 -6
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/visual_check.py +3 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib.egg-info/PKG-INFO +66 -23
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib.egg-info/SOURCES.txt +29 -0
- ecadlib-0.3.1/tests/fixtures/easyeda_live/C5423.json +379 -0
- ecadlib-0.3.1/tests/fixtures/easyeda_live/C7593.json +262 -0
- ecadlib-0.3.1/tests/fixtures_lite.py +47 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/rules_fixtures.py +20 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_agent.py +8 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_agent_soak.py +1 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_altium_ad26_fixes.py +4 -3
- ecadlib-0.3.1/tests/test_altium_ad26_overnight.py +130 -0
- ecadlib-0.3.1/tests/test_altium_edit_guard.py +141 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_altium_menu.py +77 -12
- ecadlib-0.3.1/tests/test_altium_native.py +194 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_altium_polish.py +9 -6
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_cli_smoke.py +4 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_dblib_sync.py +45 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_dedupe.py +1 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_e2e.py +3 -3
- ecadlib-0.3.1/tests/test_easyeda_live.py +60 -0
- ecadlib-0.3.1/tests/test_fab_designator.py +82 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_footprint_rulebook.py +9 -0
- ecadlib-0.3.1/tests/test_fp_edit.py +93 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_house_style.py +43 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_kicad_import.py +1 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_messages.py +5 -0
- ecadlib-0.3.1/tests/test_official_sources.py +173 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_qol.py +6 -1
- ecadlib-0.3.1/tests/test_review_1017_altium_core.py +84 -0
- ecadlib-0.3.1/tests/test_review_1017_cli.py +130 -0
- ecadlib-0.3.1/tests/test_review_1017_hub.py +72 -0
- ecadlib-0.3.1/tests/test_review_1017_official_first.py +39 -0
- ecadlib-0.3.1/tests/test_review_1017_sources.py +89 -0
- ecadlib-0.3.1/tests/test_review_1017_style.py +70 -0
- ecadlib-0.3.1/tests/test_review_1018_a365_librarian.py +80 -0
- ecadlib-0.3.1/tests/test_review_1018_ad26_recheck.py +185 -0
- ecadlib-0.3.1/tests/test_review_1018_altium_edges.py +217 -0
- ecadlib-0.3.1/tests/test_review_1018_bom_intake.py +104 -0
- ecadlib-0.3.1/tests/test_review_1018_cloud.py +30 -0
- ecadlib-0.3.1/tests/test_review_1018_footprints.py +84 -0
- ecadlib-0.3.1/tests/test_review_1018_kicad.py +196 -0
- ecadlib-0.3.1/tests/test_review_1018_models.py +153 -0
- ecadlib-0.3.1/tests/test_review_1018_team.py +57 -0
- ecadlib-0.3.1/tests/test_review_1018_ui_mcp.py +79 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_full_agent.py +1 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_full_altiumint.py +2 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_sourcing.py +35 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_step_gen.py +145 -1
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_team.py +1 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_tool_packages.py +6 -2
- ecadlib-0.3.0/ecadlib/providers.py +0 -226
- {ecadlib-0.3.0 → ecadlib-0.3.1}/LICENSE +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/MANIFEST.in +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/NOTICE +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/__main__.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/a365_sync.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/agent.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/agent_queue.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/agent_watch.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/approvals.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/assets/demo_bom.csv +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/assets/pcblib_template.json.gz +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/bom_inputs.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/cad_model.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/cfb.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/cliutil.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/completion.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/costs.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/crosscheck.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/dedupe.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/detect.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/ds_route.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/__init__.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/build_set.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/cli.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/gate.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/golden.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/replay/kicad-v1.json.gz +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/runner.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/score.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/eval/sets/kicad-v1.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/footprint_bench.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/footprint_check.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/footprint_gen.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/forge.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/fp_share.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/fp_tidy.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/fsutil.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/hub_tools.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/kicad_index.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/kicad_pcm.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/llm/__init__.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/llm/cli.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/llm/profiles.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/llm/sampling.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/migrate.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/notify.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_schema.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/CP_EIA-3216-18_Kemet-A.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/C_0402_1005Metric.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/C_0805_2012Metric.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/DFN-8-1EP_3x3mm_P0.5mm_EP1.66x2.38mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/D_SMA.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/D_SMB.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/D_SOD-123.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/D_SOD-323.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/LED_0603_1608Metric.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/LED_0805_2012Metric.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/LQFP-48_7x7mm_P0.5mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/L_0805_2012Metric.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/MSOP-8_3x3mm_P0.65mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/QFN-16-1EP_3x3mm_P0.5mm_EP1.75x1.75mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/QFN-32-1EP_5x5mm_P0.5mm_EP3.45x3.45mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/R_0402_1005Metric.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/R_0603_1608Metric.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/R_0805_2012Metric.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/R_1206_3216Metric.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/SOIC-16_3.9x9.9mm_P1.27mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/SOIC-8_3.9x4.9mm_P1.27mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/SOT-223-3_TabPin2.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/SOT-23-5.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/SOT-23-6.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/SOT-23.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/TSSOP-16_4.4x5mm_P0.65mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/VQFN-16-1EP_3x3mm_P0.5mm_EP1.68x1.68mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/BGA-100_11.0x11.0mm_Layout10x10_P1.0mm_Ball0.5mm_Pad0.4mm_NSMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/BGA-121_9.0x9.0mm_Layout11x11_P0.8mm_Ball0.4mm_Pad0.35mm_NSMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/BGA-144_7.0x7.0mm_Layout13x13_P0.5mm_Ball0.3mm_Pad0.25mm_NSMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/BGA-169_11.0x11.0mm_Layout13x13_P0.8mm_Ball0.5mm_Pad0.4mm_NSMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/BGA-256_11.0x11.0mm_Layout20x20_P0.5mm_Ball0.3mm_Pad0.25mm_NSMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/BGA-256_17.0x17.0mm_Layout16x16_P1.0mm_Ball0.5mm_Pad0.4mm_NSMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/BGA-324_15.0x15.0mm_Layout18x18_P0.8mm_Ball0.5mm_Pad0.4mm_NSMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/BGA-36_3.396x3.466mm_Layout6x6_P0.4mm_Ball0.25mm_Pad0.2mm_NSMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/BGA-672_27.0x27.0mm_Layout26x26_P1.0mm_Ball0.6mm_Pad0.5mm_NSMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/BGA-68_5.0x5.0mm_Layout9x9_P0.5mm_Ball0.3mm_Pad0.25mm_NSMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/BGA-90_8.0x13.0mm_Layout2x3x15_P0.8mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/DFN-8-1EP_3x3mm_P0.5mm_EP1.65x2.38mm_ThermalVias.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/Example_Custom_LPad_Slot.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/JST_GH_SM04B-GHS-TB_1x04-1MP_P1.25mm_Horizontal.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/JST_PH_B4B-PH-K_1x04_P2.00mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/JST_PH_S4B-PH-SM4-TB_1x04-1MP_P2.00mm_Horizontal.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/JST_SH_SM04B-SRSS-TB_1x04-1MP_P1.00mm_Horizontal.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/JST_XH_B2B-XH-A_1x02_P2.50mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/JST_XH_B4B-XH-A_1x04_P2.50mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/JST_XH_B6B-XH-A_1x06_P2.50mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/LFBGA-144_10x10mm_Layout12x12_P0.8mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/Molex_KK-254_AE-6410-04A_1x04_P2.54mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/Molex_PicoBlade_53398-0471_1x04-1MP_P1.25mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_1x05_P1.00mm_Vertical_SMD_Pin1Left.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_1x05_P1.27mm_Vertical_SMD_Pin1Left.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_1x05_P2.00mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_1x05_P2.00mm_Vertical_SMD_Pin1Left.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_1x05_P2.54mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_1x05_P2.54mm_Vertical_SMD_Pin1Left.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_1x05_P2.54mm_Vertical_SMD_Pin1Right.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_1x10_P1.00mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_2x05_P1.00mm_Vertical_SMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_2x05_P1.27mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_2x05_P1.27mm_Vertical_SMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_2x05_P2.00mm_Vertical_SMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_2x05_P2.54mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_2x05_P2.54mm_Vertical_SMD.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/PinHeader_2x20_P2.54mm_Vertical.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/QFN-16-1EP_3x3mm_P0.5mm_EP1.75x1.75mm_ThermalVias.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/UFBGA-132_7x7mm_Layout12x12_P0.5mm.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/advanced/USB_C_Receptacle_HRO_TYPE-C-31-M-12.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/package_specs/standard.json.gz +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/parts_export.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/partview.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/rebuild.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/reports.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/resolve.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/review_cli.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/sexpr.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/sheetsafe.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/sim_models.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/team_setup.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/term_views.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/testpack.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/ui/__init__.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/ui/__main__.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/ui/static/hairline.js +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/ui/static/setup.html +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/upstream.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/userconfig.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib/ws_status.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib.egg-info/dependency_links.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib.egg-info/entry_points.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib.egg-info/requires.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/ecadlib.egg-info/top_level.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/ecadlib_example_plugin/ecadlib_example_plugin/__init__.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/ecadlib_example_plugin/pyproject.toml +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/kicad_import_parts.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/kicad_lib/ecadlib_demo.kicad_sym +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/lifecycle-watch.yml +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/sample_bom.csv +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/symbols/CH340C.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/symbols/Capacitor.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/symbols/Resistor.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/symbols/TPS62133RGTR.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/upkeep.yml +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/examples/upstream-watch.yml +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/pyproject.toml +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/setup.cfg +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/__init__.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/e2e_support.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/bom_inputs/house_columns.csv +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/bom_inputs/house_columns.toml +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/bom_inputs/semicolon_utf8bom.csv +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/bom_inputs/tab_cp1252.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/bom_inputs/workbook_title_rows.xlsx +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/anthropic/datasheet_DSPART16.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/anthropic/proof_default.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-footprints/Capacitor_SMD.pretty/C_0402_1005Metric.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-footprints/Capacitor_SMD.pretty/C_0603_1608Metric.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-footprints/Package_QFP.pretty/LQFP-48_7x7mm_P0.5mm.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-footprints/Package_SO.pretty/SOIC-8_3.9x4.9mm_P1.27mm.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-footprints/Package_TO_SOT_SMD.pretty/SOT-23-5.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-footprints/Resistor_SMD.pretty/R_0402_1005Metric.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-footprints/Resistor_SMD.pretty/R_0603_1608Metric.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-symbols/Amplifier_Operational.kicad_symdir/LM2904.kicad_sym +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-symbols/Amplifier_Operational.kicad_symdir/LM358.kicad_sym +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-symbols/Device.kicad_symdir/C.kicad_sym +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-symbols/Device.kicad_symdir/R.kicad_sym +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-symbols/MCU_ST_STM32F1.kicad_symdir/STM32F103C8Tx.kicad_sym +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/e2e/kicad/kicad-symbols/MCU_ST_STM32F1.kicad_symdir/STM32F103C_8-B_Tx.kicad_sym +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/easyeda/C2002.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/easyeda/C7593.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/Regulator_Linear_AMS1117.kicad_sym +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/USB_C_Receptacle_HRO_TYPE-C-31-M-12.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/ecadlib_demorgan.kicad_sym +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/tool_export/AMASS_XT60-M_1x02_P7.20mm_Vertical.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/tool_export/Banana_Cliff_FCR7350R_S16N-PC_Horizontal.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/tool_export/D_SMC-RM10_Universal_Handsoldering.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/tool_export/Infineon_PG-HSOF-8-2_ThermalVias2.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/tool_export/LFCSP-40-1EP_6x6mm_P0.5mm_EP4.6x4.6mm_ThermalVias.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/tool_export/MMCX_Molex_73415-0961_Horizontal_1.6mm-PCB.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/tool_export/Mounting_Wuerth_WA-SMSE-ExternalM3_H14mm_9771140360.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/tool_export/Nexperia_DSN0603-2_0.6x0.3mm_P0.4mm.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/tool_export/QFN-24-1EP_3x3mm_P0.4mm_EP1.75x1.6mm.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/tool_export/README.md +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad/tool_export/SOT-89-3.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_bench.json +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/BGA-256_17.0x17.0mm_Layout16x16_P1.0mm_Ball0.5mm_Pad0.4mm_NSMD.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/CP_EIA-3216-18_Kemet-A.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/CP_Radial_D5.0mm_P2.00mm.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/C_0805_2012Metric.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/DIP-8_W7.62mm.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/D_DO-41_SOD81_P10.16mm_Horizontal.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/D_SMA.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/D_SOD-123.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/JST_SH_SM04B-SRSS-TB_1x04-1MP_P1.00mm_Horizontal.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/LED_0603_1608Metric.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/LQFP-48_7x7mm_P0.5mm.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/L_0805_2012Metric.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/PinHeader_1x04_P2.54mm_Vertical.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/PinHeader_2x05_P2.54mm_Vertical.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/QFN-24-1EP_4x4mm_P0.5mm_EP2.6x2.6mm_ThermalVias.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/QFN-32-1EP_5x5mm_P0.5mm_EP3.45x3.45mm.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/R_0402_1005Metric.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/R_0603_1608Metric.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/SOIC-8_3.9x4.9mm_P1.27mm.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/SOT-223-3_TabPin2.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/SOT-23-5.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/SOT-23.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/TO-220-3_Vertical.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_golden/TSSOP-20_4.4x6.5mm_P0.65mm.kicad_mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_sch/board.kicad_pro +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_sch/board.kicad_sch +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_sch/board_netlist_kicad7.net +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_sch/board_netlist_kicad7.xml +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_sch/board_pybom_kicad7.xml +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_sch/sub.kicad_sch +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/kicad_sch/sub2/leaf.kicad_sch +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/sim/bridge.ibs +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/sim/broken.lib +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/sim/comment_char.ibs +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/sim/vendor/EEPART1.lib +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/sim/vendor/led_red.mod +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/sim/vendor/tps1234.cir +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/stdparts_kicad_numbers.json.gz +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/symbols/esp32_wroom_32.csv +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/symbols/ft232rl_ssop28.csv +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/symbols/stm32f103vet6_lqfp100.csv +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/term/dblib_sync_plain.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/term/kicad_export_plain.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/term/migrate_plain.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/term/parity_plain.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/term/release_check_60cols.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/term/release_check_plain.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/term/release_check_quiet.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/term/release_check_tty.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/term/release_check_verbose.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/term/status_plain.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/term/status_tty.txt +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/upgrade/r5-agent.tar.gz +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/upgrade/r7-stdparts.tar.gz +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/upgrade/v0.2.0.tar.gz +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/upgrade/v0.3.0.tar.gz +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/voice/PR.md +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/voice/parity.md +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/voice/release_check.md +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/fixtures/voice/review.md +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/kicad_pcbnew_job.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/nexar/schema.graphql +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/run_all.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_a365_sync.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_agent_e2e.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_agent_queue.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_agent_watch.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_altium_interop.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_altium_project.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_altium_tht.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_approvals.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_bom_formats.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_costs.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_crosscheck.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_datasheet.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_datasheet_batch.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_ds_route.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_easy_setup.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_eval.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_evalgate.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_firstrun.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_footprint_review.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_footprints.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_footprints_advanced.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_fp_share.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_fp_tidy.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_fuzz.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_hooks.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_hub.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_independent_review.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_integration_io.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_kicad_export.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_kicad_menu.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_kicad_real.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_librarian.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_librarian_ui.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_lifecycle.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_llm.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_offline.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_packaging.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_parity.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_realworld_boms.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_release_check.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_resolve.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_resolve_ui.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_altium.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_core.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_full_altiumfiles.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_full_followup.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_full_footprints.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_full_frontends.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_full_kicad.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_full_llm.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_full_pipeline.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_full_queue_race.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_rvh.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_rvj.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_tool_exports.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_review_ui.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_rules.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_rules_infer.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_sim_models.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_site.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_stdparts.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_symbol_layout.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_team_history.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_team_setup.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_term.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_testpack.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_tool_exports.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_ui.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_ui_browser.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_ui_voice.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_upgrade.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_upkeep.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_upstream.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/test_visual_check.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/ui_browser.js +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/ui_fixture.py +0 -0
- {ecadlib-0.3.0 → ecadlib-0.3.1}/tests/upgrade_fixtures.py +0 -0
|
@@ -7,6 +7,39 @@ a minor release may change command-line options and file formats.
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.1] - 2026-10-17
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Altium builds the libraries itself (`ecadlib/altium_native.py`, docs/altium-native.md): every `.PcbLib` / `.SchLib` ecadlib writes gets a `.ecadbuild` recipe, and a DelphiScript (`ecadlib_build.pas`) rebuilds them inside Altium with its own object API; `ecadlib altium-native write|compare` and a *Rebuild with Altium* step in `altium-pkg` (`--no-native-build` to skip). `compare` reads Altium's result back pad by pad and pin by pin.
|
|
15
|
+
- The ecadlib menu in Altium lets Altium build the library files itself before it reinstalls the library: each job copies the parts' build recipes into the library folder and writes `ecadlib_build.txt`, and the menu calls `BuildLibraries` (`ecadlib_build.pas`, now part of the menu's script project). The dialog says when a library failed to build. `native_build=0` in `ecadlib_menu.ini` turns it off.
|
|
16
|
+
- Altium footprints carry the designator on the assembly drawing too: KiCad's `${REFERENCE}` on F.Fab becomes a `.Designator` on Mechanical 13 (the `[layers] assembly` layer), and footprints without one get it centred on the body. `ecadlib parity` and the footprint check compare it between KiCad and Altium (#37).
|
|
17
|
+
- Edits made in Altium are kept: each library ecadlib copies into a library folder gets a `.ecadstate` (the hash of ecadlib's file and of the file Altium built from it). A library someone changed in Altium afterwards is no longer rebuilt by the native build or replaced by `dblib-sync` / `altium-pkg`; they report it instead (`dblib-sync --overwrite-edits`, `altium-native write --rebuild-all` replace it). Libraries Altium already built and ecadlib has not changed are not rebuilt on every run.
|
|
18
|
+
- `ecadlib fp-edit PLAN --part P show|rename OLD=NEW|same-net A,B|undo`: fix a held part's datasheet pad table by hand, e.g. a connector whose pads are named 1+ / 1- or T / R / S (a footprint still needs a pad 1 or A1, so a person picks it). The edit is kept in `footprint_edits.json` next to the plan, applied whenever the librarian builds the part, and noted on the part with who made it. A part held because its datasheet pad table failed the check now says which check failed and what to do (no pad 1: rename a pad with `fp-edit`; pads of two nets overlap: `same-net` if they are one net, else pick a footprint), instead of "there is no footprint yet".
|
|
19
|
+
- `ecadlib sources-check` and a weekly `sources-canary` workflow: checks the unofficial EasyEDA / JLCPCB endpoints against known parts.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Pads on one net may overlap in a datasheet pad table: pads whose pins share a name in the pin table (VIN on pins 1, 2 and the paddle) are put in `same_net` automatically (NC / DNC pins never are). An exposed pad listed twice at the same place with another size (for its thermal vias) is one pad, not a misread; an exact copy is still an error. The accuracy gate's baseline moves to 328/331 (qfn-DAC60504).
|
|
24
|
+
- Official part APIs first: the default provider order is Nexar, DigiKey, Mouser, then the unofficial JLCPCB search and EasyEDA. Nexar / DigiKey / Mouser answers now give the LCSC number and datasheet link. `[providers] unofficial = false` turns the unofficial endpoints off completely.
|
|
25
|
+
|
|
26
|
+
- Altium (Altium 365 first) and KiCad are the supported targets. The Fusion Electronics / EAGLE and EasyEDA Pro exports are marked experimental in the README and `ecadlib -h`: they keep working but get no new features and may be removed later.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- BOM intake: `C1~C4` designator ranges are counted; European decimal quantities are not multiplied by ten; one cp1252 byte no longer garbles a UTF-8 CSV; `DNP` / `DNF` in the Value or MPN cell marks the line; a quantity-only footer row is not a part; an MPN that Excel turned into scientific notation is flagged.
|
|
31
|
+
- DbLib table: parts go to the right table (LCSC long descriptions, `easyeda:C7593` is an LCSC number, an IC package outranks the description words, menu parts follow their source).
|
|
32
|
+
- Altium: variants per channel and part, variant alternates by Design Item ID, the encoding of a DbLib Altium saved is kept, prune removes the STEP files ecadlib wrote, sheet name case, menu jobs and pin numbers; the native build keeps recipe footprint names as stored and keeps a library when a STEP file is missing.
|
|
33
|
+
- KiCad export: re-export touches nothing unchanged and never loses hand edits; Altium keep-outs and non-copper regions are not written as copper; Bottom Paste / Bottom Solder and fill rotation are kept; KiCad name clashes are reported; a database row never points at another part's symbol.
|
|
34
|
+
- 3D models: the STEP model is turned to the footprint's pads, and more EasyEDA / LCSC package names get the right body.
|
|
35
|
+
- House style: `style learn` needs coverage before a setting is high and does not write low settings; `power_side = "left"` puts a lone ground at the bottom.
|
|
36
|
+
- Standard parts refuse land variants, exposed-pad SOTs and contradicting size codes.
|
|
37
|
+
- The approval gate works under house parameter names, and placeholder MPNs are handled.
|
|
38
|
+
- Models: the feedback turn is capped, API keys are redacted, unit repair is strict, configured key names are used.
|
|
39
|
+
- Altium: DbLib table names Altium's database driver can open, install scripts written in cp1252, and a warning for Unicode pin names.
|
|
40
|
+
- Team server: no self-approval through the plan approval route, and an odd `sign_as` is a plain 400.
|
|
41
|
+
- Security: no API key in network error messages, framing refused in local mode, a deeply nested JSON body is a plain 400.
|
|
42
|
+
|
|
10
43
|
## [0.3.0] - 2026-10-17
|
|
11
44
|
|
|
12
45
|
### Added
|
|
@@ -183,7 +216,8 @@ a minor release may change command-line options and file formats.
|
|
|
183
216
|
- Initial prototypes: IPC-7351B footprint generator driven by `package_schema.json`, BOM triage
|
|
184
217
|
against local KiCad libraries and public part sources, and Altium Database Library (DbLib) export.
|
|
185
218
|
|
|
186
|
-
[Unreleased]: https://github.com/oliBrowne/PCBLIVINGLIBRARY/compare/v0.3.
|
|
219
|
+
[Unreleased]: https://github.com/oliBrowne/PCBLIVINGLIBRARY/compare/v0.3.1...HEAD
|
|
220
|
+
[0.3.1]: https://github.com/oliBrowne/PCBLIVINGLIBRARY/compare/v0.3.0...v0.3.1
|
|
187
221
|
[0.3.0]: https://github.com/oliBrowne/PCBLIVINGLIBRARY/compare/v0.2.0...v0.3.0
|
|
188
222
|
[0.2.0]: https://github.com/oliBrowne/PCBLIVINGLIBRARY/compare/v0.1.0...v0.2.0
|
|
189
223
|
[0.1.0]: https://github.com/oliBrowne/PCBLIVINGLIBRARY/releases/tag/v0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ecadlib
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: AI-assisted living ECAD component library: BOM triage, IPC-7351B footprints, Altium and KiCad export
|
|
5
5
|
Author: oliver browne
|
|
6
6
|
License-Expression: MIT
|
|
@@ -52,13 +52,38 @@ Requires-Dist: pillow; extra == "dev"
|
|
|
52
52
|
Requires-Dist: tomli; extra == "dev"
|
|
53
53
|
Dynamic: license-file
|
|
54
54
|
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
# ecadlib: a librarian for your parts
|
|
56
|
+
|
|
57
|
+
ecadlib keeps your component library alive. Give it a BOM and it finds every symbol, footprint and 3D model you are
|
|
58
|
+
missing, draws the ones nobody has from the datasheet, makes them match the rest of your library, holds anything in
|
|
59
|
+
doubt for a person to sign off, and releases the rest to **Altium 365** or **KiCad**.
|
|
60
|
+
|
|
61
|
+
* **BOM in.** Altium BOMs and ActiveBOMs, KiCad BOMs and schematics, or a hand-made CSV/XLSX. Each line comes back as
|
|
62
|
+
already in your library, available from a source, needs a footprint, or DNP.
|
|
63
|
+
* **Official sources first.** Nexar, DigiKey and Mouser identify the part; symbols and footprints come from your own
|
|
64
|
+
libraries and the official KiCad libraries before anything else. EasyEDA/LCSC is an unofficial source, used after
|
|
65
|
+
those, and one setting (`[providers] unofficial = false`) turns it off.
|
|
66
|
+
* **Drawn from the datasheet when nobody has it.** A datasheet reader fills a package description and a deterministic
|
|
67
|
+
IPC-7351B generator draws the land pattern. It works with Claude by default or the model you choose; you bring the
|
|
68
|
+
API key.
|
|
69
|
+
* **Your house style.** `ecadlib style learn` reads your existing libraries and new parts follow the same naming,
|
|
70
|
+
descriptions, value formats and parameters.
|
|
71
|
+
* **Review hold.** A release check runs on every part. Anything that fails it, or still needs a person, is held back
|
|
72
|
+
from Altium 365 until someone signs it off.
|
|
73
|
+
* **Altium 365 release.** Parts go to your Altium 365 workspace, or out as `.SchLib`/`.PcbLib`, a database library
|
|
74
|
+
and KiCad libraries, from one plan.
|
|
75
|
+
|
|
76
|
+
Install it with `pip install ecadlib` (v0.3.1, Python 3.10+), or on Windows run the installer from the
|
|
77
|
+
[Releases page](https://github.com/oliBrowne/PCBLIVINGLIBRARY/releases). It is free and open source under the MIT
|
|
78
|
+
licence. Website: [pcblivinglibrary.vercel.app](https://pcblivinglibrary.vercel.app).
|
|
79
|
+
|
|
80
|
+
**Supported tools:** Altium (Altium 365 first) and KiCad are the supported targets: they get the testing, the
|
|
81
|
+
benchmarks and the fixes. The Fusion Electronics / EAGLE and EasyEDA Pro exports (section 11b) still work but are
|
|
82
|
+
**experimental**: kept as they are, not a focus, and they may be removed.
|
|
83
|
+
|
|
84
|
+
**Where it's going:** [docs/PRODUCT_SPEC.md](docs/PRODUCT_SPEC.md) says who ecadlib is for, what it must do and how
|
|
85
|
+
success is measured; [ROADMAP.md](ROADMAP.md) lists what has shipped and the next milestones (v0.3.1, v0.4.0, v0.5.0)
|
|
86
|
+
with their dates.
|
|
62
87
|
|
|
63
88
|
## Start here (no terminal needed)
|
|
64
89
|
|
|
@@ -71,7 +96,7 @@ who use the command line or work on ecadlib itself (section 38 covers how the in
|
|
|
71
96
|
## Quick start
|
|
72
97
|
|
|
73
98
|
```
|
|
74
|
-
pip install
|
|
99
|
+
pip install ecadlib # Python 3.10+ (or `pip install -e .` from this checkout)
|
|
75
100
|
ecadlib demo # about a second, offline, no API keys: a small library in ./ecadlib-demo
|
|
76
101
|
ecadlib init # a few questions -> ecadlib.toml, then a setup check and the next commands
|
|
77
102
|
ecadlib librarian my_bom.csv -o ecadlib_workspace/librarian/my_bom # fill every missing part; `ecadlib status` shows it
|
|
@@ -100,7 +125,7 @@ See section 32 for the first-run commands in detail.
|
|
|
100
125
|
Install it with pip (Python 3.10 or later):
|
|
101
126
|
|
|
102
127
|
```
|
|
103
|
-
pip install ecadlib #
|
|
128
|
+
pip install ecadlib # from PyPI
|
|
104
129
|
pip install "ecadlib[pdf]" # pypdf trims datasheets to --pages
|
|
105
130
|
pip install -e ".[dev]" # from a checkout: editable, plus everything the test suite uses
|
|
106
131
|
```
|
|
@@ -149,7 +174,7 @@ That gives you a single `ecadlib` command (`python -m ecadlib` works too). There
|
|
|
149
174
|
```
|
|
150
175
|
|
|
151
176
|
Its tools are `workspace_info`, `triage_bom` (with `summary_only` for large BOMs), `preview_footprint`, `approve_footprint`, `librarian_run` (fill every missing part, then the release check), `release_check` (with `allow` for parts a person has signed off), `held_parts`, `part_candidates` and `choose_part` (fix a held part), `approval_status` and `approve_part` (sign-off; `user` is required, the agent must pass the person's own name), `find_duplicates` (with `merge`), `build_altium_models`, `export_altium_dblib`, `altium365_plan`, `altium365_push` (dry run unless `dry_run` is false; held parts are never pushed), `sim_models` (SPICE/IBIS models; `attach` writes them) and `list_example_specs`.
|
|
152
|
-
3. **CLI**, for scripts and CI: `ecadlib triage`, `ecadlib footprint`, `ecadlib check`, `ecadlib footprint-bench`, `ecadlib dblib`, `ecadlib dblib-sync`, `ecadlib altium-lib`, `ecadlib altium365`, `ecadlib kicad-export` (the library as KiCad files, section 11), `ecadlib eagle-export` and `ecadlib easyeda-export` (Fusion Electronics / EAGLE and EasyEDA Pro, section 11b), `ecadlib resolve`, `ecadlib approve`, `ecadlib dedupe`, `ecadlib sourcing`, `ecadlib step-gen`, `ecadlib upkeep` (section 15), `ecadlib a365`, `ecadlib project`, `ecadlib where-used` and `ecadlib sim-models` (section 17), `ecadlib init` and `ecadlib rules` (section 18), `ecadlib demo` (section 32), `ecadlib kicad-pcm` and `ecadlib altium-pkg` (section 31), `ecadlib ai` (section 33), `ecadlib symbol` (section 19), `ecadlib datasheet`, `ecadlib team`, `ecadlib agent` (the library agent, section 20), `ecadlib agent-watch` (21), `ecadlib queue` (22), `ecadlib visual-check` (23), `ecadlib migrate` and `ecadlib rebuild` (35). Run `ecadlib <command> -h` for options. Each is described below; the older `python3 -m ecadlib.<module>` form still works.
|
|
177
|
+
3. **CLI**, for scripts and CI: `ecadlib triage`, `ecadlib footprint`, `ecadlib check`, `ecadlib footprint-bench`, `ecadlib dblib`, `ecadlib dblib-sync`, `ecadlib altium-lib`, `ecadlib altium365`, `ecadlib kicad-export` (the library as KiCad files, section 11), `ecadlib eagle-export` and `ecadlib easyeda-export` (Fusion Electronics / EAGLE and EasyEDA Pro, experimental, section 11b), `ecadlib resolve`, `ecadlib approve`, `ecadlib dedupe`, `ecadlib sourcing`, `ecadlib step-gen`, `ecadlib upkeep` (section 15), `ecadlib a365`, `ecadlib project`, `ecadlib where-used` and `ecadlib sim-models` (section 17), `ecadlib init` and `ecadlib rules` (section 18), `ecadlib demo` (section 32), `ecadlib kicad-pcm` and `ecadlib altium-pkg` (section 31), `ecadlib ai` (section 33), `ecadlib symbol` (section 19), `ecadlib datasheet`, `ecadlib team`, `ecadlib agent` (the library agent, section 20), `ecadlib agent-watch` (21), `ecadlib queue` (22), `ecadlib visual-check` (23), `ecadlib migrate` and `ecadlib rebuild` (35). Run `ecadlib <command> -h` for options. Each is described below; the older `python3 -m ecadlib.<module>` form still works.
|
|
153
178
|
|
|
154
179
|
The UI and MCP server write everything to one workspace folder (default `./ecadlib_workspace`). It has these subfolders:
|
|
155
180
|
* `uploads/`
|
|
@@ -480,16 +505,27 @@ python3 -m tests.test_offline
|
|
|
480
505
|
* `unverified (source unreachable)`, which is kept separate on purpose so a network failure is never reported as "needs generation"
|
|
481
506
|
* **Providers** (`providers.py`, interface `lookup(line) -> SourceResult`, raising `NotConfigured`):
|
|
482
507
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
|
489
|
-
|
|
490
|
-
| `
|
|
491
|
-
| `
|
|
492
|
-
|
|
508
|
+
Default order: `nexar,digikey,mouser,jlcpcb_search,easyeda`. The official APIs come first; each is skipped with a
|
|
509
|
+
"not configured" note until its key is set. None of them hands out symbol or footprint geometry, so they identify
|
|
510
|
+
the part (maker, description, datasheet link, package, and the LCSC number when LCSC sells it) and the EasyEDA
|
|
511
|
+
route or the datasheet reader supplies the CAD data.
|
|
512
|
+
|
|
513
|
+
| provider | official? | auth needed | what it gives |
|
|
514
|
+
|---|---|---|---|
|
|
515
|
+
| `nexar` | yes (Octopart / Altium supply API) | OAuth2 client credentials (`NEXAR_CLIENT_ID/SECRET` or `NEXAR_SUPPLY_TOKEN`), GraphQL, quota-limited | MPN match, maker, description, best datasheet, LCSC number from LCSC's offer |
|
|
516
|
+
| `digikey` | yes (Product Information API v4) | OAuth2 client credentials (`DIGIKEY_CLIENT_ID/SECRET`) | MPN match, maker, description, datasheet, package |
|
|
517
|
+
| `mouser` | yes (Search API v1) | `MOUSER_API_KEY` | MPN match, maker, description, datasheet |
|
|
518
|
+
| `jlcpcb_search` | **no**: anonymous JSON POST to `jlcpcb.com/api/overseas-pcb-order/v1/shoppingCart/smtGood/selectSmtComponentList` (from easyeda2kicad 1.0.1) | none | MPN → LCSC, only when no official source found the LCSC number |
|
|
519
|
+
| `easyeda` | **no**: `GET https://easyeda.com/api/products/{LCSC}/components` with `Referer: https://easyeda.com/` | none | the symbol, footprint and 3D data (the only free source of ready CAD data) |
|
|
520
|
+
| `snapmagic` | partner token only, no self-serve public API | | stub |
|
|
521
|
+
| `samacsys` | account plus Library Loader or partner access, no documented public REST API | | stub |
|
|
522
|
+
|
|
523
|
+
* `[providers] unofficial = false` in `ecadlib.toml` keeps the two undocumented endpoints out entirely (triage, the
|
|
524
|
+
librarian's EasyEDA source, the UI). Parts then come from your libraries, the KiCad libraries, the standard
|
|
525
|
+
packages and the datasheet reader.
|
|
526
|
+
* `ecadlib sources-check` asks both unofficial endpoints about known parts (NE555DR, LM358DR, RP2040) and checks the
|
|
527
|
+
converter still gives the right pad and pin counts. `.github/workflows/sources-canary.yml` runs it every Monday and
|
|
528
|
+
keeps the raw answers as an artifact, so a change on their side shows up as a red run, not as broken user parts.
|
|
493
529
|
* easyeda2kicad 1.0.1 calls `/components` with no `?version=`. The `?version=6.4.19.5` suffix comes from older releases; I kept it, and it is untested.
|
|
494
530
|
* easyeda2kicad 1.0.1 also knows `pro.easyeda.com/api/components/searchByNumbers` (LCSC → v2 UUID, unauthenticated). Its other v2 endpoints are marked "requires auth" in its source.
|
|
495
531
|
* I found no public, unauthenticated LCSC search endpoint. The `wmsc.lcsc.com` endpoints are undocumented and were also blocked here.
|
|
@@ -641,6 +677,10 @@ python3 -m ecadlib.altium365 plan examples/sample_bom.csv --triage out/triage_sa
|
|
|
641
677
|
# add --models out/altium_models_kicad (section 6) -> 14 ready
|
|
642
678
|
```
|
|
643
679
|
|
|
680
|
+
**Altium can now build these files itself.** Every library written here also gets a plain-text recipe beside it
|
|
681
|
+
(`<file>.ecadbuild`), and the install script lets Altium rebuild each library from it with its own scripting API
|
|
682
|
+
before installing it. See [docs/altium-native.md](docs/altium-native.md) and `ecadlib altium-native`.
|
|
683
|
+
|
|
644
684
|
No dependencies beyond the standard library. `cfb.py` writes the OLE2 container (v3, 512-byte sectors, mini stream, DIFAT for files over ~7 MB). `altium_lib.py` builds the Altium streams inside it. The record layouts are ported from **AltiumSharp** (C#, Apache-2.0; attribution in the file header and `NOTICE`). `altium-designer-mcp` (GPL-3.0) was read for notes only, and none of its code is used.
|
|
645
685
|
|
|
646
686
|
What gets written:
|
|
@@ -844,7 +884,10 @@ Writes what the librarian built for Altium as a KiCad library: `mylib.kicad_sym`
|
|
|
844
884
|
* **Checks:** every file parses with `ecadlib.sexpr`, each footprint passes release_check's footprint rule at the level the release check recorded, and symbol pins are checked against footprint pads. **In KiCad itself** (7.0.11, see section 28): the `fp-lib-table` resolves in a KiCad project and its footprints match the library; KiCad 7 refuses the KiCad 8 symbol library as such, and loads it with the two KiCad 8 tokens (`exclude_from_sim`, `generator_version`) removed, every pin, graphic and field unchanged. KiCad 8, 9 and 10 were not run here. A KiCad 7 symbol's `ki_description` becomes the `Description` field.
|
|
845
885
|
* **License:** KiCad library content is CC-BY-SA 4.0. An export that includes some gets a `NOTICE.txt`, and the export stays out of git (`out/kicad/` is in `.gitignore`).
|
|
846
886
|
|
|
847
|
-
## 11b. `eagle_export.py` and `easyeda_pro_export.py`: Fusion Electronics / EAGLE and EasyEDA Pro
|
|
887
|
+
## 11b. `eagle_export.py` and `easyeda_pro_export.py`: Fusion Electronics / EAGLE and EasyEDA Pro (experimental)
|
|
888
|
+
|
|
889
|
+
> **Experimental.** ecadlib focuses on Altium and KiCad. These two exports keep working and keep their read-back
|
|
890
|
+
> checks, but they get no new features and may be removed in a later release.
|
|
848
891
|
|
|
849
892
|
```
|
|
850
893
|
ecadlib eagle-export out/librarian/plan.json -o out/fusion --name mylib [--kicad out/kicad] [--include-held] [--offline]
|
|
@@ -1028,7 +1071,7 @@ python3 -m tests.test_sim_models
|
|
|
1028
1071
|
* an Altium 365 part list (an `altium365` state file, or JSON in the `a365_sync` shape `{name, folder, parameters, symbol, footprint}`): folders and parameters;
|
|
1029
1072
|
* KiCad `.kicad_sym`/`.pretty`, and BOM/parts spreadsheets (column names).
|
|
1030
1073
|
|
|
1031
|
-
Names are pattern-mined per category (`RES_{package}_{value}_{tolerance}`, `R{package}_{value}`, `{mpn}` ...) with value style (`4K7`, `4.7k`, `4.7kΩ`) detected. The written file says, for every setting, where it came from and how confident the guess is. `init` asks a question only where the evidence is split (the best pattern under 60% with a runner-up at 20% or more); `--yes` takes the best guess. If `ecadlib.toml` already exists, `init` shows a diff, writes the proposal to `ecadlib.toml.proposed` and changes nothing unless you confirm or pass `--force` (the old file is kept as `.bak`).
|
|
1074
|
+
Names are pattern-mined per category (`RES_{package}_{value}_{tolerance}`, `R{package}_{value}`, `{mpn}` ...) with value style (`4K7`, `4.7k`, `4.7kΩ`) detected. The written file says, for every setting, where it came from and how confident the guess is. Confidence counts how much of the library shows the convention, not only how much of the evidence agrees: a setting backed by fewer than 3 parts, footprints or symbols, or a footprint layer seen in fewer than half of the footprints (one `.Designator` in 48 footprints), is low. Low settings are not written; they are listed as comments at the top of the file, and ecadlib's default stays. The courtyard is never learned onto a layer that holds the library's 3D bodies, and a `.Designator` on a mechanical layer is not proposed when the library has silkscreen on the overlay. `init` asks a question only where the evidence is split (the best pattern under 60% with a runner-up at 20% or more); `--yes` takes the best guess. If `ecadlib.toml` already exists, `init` shows a diff, writes the proposal to `ecadlib.toml.proposed` and changes nothing unless you confirm or pass `--force` (the old file is kept as `.bak`).
|
|
1032
1075
|
|
|
1033
1076
|
The UI has a **Library rules** card (type the folders to scan, review the proposals with their evidence, edit the TOML, save; replacing an existing file asks first and shows the diff). The MCP server has `propose_rules` and `save_rules`.
|
|
1034
1077
|
|
|
@@ -1,10 +1,35 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
# ecadlib: a librarian for your parts
|
|
2
|
+
|
|
3
|
+
ecadlib keeps your component library alive. Give it a BOM and it finds every symbol, footprint and 3D model you are
|
|
4
|
+
missing, draws the ones nobody has from the datasheet, makes them match the rest of your library, holds anything in
|
|
5
|
+
doubt for a person to sign off, and releases the rest to **Altium 365** or **KiCad**.
|
|
6
|
+
|
|
7
|
+
* **BOM in.** Altium BOMs and ActiveBOMs, KiCad BOMs and schematics, or a hand-made CSV/XLSX. Each line comes back as
|
|
8
|
+
already in your library, available from a source, needs a footprint, or DNP.
|
|
9
|
+
* **Official sources first.** Nexar, DigiKey and Mouser identify the part; symbols and footprints come from your own
|
|
10
|
+
libraries and the official KiCad libraries before anything else. EasyEDA/LCSC is an unofficial source, used after
|
|
11
|
+
those, and one setting (`[providers] unofficial = false`) turns it off.
|
|
12
|
+
* **Drawn from the datasheet when nobody has it.** A datasheet reader fills a package description and a deterministic
|
|
13
|
+
IPC-7351B generator draws the land pattern. It works with Claude by default or the model you choose; you bring the
|
|
14
|
+
API key.
|
|
15
|
+
* **Your house style.** `ecadlib style learn` reads your existing libraries and new parts follow the same naming,
|
|
16
|
+
descriptions, value formats and parameters.
|
|
17
|
+
* **Review hold.** A release check runs on every part. Anything that fails it, or still needs a person, is held back
|
|
18
|
+
from Altium 365 until someone signs it off.
|
|
19
|
+
* **Altium 365 release.** Parts go to your Altium 365 workspace, or out as `.SchLib`/`.PcbLib`, a database library
|
|
20
|
+
and KiCad libraries, from one plan.
|
|
21
|
+
|
|
22
|
+
Install it with `pip install ecadlib` (v0.3.1, Python 3.10+), or on Windows run the installer from the
|
|
23
|
+
[Releases page](https://github.com/oliBrowne/PCBLIVINGLIBRARY/releases). It is free and open source under the MIT
|
|
24
|
+
licence. Website: [pcblivinglibrary.vercel.app](https://pcblivinglibrary.vercel.app).
|
|
25
|
+
|
|
26
|
+
**Supported tools:** Altium (Altium 365 first) and KiCad are the supported targets: they get the testing, the
|
|
27
|
+
benchmarks and the fixes. The Fusion Electronics / EAGLE and EasyEDA Pro exports (section 11b) still work but are
|
|
28
|
+
**experimental**: kept as they are, not a focus, and they may be removed.
|
|
29
|
+
|
|
30
|
+
**Where it's going:** [docs/PRODUCT_SPEC.md](docs/PRODUCT_SPEC.md) says who ecadlib is for, what it must do and how
|
|
31
|
+
success is measured; [ROADMAP.md](ROADMAP.md) lists what has shipped and the next milestones (v0.3.1, v0.4.0, v0.5.0)
|
|
32
|
+
with their dates.
|
|
8
33
|
|
|
9
34
|
## Start here (no terminal needed)
|
|
10
35
|
|
|
@@ -17,7 +42,7 @@ who use the command line or work on ecadlib itself (section 38 covers how the in
|
|
|
17
42
|
## Quick start
|
|
18
43
|
|
|
19
44
|
```
|
|
20
|
-
pip install
|
|
45
|
+
pip install ecadlib # Python 3.10+ (or `pip install -e .` from this checkout)
|
|
21
46
|
ecadlib demo # about a second, offline, no API keys: a small library in ./ecadlib-demo
|
|
22
47
|
ecadlib init # a few questions -> ecadlib.toml, then a setup check and the next commands
|
|
23
48
|
ecadlib librarian my_bom.csv -o ecadlib_workspace/librarian/my_bom # fill every missing part; `ecadlib status` shows it
|
|
@@ -46,7 +71,7 @@ See section 32 for the first-run commands in detail.
|
|
|
46
71
|
Install it with pip (Python 3.10 or later):
|
|
47
72
|
|
|
48
73
|
```
|
|
49
|
-
pip install ecadlib #
|
|
74
|
+
pip install ecadlib # from PyPI
|
|
50
75
|
pip install "ecadlib[pdf]" # pypdf trims datasheets to --pages
|
|
51
76
|
pip install -e ".[dev]" # from a checkout: editable, plus everything the test suite uses
|
|
52
77
|
```
|
|
@@ -95,7 +120,7 @@ That gives you a single `ecadlib` command (`python -m ecadlib` works too). There
|
|
|
95
120
|
```
|
|
96
121
|
|
|
97
122
|
Its tools are `workspace_info`, `triage_bom` (with `summary_only` for large BOMs), `preview_footprint`, `approve_footprint`, `librarian_run` (fill every missing part, then the release check), `release_check` (with `allow` for parts a person has signed off), `held_parts`, `part_candidates` and `choose_part` (fix a held part), `approval_status` and `approve_part` (sign-off; `user` is required, the agent must pass the person's own name), `find_duplicates` (with `merge`), `build_altium_models`, `export_altium_dblib`, `altium365_plan`, `altium365_push` (dry run unless `dry_run` is false; held parts are never pushed), `sim_models` (SPICE/IBIS models; `attach` writes them) and `list_example_specs`.
|
|
98
|
-
3. **CLI**, for scripts and CI: `ecadlib triage`, `ecadlib footprint`, `ecadlib check`, `ecadlib footprint-bench`, `ecadlib dblib`, `ecadlib dblib-sync`, `ecadlib altium-lib`, `ecadlib altium365`, `ecadlib kicad-export` (the library as KiCad files, section 11), `ecadlib eagle-export` and `ecadlib easyeda-export` (Fusion Electronics / EAGLE and EasyEDA Pro, section 11b), `ecadlib resolve`, `ecadlib approve`, `ecadlib dedupe`, `ecadlib sourcing`, `ecadlib step-gen`, `ecadlib upkeep` (section 15), `ecadlib a365`, `ecadlib project`, `ecadlib where-used` and `ecadlib sim-models` (section 17), `ecadlib init` and `ecadlib rules` (section 18), `ecadlib demo` (section 32), `ecadlib kicad-pcm` and `ecadlib altium-pkg` (section 31), `ecadlib ai` (section 33), `ecadlib symbol` (section 19), `ecadlib datasheet`, `ecadlib team`, `ecadlib agent` (the library agent, section 20), `ecadlib agent-watch` (21), `ecadlib queue` (22), `ecadlib visual-check` (23), `ecadlib migrate` and `ecadlib rebuild` (35). Run `ecadlib <command> -h` for options. Each is described below; the older `python3 -m ecadlib.<module>` form still works.
|
|
123
|
+
3. **CLI**, for scripts and CI: `ecadlib triage`, `ecadlib footprint`, `ecadlib check`, `ecadlib footprint-bench`, `ecadlib dblib`, `ecadlib dblib-sync`, `ecadlib altium-lib`, `ecadlib altium365`, `ecadlib kicad-export` (the library as KiCad files, section 11), `ecadlib eagle-export` and `ecadlib easyeda-export` (Fusion Electronics / EAGLE and EasyEDA Pro, experimental, section 11b), `ecadlib resolve`, `ecadlib approve`, `ecadlib dedupe`, `ecadlib sourcing`, `ecadlib step-gen`, `ecadlib upkeep` (section 15), `ecadlib a365`, `ecadlib project`, `ecadlib where-used` and `ecadlib sim-models` (section 17), `ecadlib init` and `ecadlib rules` (section 18), `ecadlib demo` (section 32), `ecadlib kicad-pcm` and `ecadlib altium-pkg` (section 31), `ecadlib ai` (section 33), `ecadlib symbol` (section 19), `ecadlib datasheet`, `ecadlib team`, `ecadlib agent` (the library agent, section 20), `ecadlib agent-watch` (21), `ecadlib queue` (22), `ecadlib visual-check` (23), `ecadlib migrate` and `ecadlib rebuild` (35). Run `ecadlib <command> -h` for options. Each is described below; the older `python3 -m ecadlib.<module>` form still works.
|
|
99
124
|
|
|
100
125
|
The UI and MCP server write everything to one workspace folder (default `./ecadlib_workspace`). It has these subfolders:
|
|
101
126
|
* `uploads/`
|
|
@@ -426,16 +451,27 @@ python3 -m tests.test_offline
|
|
|
426
451
|
* `unverified (source unreachable)`, which is kept separate on purpose so a network failure is never reported as "needs generation"
|
|
427
452
|
* **Providers** (`providers.py`, interface `lookup(line) -> SourceResult`, raising `NotConfigured`):
|
|
428
453
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
|
435
|
-
|
|
436
|
-
| `
|
|
437
|
-
| `
|
|
438
|
-
|
|
454
|
+
Default order: `nexar,digikey,mouser,jlcpcb_search,easyeda`. The official APIs come first; each is skipped with a
|
|
455
|
+
"not configured" note until its key is set. None of them hands out symbol or footprint geometry, so they identify
|
|
456
|
+
the part (maker, description, datasheet link, package, and the LCSC number when LCSC sells it) and the EasyEDA
|
|
457
|
+
route or the datasheet reader supplies the CAD data.
|
|
458
|
+
|
|
459
|
+
| provider | official? | auth needed | what it gives |
|
|
460
|
+
|---|---|---|---|
|
|
461
|
+
| `nexar` | yes (Octopart / Altium supply API) | OAuth2 client credentials (`NEXAR_CLIENT_ID/SECRET` or `NEXAR_SUPPLY_TOKEN`), GraphQL, quota-limited | MPN match, maker, description, best datasheet, LCSC number from LCSC's offer |
|
|
462
|
+
| `digikey` | yes (Product Information API v4) | OAuth2 client credentials (`DIGIKEY_CLIENT_ID/SECRET`) | MPN match, maker, description, datasheet, package |
|
|
463
|
+
| `mouser` | yes (Search API v1) | `MOUSER_API_KEY` | MPN match, maker, description, datasheet |
|
|
464
|
+
| `jlcpcb_search` | **no**: anonymous JSON POST to `jlcpcb.com/api/overseas-pcb-order/v1/shoppingCart/smtGood/selectSmtComponentList` (from easyeda2kicad 1.0.1) | none | MPN → LCSC, only when no official source found the LCSC number |
|
|
465
|
+
| `easyeda` | **no**: `GET https://easyeda.com/api/products/{LCSC}/components` with `Referer: https://easyeda.com/` | none | the symbol, footprint and 3D data (the only free source of ready CAD data) |
|
|
466
|
+
| `snapmagic` | partner token only, no self-serve public API | | stub |
|
|
467
|
+
| `samacsys` | account plus Library Loader or partner access, no documented public REST API | | stub |
|
|
468
|
+
|
|
469
|
+
* `[providers] unofficial = false` in `ecadlib.toml` keeps the two undocumented endpoints out entirely (triage, the
|
|
470
|
+
librarian's EasyEDA source, the UI). Parts then come from your libraries, the KiCad libraries, the standard
|
|
471
|
+
packages and the datasheet reader.
|
|
472
|
+
* `ecadlib sources-check` asks both unofficial endpoints about known parts (NE555DR, LM358DR, RP2040) and checks the
|
|
473
|
+
converter still gives the right pad and pin counts. `.github/workflows/sources-canary.yml` runs it every Monday and
|
|
474
|
+
keeps the raw answers as an artifact, so a change on their side shows up as a red run, not as broken user parts.
|
|
439
475
|
* easyeda2kicad 1.0.1 calls `/components` with no `?version=`. The `?version=6.4.19.5` suffix comes from older releases; I kept it, and it is untested.
|
|
440
476
|
* easyeda2kicad 1.0.1 also knows `pro.easyeda.com/api/components/searchByNumbers` (LCSC → v2 UUID, unauthenticated). Its other v2 endpoints are marked "requires auth" in its source.
|
|
441
477
|
* I found no public, unauthenticated LCSC search endpoint. The `wmsc.lcsc.com` endpoints are undocumented and were also blocked here.
|
|
@@ -587,6 +623,10 @@ python3 -m ecadlib.altium365 plan examples/sample_bom.csv --triage out/triage_sa
|
|
|
587
623
|
# add --models out/altium_models_kicad (section 6) -> 14 ready
|
|
588
624
|
```
|
|
589
625
|
|
|
626
|
+
**Altium can now build these files itself.** Every library written here also gets a plain-text recipe beside it
|
|
627
|
+
(`<file>.ecadbuild`), and the install script lets Altium rebuild each library from it with its own scripting API
|
|
628
|
+
before installing it. See [docs/altium-native.md](docs/altium-native.md) and `ecadlib altium-native`.
|
|
629
|
+
|
|
590
630
|
No dependencies beyond the standard library. `cfb.py` writes the OLE2 container (v3, 512-byte sectors, mini stream, DIFAT for files over ~7 MB). `altium_lib.py` builds the Altium streams inside it. The record layouts are ported from **AltiumSharp** (C#, Apache-2.0; attribution in the file header and `NOTICE`). `altium-designer-mcp` (GPL-3.0) was read for notes only, and none of its code is used.
|
|
591
631
|
|
|
592
632
|
What gets written:
|
|
@@ -790,7 +830,10 @@ Writes what the librarian built for Altium as a KiCad library: `mylib.kicad_sym`
|
|
|
790
830
|
* **Checks:** every file parses with `ecadlib.sexpr`, each footprint passes release_check's footprint rule at the level the release check recorded, and symbol pins are checked against footprint pads. **In KiCad itself** (7.0.11, see section 28): the `fp-lib-table` resolves in a KiCad project and its footprints match the library; KiCad 7 refuses the KiCad 8 symbol library as such, and loads it with the two KiCad 8 tokens (`exclude_from_sim`, `generator_version`) removed, every pin, graphic and field unchanged. KiCad 8, 9 and 10 were not run here. A KiCad 7 symbol's `ki_description` becomes the `Description` field.
|
|
791
831
|
* **License:** KiCad library content is CC-BY-SA 4.0. An export that includes some gets a `NOTICE.txt`, and the export stays out of git (`out/kicad/` is in `.gitignore`).
|
|
792
832
|
|
|
793
|
-
## 11b. `eagle_export.py` and `easyeda_pro_export.py`: Fusion Electronics / EAGLE and EasyEDA Pro
|
|
833
|
+
## 11b. `eagle_export.py` and `easyeda_pro_export.py`: Fusion Electronics / EAGLE and EasyEDA Pro (experimental)
|
|
834
|
+
|
|
835
|
+
> **Experimental.** ecadlib focuses on Altium and KiCad. These two exports keep working and keep their read-back
|
|
836
|
+
> checks, but they get no new features and may be removed in a later release.
|
|
794
837
|
|
|
795
838
|
```
|
|
796
839
|
ecadlib eagle-export out/librarian/plan.json -o out/fusion --name mylib [--kicad out/kicad] [--include-held] [--offline]
|
|
@@ -974,7 +1017,7 @@ python3 -m tests.test_sim_models
|
|
|
974
1017
|
* an Altium 365 part list (an `altium365` state file, or JSON in the `a365_sync` shape `{name, folder, parameters, symbol, footprint}`): folders and parameters;
|
|
975
1018
|
* KiCad `.kicad_sym`/`.pretty`, and BOM/parts spreadsheets (column names).
|
|
976
1019
|
|
|
977
|
-
Names are pattern-mined per category (`RES_{package}_{value}_{tolerance}`, `R{package}_{value}`, `{mpn}` ...) with value style (`4K7`, `4.7k`, `4.7kΩ`) detected. The written file says, for every setting, where it came from and how confident the guess is. `init` asks a question only where the evidence is split (the best pattern under 60% with a runner-up at 20% or more); `--yes` takes the best guess. If `ecadlib.toml` already exists, `init` shows a diff, writes the proposal to `ecadlib.toml.proposed` and changes nothing unless you confirm or pass `--force` (the old file is kept as `.bak`).
|
|
1020
|
+
Names are pattern-mined per category (`RES_{package}_{value}_{tolerance}`, `R{package}_{value}`, `{mpn}` ...) with value style (`4K7`, `4.7k`, `4.7kΩ`) detected. The written file says, for every setting, where it came from and how confident the guess is. Confidence counts how much of the library shows the convention, not only how much of the evidence agrees: a setting backed by fewer than 3 parts, footprints or symbols, or a footprint layer seen in fewer than half of the footprints (one `.Designator` in 48 footprints), is low. Low settings are not written; they are listed as comments at the top of the file, and ecadlib's default stays. The courtyard is never learned onto a layer that holds the library's 3D bodies, and a `.Designator` on a mechanical layer is not proposed when the library has silkscreen on the overlay. `init` asks a question only where the evidence is split (the best pattern under 60% with a runner-up at 20% or more); `--yes` takes the best guess. If `ecadlib.toml` already exists, `init` shows a diff, writes the proposal to `ecadlib.toml.proposed` and changes nothing unless you confirm or pass `--force` (the old file is kept as `.bak`).
|
|
978
1021
|
|
|
979
1022
|
The UI has a **Library rules** card (type the folders to scan, review the proposals with their evidence, edit the TOML, save; replacing an existing file asks first and shows the diff). The MCP server has `propose_rules` and `save_rules`.
|
|
980
1023
|
|
|
@@ -247,6 +247,8 @@ def push(items, client, ws, dry_run=False, note="ecadlib sync", policy=None, rul
|
|
|
247
247
|
from .approvals import push_block
|
|
248
248
|
from .rules import house_item
|
|
249
249
|
from .a365_sync import is_a365
|
|
250
|
+
# sign-off is checked on the item as it was approved (ecadlib's parameter names: the content hash covers them)
|
|
251
|
+
blocks = [push_block(i, policy) for i in items]
|
|
250
252
|
# a pulled item already carries the workspace's own parameter names: renaming it would rename them there
|
|
251
253
|
items = [i if is_a365(i) else house_item(i, rules) for i in items]
|
|
252
254
|
defs = {} if dry_run else client.release_defs(ws)
|
|
@@ -255,14 +257,13 @@ def push(items, client, ws, dry_run=False, note="ecadlib sync", policy=None, rul
|
|
|
255
257
|
if p not in uploaded:
|
|
256
258
|
uploaded[p] = "<fileId>" if dry_run else client.upload(p)
|
|
257
259
|
return uploaded[p]
|
|
258
|
-
for it in items:
|
|
260
|
+
for it, block in zip(items, blocks):
|
|
259
261
|
res = {"name": it["name"], "action": "", "detail": ""}
|
|
260
262
|
if it.get("status") == "held": # release_check held it back: no release, no parameter update
|
|
261
263
|
res["action"], res["detail"] = "skip", "held: " + "; ".join(it.get("hold_reasons") or ["release check"])
|
|
262
264
|
results.append(res)
|
|
263
265
|
continue
|
|
264
|
-
block
|
|
265
|
-
if block:
|
|
266
|
+
if block: # sign-off policy not met, or a dedupe duplicate
|
|
266
267
|
res["action"], res["detail"] = "skip", block
|
|
267
268
|
results.append(res)
|
|
268
269
|
continue
|
|
@@ -325,7 +326,7 @@ def main(argv=None):
|
|
|
325
326
|
from . import rules as RU
|
|
326
327
|
|
|
327
328
|
if a.cmd == "plan":
|
|
328
|
-
if Path(a.out).is_dir() or a.out.endswith(("/", "\\")):
|
|
329
|
+
if Path(a.out).is_dir() or a.out.endswith(("/", "\\")) or not Path(a.out).suffix: # -o out/a365: the plan file inside that folder
|
|
329
330
|
a.out = str(Path(a.out) / "plan.json")
|
|
330
331
|
rules = RU.load(a.rules, start=Path(a.out).parent)
|
|
331
332
|
lines, _ = read_bom(a.bom, RU.bom_columns(rules))
|