refdef 0.2.0__tar.gz → 0.3.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.
- {refdef-0.2.0 → refdef-0.3.0}/PKG-INFO +1 -1
- {refdef-0.2.0 → refdef-0.3.0}/docs/CHANGELOG.md +4 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/api-snapshot.txt +10 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/guide/class-table.md +9 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/llms.txt +2 -0
- {refdef-0.2.0 → refdef-0.3.0}/pyproject.toml +1 -1
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/__init__.py +3 -1
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/_api.py +16 -1
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/scheme.py +8 -2
- refdef-0.3.0/tests/test_scheme_export.py +16 -0
- {refdef-0.2.0 → refdef-0.3.0}/uv.lock +1 -1
- {refdef-0.2.0 → refdef-0.3.0}/.gitattributes +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/.github/workflows/ci.yml +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/.github/workflows/docs.yml +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/.github/workflows/publish.yml +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/.gitignore +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/.python-version +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/AGENTS.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/CLAUDE.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/DESIGN.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/LICENSE +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/README.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/RULES.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/guide/build.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/guide/check.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/guide/index.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/guide/number.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/guide/plc.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/guide/print.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/guide/read.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/guide/sort.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/guide/terminals.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/guide/tree.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/docs/index.md +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/justfile +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/mkdocs.yml +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/scripts/build_site.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/scripts/design_guard.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/scripts/family_compare.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/scripts/family_files.txt +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/scripts/gen_render_corpus.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/scripts/gen_table.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/scripts/release_guard.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/__main__.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/_check.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/_heads.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/_parse.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/_render.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/designation.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/issues.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/level.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/numbering.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/order.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/plc.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/py.typed +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/tables/__init__.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/tables/standard.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/src/refdef/terminal.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/conftest.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/corpus/addresses.txt +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/corpus/render.txt +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/corpus/strings.txt +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/family.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/check_aspect_off.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/check_duplicate.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/check_letter_count.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/check_never_letter.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/check_unknown_class.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_bad_label.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_dot_level.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_empty.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_empty_level.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_empty_name.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_empty_pin.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_empty_top.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_free_label.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_leading_zero.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_lower_case.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_no_sign.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_number_too_large.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_unsupported_suffix.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_whitespace.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/issues/parse_zero_number.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/designation_levels_list.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/designation_levels_not_level.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/designation_top_ampersand.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/designation_top_colon.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/designation_top_gt.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/designation_top_not_str.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/designation_top_outer_space.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/designation_top_semicolon.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_aspect_not_aspect.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_code_with_digit.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_coded_and_label.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_empty.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_label_angle.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_label_coded_shape_k1.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_label_coded_shape_lower.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_label_colon.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_label_digits_only.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_label_dot.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_label_outer_space.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_label_sign_char.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_letters_without_number.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_lower_case_code.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_non_ascii_code.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_number_and_label.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_number_bool.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_number_float.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_number_too_large.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/level_number_zero.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/signal_empty_designation.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/signal_empty_name.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/signal_name_not_str.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/signal_name_outer_space.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/signal_of_not_designation.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/terminal_empty_pin.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/terminal_no_pins.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/terminal_of_not_designation.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/terminal_pin_colon.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/terminal_pin_not_str.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/terminal_pin_outer_space.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/malformed/terminal_pins_list.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fixtures/tables/classes.csv +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/fuzz.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/guide/test_guide.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/issue_hook.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_agents.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_api.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_boundary.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_boundary_r.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_check.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_deps.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_design_guard.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_designation.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_docs.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_family_compare.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_family_rules.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_gen_table.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_lean.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_level.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_licence.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_llms.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_malformed.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_numbering.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_order.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_parse.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_plc.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_pure.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_pyproject_pins.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_release_guard.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_render.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_roundtrip.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_site.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_sketch_cases.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_sketch_rd-3.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_sketch_rd-4.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_sketch_rd-5.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_sketch_rd-6b.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_sketch_rd2.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_standalone.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_surface.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_table.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_table_version.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_tree.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_tree_properties.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_vocab.py +0 -0
- {refdef-0.2.0 → refdef-0.3.0}/tests/test_wording.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: refdef
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Reference designations as strict, typed, immutable Python values: parse, check, print, number and order
|
|
5
5
|
Project-URL: Repository, https://github.com/OleJBondahl/refdef
|
|
6
6
|
Author: Ole Johan Bondahl
|
|
@@ -5,6 +5,10 @@ Every change to the public surface gets a line under Unreleased until the releas
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 0.3.0 (2026-10-24)
|
|
9
|
+
|
|
10
|
+
- Export `LetterRule` and `ClassTable` from `refdef`.
|
|
11
|
+
|
|
8
12
|
## 0.2.0 (2026-10-23)
|
|
9
13
|
|
|
10
14
|
- Add `lowest_free(taken, reserved=(), *, first=1)`: the lowest free number over plain ints.
|
|
@@ -7,6 +7,11 @@ class Aspect
|
|
|
7
7
|
class ClassEntry(code: 'str', title: 'str') -> 'None'
|
|
8
8
|
One class code with its title, the typical device of the class.
|
|
9
9
|
|
|
10
|
+
class ClassTable(name: 'str', version: 'str', depth: 'int', entries: 'tuple[ClassEntry, ...]') -> 'None'
|
|
11
|
+
Versioned class entries; `depth` is how many leading letters of a code are looked up.
|
|
12
|
+
|
|
13
|
+
A caller passes its own table to a custom Scheme; `version` names the table, not the library.
|
|
14
|
+
|
|
10
15
|
class Designation(levels: 'tuple[Level, ...]' = (), top: 'str' = '') -> 'None'
|
|
11
16
|
A tuple of levels and an optional top node, built by the constructor and `child` only.
|
|
12
17
|
|
|
@@ -18,6 +23,11 @@ class Issue(code: 'IssueCode', subject: 'str', message: 'str') -> 'None'
|
|
|
18
23
|
class IssueCode
|
|
19
24
|
The 21 issue codes: the first 16 come from the readers, the last 5 from check.
|
|
20
25
|
|
|
26
|
+
class LetterRule(min_count: 'int' = 1, max_count: 'int' = 3, never: 'frozenset[str]' = frozenset({'I', 'O'})) -> 'None'
|
|
27
|
+
How many letters a code has and which letters never appear.
|
|
28
|
+
|
|
29
|
+
A caller builds a custom Scheme with it; `Scheme.extend` checks that `never` holds A-Z letters.
|
|
30
|
+
|
|
21
31
|
class Level(aspect: 'Aspect', code: 'str' = '', number: 'int | None' = None, label: 'str' = '') -> 'None'
|
|
22
32
|
One step in a tree: letters and a number (`-K2`), a number alone (`+3`) or a label (`+ER`).
|
|
23
33
|
|
|
@@ -33,3 +33,12 @@ stay barred and `extend` never lifts a letter. Any iterable of letters works; a
|
|
|
33
33
|
strict = STANDARD.extend(never={"A"})
|
|
34
34
|
print([i.code.value for i in check([parse("-A1", bare=P).value], strict)]) # ['never_letter', 'unknown_class']
|
|
35
35
|
```
|
|
36
|
+
|
|
37
|
+
A caller who builds its own scheme passes its own `ClassTable` and `LetterRule`, both public from `refdef`.
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from refdef import Aspect, ClassEntry, ClassTable, LetterRule, Scheme
|
|
41
|
+
table = ClassTable(name="plant", version="1", depth=1, entries=(ClassEntry("A", "valve"),))
|
|
42
|
+
mine = Scheme("plant", frozenset({Aspect.PRODUCT}), LetterRule(1, 2, frozenset("IO")), table)
|
|
43
|
+
print(mine.classes.get("AB").title) # valve
|
|
44
|
+
```
|
|
@@ -60,5 +60,7 @@ ChannelTag: a terminal with an optional address (refdef.plc), printed as the ter
|
|
|
60
60
|
parse_address: reads a direct PLC address (refdef.plc), repairing outer whitespace and leading zeros with an issue each; text that is not one gives None and a NOT_ADDRESS issue.
|
|
61
61
|
Scheme: what check tests against: the aspects that are on, a letter rule and a class table; extend returns a new scheme with project classes, aspects and further barred letters (never: any iterable of A-Z letters, not a str).
|
|
62
62
|
ClassEntry: one class code with its title, the typical device of the class.
|
|
63
|
+
ClassTable: versioned class entries with the lookup depth; get(code) returns the entry or None.
|
|
64
|
+
LetterRule: how many letters a code has and which letters never appear.
|
|
63
65
|
STANDARD: the shipped scheme (function, product and location on, one to three letters without I and O, the versioned standard class table).
|
|
64
66
|
check: tests designations against a scheme and returns an issue for each finding, in order; it reads nothing but its scheme argument.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "refdef"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Reference designations as strict, typed, immutable Python values: parse, check, print, number and order"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.14"
|
|
@@ -8,16 +8,18 @@ from refdef.issues import Issue, IssueCode, Parsed
|
|
|
8
8
|
from refdef.level import Aspect, Level
|
|
9
9
|
from refdef.numbering import allocate, lowest_free, number_group
|
|
10
10
|
from refdef.order import natural_key, sort_key
|
|
11
|
-
from refdef.scheme import STANDARD, ClassEntry, Scheme
|
|
11
|
+
from refdef.scheme import STANDARD, ClassEntry, ClassTable, LetterRule, Scheme
|
|
12
12
|
from refdef.terminal import Signal, Terminal
|
|
13
13
|
|
|
14
14
|
__all__ = [
|
|
15
15
|
"STANDARD",
|
|
16
16
|
"Aspect",
|
|
17
17
|
"ClassEntry",
|
|
18
|
+
"ClassTable",
|
|
18
19
|
"Designation",
|
|
19
20
|
"Issue",
|
|
20
21
|
"IssueCode",
|
|
22
|
+
"LetterRule",
|
|
21
23
|
"Level",
|
|
22
24
|
"Parsed",
|
|
23
25
|
"Scheme",
|
|
@@ -9,9 +9,24 @@ import inspect
|
|
|
9
9
|
DOORS: tuple[str, ...] = ("refdef", "refdef.plc")
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
class _SortedSet:
|
|
13
|
+
"""A set default whose repr lists its members sorted, so the hash seed never shows."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, members: frozenset[object]) -> None:
|
|
16
|
+
self.text = "frozenset({" + ", ".join(repr(m) for m in sorted(members, key=repr)) + "})"
|
|
17
|
+
|
|
18
|
+
def __repr__(self) -> str:
|
|
19
|
+
return self.text
|
|
20
|
+
|
|
21
|
+
|
|
12
22
|
def _signature(obj: object) -> str:
|
|
13
23
|
"""The signature as source text, so 3.14 and 3.15 print the same bytes."""
|
|
14
|
-
|
|
24
|
+
sig = inspect.signature(obj, annotation_format=annotationlib.Format.STRING) # ty: ignore[invalid-argument-type] - obj is callable here
|
|
25
|
+
params = [
|
|
26
|
+
p.replace(default=_SortedSet(p.default)) if isinstance(p.default, frozenset) else p
|
|
27
|
+
for p in sig.parameters.values()
|
|
28
|
+
]
|
|
29
|
+
return str(sig.replace(parameters=params))
|
|
15
30
|
|
|
16
31
|
|
|
17
32
|
def _head(name: str, obj: object) -> str:
|
|
@@ -10,7 +10,10 @@ from refdef.tables import standard as _standard
|
|
|
10
10
|
|
|
11
11
|
@dataclass(frozen=True)
|
|
12
12
|
class LetterRule:
|
|
13
|
-
"""How many letters a code has and which letters never appear.
|
|
13
|
+
"""How many letters a code has and which letters never appear.
|
|
14
|
+
|
|
15
|
+
A caller builds a custom Scheme with it; `Scheme.extend` checks that `never` holds A-Z letters.
|
|
16
|
+
"""
|
|
14
17
|
|
|
15
18
|
min_count: int = 1
|
|
16
19
|
max_count: int = 3
|
|
@@ -27,7 +30,10 @@ class ClassEntry:
|
|
|
27
30
|
|
|
28
31
|
@dataclass(frozen=True)
|
|
29
32
|
class ClassTable:
|
|
30
|
-
"""Versioned class entries; `depth` is how many leading letters of a code are looked up.
|
|
33
|
+
"""Versioned class entries; `depth` is how many leading letters of a code are looked up.
|
|
34
|
+
|
|
35
|
+
A caller passes its own table to a custom Scheme; `version` names the table, not the library.
|
|
36
|
+
"""
|
|
31
37
|
|
|
32
38
|
name: str
|
|
33
39
|
version: str
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""LetterRule and ClassTable are public names: a caller builds a Scheme from them."""
|
|
2
|
+
|
|
3
|
+
import refdef
|
|
4
|
+
from refdef import Aspect, ClassEntry, ClassTable, LetterRule, Scheme
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_letter_rule_and_class_table_are_exported():
|
|
8
|
+
assert "LetterRule" in refdef.__all__
|
|
9
|
+
assert "ClassTable" in refdef.__all__
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_a_scheme_built_from_exported_names_looks_up_its_entry():
|
|
13
|
+
table = ClassTable(name="t", version="1", depth=1, entries=(ClassEntry("A", "x"),))
|
|
14
|
+
scheme = Scheme("custom", frozenset({Aspect.PRODUCT}), LetterRule(1, 2, frozenset("I")), table)
|
|
15
|
+
assert scheme.classes.get("A") == ClassEntry("A", "x")
|
|
16
|
+
assert scheme.letters.never == frozenset("I")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|