|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +Guidance for Claude Code when working in this repository. |
| 4 | + |
| 5 | +## Commands |
| 6 | + |
| 7 | +```bash |
| 8 | +uv run pytest # all tests (add --run-extended for huge-file tests) |
| 9 | +uv run pytest tests/test_parser.py::test_x # single test |
| 10 | +uv run ruff format . && uv run ruff check --fix . # format + import sorting (required before commit) |
| 11 | +uv run mypy pydifact # type checking |
| 12 | +uv run bandit -q -r pydifact # security lint (see `# nosec` markers) |
| 13 | +make generate RELEASE=24a # regenerate directory data (dev tool, see docs/generator.rst) |
| 14 | +make generate-service SYNTAX=4 # regenerate service segment data |
| 15 | +``` |
| 16 | + |
| 17 | +## Architecture |
| 18 | + |
| 19 | +pydifact is a UN/EDIFACT parser and serializer: |
| 20 | + |
| 21 | +``` |
| 22 | +raw string → Tokenizer → Token stream → Parser → Segment stream → SegmentCollection |
| 23 | +``` |
| 24 | + |
| 25 | +### Core (`pydifact/`) |
| 26 | + |
| 27 | +- `tokenizer.py` / `token.py` – raw string → `Token` objects; handles escape characters. |
| 28 | +- `parser.py` – `Token` stream → `Segment` objects. Detects `UNA` for control characters, reads `UNB` for syntax |
| 29 | + version/directory. |
| 30 | +- `segments.py` – `Segment` (tag + elements). `SegmentFactory` picks typed subclasses from `Segment.plugins`; |
| 31 | + subclasses with a `tag` attribute auto-register via `__init_subclass__` (`__omitted__ = True` opts out). |
| 32 | + `Segment.validate()` is XML-driven, definitions cached with `@lru_cache`. |
| 33 | +- `serializer.py` – `Segment` list → EDI string, incl. `UNA` and escaping. |
| 34 | +- `control/characters.py` – the 6 EDIFACT control characters; default `:+.? '`. |
| 35 | +- `segmentcollection.py` – `AbstractSegmentsContainer` → `RawSegmentCollection` (no envelope), `Message` |
| 36 | + (UNH/UNT), `Interchange` (UNB/UNZ, main entry point: `from_file()`, `from_str()`, `get_messages()`). |
| 37 | +- `constants.py` – `Element = str | list[str]`, `Elements = list[Element]`, defaults (`EDI_DEFAULT_DIRECTORY = "d24a"`). |
| 38 | + |
| 39 | +### Syntax definitions (`pydifact/syntax/`) |
| 40 | + |
| 41 | +- `common.py` – `DataElement`, `CompositeDataElement`, type/length assertions. |
| 42 | +- `v1/` … `v4/` – typed service segment classes (`UNB`, `UNH`, …) per syntax version. |
| 43 | +- `service/v100` … `v402/` – XML service segment definitions per syntax release. |
| 44 | +- `d21a/`, `d23a/`, `d24a/` – XML message directories (segments, elements, codes, message structures). |
| 45 | + |
| 46 | +### Generator (`pydifact/generator/`) |
| 47 | + |
| 48 | +Dev-only tool (excluded from mypy) that downloads UNECE directory zips and generates the XML data above. |
| 49 | +Parses untrusted XML via `defusedxml`; stdlib `ElementTree` is only used to build XML (`# nosec B405`). |
| 50 | + |
| 51 | +## Tests |
| 52 | + |
| 53 | +`tests/data/*.edi` holds sample interchanges; `tests/messagetypes/` and `tests/segments/` cover typed messages |
| 54 | +and segments. |
0 commit comments