Skip to content

v2.2.0 Release#147

Open
mike-finopsorg wants to merge 18 commits into
mainfrom
dev
Open

v2.2.0 Release#147
mike-finopsorg wants to merge 18 commits into
mainfrom
dev

Conversation

@mike-finopsorg

Copy link
Copy Markdown
Contributor

FOCUS 1.4 Support
Added new check functions and support for 1.4 validation

mike-finopsorg and others added 16 commits March 2, 2026 08:54
…ng and entity type Object. (#132)

Signed-off-by: Mike Fuller <mike@finops.org>

---------

Signed-off-by: Mike Fuller <mike@finops.org>
Bumped version
Signed-off-by: Mike Fuller <mike@finops.org>

Signed-off-by: Mike Fuller <mike@finops.org>
Signed-off-by: Mike Fuller <mike@finops.org>

Signed-off-by: Mike Fuller <mike@finops.org>
Signed-off-by: Mike Fuller <mike@finops.org>

Signed-off-by: Mike Fuller <mike@finops.org>
Co-authored-by: Matt Cowsert <matthew@finops.org>
Signed-off-by: Mike Fuller <mike@finops.org>
Co-authored-by: Matt Cowsert <matthew@finops.org>
Signed-off-by: Mike Fuller <mike@finops.org>
Co-authored-by: Matt Cowsert <matthew@finops.org>
Signed-off-by: Mike Fuller <mike@finops.org>
Co-authored-by: Matt Cowsert <matthew@finops.org>
Signed-off-by: Mike Fuller <mike@finops.org>
Co-authored-by: Matt Cowsert <matthew@finops.org>
Signed-off-by: Mike Fuller <mike@finops.org>
Co-authored-by: Matt Cowsert <matthew@finops.org>
Signed-off-by: Mike Fuller <mike@finops.org>
Co-authored-by: Matt Cowsert <matthew@finops.org>
Signed-off-by: Mike Fuller <mike@finops.org>
Apply review feedback across the FOCUS 1.4 check generators:

- Make every leaf generator row-condition-aware by wrapping its
  predicate_sql in _apply_condition, matching FormatJSON. Previously
  only FormatJSON did this; the predicate is read directly off the
  stored SQLQuery, so the condition must be baked in at construction.
- Fix CheckColumnComparison null handling. The violation condition now
  requires both columns non-null before comparing, so null rows are no
  longer flagged. This aligns it with CheckSameValue's convention.
- Collapse CheckGreaterOrEqual, CheckGreaterThan, and CheckLessOrEqual
  into a shared _CheckScalarComparisonGenerator base. Each subclass now
  sets only its operators, message phrase, and check type. This also
  standardizes literal quoting and predicate gating across the three.

Tests:

- Add a row-condition predicate test covering the named comparison
  generators to lock in the now-uniform behavior.
- Update the CheckStringEndsWith assertion to expect the ends_with SQL.
- Add tests/config_objects/test_generator_edge_cases.py, which executes
  generated SQL against a real in-memory DuckDB to cover null handling,
  multi-byte suffixes, malformed JSON paths, a missing jsonschema
  dependency, and row-filtered de-duplication.

Signed-off-by: Mike Fuller <mike@finops.org>
Co-authored-by: Matt Cowsert <matthew@finops.org>
The Utf8 datetime parsing strategies each required a zero null_count,
so a single null cell (an originally-null value or one unparseable
entry) forced every strategy to fail and the column to stay a string.
Nullable datetime columns are common in FOCUS, so this path was hit in
practice.

Judge parse success against the original null count instead of zero:
a strategy now succeeds when parsing introduces no new nulls beyond
those already present and the column has at least one real value. A
nullable single-format column converts, a genuinely mixed or
unparseable column is still rejected, and an all-null column is left
as a string rather than coerced.

Add regression tests covering nullable ISO (Z and offset), date-only,
and space-separated columns, plus a mixed-format column that must be
dropped.

Also fix a stale TypeJSON test assertion: the generator now emits
NOT json_valid(...) rather than typeof(...) != 'JSON'.
Signed-off-by: Mike Fuller <mike@finops.org>
Signed-off-by: Mike Fuller <mike@finops.org>
Signed-off-by: Mike Fuller <mike@finops.org>
@mike-finopsorg mike-finopsorg self-assigned this Jun 25, 2026

@Matt-Cowsert Matt-Cowsert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

FOCUS 1.4 support. One item to address in the explain path; the inline notes are optional.

explain type rename is incomplete. _explain_check_sql now returns "type": "special" for special-executor leaf checks where it previously returned "type": "reference" (focus_to_duckdb_converter.py:6453). Three places still expect "reference":

  • focus_to_duckdb_converter.py:6544print_sql_map's elif t == "reference": is now unreachable, so the Reference to: … line no longer prints.
  • validator.py:327if child_type == "reference": no longer matches, so composite explain output drops the child_id -> referenced_id mapping for reference children.
  • focus_to_duckdb_converter.py:6459-6463 — the note ternary checks special_kind == "reference", but the conformance-reference executor (:2166-2168) sets exec_mode = "reference" and never sets meta["special_executor_kind"] = "reference" (only the JSON-schema path sets that key, :1327), so reference checks fall through to the generic executed via special executor note.

These affect explain/introspection output only, not validation results, which is why the suite stays green. One way to close it: set chk.meta["special_executor_kind"] = "reference" in the reference executor, then branch the two consumers on type == "special" (plus the kind) rather than type == "reference".

Comment on lines +1257 to +1258
sql = query.replace("{table_name}", table_name)
sql = sql.replace("{table_name}", table_name)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The second replace is a no-op — the first call already substituted the only {table_name} placeholder.

Suggested change
sql = query.replace("{table_name}", table_name)
sql = sql.replace("{table_name}", table_name)
sql = query.replace("{table_name}", table_name)

"CheckJSONSchema requires the 'jsonschema' package to be installed"
) from exc

Draft202012Validator.check_schema(schema)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

check_schema() runs on every execution and raises jsonschema.SchemaError for a malformed model schema, surfacing as an unhandled exception mid-run. Validating it in generateCheck() would fail fast as InvalidRuleException, consistent with how a missing SchemaId is already handled here.


failure_messages: list[str] = []
violations = 0
for row_num, row in enumerate(rows, start=1):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

row_num counts position within the filtered result set, so row {row_num} in the failure message won't match the source data row once nulls or a row condition drop rows. Minor, but worth noting if these messages reach users.

def get_sample_sql(self) -> str:
col_a = self.params.ColumnAName
col_b = self.params.ColumnBName
comparator = self.params.Comparator

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Comparator isn't re-validated here the way generateSql() does at :1927. Safe today since generateSql() runs first and raises on an unknown comparator, but factoring the check (and the shared violation condition) out would keep the two paths from drifting.

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