Skip to content

Claude/dreamy goldberg wjzix8 - #2

Merged
DHoffmannOVGU merged 3 commits into
AutomationML:mainfrom
DHoffmannOVGU:claude/dreamy-goldberg-wjzix8
Oct 17, 2026
Merged

DHoffmannOVGU merged 3 commits into
AutomationML:mainfrom
DHoffmannOVGU:claude/dreamy-goldberg-wjzix8

Conversation

@DHoffmannOVGU

@DHoffmannOVGU DHoffmannOVGU commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Describe the AutomationML use case and the change made.

Compatibility

  • The change is additive and backward compatible.
  • The change intentionally modifies a public API or serialization contract.
  • The compatibility impact is documented below.

Verification

  • python -m pytest passes locally.
  • Tests cover the new behavior or regression.
  • Validation examples were updated when applicable.
  • CHANGELOG.md was updated for user-visible changes.
  • No confidential AML data is included.

Additional context

List relevant CAEX paths, schema sections, issues, or design decisions.

The documented Python API builds models with snake_case names, such as
InternalElement(name="Motor"). Pydantic accepts that at runtime through
populate_by_name, but type checkers name a model's __init__ parameters
after the alias of the assigned Field. pyright, and therefore Pylance in
VS Code, rejected every snake_case argument and demanded the PascalCase
alias instead: a 13-line sample using the documented API produced 37
false errors.

Move the 105 CAEX aliases in models.py into Annotated metadata, which
type checkers ignore, and keep the defaults on the right-hand side:

    name: Annotated[str, Field(alias="Name")]
    unit: Annotated[str | None, Field(alias="Unit")] = None

The rewrite was mechanical. Verified that the runtime model is
unchanged: every field's alias, validation and serialization alias,
annotation, required flag, default, default factory, and description is
identical to main for all models, the generated JSON Schema is
byte-identical, and all tests pass. On the sample, pyright now reports
only the two deliberate mistakes (a missing required name and a
misspelled keyword), as mypy already did. Errors on the SDK's own
source drop from 163 to 58 under pyright and from 167 to 86 under mypy,
with mypy call-arg errors going from 84 to 0.

A test keeps aliases out of assigned Fields, and the design notes
explain the convention for future fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VzX3UpZysYhwy1ZMJNcVvq
The builders covered only the instance side. Authoring a library meant
constructing models directly, and the obvious attempt fails:
SystemUnitClassLib(system_unit_classes=[SystemUnitClass(...)]) raises a
Pydantic type error because libraries hold the hierarchical
SystemUnitFamily, RoleFamily, and InterfaceFamily models. The README
tutorial had to explain that distinction to beginners.

Add system_unit_class, role_class, interface_class, and attribute_type,
plus a *_lib builder for each, following the existing conventions:
attributes accept a mapping or a list of attribute() results (now one
shared helper, also used by internal_element), role_paths become
SupportedRoleClass entries just as internal_element turns them into
RoleRequirements, children holds nested InternalElements, and classes
nests further classes in the library tree.

Tests build a document from builders alone and check that every kind of
reference resolves with no validation issues, that a nested class
inherits from its base when instantiated, and the exact AML JSON
emitted. The README tutorial now uses the builders, and every snippet
still runs on the base install.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VzX3UpZysYhwy1ZMJNcVvq
Three rough edges a newcomer hits early:

- Using OPC UA or RDF conversion on a base install failed with a bare
  "No module named 'lxml'" (or 'rdflib'), with no hint that an extra
  exists. The modules that need those packages now raise
  MissingDependencyError, a ModuleNotFoundError subclass, whose message
  names the command, for example:
  python -m pip install "automationml[opcua]"
- A malformed or non-CAEX XML file raised LegacyConversionError, even
  for CAEX 3.0 input that has nothing to do with legacy conversion. The
  three "not a readable CAEX document" cases (unparsable XML, wrong root,
  unsupported schema version) now raise AMLParseError. It subclasses
  LegacyConversionError so existing handlers keep working. CAEX 2.15
  schema and upgrade failures are unchanged.
- The package had no __version__, and source_document() recorded a
  hard-coded OriginVersion of "0.1.0" while the package is 0.1.0a1. The
  version now lives once in automationml/_version.py; hatchling reads it
  through [tool.hatch.version], the package exports it, and
  source_document() uses it by default.

The base AutomationMLError and CAEXValidationError are now importable
from the top-level package as well.

Verified on a real base install without lxml or rdflib that both
conversions raise the new message. The built wheel's metadata reports
0.1.0a1 and twine check passes. The TestPyPI rename step still matches
pyproject.toml. All tests pass, every README and OPC UA guide snippet
runs, the learning notebooks execute, and the OPC UA release gate stays
at 121/121.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VzX3UpZysYhwy1ZMJNcVvq
@DHoffmannOVGU
DHoffmannOVGU merged commit 6dffa0e into AutomationML:main Oct 17, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants