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
6 changes: 4 additions & 2 deletions docs/core-modules/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ The Fluidize Client is the primary interface to create and edit projects. There
::: fluidize.client.FluidizeClient
options:
show_source: false
show_root_heading: true
heading_level: 3
extra:
show_root_heading: true
members:
- mode
- adapters
Expand All @@ -20,8 +21,9 @@ The Fluidize Client is the primary interface to create and edit projects. There
::: fluidize.config.FluidizeConfig
options:
show_source: false
show_root_heading: true
heading_level: 3
extra:
show_root_heading: true
members:
- is_local_mode
- is_api_mode
21 changes: 13 additions & 8 deletions docs/core-modules/graph.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
::: fluidize.managers.graph.GraphManager
options:
show_source: false
how_root_heading: true
heading_level: 3
extra:
show_root_heading: true
members:
- get
- add_node
Expand All @@ -18,27 +19,31 @@
::: fluidize.core.modules.graph.GraphProcessor
options:
show_source: false
show_root_heading: true
heading_level: 3
extra:
show_root_heading: true

## Graph Types

::: fluidize.core.types.graph.GraphData
options:
show_attributes: true
show_root_heading: true
heading_level: 3
extra:
show_attributes: true
show_root_heading: true


::: fluidize.core.types.graph.GraphNode
options:
show_attributes: true
show_root_heading: true
heading_level: 3
extra:
show_attributes: true
show_root_heading: true


::: fluidize.core.types.graph.GraphEdge
options:
show_attributes: true
show_root_heading: true
heading_level: 3
extra:
show_attributes: true
show_root_heading: true
6 changes: 4 additions & 2 deletions docs/core-modules/projects.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
::: fluidize.managers.registry.RegistryManager
options:
show_source: false
show_root_heading: true
heading_level: 3
extra:
show_root_heading: true

## Project
::: fluidize.managers.project.ProjectManager
options:
show_source: false
show_root_heading: true
heading_level: 3
extra:
show_root_heading: true
9 changes: 6 additions & 3 deletions docs/core-modules/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
::: fluidize.managers.runs.RunsManager
options:
show_source: false
show_root_heading: true
heading_level: 3
extra:
show_root_heading: true
members:
- run_flow
- list
Expand All @@ -17,11 +18,13 @@
::: fluidize.core.modules.run.RunJob
options:
show_source: false
show_root_heading: true
heading_level: 3
extra:
show_root_heading: true

::: fluidize.core.modules.run.project.ProjectRunner
options:
show_source: false
show_root_heading: true
heading_level: 3
extra:
show_root_heading: true
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ make install

## Run Examples

