Skip to content

Improve pySpecs robustness: graceful failures, regex support, and reusable API#512

Merged
shigoel merged 2 commits intomainfrom
jhx/pyspec_re
Mar 9, 2026
Merged

Improve pySpecs robustness: graceful failures, regex support, and reusable API#512
shigoel merged 2 commits intomainfrom
jhx/pyspec_re

Conversation

@joehendrix
Copy link
Contributor

@joehendrix joehendrix commented Mar 3, 2026

Summary

Improves the robustness of the pySpecs command so it reports failures
gracefully — including regex usage — instead of aborting, and extracts
the core logic into a reusable API with CLI flags for skipping
definitions, controlling verbosity, and selecting log events.

Details

  • Graceful failure handling. When a Python import cannot be resolved,
    the translator now registers the imported names as opaque extern types
    and continues, rather than aborting. This means downstream references
    to those names still produce valid (if incomplete) output. Overload
    stubs with unexpected bodies produce a warning instead of failing.
  • Regex support. from re import compile is recognized via the
    built-in prelude, so Python files that use regex no longer trigger
    unknown-identifier errors. A test confirms this import resolves
    without warnings.
  • Reusable API. The translation logic that was inline in the CLI
    callback is extracted into a self-contained entry point in SimpleAPI.
    It validates inputs, parses skip-name strings, translates, writes
    output, and reports warnings — all returning structured errors instead
    of calling exitFailure. The CLI callback now delegates to this.
  • CLI flags. --skip <name> omits named top-level definitions from
    output (overloaded variants are always kept). --quiet suppresses
    logging and warnings. --log <event> enables specific event types.
  • Warning pipeline. Warnings are now collected during translation
    and returned to the caller as data, rather than being printed to
    stderr internally. A three-level verbosity setting (none / summary /
    detail) controls how they are reported.
  • Composable assertion expressions. The expression tree for
    preconditions and postconditions is refactored from fused nodes
    (e.g., "length >= N" as one node) into orthogonal building blocks
    (length, integer literal, greater-or-equal, etc.). This makes
    serialization a direct structural recursion with no special cases.
  • Readable DDM output. Assertions print as ensure(pred, msg).
    Comparisons use infix >=/<=. Class member blocks are indented
    on separate lines. These changes make the generated specs easier to
    read and diff.
  • Event logging cleanup. Logging no longer uses a global mutable
    reference; the set of enabled events is threaded through the
    translation context. Import messages now report after completion
    (past tense) and include warning counts.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@joehendrix joehendrix marked this pull request as draft March 3, 2026 23:27
Base automatically changed from jhx/pyspec_exceptions to main March 3, 2026 23:30
@joehendrix joehendrix force-pushed the jhx/pyspec_re branch 11 times, most recently from af909a0 to bbb3c3b Compare March 6, 2026 17:34
@joehendrix joehendrix changed the title Add re.compile to prelude to avoid crash on regex imports Improve pySpecs robustness: graceful failures, regex support, and reusable API Mar 6, 2026
@joehendrix joehendrix marked this pull request as ready for review March 6, 2026 17:35
@shigoel shigoel enabled auto-merge March 6, 2026 20:29
shigoel
shigoel previously approved these changes Mar 6, 2026
@joehendrix joehendrix force-pushed the jhx/pyspec_re branch 2 times, most recently from 4d5ec7c to 620f665 Compare March 9, 2026 17:18
joehendrix and others added 2 commits March 9, 2026 13:24
Improves the robustness of the pySpecs command so it reports failures
gracefully — including regex usage — instead of aborting, and extracts
the core logic into a reusable API with CLI flags for skipping
definitions, controlling verbosity, and selecting log events.

- Graceful failure handling: when a Python import cannot be resolved,
  the translator now registers the imported names as opaque extern types
  and continues, rather than aborting. Overload stubs with unexpected
  bodies produce a warning instead of failing.
- Regex support: `from re import compile` is recognized via the built-in
  prelude, so Python files that use regex no longer trigger
  unknown-identifier errors.
- Reusable API: the translation logic that was inline in the CLI callback
  is extracted into a self-contained entry point in SimpleAPI, returning
  structured errors instead of calling exitFailure.
- CLI flags: --skip omits named top-level definitions (overloads kept),
  --quiet suppresses logging and warnings, --log enables event types.
- Warning pipeline: warnings are collected during translation and
  returned as data; a three-level verbosity setting controls reporting.
- Composable assertion expressions: the expression tree is refactored
  from fused nodes into orthogonal building blocks, making serialization
  a direct structural recursion with no special cases.
- Readable DDM output: ensure(pred, msg) format, infix comparisons,
  indented class member blocks.
- Event logging cleanup: global mutable reference replaced by a context-
  threaded event set.
Replace FileMaps.ppSourceRange (which used panic! for missing paths)
with a local ppErr helper that returns an error via throw instead.
Remove redundant variable alias in SimpleAPI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@shigoel shigoel added this pull request to the merge queue Mar 9, 2026
Merged via the queue into main with commit 435b1ce Mar 9, 2026
15 checks passed
@shigoel shigoel deleted the jhx/pyspec_re branch March 9, 2026 21:53
github-merge-queue bot pushed a commit that referenced this pull request Mar 11, 2026
…cts (#537)

## Summary

Extend the Strata `pySpecs` Python-to-spec translator to handle the full
range of assertion patterns found across service specification files.
Before this change the translator emitted warnings on many common
patterns; after, it handles all constructs without warnings.

Builds on the robustness and API improvements from #512.

## Details

- **F-string messages.**  Assertion messages that use Python f-strings
  are now preserved semantically (distinguishing literal text from
  interpolated expressions) rather than being flattened to a single
  string.
- **For-loop quantifiers.**  `for item in kwargs["field"]` loops are
  translated to `forallList` quantifiers.  The element type is inferred
  from `typing.List` or `typing.Sequence` annotations in the
  corresponding TypedDict.  `for k, v in dict.items()` tuple unpacking
  is handled similarly via `forallDict`, with key/value types inferred
  from `Dict` or `Mapping` annotations.
- **Conditional implication.**  When assertions appear inside an `if`
  block (e.g. `if "Items" in kwargs:`), the condition becomes an
  antecedent: `implies(condition, assertion)`.  Else-branch assertions
  receive the negated condition.
- **`__init__` as class fields.**  Rather than treating `__init__` as a
  regular method, the translator now extracts
  `self.field = self._ClassName()` assignments as typed class fields
  with an optional constant value.  Unhandled `__init__` patterns
  emit warnings.
- **Type-checked numeric comparisons.**  Comparison assertions
  (`>=`, `<=`) now use type inference to choose between integer and
  floating-point operators.  When a float-typed field is compared
  against an integer literal (e.g. `SampleSize >= 0`), the bound is
  promoted to float automatically.  Negative integer bounds (`>= -1`)
  are also supported.
- **Negative-integer DDM encoding.**  Fixed the `negSucc` round-trip in
  the DDM serialization layer so that `-1` renders as `"-1"` rather
  than `"-0"`.
- **DDM operator precedences.**  Subscript, comparison, and implication
  operators have explicit precedences so the pretty-printer no longer
  emits unnecessary parentheses.
- **Test coverage.**  Positive tests cover f-strings, for-loops, dict
  iteration, conditionals, `__init__` fields, float/int comparisons,
  and negative bounds.  A separate negative-test file (`warnings.py`)
  verifies that unsupported patterns produce the expected warnings.
  Test assertions now throw descriptive errors instead of panicking.

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

4 participants