Skip to content
Draft
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
235 changes: 123 additions & 112 deletions poetry.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ readme = "README.md"
[tool.poetry.dependencies]
pydantic = "^2.10.5"
python = ">=3.10,<4.0"
autopep8 = "^2.3.2"

[tool.poetry.group.dev.dependencies]
black = "^24.10.0"
Expand Down
5 changes: 1 addition & 4 deletions tests/test_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
File,
Image,
LocalStorage,
Mesh,
S3Storage,
SQLTable,
MeshFile,
TabularData,
WebPage,
)
Expand Down Expand Up @@ -80,7 +80,6 @@ def test_local_storage_raise_missing(local_storage_data: dict):
PDF,
Document,
Image,
Mesh,
TabularData,
],
)
Expand Down Expand Up @@ -108,7 +107,6 @@ def test_file_s3(s3_storage_data: dict, file_type: File):
PDF,
Document,
Image,
Mesh,
TabularData,
],
)
Expand Down Expand Up @@ -136,7 +134,6 @@ def test_file_local(file_type: File, local_storage_data: dict):
PDF,
Document,
Image,
Mesh,
TabularData,
],
)
Expand Down
10 changes: 8 additions & 2 deletions tests/test_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,16 @@ def test_llm_config(llm_config_data: dict):

@pytest.mark.parametrize(
"llm_provider_field, field, expected",
[("openai", "ollama_url", None), ("ollama", "openai_api_key", None), ("ollama", "temperature", 0.0)],
[
("openai", "ollama_url", None),
("ollama", "openai_api_key", None),
("ollama", "temperature", 0.0),
],
indirect=["llm_provider_field"],
)
def test_llm_config_optional(llm_config_data: dict, field: str, expected: Optional[float]):
def test_llm_config_optional(
llm_config_data: dict, field: str, expected: Optional[float]
):
"""
Test that LLMConfig object does not raise an error when missing an optional field.

Expand Down
98 changes: 98 additions & 0 deletions tests/test_mesh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import pytest
from datetime import datetime
from unittest.mock import Mock

from uncertainty_engine_types import MeshFile, Mesh


def test_mesh_initialization():
"""Test that Mesh initializes correctly with required fields."""
mock_file = Mock(spec=MeshFile)
mesh = Mesh(
created_by="user123",
project_id="proj_001",
name="TestMesh",
version="1.0",
nodes=[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]],
elements=[("triangle", [[0, 1, 2]])],
location=mock_file,
element_type="triangle",
)

assert mesh.created_by == "user123"
assert mesh.project_id == "proj_001"
assert mesh.name == "TestMesh"
assert mesh.version == "1.0"
assert isinstance(mesh.date_created, datetime)
assert isinstance(mesh.last_edited, datetime)
assert mesh.nel == 1 # 1 element added
assert mesh.nnodes == 2 # 2 nodes added


def test_mesh_defaults():
"""Test that Mesh defaults are correctly assigned."""
mock_file = Mock(spec=MeshFile)
mesh = Mesh(
created_by="user123",
project_id="proj_002",
name="DefaultMesh",
version="1.0",
location=mock_file,
element_type="quad",
)

assert mesh.nodes == []
assert mesh.elements == []
assert mesh.node_data == {}
assert mesh.element_data == {}
assert mesh.nel == 0
assert mesh.nnodes == 0


def test_mesh_computed_fields():
"""Test that nel and nnodes are computed correctly."""
mock_file = Mock(spec=MeshFile)
mesh = Mesh(
created_by="user123",
project_id="proj_003",
name="ComputedMesh",
version="1.0",
nodes=[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]],
elements=[("triangle", [[0, 1, 3], [1, 2, 3]])],
location=mock_file,
element_type="triangle",
)

assert mesh.nel == 2
assert mesh.nnodes == 3


def test_mesh_invalid_nodes():
"""Test that an invalid node structure raises a validation error."""
mock_file = Mock(spec=MeshFile)
with pytest.raises(ValueError):
Mesh(
created_by="user123",
project_id="proj_004",
name="InvalidNodesMesh",
version="1.0",
nodes=[[0.0, 0.0], [1.0, 0.0]], # Invalid: should be 3D coordinates
location=mock_file,
element_type="triangle",
)


def test_mesh_invalid_elements():
"""Test that an invalid element structure raises a validation error."""
mock_file = Mock(spec=MeshFile)
with pytest.raises(ValueError):
Mesh(
created_by="user123",
project_id="proj_005",
name="InvalidElementsMesh",
version="1.0",
nodes=[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
elements=[("triangle", [[0, 1]])], # Invalid: should have 3 indices
location=mock_file,
element_type="triangle",
)
4 changes: 3 additions & 1 deletion tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ def test_machine_learning_model(machine_learning_model_data: dict):


@pytest.mark.parametrize("field", ["model_type", "config", "metadata"])
def test_machine_learning_model_raise_missing(machine_learning_model_data: dict, field: str):
def test_machine_learning_model_raise_missing(
machine_learning_model_data: dict, field: str
):
"""
Test that MachineLearningModel object raises an error when missing a required field.

