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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple attributes per node #964

Merged
merged 4 commits into from
Jun 20, 2024
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
3 changes: 2 additions & 1 deletion docs/hamilton-ui/ui.rst
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ Add the following adapter to your code if you have existing Hamilton code:
.build()
)

Then run your DAG, and follow the links in the logs!
Then run your DAG, and follow the links in the logs! Note that the link is correct if you're using
the local mode -- if you're on postgres it links to 8241 (but you'll want to follow it to 8241).

I need some Hamilton code to run
--------------------------------
Expand Down
27 changes: 8 additions & 19 deletions ui/frontend/src/components/dashboard/Runs/Task/Task.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,12 @@ import {
getNodeOutputType,
} from "../../../../state/api/friendlyApi";
import { NodeMetadataPythonType1 } from "../../../../state/api/backendApiRaw";
import { ResultsSummaryView } from "./result-summaries/DataObservability";
import {
MultiResultSummaryView,
} from "./result-summaries/DataObservability";
import { RunLink } from "../../../common/CommonLinks";
import { extractCodeContents } from "../../../../utils/codeExtraction";

/*
This example requires some changes to your config:

```
// tailwind.config.js
module.exports = {
// ...
plugins: [
// ...
require('@tailwindcss/forms'),
],
}
```
*/
const tabs = [
// { name: "Code", href: "#" },
{ name: "Output", href: "#" },
Expand Down Expand Up @@ -334,8 +322,7 @@ export const TaskView = (props: {
};
const whichTab = searchParams.get("tab");
return (
<div className="pt-10">
<div className="text-gray-500 text-xl pb-2">Viewing {taskName}</div>
<div className="pt-10 flex flex-col gap-5">
<div className="sm:hidden">
<label htmlFor="tabs" className="sr-only">
Select a tab
Expand Down Expand Up @@ -363,7 +350,7 @@ export const TaskView = (props: {
<Link
className={classNames(
"text-gray-500 hover:text-gray-700",
"px-3 py-2 font-medium text-md rounded-md"
"py-2 font-medium text-md rounded-md"
)}
to={path.split("/task/")[0]}
>
Expand Down Expand Up @@ -412,6 +399,8 @@ export const TaskView = (props: {
upstreamNodes={upstreamNodes}
downstreamNodes={downstreamNodes}
/> */}
<h2 className="text-gray-800 text-xl pb-2 font-semibold">{taskName}</h2>

{whichTab === "Errors" ? (
<div className="pt-4">
<ErrorView
Expand All @@ -420,7 +409,7 @@ export const TaskView = (props: {
></ErrorView>
</div>
) : whichTab === "Output" ? (
<ResultsSummaryView
<MultiResultSummaryView
projectId={props.projectId}
nodeRunData={nodeRunData}
taskName={taskName}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
AttributeUnsupported1,
} from "../../../../../state/api/backendApiRaw";
import {
NodeRunAttribute,
NodeRunWithAttributes,
getNodeRunAttributes,
} from "../../../../../state/api/friendlyApi";
Expand Down Expand Up @@ -131,11 +132,52 @@ const Unsupported1View = (props: {
);
};

export const ResultsSummaryView = (props: {
export const snakeToTitle = (s: string) => {
return s
.split("_")
.map((i, n) => (n === 0 ? i[0].toUpperCase() : i[0]) + i.slice(1))
.join(" ");
};

export const MultiResultSummaryView = (props: {
nodeRunData: (NodeRunWithAttributes | null)[];
taskName: string | undefined;
projectId: number;
runIds: number[];
}) => {
const attributes = props.nodeRunData.flatMap((i) => i?.attributes || []);
const attributesGroupedByName = attributes.reduce((acc, item) => {
if (acc[item.name]) {
acc[item.name].push(item);
} else {
acc[item.name] = [item];
}
return acc;
}, {} as { [key: string]: NodeRunAttribute[] });
return (
<div className="flex flex-col gap-2">
{Object.entries(attributesGroupedByName).map(([key, value]) => (
<div key={key}>
<h2 className="text-lg font-semibold text-gray-800">
{snakeToTitle(key)}
</h2>
<ResultsSummaryView
runAttributes={value}
taskName={props.taskName}
projectId={props.projectId}
runIds={props.runIds}
/>
</div>
))}
</div>
);
};
export const ResultsSummaryView = (props: {
// nodeRunData: (NodeRunWithAttributes | null)[];
runAttributes: NodeRunAttribute[];
taskName: string | undefined;
projectId: number;
runIds: number[];
}) => {
const allViews = [];
/**
Expand All @@ -148,7 +190,7 @@ export const ResultsSummaryView = (props: {
*/

const primitive1Views = getNodeRunAttributes<AttributePrimitive1>(
props.nodeRunData.flatMap((i) => i?.attributes || []),
props.runAttributes,
props.runIds,
"AttributePrimitive1"
);
Expand All @@ -163,11 +205,10 @@ export const ResultsSummaryView = (props: {
);
}


// ... [similar blocks for other attributes]

// const error1Views = getNodeRunAttributes<AttributeError1>(
// props.nodeRunData.flatMap((i) => i?.attributes || []),
// props.runAttributes
// "AttributeError1"
// );
// if (error1Views.length > 0) {
Expand All @@ -181,7 +222,7 @@ export const ResultsSummaryView = (props: {
// }

const dict1Views = getNodeRunAttributes<AttributeDict1>(
props.nodeRunData.flatMap((i) => i?.attributes || []),
props.runAttributes,
props.runIds,
"AttributeDict1"
);
Expand All @@ -197,7 +238,7 @@ export const ResultsSummaryView = (props: {
}

const dict2Views = getNodeRunAttributes<AttributeDict2>(
props.nodeRunData.flatMap((i) => i?.attributes || []),
props.runAttributes,
props.runIds,
"AttributeDict2"
);
Expand All @@ -213,7 +254,7 @@ export const ResultsSummaryView = (props: {

const dagworksDescribe3Views =
getNodeRunAttributes<AttributeDagworksDescribe3>(
props.nodeRunData.flatMap((i) => i?.attributes || []),
props.runAttributes,
props.runIds,
"AttributeDagworksDescribe3"
);
Expand All @@ -229,7 +270,7 @@ export const ResultsSummaryView = (props: {
}

const pandasDescribe1View = getNodeRunAttributes<AttributePandasDescribe1>(
props.nodeRunData.flatMap((i) => i?.attributes || []),
props.runAttributes,
props.runIds,
"AttributePandasDescribe1"
);
Expand All @@ -246,7 +287,7 @@ export const ResultsSummaryView = (props: {
}

const unsupportedViews = getNodeRunAttributes<AttributeUnsupported1>(
props.nodeRunData.flatMap((i) => i?.attributes || []),
props.runAttributes,
props.runIds,
"AttributeUnsupported1"
);
Expand All @@ -262,7 +303,7 @@ export const ResultsSummaryView = (props: {
}

return (
<div className="flex flex-col">
<div className="flex flex-col border-l-8 my-2 border-gray-100 hover:bg-gray-100">
{allViews.map((item, i) => {
return <div key={i}>{item}</div>;
})}
Expand Down
14 changes: 8 additions & 6 deletions ui/sdk/src/hamilton_sdk/api/clients.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import abc
import datetime
import functools
import logging
import queue
import threading
import time
from collections import defaultdict
from functools import reduce
from typing import Any, Callable, Dict, List
from urllib.parse import urlencode

Expand Down Expand Up @@ -233,12 +233,14 @@ def flush(self, batch):
continue
task_updates[task_update["node_name"]].append(task_update)

# this assumes correct ordering of the attributes and task_updates
attributes_list = [
reduce(lambda x, y: {**x, **y}, attributes[node_name]) for node_name in attributes
]
# We do not care about disambiguating here -- only one named attribute should be logged

attributes_list = []
for node_name in attributes:
attributes_list.extend(attributes[node_name])
# in this case we do care about order so we don't send double the updates.
task_updates_list = [
reduce(lambda x, y: {**x, **y}, task_updates[node_name])
functools.reduce(lambda x, y: {**x, **y}, task_updates[node_name])
for node_name in task_updates
]

Expand Down
2 changes: 1 addition & 1 deletion ui/sdk/src/hamilton_sdk/api/constants.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
HAMILTON_API_URL = "http://localhost:8241"
HAMILTON_UI_URL = "http://localhost:8242"
HAMILTON_UI_URL = "http://localhost:8241" # optimizing for mini-mode
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

err -- docs need to be updated then for use with docker then right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or there needs to be a way to know which URL to use that the SDK can figure out

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See commit notes, this was the quickest change but yeah we can update docs

Copy link
Collaborator

@zilto zilto Jun 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

side note: 127.0.0.1 should be preferred to localhost ref.

Also, for mini-mode, the entrypoint 127.0.0.1 should be preferred to 0.0.0.0. But this would provide minimal value if requires a bigger refactoring because Docker-mode would require 0.0.0.0 most likely

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I'm generally against using a hardcoded value for the purpose of small optimizations, although there are other reasons... Good video.

Loading