merging branch local two edges
This commit is contained in:
commit
9ad10b33f2
17 changed files with 227 additions and 500 deletions
|
|
@ -1,4 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from langchain_anthropic.chat_models import ChatAnthropic
|
||||
from pydantic.v1 import SecretStr
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Any, Dict, Optional
|
||||
from typing import Optional
|
||||
|
||||
from langchain_community.chat_models.litellm import ChatLiteLLM, ChatLiteLLMException
|
||||
from langflow.base.constants import STREAM_INFO_TEXT
|
||||
|
|
@ -177,4 +177,4 @@ class ChatLiteLLMModelComponent(LCModelComponent):
|
|||
)
|
||||
|
||||
return output
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from langchain_groq import ChatGroq
|
||||
from langflow.base.models.groq_constants import MODEL_NAMES
|
||||
|
|
@ -103,4 +102,4 @@ class GroqModel(LCModelComponent):
|
|||
streaming=stream,
|
||||
)
|
||||
|
||||
return output
|
||||
return output
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
from typing import Optional
|
||||
|
||||
from langchain_community.chat_models.huggingface import ChatHuggingFace
|
||||
from langchain_community.llms.huggingface_endpoint import HuggingFaceEndpoint
|
||||
|
|
@ -65,4 +64,4 @@ class HuggingFaceEndpointsComponent(LCModelComponent):
|
|||
raise ValueError("Could not connect to HuggingFace Endpoints API.") from e
|
||||
|
||||
output = ChatHuggingFace(llm=llm)
|
||||
return output
|
||||
return output
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from langchain_community.chat_models import ChatOllama
|
||||
from langflow.base.constants import STREAM_INFO_TEXT
|
||||
|
|
@ -226,4 +225,4 @@ class ChatOllamaComponent(LCModelComponent):
|
|||
except Exception as e:
|
||||
raise ValueError("Could not initialize Ollama LLM.") from e
|
||||
|
||||
return output
|
||||
return output
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ from langflow.type_extraction.type_extraction import (
|
|||
extract_union_types_from_generic_alias,
|
||||
)
|
||||
from langflow.utils import validate
|
||||
from pydantic import BaseModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.graph.graph.base import Graph
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from langflow.graph.utils import UnbuiltObject, UnbuiltResult
|
|||
from langflow.interface.initialize import loading
|
||||
from langflow.interface.listing import lazy_load_dict
|
||||
from langflow.schema.artifact import ArtifactType
|
||||
from langflow.schema.schema import INPUT_FIELD_NAME, Log, build_logs
|
||||
from langflow.schema.schema import INPUT_FIELD_NAME, Log
|
||||
from langflow.services.deps import get_storage_service
|
||||
from langflow.services.monitor.utils import log_transaction
|
||||
from langflow.utils.constants import DIRECT_TYPES
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -117,51 +117,3 @@ def set_langchain_cache(settings):
|
|||
logger.warning(f"Could not import {cache_type}. ")
|
||||
else:
|
||||
logger.info("No LLM cache set.")
|
||||
|
||||
|
||||
def build_template_from_class(name: str, type_to_cls_dict: Dict, add_function: bool = False):
|
||||
classes = [item.__name__ for item in type_to_cls_dict.values()]
|
||||
|
||||
# Raise error if name is not in chains
|
||||
if name not in classes:
|
||||
raise ValueError(f"{name} not found.")
|
||||
|
||||
for _type, v in type_to_cls_dict.items():
|
||||
if v.__name__ == name:
|
||||
_class = v
|
||||
|
||||
# Get the docstring
|
||||
docs = parse(_class.__doc__)
|
||||
|
||||
variables = {"_type": _type}
|
||||
|
||||
if "__fields__" in _class.__dict__:
|
||||
for class_field_items, value in _class.__fields__.items():
|
||||
if class_field_items in ["callback_manager"]:
|
||||
continue
|
||||
variables[class_field_items] = {}
|
||||
for name_, value_ in value.__repr_args__():
|
||||
if name_ == "default_factory":
|
||||
try:
|
||||
variables[class_field_items]["default"] = get_default_factory(
|
||||
module=_class.__base__.__module__,
|
||||
function=value_,
|
||||
)
|
||||
except Exception:
|
||||
variables[class_field_items]["default"] = None
|
||||
elif name_ not in ["name"]:
|
||||
variables[class_field_items][name_] = value_
|
||||
|
||||
variables[class_field_items]["placeholder"] = (
|
||||
docs.params[class_field_items] if class_field_items in docs.params else ""
|
||||
)
|
||||
base_classes = get_base_classes(_class)
|
||||
# Adding function to base classes to allow
|
||||
# the output to be a function
|
||||
if add_function:
|
||||
base_classes.append("Callable")
|
||||
return {
|
||||
"template": format_dict(variables, name),
|
||||
"description": docs.short_description or "",
|
||||
"base_classes": base_classes,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Any, Literal
|
||||
from typing import Literal
|
||||
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ export default function InputComponent({
|
|||
blurOnEnter = false,
|
||||
optionsIcon = "ChevronsUpDown",
|
||||
selectedOption,
|
||||
|
||||
setSelectedOption,
|
||||
selectedOptions = [],
|
||||
setSelectedOptions,
|
||||
|
|
@ -72,7 +71,7 @@ export default function InputComponent({
|
|||
editNode ? "input-edit-node" : "",
|
||||
password && editNode ? "pr-8" : "",
|
||||
password && !editNode ? "pr-10" : "",
|
||||
className!
|
||||
className!,
|
||||
)}
|
||||
placeholder={password && editNode ? "Key" : placeholder}
|
||||
onChange={(e) => {
|
||||
|
|
@ -155,7 +154,7 @@ export default function InputComponent({
|
|||
<span
|
||||
className={cn(
|
||||
password && selectedOption === "" ? "right-8" : "right-0",
|
||||
"absolute inset-y-0 flex items-center pr-2.5"
|
||||
"absolute inset-y-0 flex items-center pr-2.5",
|
||||
)}
|
||||
>
|
||||
<button
|
||||
|
|
@ -168,7 +167,7 @@ export default function InputComponent({
|
|||
onChange && setSelectedOption && selectedOption !== ""
|
||||
? "text-medium-indigo"
|
||||
: "text-muted-foreground",
|
||||
"hover:text-accent-foreground"
|
||||
"hover:text-accent-foreground",
|
||||
)}
|
||||
>
|
||||
<ForwardedIconComponent
|
||||
|
|
@ -188,7 +187,7 @@ export default function InputComponent({
|
|||
"mb-px",
|
||||
editNode
|
||||
? "input-component-true-button"
|
||||
: "input-component-false-button"
|
||||
: "input-component-false-button",
|
||||
)}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
|
|
@ -205,7 +204,7 @@ export default function InputComponent({
|
|||
className={classNames(
|
||||
editNode
|
||||
? "input-component-true-svg"
|
||||
: "input-component-false-svg"
|
||||
: "input-component-false-svg",
|
||||
)}
|
||||
>
|
||||
<path
|
||||
|
|
@ -224,7 +223,7 @@ export default function InputComponent({
|
|||
className={classNames(
|
||||
editNode
|
||||
? "input-component-true-svg"
|
||||
: "input-component-false-svg"
|
||||
: "input-component-false-svg",
|
||||
)}
|
||||
>
|
||||
<path
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
import TextModal from "../../modals/textModal";
|
||||
|
||||
export default function StringReader({
|
||||
string,
|
||||
}: {
|
||||
string: string;
|
||||
}): JSX.Element {
|
||||
return <span className="truncate">{string}</span>;
|
||||
return string.length > 10 ? (
|
||||
<TextModal value={string}>
|
||||
<span className="truncate">{string}</span>
|
||||
</TextModal>
|
||||
) : (
|
||||
<span className="truncate">{string}</span>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ export const CODE_PROMPT_DIALOG_SUBTITLE =
|
|||
|
||||
export const CODE_DICT_DIALOG_SUBTITLE =
|
||||
"Edit your dictionary. This dialog allows you to create your own customized dictionary. You can add as many key-value pairs as you want. While in edit mode, you can enter ({}) or ([]), and this will result in adding a new object or array.";
|
||||
|
||||
/**
|
||||
* The base text for subtitle of Prompt Dialog
|
||||
* @constant
|
||||
|
|
@ -859,4 +860,4 @@ export const ERROR_UPDATING_COMPONENT =
|
|||
export const TITLE_ERROR_UPDATING_COMPONENT =
|
||||
"Error while updating the Component";
|
||||
|
||||
export const EMPTY_INPUT_SEND_MESSAGE = "No input message provided.";
|
||||
export const EMPTY_INPUT_SEND_MESSAGE = "No input message provided.";
|
||||
|
|
|
|||
56
src/frontend/src/modals/textModal/index.tsx
Normal file
56
src/frontend/src/modals/textModal/index.tsx
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import "ace-builds/src-noconflict/ace";
|
||||
import "ace-builds/src-noconflict/ext-language_tools";
|
||||
import "ace-builds/src-noconflict/mode-python";
|
||||
import "ace-builds/src-noconflict/theme-github";
|
||||
import "ace-builds/src-noconflict/theme-twilight";
|
||||
// import "ace-builds/webpack-resolver";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { useEffect, useState } from "react";
|
||||
import JsonView from "react18-json-view";
|
||||
import "react18-json-view/src/dark.css";
|
||||
import "react18-json-view/src/style.css";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import {
|
||||
CODE_DICT_DIALOG_SUBTITLE,
|
||||
TEXT_DIALOG_SUBTITLE,
|
||||
} from "../../constants/constants";
|
||||
import { useDarkStore } from "../../stores/darkStore";
|
||||
import BaseModal from "../baseModal";
|
||||
import TextOutputView from "../../shared/components/textOutputView";
|
||||
import { Button } from "../../components/ui/button";
|
||||
|
||||
export default function TextModal({
|
||||
children,
|
||||
value,
|
||||
}: {
|
||||
children: JSX.Element;
|
||||
value: Object;
|
||||
}): JSX.Element {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<BaseModal size="medium-h-full" open={open} setOpen={setOpen}>
|
||||
<BaseModal.Trigger className="h-full">{children}</BaseModal.Trigger>
|
||||
<BaseModal.Header description={"Inspect the text below."}>
|
||||
<span className="pr-2">{"View Text"}</span>
|
||||
<IconComponent
|
||||
name="Type"
|
||||
className="h-6 w-6 pl-1 text-primary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</BaseModal.Header>
|
||||
<BaseModal.Content>
|
||||
<div className="flex h-full w-full flex-col transition-all">
|
||||
<TextOutputView value={value} left={false} />
|
||||
</div>
|
||||
</BaseModal.Content>
|
||||
<BaseModal.Footer>
|
||||
<div className="flex w-full justify-end pt-2">
|
||||
<Button className="flex gap-2 px-3" onClick={() => setOpen(false)}>
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
</BaseModal.Footer>
|
||||
</BaseModal>
|
||||
);
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
updateFlowPool: (
|
||||
nodeId: string,
|
||||
data: VertexBuildTypeAPI | ChatOutputType | ChatInputType,
|
||||
buildId?: string
|
||||
buildId?: string,
|
||||
) => {
|
||||
let newFlowPool = cloneDeep({ ...get().flowPool });
|
||||
if (!newFlowPool[nodeId]) {
|
||||
|
|
@ -167,7 +167,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
flowsManager.autoSaveCurrentFlow(
|
||||
newChange,
|
||||
newEdges,
|
||||
get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }
|
||||
get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 },
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
@ -183,7 +183,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
flowsManager.autoSaveCurrentFlow(
|
||||
get().nodes,
|
||||
newChange,
|
||||
get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }
|
||||
get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 },
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
@ -201,7 +201,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
return newChange;
|
||||
}
|
||||
return node;
|
||||
})
|
||||
}),
|
||||
);
|
||||
},
|
||||
getNode: (id: string) => {
|
||||
|
|
@ -212,8 +212,8 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
get().nodes.filter((node) =>
|
||||
typeof nodeId === "string"
|
||||
? node.id !== nodeId
|
||||
: !nodeId.includes(node.id)
|
||||
)
|
||||
: !nodeId.includes(node.id),
|
||||
),
|
||||
);
|
||||
},
|
||||
deleteEdge: (edgeId) => {
|
||||
|
|
@ -221,8 +221,8 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
get().edges.filter((edge) =>
|
||||
typeof edgeId === "string"
|
||||
? edge.id !== edgeId
|
||||
: !edgeId.includes(edge.id)
|
||||
)
|
||||
: !edgeId.includes(edge.id),
|
||||
),
|
||||
);
|
||||
},
|
||||
paste: (selection, position) => {
|
||||
|
|
@ -288,7 +288,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
let source = idsMap[edge.source];
|
||||
let target = idsMap[edge.target];
|
||||
const sourceHandleObject: sourceHandleType = scapeJSONParse(
|
||||
edge.sourceHandle!
|
||||
edge.sourceHandle!,
|
||||
);
|
||||
let sourceHandle = scapedJSONStringfy({
|
||||
...sourceHandleObject,
|
||||
|
|
@ -298,7 +298,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
|
||||
edge.data.sourceHandle = sourceHandleObject;
|
||||
const targetHandleObject: targetHandleType = scapeJSONParse(
|
||||
edge.targetHandle!
|
||||
edge.targetHandle!,
|
||||
);
|
||||
let targetHandle = scapedJSONStringfy({
|
||||
...targetHandleObject,
|
||||
|
|
@ -317,7 +317,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
data: cloneDeep(edge.data),
|
||||
selected: false,
|
||||
},
|
||||
newEdges.map((edge) => ({ ...edge, selected: false }))
|
||||
newEdges.map((edge) => ({ ...edge, selected: false })),
|
||||
);
|
||||
});
|
||||
get().setEdges(newEdges);
|
||||
|
|
@ -336,10 +336,10 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
});
|
||||
|
||||
const newNodes = get().nodes.filter(
|
||||
(node) => !nodesIdsSelected.includes(node.id)
|
||||
(node) => !nodesIdsSelected.includes(node.id),
|
||||
);
|
||||
const newEdges = get().edges.filter(
|
||||
(edge) => !edgesIdsSelected.includes(edge.id)
|
||||
(edge) => !edgesIdsSelected.includes(edge.id),
|
||||
);
|
||||
|
||||
set({ nodes: newNodes, edges: newEdges });
|
||||
|
|
@ -397,7 +397,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
// style: { stroke: "#555" },
|
||||
// className: "stroke-foreground stroke-connection",
|
||||
},
|
||||
oldEdges
|
||||
oldEdges,
|
||||
);
|
||||
|
||||
return newEdges;
|
||||
|
|
@ -407,7 +407,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
.autoSaveCurrentFlow(
|
||||
get().nodes,
|
||||
newEdges,
|
||||
get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }
|
||||
get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 },
|
||||
);
|
||||
},
|
||||
unselectAll: () => {
|
||||
|
|
@ -442,7 +442,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
function validateSubgraph(nodes: string[]) {
|
||||
const errorsObjs = validateNodes(
|
||||
get().nodes.filter((node) => nodes.includes(node.id)),
|
||||
get().edges
|
||||
get().edges,
|
||||
);
|
||||
|
||||
const errors = errorsObjs.map((obj) => obj.errors).flat();
|
||||
|
|
@ -461,13 +461,13 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
function handleBuildUpdate(
|
||||
vertexBuildData: VertexBuildTypeAPI,
|
||||
status: BuildStatus,
|
||||
runId: string
|
||||
runId: string,
|
||||
) {
|
||||
if (vertexBuildData && vertexBuildData.inactivated_vertices) {
|
||||
get().removeFromVerticesBuild(vertexBuildData.inactivated_vertices);
|
||||
get().updateBuildStatus(
|
||||
vertexBuildData.inactivated_vertices,
|
||||
BuildStatus.INACTIVE
|
||||
BuildStatus.INACTIVE,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -483,14 +483,14 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
|
||||
// next_vertices_ids should be next_vertices_ids without the inactivated vertices
|
||||
const next_vertices_ids = vertexBuildData.next_vertices_ids.filter(
|
||||
(id) => !vertexBuildData.inactivated_vertices?.includes(id)
|
||||
(id) => !vertexBuildData.inactivated_vertices?.includes(id),
|
||||
);
|
||||
const top_level_vertices = vertexBuildData.top_level_vertices.filter(
|
||||
(vertex) => !vertexBuildData.inactivated_vertices?.includes(vertex)
|
||||
(vertex) => !vertexBuildData.inactivated_vertices?.includes(vertex),
|
||||
);
|
||||
const nextVertices: VertexLayerElementType[] = zip(
|
||||
next_vertices_ids,
|
||||
top_level_vertices
|
||||
top_level_vertices,
|
||||
).map(([id, reference]) => ({ id: id!, reference }));
|
||||
|
||||
const newLayers = [
|
||||
|
|
@ -512,7 +512,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
|
||||
get().addDataToFlowPool(
|
||||
{ ...vertexBuildData, run_id: runId },
|
||||
vertexBuildData.id
|
||||
vertexBuildData.id,
|
||||
);
|
||||
|
||||
useFlowStore.getState().updateBuildStatus([vertexBuildData.id], status);
|
||||
|
|
@ -521,7 +521,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
const newFlowBuildStatus = { ...get().flowBuildStatus };
|
||||
// filter out the vertices that are not status
|
||||
const verticesToUpdate = verticesIds?.filter(
|
||||
(id) => newFlowBuildStatus[id]?.status !== BuildStatus.BUILT
|
||||
(id) => newFlowBuildStatus[id]?.status !== BuildStatus.BUILT,
|
||||
);
|
||||
|
||||
if (verticesToUpdate) {
|
||||
|
|
@ -542,15 +542,15 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
onBuildComplete: (allNodesValid) => {
|
||||
const nodeId = startNodeId || stopNodeId;
|
||||
if (!silent) {
|
||||
if (nodeId && allNodesValid) {
|
||||
if (allNodesValid) {
|
||||
setSuccessData({
|
||||
title: `${
|
||||
get().nodes.find((node) => node.id === nodeId)?.data.node
|
||||
?.display_name
|
||||
} built successfully`,
|
||||
title: nodeId
|
||||
? `${
|
||||
get().nodes.find((node) => node.id === nodeId)?.data.node
|
||||
?.display_name
|
||||
} built successfully`
|
||||
: FLOW_BUILD_SUCCESS_ALERT,
|
||||
});
|
||||
} else {
|
||||
setSuccessData({ title: FLOW_BUILD_SUCCESS_ALERT });
|
||||
}
|
||||
}
|
||||
get().setIsBuilding(false);
|
||||
|
|
@ -591,7 +591,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
verticesLayers: VertexLayerElementType[][];
|
||||
runId: string;
|
||||
verticesToRun: string[];
|
||||
} | null
|
||||
} | null,
|
||||
) => {
|
||||
set({ verticesBuild: vertices });
|
||||
},
|
||||
|
|
@ -616,7 +616,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
|
|||
// that are going to be built
|
||||
verticesIds: get().verticesBuild!.verticesIds.filter(
|
||||
// keep the vertices that are not in the list of vertices to remove
|
||||
(vertex) => !vertices.includes(vertex)
|
||||
(vertex) => !vertices.includes(vertex),
|
||||
),
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import {
|
|||
updateEdgesHandleIdsType,
|
||||
} from "../types/utils/reactflowUtils";
|
||||
import { createRandomKey, toTitleCase } from "./utils";
|
||||
const uid = new ShortUniqueId({ length: 5 });
|
||||
const uid = new ShortUniqueId();
|
||||
|
||||
export function checkChatInput(nodes: Node[]) {
|
||||
return nodes.some((node) => node.data.type === "ChatInput");
|
||||
|
|
@ -712,7 +712,6 @@ export function generateFlow(
|
|||
name: string,
|
||||
): generateFlowType {
|
||||
const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } };
|
||||
const uid = new ShortUniqueId();
|
||||
/* remove edges that are not connected to selected nodes on both ends
|
||||
*/
|
||||
newFlowData.edges = edges.filter(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import importlib
|
|||
from typing import Dict, List, Optional
|
||||
|
||||
import pytest
|
||||
from langflow.interface.utils import build_template_from_class
|
||||
from langflow.utils.util import build_template_from_function, get_base_classes, get_default_factory
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
|
@ -68,25 +67,6 @@ def test_build_template_from_function():
|
|||
build_template_from_function("NonExistent", type_to_loader_dict)
|
||||
|
||||
|
||||
# Test build_template_from_class
|
||||
def test_build_template_from_class():
|
||||
type_to_cls_dict: Dict[str, type] = {"parent": Parent, "child": Child}
|
||||
|
||||
# Test valid input
|
||||
result = build_template_from_class("Child", type_to_cls_dict)
|
||||
assert result is not None
|
||||
assert "template" in result
|
||||
assert "description" in result
|
||||
assert "base_classes" in result
|
||||
assert "Child" in result["base_classes"]
|
||||
assert "Parent" in result["base_classes"]
|
||||
assert result["description"] == "Child Class"
|
||||
|
||||
# Test invalid input
|
||||
with pytest.raises(ValueError, match="InvalidClass not found."):
|
||||
build_template_from_class("InvalidClass", type_to_cls_dict)
|
||||
|
||||
|
||||
# Test get_base_classes
|
||||
def test_get_base_classes():
|
||||
base_classes_parent = get_base_classes(Parent)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue