Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

bump fastapi and add pydantic compatibility #1529

1 change: 1 addition & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Please follow the established format:
## Bug fixes and other changes

- Fix for Kedro Viz Connection Error (#1507)
- Add support for pydantic v2 and fastapi >= 0.100.0 (#1529)
fdroessler marked this conversation as resolved.
Show resolved Hide resolved

# Release 6.5.1

Expand Down
3 changes: 2 additions & 1 deletion package/features/steps/lower_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
semver==3.0
ipython==7.0.0
fastapi==0.73.0
fastapi==0.100.0
fsspec==2021.4
aiofiles==22.1.0
uvicorn[standard]==0.22.0
Expand All @@ -13,3 +13,4 @@ strawberry-graphql==0.192.0
networkx==2.5
orjson==3.9
secure==0.3.0
pydantic<2
fdroessler marked this conversation as resolved.
Show resolved Hide resolved
239 changes: 138 additions & 101 deletions package/kedro_viz/api/rest/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
from typing import Any, Dict, List, Optional, Union

import orjson
from fastapi._compat import PYDANTIC_V2
from fastapi.responses import ORJSONResponse
from pydantic import BaseModel
from pydantic import BaseModel, ConfigDict

fdroessler marked this conversation as resolved.
Show resolved Hide resolved
from kedro_viz.data_access import data_access_manager

Expand All @@ -15,8 +16,12 @@ class APIErrorMessage(BaseModel):


class BaseAPIResponse(BaseModel, abc.ABC):
class Config:
orm_mode = True
if PYDANTIC_V2:
model_config = ConfigDict(from_attributes=True)
else:

class Config:
orm_mode = True


class BaseGraphNodeAPIResponse(BaseAPIResponse):
Expand All @@ -27,58 +32,70 @@ class BaseGraphNodeAPIResponse(BaseAPIResponse):
type: str

# If a node is a ModularPipeline node, this value will be None, hence Optional.
modular_pipelines: Optional[List[str]]
modular_pipelines: Optional[List[str]] = None


task_node_api_response_example = {
"example": {
"id": "6ab908b8",
"name": "split_data_node",
"tags": [],
"pipelines": ["__default__", "ds"],
"modular_pipelines": [],
"type": "task",
"parameters": {
"test_size": 0.2,
"random_state": 3,
"features": [
"engines",
"passenger_capacity",
"crew",
"d_check_complete",
"moon_clearance_complete",
"iata_approved",
"company_rating",
"review_scores_rating",
],
},
}
}


class TaskNodeAPIResponse(BaseGraphNodeAPIResponse):
parameters: Dict
if PYDANTIC_V2:
model_config = ConfigDict(json_schema_extra=task_node_api_response_example) # type: ignore
else:

class Config:
schema_extra = task_node_api_response_example

class Config:
schema_extra = {
"example": {
"id": "6ab908b8",
"name": "split_data_node",
"tags": [],
"pipelines": ["__default__", "ds"],
"modular_pipelines": [],
"type": "task",
"parameters": {
"test_size": 0.2,
"random_state": 3,
"features": [
"engines",
"passenger_capacity",
"crew",
"d_check_complete",
"moon_clearance_complete",
"iata_approved",
"company_rating",
"review_scores_rating",
],
},
}
}

data_node_api_response_example = {
"example": {
"id": "d7b83b05",
"name": "master_table",
"tags": [],
"pipelines": ["__default__", "dp", "ds"],
"modular_pipelines": [],
"type": "data",
"layer": "primary",
"dataset_type": "kedro.extras.datasets.pandas.csv_dataset.CSVDataSet",
"stats": {"rows": 10, "columns": 2, "file_size": 2300},
}
}


class DataNodeAPIResponse(BaseGraphNodeAPIResponse):
layer: Optional[str]
dataset_type: Optional[str]
stats: Optional[Dict]

class Config:
schema_extra = {
"example": {
"id": "d7b83b05",
"name": "master_table",
"tags": [],
"pipelines": ["__default__", "dp", "ds"],
"modular_pipelines": [],
"type": "data",
"layer": "primary",
"dataset_type": "kedro.extras.datasets.pandas.csv_dataset.CSVDataSet",
"stats": {"rows": 10, "columns": 2, "file_size": 2300},
}
}
layer: Optional[str] = None
dataset_type: Optional[str] = None
stats: Optional[Dict] = None
if PYDANTIC_V2:
model_config = ConfigDict(json_schema_extra=data_node_api_response_example) # type: ignore
else:

class Config:
schema_extra = data_node_api_response_example


NodeAPIResponse = Union[
Expand All @@ -87,77 +104,97 @@ class Config:
]


task_node_metadata_api_example = {
"example": {
"code": "def split_data(data: pd.DataFrame, parameters: Dict) -> Tuple:",
"filepath": "proj/src/new_kedro_project/pipelines/data_science/nodes.py",
"parameters": {"test_size": 0.2},
"inputs": ["params:input1", "input2"],
"outputs": ["output1"],
"run_command": "kedro run --to-nodes=split_data",
}
}


class TaskNodeMetadataAPIResponse(BaseAPIResponse):
code: Optional[str]
filepath: Optional[str]
parameters: Optional[Dict]
code: Optional[str] = None
filepath: Optional[str] = None
parameters: Optional[Dict] = None
inputs: List[str]
outputs: List[str]
run_command: Optional[str]

class Config:
schema_extra = {
"example": {
"code": "def split_data(data: pd.DataFrame, parameters: Dict) -> Tuple:",
"filepath": "proj/src/new_kedro_project/pipelines/data_science/nodes.py",
"parameters": {"test_size": 0.2},
"inputs": ["params:input1", "input2"],
"outputs": ["output1"],
"run_command": "kedro run --to-nodes=split_data",
}
}
run_command: Optional[str] = None
if PYDANTIC_V2:
model_config = ConfigDict(json_schema_extra=task_node_metadata_api_example) # type: ignore
else:

class Config:
schema_extra = task_node_metadata_api_example


data_node_metadata_api_example = {
"example": {
"filepath": "/my-kedro-project/data/03_primary/master_table.csv",
"type": "pandas.csv_dataset.CSVDataSet",
"run_command": "kedro run --to-outputs=master_table",
}
}


class DataNodeMetadataAPIResponse(BaseAPIResponse):
filepath: Optional[str]
filepath: Optional[str] = None
type: str
plot: Optional[Dict]
image: Optional[str]
tracking_data: Optional[Dict]
run_command: Optional[str]
preview: Optional[Dict]
stats: Optional[Dict]

class Config:
schema_extra = {
"example": {
"filepath": "/my-kedro-project/data/03_primary/master_table.csv",
"type": "pandas.csv_dataset.CSVDataSet",
"run_command": "kedro run --to-outputs=master_table",
}
}
plot: Optional[Dict] = None
image: Optional[str] = None
tracking_data: Optional[Dict] = None
run_command: Optional[str] = None
preview: Optional[Dict] = None
stats: Optional[Dict] = None
if PYDANTIC_V2:
model_config = ConfigDict(json_schema_extra=data_node_metadata_api_example) # type: ignore
else:

class Config:
schema_extra = data_node_metadata_api_example


class TranscodedDataNodeMetadataAPIReponse(BaseAPIResponse):
filepath: str
original_type: str
transcoded_types: List[str]
run_command: Optional[str]
stats: Optional[Dict]
run_command: Optional[str] = None
stats: Optional[Dict] = None


parameters_node_metaxata_api_example = {
"example": {
"parameters": {
"test_size": 0.2,
"random_state": 3,
"features": [
"engines",
"passenger_capacity",
"crew",
"d_check_complete",
"moon_clearance_complete",
"iata_approved",
"company_rating",
"review_scores_rating",
],
}
}
}


class ParametersNodeMetadataAPIResponse(BaseAPIResponse):
parameters: Dict
if PYDANTIC_V2:
model_config = ConfigDict(
json_schema_extra=parameters_node_metaxata_api_example # type: ignore
)
else:

class Config:
schema_extra = {
"example": {
"parameters": {
"test_size": 0.2,
"random_state": 3,
"features": [
"engines",
"passenger_capacity",
"crew",
"d_check_complete",
"moon_clearance_complete",
"iata_approved",
"company_rating",
"review_scores_rating",
],
}
}
}
class Config:
schema_extra = parameters_node_metaxata_api_example


NodeMetadataAPIResponse = Union[
Expand All @@ -179,7 +216,7 @@ class NamedEntityAPIResponse(BaseAPIResponse):
"""

id: str
name: Optional[str]
name: Optional[str] = None


class ModularPipelineChildAPIResponse(BaseAPIResponse):
Expand Down
16 changes: 12 additions & 4 deletions package/kedro_viz/models/experiment_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
from enum import Enum
from typing import TYPE_CHECKING, Any, Dict

from fastapi._compat import PYDANTIC_V2
from kedro.io import Version
from pydantic import ConfigDict
from sqlalchemy import Column
from sqlalchemy.orm import declarative_base # type: ignore
from sqlalchemy.sql.schema import ForeignKey
Expand All @@ -33,9 +35,12 @@ class RunModel(Base): # type: ignore

id = Column(String, primary_key=True, index=True)
blob = Column(JSON)
if PYDANTIC_V2:
model_config = ConfigDict(from_attributes=True)
else:

class Config:
orm_mode = True
class Config:
orm_mode = True


class UserRunDetailsModel(Base): # type: ignore
Expand All @@ -48,9 +53,12 @@ class UserRunDetailsModel(Base): # type: ignore
bookmark = Column(Boolean, default=False)
title = Column(String)
notes = Column(String)
if PYDANTIC_V2:
model_config = ConfigDict(from_attributes=True)
else:

class Config:
orm_mode = True
class Config:
orm_mode = True
fdroessler marked this conversation as resolved.
Show resolved Hide resolved


class TrackingDatasetGroup(str, Enum):
Expand Down
4 changes: 2 additions & 2 deletions package/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
semver>=2.10 # Needs to be at least 2.10.0 to make use of `VersionInfo.match`.
kedro>=0.17.5
ipython>=7.0.0, <9.0
fastapi>=0.73.0, <0.96.0
fsspec>=2021.4, <2024.1
fastapi>=0.73.0, <0.104.0
fdroessler marked this conversation as resolved.
Show resolved Hide resolved
fsspec>=2021.4, <2024.1
aiofiles==22.1.0
uvicorn[standard]~=0.22.0
watchgod~=0.8.2
Expand Down
4 changes: 2 additions & 2 deletions package/test_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ behave~=1.2
black~=23.3
boto3~=1.26
flake8~=5.0
fastapi[all]>=0.73.0, <0.96.0
fastapi[all]>=0.73.0, <0.104.0
isort~=5.11
matplotlib~=3.5
mypy~=1.0
moto~=4.1.14
moto~=4.1.14
psutil==5.9.5 # same as Kedro for now
pylint~=2.17
pytest~=7.4
Expand Down