Skip to content

Commit

Permalink
Merge branch 'master' into bedrock-integration
Browse files Browse the repository at this point in the history
  • Loading branch information
J2-D2-3PO authored Jan 22, 2025
2 parents 1a02e37 + 980abad commit adf16aa
Show file tree
Hide file tree
Showing 26 changed files with 562 additions and 109 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ docs:
build:
uv build

prerelease-dry-run:
uv run ./weave/scripts/prerelease_dry_run.py

prepare-release: docs build

synchronize-base-object-schemas:
Expand Down
4 changes: 3 additions & 1 deletion dev_docs/RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ This document outlines how to publish a new Weave release to our public [PyPI pa

1. Verify the head of master is ready for release and announce merge freeze to the Weave team while the release is being published (Either ask an admin on the Weave repo to place a freeze on https://www.mergefreeze.com/ or use the mergefreeze Slack app if it is set up or just post in Slack)

2. You should also run through this [sample notebook](https://colab.research.google.com/drive/1DmkLzhFCFC0OoN-ggBDoG1nejGw2jQZy#scrollTo=29hJrcJQA7jZ) remember to install from master. You can also just run the [quickstart](http://wandb.me/weave_colab).
2. Manual Verifications:
- Run `make prerelease-dry-run` to verify that the dry run script works.
- You should also run through this [sample notebook](https://colab.research.google.com/drive/1DmkLzhFCFC0OoN-ggBDoG1nejGw2jQZy#scrollTo=29hJrcJQA7jZ) remember to install from master. You can also just run the [quickstart](http://wandb.me/weave_colab).

3. To prepare a PATCH release, go to GitHub Actions and run the [bump-python-sdk-version](https://github.com/wandb/weave/actions/workflows/bump_version.yaml) workflow on master. This will:

Expand Down
22 changes: 22 additions & 0 deletions docs/docs/guides/tracking/objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,28 @@ Saving an object with a name will create the first version of that object if it
</TabItem>
</Tabs>

## Deleting an object

<Tabs groupId="programming-language" queryString>
<TabItem value="python" label="Python" default>
To delete a version of an object, call `.delete()` on the object ref.

```python
weave.init('intro-example')
cat_names_ref = weave.ref('cat-names:v1')
cat_names_ref.delete()
```

Trying to access a deleted object will result in an error. Resolving an object that has a reference to a deleted object will return a `DeletedRef` object in place of the deleted object.

</TabItem>
<TabItem value="typescript" label="TypeScript">
```plaintext
This feature is not available in TypeScript yet. Stay tuned!
```
</TabItem>
</Tabs>

## Ref styles

A fully qualified weave object ref uri looks like this:
Expand Down
22 changes: 22 additions & 0 deletions docs/docs/guides/tracking/ops.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,25 @@ If you want to suppress the printing of call links during logging, you can set t
```bash
export WEAVE_PRINT_CALL_LINK=false
```

## Deleting an op

<Tabs groupId="programming-language" queryString>
<TabItem value="python" label="Python" default>
To delete a version of an op, call `.delete()` on the op ref.

```python
weave.init('intro-example')
my_op_ref = weave.ref('track_me:v1')
my_op_ref.delete()
```

Trying to access a deleted op will result in an error.

</TabItem>
<TabItem value="typescript" label="TypeScript">
```plaintext
This feature is not available in TypeScript yet. Stay tuned!
```
</TabItem>
</Tabs>
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ module = "weave_query.*"
ignore_errors = true

[tool.bumpversion]
current_version = "0.51.30-dev0"
current_version = "0.51.31-dev0"
parse = """(?x)
(?P<major>0|[1-9]\\d*)\\.
(?P<minor>0|[1-9]\\d*)\\.
Expand Down
22 changes: 22 additions & 0 deletions tests/trace/image_patch_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from tempfile import NamedTemporaryFile

from weave.initialization import pil_image_thread_safety


def test_patching_import_order():
# This test verifies the correct behavior if patching occurs after the construction
# of an image
assert pil_image_thread_safety._patched
pil_image_thread_safety.undo_threadsafe_patch_to_pil_image()
assert not pil_image_thread_safety._patched
import PIL

image = PIL.Image.new("RGB", (10, 10))
with NamedTemporaryFile(suffix=".png") as f:
image.save(f.name)
image = PIL.Image.open(f.name)

pil_image_thread_safety.apply_threadsafe_patch_to_pil_image()
assert pil_image_thread_safety._patched

image.crop((0, 0, 10, 10))
45 changes: 45 additions & 0 deletions tests/trace/test_dictifiable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import weave


def test_dictifiable(client):
class NonDictifiable:
attr: int

def __init__(self, attr: int):
self.attr = attr

class Dictifiable:
attr: int

def __init__(self, attr: int):
self.attr = attr

def to_dict(self):
return {"attr": self.attr}

@weave.op
def func(d: Dictifiable, nd: NonDictifiable) -> dict:
return {
"d": Dictifiable(d.attr),
"nd": NonDictifiable(nd.attr),
}

val = 42
d = Dictifiable(val)
nd = NonDictifiable(val)
res = func(d, nd)
assert isinstance(res["d"], Dictifiable)
assert res["d"].attr == val
assert isinstance(res["nd"], NonDictifiable)
assert res["nd"].attr == val

call = func.calls()[0]

assert call.inputs["d"] == {"attr": val}
assert call.inputs["nd"].startswith(
"<test_dictifiable.test_dictifiable.<locals>.NonDictifiable object at"
)
assert call.output["d"] == {"attr": val}
assert call.output["nd"].startswith(
"<test_dictifiable.test_dictifiable.<locals>.NonDictifiable object at"
)
34 changes: 24 additions & 10 deletions tests/trace/type_handlers/Image/image_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,20 +149,19 @@ def accept_image_jpg_pillow(val):
file_path.unlink()


def make_random_image(image_size: tuple[int, int] = (1024, 1024)):
random_colour = (
random.randint(0, 255),
random.randint(0, 255),
random.randint(0, 255),
)
return Image.new("RGB", image_size, random_colour)


@pytest.fixture
def dataset_ref(client):
# This fixture represents a saved dataset containing images
IMAGE_SIZE = (1024, 1024)
N_ROWS = 50

def make_random_image():
random_colour = (
random.randint(0, 255),
random.randint(0, 255),
random.randint(0, 255),
)
return Image.new("RGB", IMAGE_SIZE, random_colour)

rows = [{"img": make_random_image()} for _ in range(N_ROWS)]
dataset = weave.Dataset(rows=rows)
ref = weave.publish(dataset)
Expand Down Expand Up @@ -202,3 +201,18 @@ async def test_many_images_will_consistently_log():

# But if there's an issue, the stderr will contain `Task failed:`
assert "Task failed" not in res.stderr


def test_images_in_load_of_dataset(client):
N_ROWS = 50
rows = [{"img": make_random_image()} for _ in range(N_ROWS)]
dataset = weave.Dataset(rows=rows)
ref = weave.publish(dataset)

dataset = ref.get()
for gotten_row, local_row in zip(dataset, rows):
assert isinstance(gotten_row["img"], Image.Image)
assert gotten_row["img"].size == local_row["img"].size
assert gotten_row["img"].tobytes() == local_row["img"].tobytes()

return ref
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React, {useMemo} from 'react';
import {Icon} from '../../../../Icon';
import {LoadingDots} from '../../../../LoadingDots';
import {Tailwind} from '../../../../Tailwind';
import {Timestamp} from '../../../../Timestamp';
import {WeaveCHTableSourceRefContext} from '../pages/CallPage/DataTableView';
import {ObjectViewerSection} from '../pages/CallPage/ObjectViewerSection';
import {objectVersionText} from '../pages/common/Links';
Expand All @@ -30,6 +31,7 @@ export const DatasetVersionPage: React.FC<{
const projectName = objectVersion.project;
const objectName = objectVersion.objectId;
const objectVersionIndex = objectVersion.versionIndex;
const {createdAtMs} = objectVersion;

const objectVersions = useRootObjectVersions(
entityName,
Expand Down Expand Up @@ -76,7 +78,7 @@ export const DatasetVersionPage: React.FC<{
}
headerContent={
<Tailwind>
<div className="grid w-full grid-flow-col grid-cols-[auto_auto_1fr] gap-[16px] text-[14px]">
<div className="grid w-full grid-flow-col grid-cols-[auto_auto_auto_1fr] gap-[16px] text-[14px]">
<div className="block">
<p className="text-moon-500">Name</p>
<ObjectVersionsLink
Expand Down Expand Up @@ -109,6 +111,12 @@ export const DatasetVersionPage: React.FC<{
<p className="text-moon-500">Version</p>
<p>{objectVersionIndex}</p>
</div>
<div className="block">
<p className="text-moon-500">Created</p>
<p>
<Timestamp value={createdAtMs / 1000} format="relative" />
</p>
</div>
{objectVersion.userId && (
<div className="block">
<p className="text-moon-500">Created by</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import {Box, Drawer} from '@mui/material';
import {Box} from '@mui/material';
import {MOON_200} from '@wandb/weave/common/css/color.styles';
import {Tag} from '@wandb/weave/components/Tag';
import {Icon} from '@wandb/weave/components/Icon';
import {Tailwind} from '@wandb/weave/components/Tailwind';
import React from 'react';
import React, {useCallback, useEffect, useState} from 'react';

import {Button} from '../../../../../Button';
import {ResizableDrawer} from '../common/ResizableDrawer';
import {ChoiceView} from './ChoiceView';
import {Choice} from './types';

Expand All @@ -25,21 +26,38 @@ export const ChoicesDrawer = ({
selectedChoiceIndex,
setSelectedChoiceIndex,
}: ChoicesDrawerProps) => {
const [width, setWidth] = useState(784);
const [maxAllowedWidth, setMaxAllowedWidth] = useState(
window.innerWidth - 73
);

useEffect(() => {
const handleResize = () => {
const newMaxWidth = window.innerWidth - 73;
setMaxAllowedWidth(newMaxWidth);
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);

const handleFullScreen = useCallback(() => {
const newWidth = width === maxAllowedWidth ? 784 : maxAllowedWidth;
setWidth(newWidth);
}, [width, maxAllowedWidth]);

return (
<Drawer
<ResizableDrawer
open={isDrawerOpen}
onClose={() => setIsDrawerOpen(false)}
title="Choices"
anchor="right"
sx={{
'& .MuiDrawer-paper': {mt: '60px', width: '400px'},
}}>
defaultWidth={width}
setWidth={setWidth}>
<Box
sx={{
position: 'sticky',
top: 0,
zIndex: 1,
px: 2,
zIndex: 20,
pl: '16px',
pr: '8px',
height: 44,
width: '100%',
borderBottom: `1px solid ${MOON_200}`,
Expand All @@ -57,50 +75,64 @@ export const ChoicesDrawer = ({
fontWeight: 600,
fontSize: '1.25rem',
}}>
Responses
Trials
</Box>
<Box sx={{display: 'flex', gap: 1}}>
<Button
size="medium"
variant="ghost"
icon="full-screen-mode-expand"
onClick={handleFullScreen}
tooltip={
width === maxAllowedWidth ? 'Exit full screen' : 'Full screen'
}
/>
<Button
size="medium"
variant="ghost"
icon="close"
onClick={() => setIsDrawerOpen(false)}
tooltip="Close"
/>
</Box>
<Button
size="medium"
variant="ghost"
icon="close"
onClick={() => setIsDrawerOpen(false)}
tooltip="Close"
/>
</Box>
<Tailwind>
<div className="flex flex-col p-12">
<div className="mb-[72px] flex flex-col gap-[16px] px-[16px] pb-[16px] pt-[8px]">
{choices.map((c, index) => (
<div key={index}>
<div className="flex items-center gap-4 font-semibold">
<Tag color="moon" label={`Response ${index + 1}`} />
<div className="sticky top-[44px] z-10 flex items-center bg-white py-[8px]">
<p className="mr-[8px] text-[14px] font-semibold">
Trial {index + 1}
</p>
{index === selectedChoiceIndex ? (
<Button
className="text-green-500"
size="small"
variant="ghost"
icon="checkmark">
<span className="text-moon-500">Response selected</span>
</Button>
<div className="flex items-center gap-[2px]">
<Icon
name="checkmark"
className="ml-[4px] w-[16px] text-green-500"
/>
<span className="text-sm font-semibold">
Response selected
</span>
</div>
) : (
<Button
size="small"
variant="ghost"
icon="boolean"
variant="secondary"
icon="checkmark"
onClick={() => setSelectedChoiceIndex(index)}>
<span className="text-moon-500">Select response</span>
Select response
</Button>
)}
</div>
<ChoiceView
choice={c}
isStructuredOutput={isStructuredOutput}
choiceIndex={index}
isNested
/>
</div>
))}
</div>
</Tailwind>
</Drawer>
</ResizableDrawer>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const ChoicesViewCarousel = ({
icon="visible"
onClick={() => setIsDrawerOpen(true)}
tooltip="View all choices">
Review
View trials
</Button>
</div>
}
Expand Down
Loading

0 comments on commit adf16aa

Please sign in to comment.