Expand Down
4 changes: 3 additions & 1 deletion uncertainty_engine_types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
FileLocation,
Image,
LocalStorage,
Mesh,
MeshFile,
S3Storage,
SQLTable,
TabularData,
Expand All @@ -21,6 +21,7 @@
from .handle import Handle
from .job import JobInfo, JobStatus
from .llm import LLMConfig, LLMProvider
from .mesh import Mesh
from .message import Message
from .model import MachineLearningModel
from .node_info import NodeInfo, NodeInputInfo, NodeOutputInfo
Expand Down Expand Up @@ -49,6 +50,7 @@
"LocalStorage",
"MachineLearningModel",
"Mesh",
"MeshFile",
"Message",
"NodeElement",
"NodeId",
Expand Down
7 changes: 4 additions & 3 deletions uncertainty_engine_types/file.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Union
from typing import Union, List, Tuple, Dict
from datetime import datetime

from pydantic import BaseModel
from pydantic import BaseModel, Field, model_validator


class S3Storage(BaseModel):
Expand All @@ -27,7 +28,7 @@ class Image(File):
location: FileLocation


class Mesh(File):
class MeshFile(File):
location: FileLocation


Expand Down
50 changes: 50 additions & 0 deletions uncertainty_engine_types/mesh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from typing import Union, List, Tuple, Dict
from datetime import datetime

from pydantic import BaseModel, Field, model_validator

from uncertainty_engine_types import MeshFile

DataType = Union[List[float], List[List[float]]] # Scalars or Vectors


class Mesh(BaseModel):
"""
Model representing a mesh with nodes, elements, and associated data
Includes metadata about the mesh and its storage location
"""

# Metadata
created_by: str
project_id: str
date_created: datetime = Field(default_factory=datetime.now)
last_edited: datetime = Field(default_factory=datetime.now)
name: str
version: str

# Mesh data
nodes: List[List[float]] = Field(default_factory=list) # 3D coordinates of nodes
elements: List[Tuple[str, List[List[int]]]] = Field(
default_factory=list
) # Elements with type and connectivity
node_data: Dict[str, DataType] = Field(
default_factory=dict
) # Additional data associated with nodes
element_data: Dict[str, List[List[List[int]]]] = Field(
default_factory=dict
) # Additional data associated with elements

# Storage info
location: MeshFile

# Element properties
element_type: str
nel: int = 0 # Number of elements (computed)
nnodes: int = 0 # Number of nodes (computed)

@model_validator(mode="after")
def compute_derived_fields(self):
"""Automatically calculate number of elements and nodes after model initialization"""
self.nel = len(self.elements)
self.nnodes = len(self.nodes)
return self