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
29 changes: 26 additions & 3 deletions py/bin/sanitize_schema_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,15 @@ def is_rootmodel_class(self, node: ast.ClassDef) -> bool:
return True
return False

def create_model_config(self, existing_config: ast.Call | None = None) -> ast.Assign:
def create_model_config(self, existing_config: ast.Call | None = None, frozen: bool = False) -> ast.Assign:
"""Create or update a model_config assignment.

Ensures populate_by_name=True and extra='forbid', keeping other existing
settings.
"""
keywords = []
found_populate = False
found_frozen = False

# Preserve existing keywords if present, but override 'extra'
if existing_config:
Expand All @@ -89,6 +90,15 @@ def create_model_config(self, existing_config: ast.Call | None = None) -> ast.As
elif kw.arg == 'extra':
# Skip the existing 'extra', we will enforce 'forbid'
continue
elif kw.arg == 'frozen':
# Use the provided 'frozen' value
keywords.append(
ast.keyword(
arg='frozen',
value=ast.Constant(value=frozen),
)
)
found_frozen = True
else:
keywords.append(kw) # Keep other existing settings

Expand All @@ -99,6 +109,10 @@ def create_model_config(self, existing_config: ast.Call | None = None) -> ast.As
if not found_populate:
keywords.append(ast.keyword(arg='populate_by_name', value=ast.Constant(value=True)))

# Add frozen=True if it was requested and not found
if frozen and not found_frozen:
keywords.append(ast.keyword(arg='frozen', value=ast.Constant(value=True)))

# Sort keywords for consistent output (optional but good practice)
keywords.sort(key=lambda kw: kw.arg or '')

Expand Down Expand Up @@ -196,27 +210,36 @@ def visit_ClassDef(self, node: ast.ClassDef) -> Any:
elif any(isinstance(base, ast.Name) and base.id == 'BaseModel' for base in node.bases):
# Add or update model_config for BaseModel classes
added_config = False
frozen = node.name == 'PathMetadata'
for stmt in node.body[body_start_index:]:
if isinstance(stmt, ast.Assign) and any(
isinstance(target, ast.Name) and target.id == 'model_config' for target in stmt.targets
):
# Update existing model_config
updated_config = self.create_model_config(existing_model_config_call)
updated_config = self.create_model_config(existing_model_config_call, frozen=frozen)
# Check if the config actually changed
if ast.dump(updated_config) != ast.dump(stmt):
new_body.append(updated_config)
self.modified = True
else:
new_body.append(stmt) # No change needed
added_config = True
elif (
isinstance(stmt, ast.Assign)
and any(isinstance(target, ast.Name) and target.id == '__hash__' for target in stmt.targets)
and frozen
):
# Skip manual __hash__ for PathMetadata
self.modified = True
continue
else:
new_body.append(stmt)

if not added_config:
# Add model_config if it wasn't present
# Insert after potential docstring
insert_pos = 1 if len(new_body) > 0 and isinstance(new_body[0], ast.Expr) else 0
new_body.insert(insert_pos, self.create_model_config())
new_body.insert(insert_pos, self.create_model_config(frozen=frozen))
self.modified = True
elif any(isinstance(base, ast.Name) and base.id == 'Enum' for base in node.bases):
# Uppercase Enum members
Expand Down
2 changes: 1 addition & 1 deletion py/packages/genkit/src/genkit/core/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ class InstrumentationLibrary(BaseModel):
class PathMetadata(BaseModel):
"""Model for pathmetadata data."""

model_config = ConfigDict(extra='forbid', populate_by_name=True)
model_config = ConfigDict(extra='forbid', frozen=True, populate_by_name=True)
path: str
status: str
error: str | None = None
Expand Down
14 changes: 10 additions & 4 deletions py/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ authorized_licenses = [
"python software foundation license",
"simplified bsd",
"the unlicense (unlicense)", # TODO: verify.
"bsd-2-clause",
"apache license 2.0",
"apache-2.0 and mit",
]
dependencies = true
unauthorized_licenses = [
Expand All @@ -259,8 +262,11 @@ unauthorized_licenses = [
]

[tool.liccheck.authorized_packages]
aiohappyeyeballs = "2.6.1" # Python Software Foundation (transitive dep of xai-sdk)
aiohttp = "3.13.2" # Apache-2.0 AND MIT (transitive dep of xai-sdk)
certifi = "2025.4.26" # TODO: Verify.
aiohappyeyeballs = "2.6.1" # Python Software Foundation (transitive dep of xai-sdk)
aiohttp = "3.13.3" # Apache-2.0 AND MIT (transitive dep of xai-sdk)
certifi = "2026.1.4" # TODO: Verify.
dependencies = true
ollama = "0.5.1" # MIT "https://github.com/ollama/ollama-python/blob/main/LICENSE"
google-crc32c = "1.8.0" # Apache-2.0
multidict = "6.7.0" # Apache-2.0
ollama = "0.5.1" # MIT "https://github.com/ollama/ollama-python/blob/main/LICENSE"
pyasn1 = "0.6.2" # BSD-2-Clause
Loading
Loading