elecdef 0.1.0__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.
- elecdef-0.1.0/.gitattributes +1 -0
- elecdef-0.1.0/.github/workflows/ci.yml +31 -0
- elecdef-0.1.0/.github/workflows/docs.yml +35 -0
- elecdef-0.1.0/.github/workflows/publish.yml +39 -0
- elecdef-0.1.0/.gitignore +12 -0
- elecdef-0.1.0/.python-version +1 -0
- elecdef-0.1.0/AGENTS.md +12 -0
- elecdef-0.1.0/CLAUDE.md +48 -0
- elecdef-0.1.0/DESIGN.md +209 -0
- elecdef-0.1.0/LICENSE +21 -0
- elecdef-0.1.0/PKG-INFO +34 -0
- elecdef-0.1.0/README.md +23 -0
- elecdef-0.1.0/RULES.md +195 -0
- elecdef-0.1.0/data/tables/awg.toml +49 -0
- elecdef-0.1.0/data/tables/breaker_currents.toml +21 -0
- elecdef-0.1.0/data/tables/breaker_curves.toml +11 -0
- elecdef-0.1.0/data/tables/breaker_icn.toml +12 -0
- elecdef-0.1.0/data/tables/cable_voltages.toml +11 -0
- elecdef-0.1.0/data/tables/core_colours.toml +50 -0
- elecdef-0.1.0/data/tables/cross_sections.toml +39 -0
- elecdef-0.1.0/data/tables/e_series.toml +54 -0
- elecdef-0.1.0/data/tables/held.toml +12 -0
- elecdef-0.1.0/data/tables/overvoltage_impulse.toml +10 -0
- elecdef-0.1.0/data/tables/trip_times.toml +10 -0
- elecdef-0.1.0/docs/CHANGELOG.md +23 -0
- elecdef-0.1.0/docs/api-snapshot.txt +544 -0
- elecdef-0.1.0/docs/guide/blocks.md +203 -0
- elecdef-0.1.0/docs/guide/cables.md +40 -0
- elecdef-0.1.0/docs/guide/connections.md +18 -0
- elecdef-0.1.0/docs/guide/examples.md +155 -0
- elecdef-0.1.0/docs/guide/index.md +11 -0
- elecdef-0.1.0/docs/guide/lookup.md +57 -0
- elecdef-0.1.0/docs/guide/pins.md +39 -0
- elecdef-0.1.0/docs/guide/ranges.md +73 -0
- elecdef-0.1.0/docs/guide/tables.md +66 -0
- elecdef-0.1.0/docs/guide/values.md +84 -0
- elecdef-0.1.0/docs/guide/vocab.md +525 -0
- elecdef-0.1.0/docs/index.md +6 -0
- elecdef-0.1.0/docs/llms.txt +178 -0
- elecdef-0.1.0/justfile +61 -0
- elecdef-0.1.0/mkdocs.yml +35 -0
- elecdef-0.1.0/pyproject.toml +180 -0
- elecdef-0.1.0/scripts/build_site.py +142 -0
- elecdef-0.1.0/scripts/design_guard.py +91 -0
- elecdef-0.1.0/scripts/family_compare.py +55 -0
- elecdef-0.1.0/scripts/family_files.txt +18 -0
- elecdef-0.1.0/scripts/gen_tables.py +271 -0
- elecdef-0.1.0/scripts/release_guard.py +93 -0
- elecdef-0.1.0/src/elecdef/__init__.py +51 -0
- elecdef-0.1.0/src/elecdef/__main__.py +18 -0
- elecdef-0.1.0/src/elecdef/_api.py +56 -0
- elecdef-0.1.0/src/elecdef/_block.py +56 -0
- elecdef-0.1.0/src/elecdef/_body.py +25 -0
- elecdef-0.1.0/src/elecdef/_breaker.py +62 -0
- elecdef-0.1.0/src/elecdef/_check.py +62 -0
- elecdef-0.1.0/src/elecdef/_checkpins.py +84 -0
- elecdef-0.1.0/src/elecdef/_checkwalk.py +26 -0
- elecdef-0.1.0/src/elecdef/_coil.py +52 -0
- elecdef-0.1.0/src/elecdef/_connection.py +28 -0
- elecdef-0.1.0/src/elecdef/_contact.py +69 -0
- elecdef-0.1.0/src/elecdef/_device.py +36 -0
- elecdef-0.1.0/src/elecdef/_issue.py +26 -0
- elecdef-0.1.0/src/elecdef/_numbering.py +29 -0
- elecdef-0.1.0/src/elecdef/_overload.py +76 -0
- elecdef-0.1.0/src/elecdef/_plccard.py +71 -0
- elecdef-0.1.0/src/elecdef/_product.py +54 -0
- elecdef-0.1.0/src/elecdef/_psu.py +74 -0
- elecdef-0.1.0/src/elecdef/_quantity.py +160 -0
- elecdef-0.1.0/src/elecdef/_range.py +176 -0
- elecdef-0.1.0/src/elecdef/_rating.py +26 -0
- elecdef-0.1.0/src/elecdef/_relay.py +121 -0
- elecdef-0.1.0/src/elecdef/cable.py +102 -0
- elecdef-0.1.0/src/elecdef/computer.py +61 -0
- elecdef-0.1.0/src/elecdef/conductor.py +30 -0
- elecdef-0.1.0/src/elecdef/connections.py +34 -0
- elecdef-0.1.0/src/elecdef/connector.py +56 -0
- elecdef-0.1.0/src/elecdef/fuse.py +91 -0
- elecdef-0.1.0/src/elecdef/pins.py +158 -0
- elecdef-0.1.0/src/elecdef/plc.py +124 -0
- elecdef-0.1.0/src/elecdef/py.typed +0 -0
- elecdef-0.1.0/src/elecdef/supply.py +26 -0
- elecdef-0.1.0/src/elecdef/tables/HELD.txt +20 -0
- elecdef-0.1.0/src/elecdef/tables/__init__.py +27 -0
- elecdef-0.1.0/src/elecdef/tables/awg.py +98 -0
- elecdef-0.1.0/src/elecdef/tables/breaker_currents.py +22 -0
- elecdef-0.1.0/src/elecdef/tables/breaker_curves.py +10 -0
- elecdef-0.1.0/src/elecdef/tables/breaker_icn.py +13 -0
- elecdef-0.1.0/src/elecdef/tables/cable_voltages.py +12 -0
- elecdef-0.1.0/src/elecdef/tables/core_colours.py +51 -0
- elecdef-0.1.0/src/elecdef/tables/cross_sections.py +35 -0
- elecdef-0.1.0/src/elecdef/tables/e_series.py +50 -0
- elecdef-0.1.0/src/elecdef/tables/overvoltage_impulse.py +12 -0
- elecdef-0.1.0/src/elecdef/tables/trip_times.py +11 -0
- elecdef-0.1.0/src/elecdef/terminal.py +87 -0
- elecdef-0.1.0/src/elecdef/vocab/__init__.py +118 -0
- elecdef-0.1.0/src/elecdef/vocab/_base.py +17 -0
- elecdef-0.1.0/src/elecdef/vocab/_cable.py +92 -0
- elecdef-0.1.0/src/elecdef/vocab/_coil.py +53 -0
- elecdef-0.1.0/src/elecdef/vocab/_conditions.py +51 -0
- elecdef-0.1.0/src/elecdef/vocab/_connection.py +84 -0
- elecdef-0.1.0/src/elecdef/vocab/_contact.py +30 -0
- elecdef-0.1.0/src/elecdef/vocab/_misc.py +85 -0
- elecdef-0.1.0/src/elecdef/vocab/_plc.py +105 -0
- elecdef-0.1.0/src/elecdef/vocab/_protection.py +93 -0
- elecdef-0.1.0/tests/family.py +461 -0
- elecdef-0.1.0/tests/fixtures/issues/bad_marking.py +10 -0
- elecdef-0.1.0/tests/fixtures/issues/dangling_link.py +11 -0
- elecdef-0.1.0/tests/fixtures/issues/duplicate_marking.py +10 -0
- elecdef-0.1.0/tests/fixtures/issues/end_order.py +10 -0
- elecdef-0.1.0/tests/fixtures/issues/missing_figure.py +10 -0
- elecdef-0.1.0/tests/fixtures/issues/pick_ambiguous.py +14 -0
- elecdef-0.1.0/tests/fixtures/issues/pick_no_rating.py +13 -0
- elecdef-0.1.0/tests/fixtures/issues/unknown_class.py +16 -0
- elecdef-0.1.0/tests/fixtures/malformed/at_two_conditions.py +8 -0
- elecdef-0.1.0/tests/fixtures/malformed/link_one_marking.py +7 -0
- elecdef-0.1.0/tests/fixtures/malformed/link_three_markings.py +7 -0
- elecdef-0.1.0/tests/fixtures/malformed/quantity_bool.py +10 -0
- elecdef-0.1.0/tests/fixtures/malformed/range_no_end.py +7 -0
- elecdef-0.1.0/tests/test_agents.py +112 -0
- elecdef-0.1.0/tests/test_api.py +76 -0
- elecdef-0.1.0/tests/test_blocks.py +213 -0
- elecdef-0.1.0/tests/test_boundary.py +15 -0
- elecdef-0.1.0/tests/test_boundary_e.py +102 -0
- elecdef-0.1.0/tests/test_cable.py +126 -0
- elecdef-0.1.0/tests/test_check.py +7 -0
- elecdef-0.1.0/tests/test_check_e.py +300 -0
- elecdef-0.1.0/tests/test_connections.py +105 -0
- elecdef-0.1.0/tests/test_contact_coil.py +122 -0
- elecdef-0.1.0/tests/test_deps.py +7 -0
- elecdef-0.1.0/tests/test_design_guard.py +121 -0
- elecdef-0.1.0/tests/test_design_guard_e.py +17 -0
- elecdef-0.1.0/tests/test_docs.py +104 -0
- elecdef-0.1.0/tests/test_family_compare.py +58 -0
- elecdef-0.1.0/tests/test_family_rules.py +36 -0
- elecdef-0.1.0/tests/test_kinds.py +191 -0
- elecdef-0.1.0/tests/test_lean.py +98 -0
- elecdef-0.1.0/tests/test_licence.py +27 -0
- elecdef-0.1.0/tests/test_malformed.py +7 -0
- elecdef-0.1.0/tests/test_pick.py +90 -0
- elecdef-0.1.0/tests/test_pin_roles_e.py +11 -0
- elecdef-0.1.0/tests/test_pins.py +342 -0
- elecdef-0.1.0/tests/test_plc.py +118 -0
- elecdef-0.1.0/tests/test_product.py +48 -0
- elecdef-0.1.0/tests/test_protection.py +141 -0
- elecdef-0.1.0/tests/test_psu.py +75 -0
- elecdef-0.1.0/tests/test_pure.py +31 -0
- elecdef-0.1.0/tests/test_pyproject_pins.py +41 -0
- elecdef-0.1.0/tests/test_quantity.py +100 -0
- elecdef-0.1.0/tests/test_range.py +138 -0
- elecdef-0.1.0/tests/test_relay.py +131 -0
- elecdef-0.1.0/tests/test_release_guard.py +114 -0
- elecdef-0.1.0/tests/test_rules_lists.py +85 -0
- elecdef-0.1.0/tests/test_site.py +100 -0
- elecdef-0.1.0/tests/test_standalone.py +24 -0
- elecdef-0.1.0/tests/test_supply.py +57 -0
- elecdef-0.1.0/tests/test_surface.py +170 -0
- elecdef-0.1.0/tests/test_tables.py +155 -0
- elecdef-0.1.0/tests/test_terminal_connector.py +144 -0
- elecdef-0.1.0/tests/test_vocab.py +7 -0
- elecdef-0.1.0/tests/test_vocab_e.py +108 -0
- elecdef-0.1.0/tests/test_wording.py +131 -0
- elecdef-0.1.0/uv.lock +479 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* text=auto eol=lf
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
ci:
|
|
13
|
+
runs-on: ubuntu-24.04
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
fetch-tags: true
|
|
19
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
20
|
+
with:
|
|
21
|
+
version: "0.13.5"
|
|
22
|
+
- run: uv sync
|
|
23
|
+
- run: uv python install 3.14
|
|
24
|
+
- run: uvx --from rust-just==1.59.0 just ci
|
|
25
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
if: github.event.repository.private == false
|
|
27
|
+
with:
|
|
28
|
+
repository: OleJBondahl/refdef
|
|
29
|
+
path: sibling
|
|
30
|
+
- run: uv run python scripts/family_compare.py sibling
|
|
31
|
+
if: github.event.repository.private == false
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*.*.*"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-24.04
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
15
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
16
|
+
with:
|
|
17
|
+
version: "0.13.5"
|
|
18
|
+
- run: uv run python scripts/build_site.py
|
|
19
|
+
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
|
20
|
+
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
21
|
+
with:
|
|
22
|
+
path: .site/
|
|
23
|
+
|
|
24
|
+
deploy:
|
|
25
|
+
needs: build
|
|
26
|
+
runs-on: ubuntu-24.04
|
|
27
|
+
environment:
|
|
28
|
+
name: github-pages
|
|
29
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
30
|
+
permissions:
|
|
31
|
+
pages: write
|
|
32
|
+
id-token: write
|
|
33
|
+
steps:
|
|
34
|
+
- id: deployment
|
|
35
|
+
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*.*.*"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-24.04
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
15
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
16
|
+
with:
|
|
17
|
+
version: "0.13.5"
|
|
18
|
+
- name: The tag matches the package version
|
|
19
|
+
run: test "v$(uv version --short)" = "$GITHUB_REF_NAME"
|
|
20
|
+
- run: uv build
|
|
21
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
22
|
+
with:
|
|
23
|
+
name: dist
|
|
24
|
+
path: dist/
|
|
25
|
+
|
|
26
|
+
pypi:
|
|
27
|
+
needs: build
|
|
28
|
+
runs-on: ubuntu-24.04
|
|
29
|
+
environment: pypi
|
|
30
|
+
permissions:
|
|
31
|
+
id-token: write # trusted publishing: no token secret
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
34
|
+
with:
|
|
35
|
+
name: dist
|
|
36
|
+
path: dist/
|
|
37
|
+
- uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
|
|
38
|
+
with:
|
|
39
|
+
attestations: true
|
elecdef-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.15.0
|
elecdef-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Agent guide
|
|
2
|
+
|
|
3
|
+
- Docs site: https://olejbondahl.github.io/elecdef/
|
|
4
|
+
- Surface: `python -m elecdef api`, snapshot in `docs/api-snapshot.txt`
|
|
5
|
+
- Guide: `docs/guide/`
|
|
6
|
+
- Design: `DESIGN.md`
|
|
7
|
+
- Rules: `RULES.md`
|
|
8
|
+
- A change follows RULES.md.
|
|
9
|
+
- Design-review paths: `DESIGN.md`, `RULES.md`, `docs/api-snapshot.txt`, `src/elecdef/tables/`.
|
|
10
|
+
A commit touching them needs a `Design-review: <ID>` trailer.
|
|
11
|
+
- A need the surface does not meet is a reviewed design change, never a workaround.
|
|
12
|
+
- Use `uv` only, with exact pins.
|
elecdef-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# elecdef: agent guide
|
|
2
|
+
|
|
3
|
+
elecdef is a standard-agnostic electrical engineering vocabulary: strict, typed, immutable Python
|
|
4
|
+
values with no runtime dependency. A sibling library follows the same family rules.
|
|
5
|
+
Docs: <https://olejbondahl.github.io/elecdef/>. Surface: `python -m elecdef api`.
|
|
6
|
+
|
|
7
|
+
## Read first
|
|
8
|
+
|
|
9
|
+
Read `DESIGN.md`, then `RULES.md`. They bind: a change follows RULES.md, and code that disagrees
|
|
10
|
+
with them is wrong. Family rules F1-F17 are shared with the sibling library; E1-E19 are ours.
|
|
11
|
+
|
|
12
|
+
## Gate
|
|
13
|
+
|
|
14
|
+
`just ci` runs locally (no hosted gate beyond one CI job): ruff, ty, vulture, pytest with a 95 %
|
|
15
|
+
coverage floor, the tests on Python 3.14, the two guards, and the strict site build. Its last
|
|
16
|
+
stdout line is `site built: .site`. Each shared test guards one family rule:
|
|
17
|
+
|
|
18
|
+
- `test_deps` (F1): no runtime dependency, stdlib and the package only.
|
|
19
|
+
- `test_pure` (F2), `test_check` and `test_malformed` (F3): frozen values, no I/O, issues as values.
|
|
20
|
+
- `test_vocab` (F4): a closed vocabulary is never a bare `str`.
|
|
21
|
+
- `test_boundary` (F5, F6, F13): no boundary names, no application default, no sibling import.
|
|
22
|
+
- `test_wording` (F7 and the em-dash rule): no standard cited by number, clause or year.
|
|
23
|
+
- `test_surface` (F8, F15): the snapshot equals `python -m elecdef api`; no operators on surface classes.
|
|
24
|
+
- `test_docs` (F9) and `test_site`: every name has a docstring and a runnable guide block.
|
|
25
|
+
- `test_lean` (F10): no nested def, 300 code lines, short docstrings, every noqa with a reason.
|
|
26
|
+
- `test_release_guard` (F11) and `test_design_guard` (F12): the guard scripts can fail.
|
|
27
|
+
- `test_licence` (F14), `test_agents` (F16), `test_standalone` (F17), `test_family_rules`, `test_pyproject_pins`.
|
|
28
|
+
|
|
29
|
+
## Process
|
|
30
|
+
|
|
31
|
+
- F12: a commit that touches a review path (`DESIGN.md`, `RULES.md`, `docs/api-snapshot.txt`,
|
|
32
|
+
`src/elecdef/tables/`) carries a trailer `Design-review: <ID>`. The maintainer approves the
|
|
33
|
+
contract; the design reviewer approves surface and table changes.
|
|
34
|
+
- F13: a missing need is a reviewed extension of the surface, never a workaround or a private import.
|
|
35
|
+
- F17: name no application anywhere, in a tracked or an untracked file, or in a commit message.
|
|
36
|
+
- One source of truth for the surface: `docs/api-snapshot.txt`, regenerated with `just api-write`,
|
|
37
|
+
never edited by hand. A new surface name adds its door to `[tool.family].doors` and `_api.DOORS`
|
|
38
|
+
together, a docstring, a runnable guide block, a CHANGELOG line and its `docs/llms.txt` lines.
|
|
39
|
+
- The identical test set listed in `scripts/family_files.txt` is copied byte for byte between the
|
|
40
|
+
sibling repositories; `scripts/family_compare.py` checks it. Edit it in both or in neither.
|
|
41
|
+
|
|
42
|
+
## Style
|
|
43
|
+
|
|
44
|
+
- `uv` only; no bare `python` or `pip`. Dependencies are exact pins (`name==X.Y.Z`).
|
|
45
|
+
- No em-dashes in any text file.
|
|
46
|
+
- Lean limits (F10): 15 statements, 12 branches, complexity 8, no nested `def`, 300 code lines per
|
|
47
|
+
module, docstrings of one summary line plus at most two of why, `# noqa: CODE - reason`.
|
|
48
|
+
- Stage named paths with git; never `git add -A`.
|
elecdef-0.1.0/DESIGN.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# elecdef: design
|
|
2
|
+
|
|
3
|
+
`elecdef` defines what electrical and electronic things are: a coil, a contact, a terminal, a
|
|
4
|
+
connection, a fuse, a power supply, a PLC channel, a conductor, a cable. Each is a block with
|
|
5
|
+
typed, exact, kind-checked values, its pin markings and its internal links. This file is the
|
|
6
|
+
current truth of the model; `RULES.md` is the rule set every change follows.
|
|
7
|
+
|
|
8
|
+
## 1. Purpose
|
|
9
|
+
|
|
10
|
+
elecdef is for every electrical and electronic engineer working in Python: one typed, exact
|
|
11
|
+
definition of each basic thing in the electrical world, so that nobody types a coil, a contact or
|
|
12
|
+
a cable again. A parts library describes a real product by filling the blocks' values. An
|
|
13
|
+
application, a script or a notebook reads the values through one small typed surface. The
|
|
14
|
+
library judges nothing: it holds facts and looks them up. It has no runtime dependency and
|
|
15
|
+
runs with or without the rest of the family.
|
|
16
|
+
|
|
17
|
+
## 2. The family
|
|
18
|
+
|
|
19
|
+
| Library | Owns | Never holds |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `symdef` | how a thing is drawn: symbols, frames, ports, geometry | a rating, a unit, a marking's meaning |
|
|
22
|
+
| `elecdef` | what a thing is: blocks, values, markings, internal links | a coordinate, a page, a designation string, a drawing key's meaning |
|
|
23
|
+
| `refdef` | what a thing is called: designations, levels, letter codes, numbering, sort | a device fact, a marking's meaning |
|
|
24
|
+
| an application | how a project connects, lays out, checks and prints | a copy of any fact above |
|
|
25
|
+
|
|
26
|
+
A fact lives in exactly one library. A block names its symbol by a `Symbol(key, version)` and
|
|
27
|
+
reads nothing from `symdef`. A pin marking (`13`, `A1`, `95`) is an elecdef fact; the string
|
|
28
|
+
`-K1:13` is a refdef fact; which wire lands on it is the application's fact.
|
|
29
|
+
|
|
30
|
+
## 3. Core model
|
|
31
|
+
|
|
32
|
+
### 3.1 Values
|
|
33
|
+
|
|
34
|
+
A `Quantity` is a `Decimal` and a `Unit`. A `Unit` is an enum member carrying a symbol, a `Kind`
|
|
35
|
+
(voltage, current, power, apparent power, resistance, frequency, time, length, area, gauge,
|
|
36
|
+
torque, ratio, temperature, temperature difference) and an exact factor to the kind's base unit.
|
|
37
|
+
`U.V(24)`, `U.MM2("2.5")` is the one spelling; a `float` is refused. `==` compares as written,
|
|
38
|
+
`same()` and ordering compare in base units, `to(unit)` converts within a kind and refuses across
|
|
39
|
+
kinds. Percent is a unit of kind ratio. Degrees Celsius and kelvin are different kinds.
|
|
40
|
+
|
|
41
|
+
A `Range` is written the way a datasheet states it: a role and up to three ends.
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
Range(Role.RATED, nom=U.V(24), min=U.V("20.4"), max=U.V(30), at=At(Current.DC))
|
|
45
|
+
Range(Role.LIMITING, max=U.V(250))
|
|
46
|
+
Range(Role.REFERENCE, min=U.DEG_C(23), max=U.DEG_C(27))
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`role` is positional and required: `RATED` is what the maker states for the stated conditions,
|
|
50
|
+
`LIMITING` is an extreme the thing withstands, `REFERENCE` is the band other figures are stated
|
|
51
|
+
for. `nom` is the marked value; an optional `typ` holds a measured typical and is never confused
|
|
52
|
+
with it. `tolerance` is a property returning exact fractions derived from the ends; it is never
|
|
53
|
+
written. Every end has one kind. `contains(quantity)` and `covers(range)` are the two tests.
|
|
54
|
+
|
|
55
|
+
`At` is the set of conditions a figure holds under, one per kind: a `Quantity` (at 400 V), a
|
|
56
|
+
`Range` (up to 250 V), or an enum member (`Current.DC`, `Utilisation.AC_3`, `CoilState.HOLD`,
|
|
57
|
+
`ConductorKind.FINE`). A condition's kind is its unit's kind or its enum class. AC and DC are
|
|
58
|
+
conditions, not fields, so one `Ranges` field (a tuple of `Range`) holds the 50 Hz, the 60 Hz
|
|
59
|
+
and the DC figures side by side.
|
|
60
|
+
|
|
61
|
+
### 3.2 Lookup
|
|
62
|
+
|
|
63
|
+
`pick(ranges, *ask) -> Pick(found, issue)` returns the single range whose conditions cover the
|
|
64
|
+
ask. A `Range` condition covers by inclusion, a `Quantity` by equality in base units, an enum by
|
|
65
|
+
identity. A row may state more kinds than the ask names; the ask may not name a kind the row
|
|
66
|
+
lacks. No covering row gives the issue `NO_RATING`; more than one gives `AMBIGUOUS_RATING`;
|
|
67
|
+
there is no silent first match. This is data access. Whether a load is acceptable against the
|
|
68
|
+
found range is the application's check, and elecdef stops at `found`.
|
|
69
|
+
|
|
70
|
+
### 3.3 Blocks
|
|
71
|
+
|
|
72
|
+
A block is a frozen dataclass stating what one kind of thing is. Every property may be unfilled.
|
|
73
|
+
A property is a `Quantity` for a dimension or a count-like figure, a `Range` for an electrical
|
|
74
|
+
figure, `Ranges` when it varies with conditions, an enum for a closed vocabulary, `int` or `bool`
|
|
75
|
+
otherwise. Every quantity field declares its kind; a value of another kind is refused at
|
|
76
|
+
construction. A field that holds a closed set is an enum, never a string.
|
|
77
|
+
|
|
78
|
+
Blocks compose by typed fields, by value: `Relay.coil: Coil`, `Relay.contacts: tuple[Contact,
|
|
79
|
+
...]`, `Coil.connection: Connection`. A leaf defined once is passed by reference into every block
|
|
80
|
+
that has it; equality is by value. `elecdef.connections` ships technology-only leaves (`SCREW`,
|
|
81
|
+
`PUSH_IN`, ...) with ranges unfilled; a parts library derives its vendor leaves from them with
|
|
82
|
+
`dataclasses.replace` and shares those. Family identity of a derived leaf is not tracked. A
|
|
83
|
+
`Connection` belongs to the pins a block owns itself: a block that owns pins directly has one
|
|
84
|
+
`connection` field (a terminal block has one per side in `sides`), and a block whose pins all
|
|
85
|
+
come from its sub-blocks has none. So `Coil`, `Contact`, `SupplyInput`, `ChannelGroup`, `Fuse`,
|
|
86
|
+
`FuseHolder`, `Breaker`, `Overload`, `PowerSupply` (its output pins), `Connector` and `Device`
|
|
87
|
+
carry one; `Relay`, `Contactor`, `ContactBlock`, `PlcCard` and `Computer` carry none.
|
|
88
|
+
|
|
89
|
+
There is one base class, `Block`, for mechanism only: it runs the kind check and normalises a
|
|
90
|
+
bare `Range` given to a `Ranges` field. An application never subclasses a block; `check` reports a
|
|
91
|
+
block whose class is not in the catalogue. A family template and a product are the same class:
|
|
92
|
+
the template holds ranges and gaps, the product holds values.
|
|
93
|
+
|
|
94
|
+
### 3.4 Pins, markings and links
|
|
95
|
+
|
|
96
|
+
A `Pin` is `(marking, role, side, alternates)`; a `Link` is `(markings, kind, closed_at_rest)`, `markings` a pair, with
|
|
97
|
+
kind `CONDUCTIVE`, `SWITCHED` or `PROTECTIVE`. Markings follow the block: `elecdef.pins` derives
|
|
98
|
+
them by form, index and `Marking` scheme (`AUX` n3-n4, n1-n2, n1-n2-n4; `MAIN` 1/L1-2/T1 ...;
|
|
99
|
+
`OVERLOAD` 95-96, 97-98; `TIMER` n5-n6-n8; `PLAIN` 1-8) with alternates as data. A composite
|
|
100
|
+
numbers its unnumbered sub-blocks on every read: a relay's contacts 1..n, a contactor's main
|
|
101
|
+
poles then its auxiliaries, a contact block from `numbered_from`, a card's channels across its
|
|
102
|
+
groups. A product may give pins outright; a coil or contact stores only those and computes the rest, so `replace` never leaves a stale marking. A composite's `pins` and `links` are computed over its
|
|
103
|
+
sub-blocks and stored nowhere else. A marking is a non-empty string of letters, digits and
|
|
104
|
+
`/ + - . '`, so every marking reads back unchanged in a designation string such as `-K1:13`.
|
|
105
|
+
|
|
106
|
+
### 3.5 Product
|
|
107
|
+
|
|
108
|
+
`Product(mpn, manufacturer, block, name)` is the one identity envelope: a block with its values
|
|
109
|
+
filled, under a maker's part number. An application wraps it in its own record (suppliers,
|
|
110
|
+
footprint, class letter) and never copies a block value out of it.
|
|
111
|
+
|
|
112
|
+
### 3.6 Issues
|
|
113
|
+
|
|
114
|
+
`check(block | product) -> tuple[Issue, ...]` reports content problems as values: an end below
|
|
115
|
+
another, a marking that repeats, a marking outside the character set, a link naming no pin, a
|
|
116
|
+
block kind missing a figure it needs, a class outside the catalogue. An `Issue` is `(code:
|
|
117
|
+
IssueCode, message, subject)`. `IssueCode` has eight members: the six that `check` reports and the
|
|
118
|
+
two that `pick` returns (`NO_RATING`, `AMBIGUOUS_RATING`). A malformed call (a wrong type, a wrong
|
|
119
|
+
kind, two conditions of one kind in an `At`) raises `TypeError`; content never does.
|
|
120
|
+
|
|
121
|
+
## 4. v1 catalogue
|
|
122
|
+
|
|
123
|
+
| Block | Reuses | States |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| `Body` | - | width, height, depth; ip; temperature (rated, storage); mounting |
|
|
126
|
+
| `Connection` | - | technology; conductor area per conductor kind; AWG as stated; conductors per clamp; strip length; torque; screw; pitch; material |
|
|
127
|
+
| `Rating` | - | operational voltage per current kind; insulation and impulse voltage; thermal current; frequency; overvoltage category; pollution degree |
|
|
128
|
+
| `SupplyInput` | Connection | what a powered thing draws: voltage and current per conditions; its supply pins |
|
|
129
|
+
| `Contact` | Connection | form (make, break, changeover) and features; switching current per voltage, current kind and utilisation code; limiting voltage; minimum load; material; life |
|
|
130
|
+
| `Coil` | Connection | kind; voltage per current kind and frequency; pick-up and drop-out as ratio; resistance; power and apparent power per coil state; times; suppression; A1-A2 |
|
|
131
|
+
| `Conductor` | - | material; class; area; insulation; temperature; colour; voltages |
|
|
132
|
+
| `Cable` | Conductor | cores (number, colour, pair, drain); screen; armour; diameter; bend radii; sheath; temperature; flags; opaque type code with scheme |
|
|
133
|
+
| `TerminalBlock` | Connection per side, Rating, Body | kind; levels with marking and potential; sides; cross-section; width; rail |
|
|
134
|
+
| `Relay` | Coil, Contact, Body | kind; contacts; latching; force-guided; timer function |
|
|
135
|
+
| `Contactor` | Coil, Contact, Rating, Body | main poles; auxiliaries (a mirror contact is an auxiliary with that feature) |
|
|
136
|
+
| `ContactBlock` | Contact, Body | a coil-less carrier: snap-on auxiliary block, button block, limit switch; actuator; first number |
|
|
137
|
+
| `Overload` | Contact, Connection, Body | poles; setting; trip class; reset; phase failure; auxiliaries |
|
|
138
|
+
| `Fuse`, `FuseHolder` | Connection, Rating, Body | system; class; current; voltage and breaking capacity per current kind; speed; indicator; poles; disconnect |
|
|
139
|
+
| `Breaker` | Connection, Rating, Contact, Body | poles; current; curve; breaking capacities; auxiliaries |
|
|
140
|
+
| `PowerSupply` | SupplyInput, Contact, Connection, Body | kind; input; output voltage and current; boost; hold-up; overload behaviour; circuit class; isolation; redundancy; efficiency; OK contact (`ok_contact`) |
|
|
141
|
+
| `Channel`, `ChannelGroup` | Connection | signal and number; digital input, digital output, analog or relay data; a group's markings, commons, isolation and connection, written once for many channels |
|
|
142
|
+
| `PlcCard` | SupplyInput, ChannelGroup, Body | form; role; bus; groups; safety levels |
|
|
143
|
+
| `Connector` | Rating, Connection, Body | family; coding; poles; gender; locking |
|
|
144
|
+
| `Computer` | SupplyInput, Connector, Body | supply; power; ports |
|
|
145
|
+
| `Device` | Rating, Connection, Body | pins and links given outright: the typed fallback for a thing with no block yet |
|
|
146
|
+
|
|
147
|
+
Vocabularies ship as enums in `elecdef.vocab`: industry codes are the member names
|
|
148
|
+
(`Utilisation.AC_3`, `FuseClass.gG`, `TripCurve.C`) with short descriptions in our own words.
|
|
149
|
+
Data tables ship as generated Python in `elecdef.tables`: the cross-section series, the AWG
|
|
150
|
+
formula, colour letter codes, the 44-core colour sequence, breaker curve bands, trip classes,
|
|
151
|
+
cable voltage digits, overvoltage categories, the E series. A table row ships only when its
|
|
152
|
+
value is confirmed; a contested row waits.
|
|
153
|
+
|
|
154
|
+
## 5. Public surface
|
|
155
|
+
|
|
156
|
+
Top level (`elecdef.__all__`): `Unit`, `Quantity`, `Range`, `Ranges`, `Role`, `At`, `pick`,
|
|
157
|
+
`Pick`, `Issue`, `IssueCode`, `check`, `Symbol`, `Product`, `Body`, `Rating`, `Connection`,
|
|
158
|
+
`Contact`, `Coil`, `Relay`, `Contactor`, `ContactBlock`, `Overload`, `TerminalBlock`, `Fuse`,
|
|
159
|
+
`Breaker`, `PowerSupply`, `PlcCard`, `Device`. Twelve doors, each with its own `__all__` of the
|
|
160
|
+
names not exported at top level: `elecdef.vocab` (`Kind` and every vocabulary enum),
|
|
161
|
+
`elecdef.pins` (`Pin`, `PinRole`, `Side`, `Link`, `LinkKind`, `Marking` and the marking
|
|
162
|
+
functions), `elecdef.connections` (`SCREW`, `SPRING_CAGE`, `PUSH_IN`, `TENSION`, `IDC`, `CRIMP`,
|
|
163
|
+
`SOLDER`, `PRESS_IN`, `PLUG_IN`, `BOLT`, `WIRE_WRAP`, `THT`, `SMD`), `elecdef.tables`,
|
|
164
|
+
`elecdef.supply` (`SupplyInput`), `elecdef.fuse` (`FuseHolder`), `elecdef.plc` (`Channel`,
|
|
165
|
+
`ChannelGroup`, `DigitalInput`, `DigitalOutput`, `AnalogIo`), `elecdef.terminal` (`Level`),
|
|
166
|
+
`elecdef.conductor` (`Conductor`), `elecdef.cable` (`Cable`, `Core`, `TypeCode`),
|
|
167
|
+
`elecdef.connector` (`Connector`), `elecdef.computer` (`Computer`, `Port`). The examples in this file assume `from elecdef import
|
|
168
|
+
Unit as U`. `python -m elecdef api` prints every surface name with its signature and docstring;
|
|
169
|
+
`docs/api-snapshot.txt` is that output, and a test fails when they differ.
|
|
170
|
+
|
|
171
|
+
## 6. Out of scope
|
|
172
|
+
|
|
173
|
+
Checks and judgements (is this load acceptable, is this wire big enough), derating and
|
|
174
|
+
temperature factors, conductor resistance, cable type-code decoding (the `Scheme` enum and the
|
|
175
|
+
opaque `TypeCode` leave the slot), calculations across blocks, instances and topology, where a
|
|
176
|
+
pin is wired, drawing, designations and PLC tags, file reading or writing, multilingual names,
|
|
177
|
+
assemblies of several products. Pilot devices, sensors, motors, passives and semiconductors
|
|
178
|
+
arrive as blocks after v1; until then they are a `Device`.
|
|
179
|
+
|
|
180
|
+
## 7. Docs and agents
|
|
181
|
+
|
|
182
|
+
The repository publishes a GitHub Pages site built with Zensical (as `symdef` does) from the first
|
|
183
|
+
public release. The site holds this design, the rules, a guide with one runnable example per
|
|
184
|
+
surface name, and an API reference generated from the docstrings, so a name documented in code
|
|
185
|
+
is documented on the site by construction. The strict Zensical docs build runs in CI.
|
|
186
|
+
|
|
187
|
+
`llms.txt` at the site root lists, in plain text, what the library is, the surface names, the
|
|
188
|
+
guide pages and the rules, with one link each. `AGENTS.md` at the repository root tells an
|
|
189
|
+
agent: read `DESIGN.md` then `RULES.md`; read the surface with `python -m elecdef api` and never
|
|
190
|
+
the source to use the library; every public name has an example under `docs/guide/`; the tests
|
|
191
|
+
named in `RULES.md` are the definition of done; a change that touches the surface, the design or
|
|
192
|
+
the rules needs a design review before it is written.
|
|
193
|
+
|
|
194
|
+
## 8. How it changes
|
|
195
|
+
|
|
196
|
+
Semantic versioning. Every surface change carries a changelog line. A pull request that edits
|
|
197
|
+
`DESIGN.md` or `RULES.md`, changes `docs/api-snapshot.txt` or changes a shipped table under
|
|
198
|
+
`src/elecdef/tables/`, carries a `Design-review:` trailer naming an approved review; a guard
|
|
199
|
+
script fails it otherwise. An application's missing need is never met by a workaround in the
|
|
200
|
+
application or a private path into the library: it is a reviewed design change that extends the
|
|
201
|
+
surface. An application that adopts elecdef shrinks: it deletes its copy of the fact and reads
|
|
202
|
+
the surface.
|
|
203
|
+
|
|
204
|
+
Who approves is family rule F12: the maintainer approves the contract, and the design reviewer approves surface and table changes.
|
|
205
|
+
|
|
206
|
+
## 9. Licence
|
|
207
|
+
|
|
208
|
+
MIT, covering the code and the shipped tables. An open source used for a table is credited in
|
|
209
|
+
the README and is never share-alike or non-commercial.
|
elecdef-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ole Johan Bondahl
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
elecdef-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: elecdef
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Standard-agnostic electrical engineering vocabulary as strict, typed, immutable Python values
|
|
5
|
+
Project-URL: Repository, https://github.com/OleJBondahl/elecdef
|
|
6
|
+
Author: Ole Johan Bondahl
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Python: >=3.14
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# elecdef
|
|
13
|
+
|
|
14
|
+
Standard-agnostic electrical engineering vocabulary as strict, typed, immutable Python values.
|
|
15
|
+
The library has no runtime dependencies and does no file, network, clock or random access.
|
|
16
|
+
Every value is a frozen dataclass or an enum.
|
|
17
|
+
|
|
18
|
+
Status: pre-release, version 0.1.0. The package is an empty scaffold.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
uv add elecdef
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Compatible with IEC conventions.
|
|
27
|
+
|
|
28
|
+
Documentation: <https://olejbondahl.github.io/elecdef/>
|
|
29
|
+
|
|
30
|
+
Licence: MIT.
|
|
31
|
+
|
|
32
|
+
<!-- credit:start -->
|
|
33
|
+
Credits: none yet.
|
|
34
|
+
<!-- credit:end -->
|
elecdef-0.1.0/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# elecdef
|
|
2
|
+
|
|
3
|
+
Standard-agnostic electrical engineering vocabulary as strict, typed, immutable Python values.
|
|
4
|
+
The library has no runtime dependencies and does no file, network, clock or random access.
|
|
5
|
+
Every value is a frozen dataclass or an enum.
|
|
6
|
+
|
|
7
|
+
Status: pre-release, version 0.1.0. The package is an empty scaffold.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
uv add elecdef
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Compatible with IEC conventions.
|
|
16
|
+
|
|
17
|
+
Documentation: <https://olejbondahl.github.io/elecdef/>
|
|
18
|
+
|
|
19
|
+
Licence: MIT.
|
|
20
|
+
|
|
21
|
+
<!-- credit:start -->
|
|
22
|
+
Credits: none yet.
|
|
23
|
+
<!-- credit:end -->
|