Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file removed steps/src/.gitkeep
Empty file.
20 changes: 20 additions & 0 deletions steps/src/verify_schema/item.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: v1
categories:
- data-preparation
- model-serving
- utilities
description: Verifies the event is aligned with the provided schema
example: verify_schema.ipynb
generationDate: 2025-12-29:11-59
hidden: false
labels:
author: Iguazio
mlrunVersion: 1.10.0
name: verify_schema
className: VerifySchema
defaultHandler:
spec:
filename: verify_schema.py
image: mlrun/mlrun
requirements:
version: 1.0.0
66 changes: 66 additions & 0 deletions steps/src/verify_schema/test_verify_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright 2025 Iguazio
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

from verify_schema import VerifySchema

class TestVerifySchema:
def test_verify_schema(self):
schema = ["id", "name", "active"]
verifier = VerifySchema(schema=schema, allow_unexpected_keys=False)

# Test with valid event
event = {
"id": 1,
"name": "Test Event",
"active": True
}
result = verifier.do(event)
assert result == event

# Test with missing key
event_missing_key = {
"id": 1,
"name": "Test Event"
}
try:
verifier.do(event_missing_key)
except KeyError as e:
assert "missing keys {'active'} in event" in str(e)

# Test with unexpected key
event_unexpected_key = {
"id": 1,
"name": "Test Event",
"active": True,
"extra": "unexpected"
}
try:
verifier.do(event_unexpected_key)
except KeyError as e:
assert "unexpected keys {'extra'} in event" in str(e)

def test_verify_schema_allow_unexpected(self):
schema = ["id", "name", "active"]
verifier = VerifySchema(schema=schema, allow_unexpected_keys=True)

# Test with valid event and unexpected key
event = {
"id": 1,
"name": "Test Event",
"active": True,
"extra": "unexpected"
}
result = verifier.do(event)
assert result == event
33 changes: 33 additions & 0 deletions steps/src/verify_schema/verify_schema.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"cells": [
{
"metadata": {},
"cell_type": "code",
"outputs": [],
"execution_count": null,
"source": "",
"id": "556b36b9b89d0515"
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
40 changes: 40 additions & 0 deletions steps/src/verify_schema/verify_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2025 Iguazio
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

class VerifySchema:
"""
This step validates that an event dictionary contains exactly the keys defined in the schema,
raising a KeyError if any are missing or unexpected.
"""

def __init__(self, schema: list, allow_unexpected_keys: bool = False):
self.schema = schema
self.allow_unexpected_keys = allow_unexpected_keys

def do(self, event: dict):
# Check if all keys in the expected schema are present in the event
missing = set(self.schema) - set(event)
if missing:
raise KeyError(f"Schema verification failed: missing keys {missing} in event: {event}")

if self.allow_unexpected_keys:
return event

# Check if there are any unexpected keys in the event
unexpected = set(event) - set(self.schema)
if unexpected:
raise KeyError(f"Schema verification failed: unexpected keys {unexpected} in event: {event}")

return event