Skip to content

feat(sdk): add the remaining Morphir SDK modules - #25

Merged
DamianReeves merged 7 commits into
mainfrom
feat/sdk-extended
Sep 18, 2026
Merged

DamianReeves merged 7 commits into
mainfrom
feat/sdk-extended

Conversation

@DamianReeves

Copy link
Copy Markdown
Member

Summary

Completes morphir.sdk against the Morphir.SDK package specification in morphir-elm. #24 added the twelve core modules; this adds the other ten: local_date, local_time, instant, uuid, regex, aggregate, rule, key, stateful_app and result_list.

test_spec_coverage.py now lists all 372 values of the 22 Morphir.IR.SDK.* module specifications and checks that each exists under its Python name. The Json modules are not part of the SDK package specification and are not included. The design mirrors finos/morphir-typescript#28.

Design

Same conventions as the core modules: snake_case Elm names, Elm argument order with the data last, immutable data, standard library only.

  • local_date.LocalDate is datetime.date, with no time zone. Month and DayOfWeek are Enums with the Elm constructor names. Month-end clamping matches justinmimbs/date, which the Elm runtime uses.
  • local_time.LocalTime is a frozen dataclass holding milliseconds from the epoch. In Elm it is an alias of Time.Posix, so it is a point in time and does not go around midnight; the Elm tests require from_iso("12:56:30") to be Nothing.
  • instant.Instant is a datetime.datetime with a time zone. The specification gives it a type and no functions; two conversion helpers are marked as additions.
  • uuid.UUID is the standard library uuid.UUID. parse follows the elm-uuid rules and error order; for_name is version 5.
  • regex.Regex wraps the re module.
  • result_list.ResultList[E, A] is tuple[Result[E, A], ...] and StatefulApp holds logic: (state, command) -> (state, event), both exactly as the Elm types are.
  • key.Key2 to Key16 are flat tuples, so they work as Dict keys. Elm nests them only because its tuples stop at three elements; the ordering is the same.

Name mapping additions: is becomes is_, and the initialisms toISOString and fromISO become to_iso_string and from_iso.

Deliberate departures from the Elm runtime

Each is documented in the module docstring.

  • regex patterns use Python re syntax, which differs from JavaScript in places: named groups are (?P<name>...), and \d, \w and \b follow Unicode. Match.index counts code points. split terminates on a pattern that matches the empty string, where Elm does not stop.
  • aggregate omits constructAggregationCall and its types. They inspect Morphir IR values, belong to tooling, and have no entry in the specification. aggregate yields rows in ascending key order, because it uses the SDK Dict where Elm uses an insertion-ordered AssocList. count is a function, count(), so the type checker can infer the row type.
  • local_date.diff_in_months and diff_in_years use integer arithmetic. Elm's float formula loses a month when the month count crosses a power of two. datetime.date holds the years 1 to 9999 only.
  • local_time.from_iso rejects out-of-range fields that the Elm library accepts, and subtracts the minutes of a negative offset, which Elm adds.
  • uuid.parse accepts versions 1 to 8, as elm-uuid 4.3.1 does.

Test plan

  • uv run pytest tests/: 1579 passed. Every Elm test case for these modules is ported.
  • uv run behave features/: 19 scenarios passed.
  • uv run ruff check . and uv run ruff format --check .
  • uv run mypy packages/morphir/src packages/morphir-tools/src
  • uv run pyright packages/morphir/src packages/morphir-tools/src
  • Docstring examples of all 22 modules run through test_doctests.py.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-18T07:20:25.836251Z bff4c3f PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bff4c3f8b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +34 to +35
Instant = datetime.datetime
"""The standard library datetime type, used with a time zone."""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Prevent constructing naive Instant values

Because Instant is only an alias for datetime.datetime, callers can construct Instant(2026, 9, 18) and it passes every annotation despite not identifying a point on the timeline. Such a value raises TypeError when compared with an aware instant and ValueError when passed to to_milliseconds_since_epoch; represent Instant with a validated constructor or wrapper that requires a non-None UTC offset.

AGENTS.md reference: AGENTS.md:L96-L99

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in ca82532. Instant is no longer an alias of datetime.datetime. It is a frozen, ordered dataclass that holds milliseconds since the epoch, the form of Elm's Time.Posix and of local_time.LocalTime. The constructor rejects anything that is not an int, so Instant(datetime.datetime(2026, 9, 18)) raises TypeError, and a naive value cannot exist. from_datetime raises ValueError for a naive datetime; to_datetime yields UTC. Tests: tests/unit/sdk/test_instant.py.

Instant was an alias of datetime.datetime, so a naive datetime passed every
annotation and failed later on comparison or conversion. Instant is now a
frozen dataclass that holds milliseconds since the epoch, as Elm's Time.Posix
and LocalTime do, so a value that is not a point on the timeline cannot be
made. from_datetime rejects a naive datetime; to_datetime yields UTC.
@DamianReeves
DamianReeves merged commit dc0b317 into main Sep 18, 2026
5 checks passed
@DamianReeves
DamianReeves deleted the feat/sdk-extended branch September 18, 2026 12:26
DamianReeves added a commit to finos/morphir that referenced this pull request Sep 18, 2026
…#847)

Move ecosystem/morphir-typescript from 692557c to a5e3be0 (finos/morphir-typescript#28) and ecosystem/morphir-python from 2047614 to dc0b317 (finos/morphir-python#25). Both add the remaining modules of the Morphir.SDK package specification.
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.

1 participant