Example projects are located in this folder: [examples/](examples/). There you can find an [Jupyter Notebook](examples/demo.ipynb) of a simple simulation
Example projects are located in this folder: [examples/](https://github.com/Fluidize-Inc/fluidize-python/tree/main/examples). There you can find an [Jupyter Notebook](https://github.com/Fluidize-Inc/fluidize-python/blob/main/examples/demo.ipynb) of a simple simulation

## Architecture

Expand Down Expand Up @@ -85,7 +85,7 @@ Pipelines can be executed both locally and on the cloud. Local execution is hand

## Contributing

We would love to collaborate with you! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
We would love to collaborate with you! Please see our [Contributing Guide](https://github.com/Fluidize-Inc/fluidize-python/blob/main/CONTRIBUTING.md) for details.

Also - we would love to help streamline your pipeline! Please reach out to us at [founders@fluidize.ai](mailto:founders@fluidize.ai).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
"name": "motor_strength",
"latex": null,
"location": [
"source/pinata_simulation.py",
"source/pinata_simulation.py",
"source/pinata_simulation.py",
"source/pinata_simulation.py"
],
"options": null,
Expand Down
35 changes: 14 additions & 21 deletions fluidize/adapters/local/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@

from typing import Optional

from fluidize.core.modules.graph.parameters import parse_parameters_from_json
from fluidize.core.modules.graph.processor import GraphProcessor
from fluidize.core.types.graph import GraphData, GraphEdge, GraphNode
from fluidize.core.types.node import nodeMetadata_simulation, nodeProperties_simulation
from fluidize.core.types.node import nodeMetadata_simulation, nodeParameters_simulation, nodeProperties_simulation
from fluidize.core.types.parameters import Parameter
from fluidize.core.types.project import ProjectSummary
from fluidize.core.utils.dataloader.data_loader import DataLoader
from fluidize.core.utils.dataloader.data_writer import DataWriter
from fluidize.core.utils.pathfinder.path_finder import PathFinder


Expand Down Expand Up @@ -171,9 +168,9 @@ def get_parameters(self, project: ProjectSummary, node_id: str) -> list[Paramete
Returns:
A list of Parameter objects for the node
"""
parameters_path = PathFinder.get_node_parameters_path(project, node_id)
data = DataLoader.load_json(parameters_path)
return parse_parameters_from_json(data)
node_path = PathFinder.get_node_path(project, node_id)
parameters_model = nodeParameters_simulation.from_file(node_path)
return parameters_model.parameters

def upsert_parameter(self, project: ProjectSummary, node_id: str, parameter: Parameter) -> Parameter:
"""
Expand All @@ -187,12 +184,11 @@ def upsert_parameter(self, project: ProjectSummary, node_id: str, parameter: Par
Returns:
The upserted parameter
"""
parameters_path = PathFinder.get_node_parameters_path(project, node_id)
data = DataLoader.load_json(parameters_path)
params = parse_parameters_from_json(data)
node_path = PathFinder.get_node_path(project, node_id)
parameters_model = nodeParameters_simulation.from_file(node_path)

# Check if parameter with same name exists
for p in params:
for p in parameters_model.parameters:
if p.name == parameter.name:
# Update the existing parameter with new values
p.value = parameter.value
Expand All @@ -211,13 +207,10 @@ def upsert_parameter(self, project: ProjectSummary, node_id: str, parameter: Par
break
else:
# Parameter doesn't exist, add it
params.append(parameter)
parameters_model.parameters.append(parameter)

# Write updated parameters back
DataWriter.write_json(
filepath=parameters_path,
data={"parameters": [p.model_dump() for p in params]},
)
# Save updated parameters back
parameters_model.save()
return parameter

def set_parameters(self, project: ProjectSummary, node_id: str, parameters: list[Parameter]) -> list[Parameter]:
Expand All @@ -232,10 +225,10 @@ def set_parameters(self, project: ProjectSummary, node_id: str, parameters: list
Returns:
The list of parameters that were set
"""
parameters_path = PathFinder.get_node_parameters_path(project, node_id)
data = {"parameters": [p.model_dump() for p in parameters]}

DataWriter.write_json(filepath=parameters_path, data=data)
node_path = PathFinder.get_node_path(project, node_id)
parameters_model = nodeParameters_simulation.from_file(node_path)
parameters_model.parameters = parameters
parameters_model.save()
return parameters

def show_parameters(self, project: ProjectSummary, node_id: str) -> str:
Expand Down
106 changes: 106 additions & 0 deletions fluidize/core/types/file_models/json_file_model_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from __future__ import annotations

from typing import Any, TypeVar, Union

from pydantic import BaseModel, ConfigDict, PrivateAttr, ValidationError
from upath import UPath

T = TypeVar("T", bound="JSONFileModelBase")


class JSONFileModelBase(BaseModel):
_filepath: Union[UPath, None] = PrivateAttr(default=None)

@property
def filepath(self) -> UPath:
"""Return the exact path to the model file. Raises if not set."""
if not self._filepath:
raise ValueError()
return self._filepath

@property
def directory(self) -> UPath:
"""Return the folder containing the model file. Raises if filepath not set."""
fp = self.filepath
return fp.parent

@classmethod
def from_file(cls: type[T], directory: Union[str, UPath]) -> T:
from fluidize.core.utils.dataloader.data_loader import DataLoader

filename = getattr(cls, "_filename", None)
if not filename:
raise TypeError()

path = UPath(directory) / filename
data = DataLoader.load_json(path)

if not data:
raise FileNotFoundError()

try:
instance = cls.model_validate(data)
except ValidationError:
raise
except Exception as e:
raise ValueError() from e
else:
instance._filepath = path
return instance

@classmethod
def from_dict_and_path(cls: type[T], data: dict, path: UPath) -> T:
"""Creates a model instance from a dictionary and a path, without reading the file again."""
if not data:
raise ValueError()

try:
instance = cls.model_validate(data)
except ValidationError:
raise
except Exception as e:
raise ValueError() from e
else:
instance._filepath = path
return instance

def model_dump_wrapped(self) -> dict[str, Any]:
config = getattr(self, "Key", None)
key = getattr(config, "key", None)

if not key:
return self.model_dump()

return {key: self.model_dump(mode="json")}

def save(self, directory: UPath | None = None) -> None:
from fluidize.core.utils.dataloader.data_loader import DataLoader
from fluidize.core.utils.dataloader.data_writer import DataWriter

if directory:
filename = getattr(self.__class__, "_filename", None)
if not filename:
raise TypeError()
self._filepath = UPath(directory) / filename

if not self._filepath:
raise ValueError()

# Load existing data to preserve other keys, if the file already exists.
# Pass a new UPath object to avoid issues with object caching if it's the same file.
existing_data = DataLoader.load_json(UPath(self._filepath))

new_data = self.model_dump_wrapped()
existing_data.update(new_data)

DataWriter.write_json(self._filepath, existing_data)

def edit(self, **kwargs: Any) -> None:
for key, value in kwargs.items():
if hasattr(self, key):
setattr(self, key, value)
else:
raise AttributeError()
self.save()

model_config = ConfigDict(arbitrary_types_allowed=True)
56 changes: 56 additions & 0 deletions fluidize/core/types/file_models/parameters_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from typing import Any, ClassVar

from pydantic import Field, model_validator

from fluidize.core.constants import FileConstants
from fluidize.core.types.parameters import Parameter

from .json_file_model_base import JSONFileModelBase


class ParametersModel(JSONFileModelBase):
_filename: ClassVar[str] = FileConstants.PARAMETERS_SUFFIX
"""
A base model for parameters objects stored in JSON structure.

This model provides two main functionalities:
1. A validator to automatically unpack nested data based on a 'key'
from the subclass's Config.
2. A method to wrap the model's data back into the nested structure
for serialization.
"""

parameters: list[Parameter] = Field(default_factory=list)

@model_validator(mode="before")
@classmethod
def _unpack_and_validate(cls, data: Any) -> Any:
"""
Unpacks and validates the data against the key
specified in the subclass's Config.
"""
if not isinstance(data, dict):
return data

config = getattr(cls, "Key", None)
key = getattr(config, "key", None)

# If there's no key in the config or the key is not in the data,
# assume the data is already in the correct, unpacked structure.
if not key or key not in data:
return data

unpacked_data = data[key]
if not isinstance(unpacked_data, list):
# If parameters is not a list, treat it as empty
unpacked_data = []

# Return data in the format expected by the model
return {"parameters": unpacked_data}

def model_dump_wrapped(self) -> dict[str, Any]:
"""Override to avoid double wrapping of parameters key."""
return {"parameters": [p.model_dump() for p in self.parameters]}

class Key:
key = "parameters"
Loading