Skip to content

Commit

Permalink
Merge branch 'master' into griffin/fix-link-double-click
Browse files Browse the repository at this point in the history
  • Loading branch information
gtarpenning authored Jan 22, 2025
2 parents 398cdab + 980abad commit 3e3d604
Show file tree
Hide file tree
Showing 36 changed files with 762 additions and 165 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>
73 changes: 62 additions & 11 deletions docs/docs/guides/tracking/tracing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import TracingCallsMacroImage from '@site/static/img/screenshots/calls_macro.png
import TracingCallsFilterImage from '@site/static/img/screenshots/calls_filter.png';
import BasicCallImage from '@site/static/img/screenshots/basic_call.png';


# Calls

<DesktopWindow
Expand Down Expand Up @@ -699,17 +700,7 @@ The easiest way to get started is to construct a view in the UI, then learn more
:::info[Comming Soon]
::: */}

## Call FAQ

{/* TODO:
Common Questions / Variations:
* Images
* Ops
* Cost?
* General data model
*/}

#### Call Schema
### Call Schema

Please see the [schema](../../reference/python-sdk/weave/trace_server/weave.trace_server.trace_server_interface#class-callschema) for a complete list of fields.

Expand Down Expand Up @@ -748,4 +739,64 @@ Calculated Fields:
* Duration
* Status

## FAQs

### How do I disable tracing?

**Environment Variable:**

In situations where you want to unconditionally disable tracing for the entire program, you can set the environment variable `WEAVE_DISABLED=true`.

**Client Initialization:**

Sometimes, you may want to conditionally enable tracing for a specific initialization based on some condition. In this case, you can initialize the client with the `disabled` flag in init settings.

```python
import weave

# Initialize the client
client = weave.init(..., settings={"disabled": True})
```

**Context Manager:**

Finally, you may want to conditionally disable tracing for a single function based on some application logic. In this case, you can use the context manager `with set_tracing_enabled(False)` which can be imported from `weave.trace.context.call_context`.

```python
import weave
from weave.trace.context.call_context import set_tracing_enabled

client = weave.init(...)

@weave.op
def my_op():
...

with set_tracing_enabled(False):
my_op()
```

### How do I capture information about a call?

Typically you would call an op directly:

```python
@weave.op
def my_op():
...

my_op()
```

However, you can also get access to the call object directly by invoking the `call` method on the op:

```python
@weave.op
def my_op():
...

output, call = my_op.call()
```

From here, the `call` object will have all the information about the call, including the inputs, outputs, and other metadata.

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,7 +1,7 @@
import {GridPaginationModel} from '@mui/x-data-grid-pro';

const MAX_PAGE_SIZE = 100;
export const DEFAULT_PAGE_SIZE = 100;
export const DEFAULT_PAGE_SIZE = 50;

export const getValidPaginationModel = (
queryPage: string | undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ export const CallDetails: FC<{
entity={call.entity}
project={call.project}
allowedColumnPatterns={ALLOWED_COLUMN_PATTERNS}
paginationModel={isPeeking ? {page: 0, pageSize: 10} : undefined}
/>
);
if (isPeeking) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ const Spacer = styled.div`
`;
Spacer.displayName = 'S.Spacer';

const Collapsed = styled.div<{hasScrolling: boolean}>`
const Collapsed = styled.div`
min-height: 38px;
line-height: 38px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: ${props => (props.hasScrolling ? 'pointer' : 'default')};
cursor: pointer;
`;
Collapsed.displayName = 'S.Collapsed';

Expand Down Expand Up @@ -100,12 +100,10 @@ export const ValueViewString = ({value, isExpanded}: ValueViewStringProps) => {
setMode(hasScrolling ? (isExpanded ? 1 : 0) : 0);
}, [hasScrolling, isExpanded]);

const onClick = hasScrolling
? () => {
const numModes = hasFull ? 3 : 2;
setMode((mode + 1) % numModes);
}
: undefined;
const onClick = () => {
const numModes = hasFull ? 3 : 2;
setMode((mode + 1) % numModes);
};
const copy = useCallback(() => {
copyToClipboard(value);
toast('Copied to clipboard');
Expand Down Expand Up @@ -209,9 +207,5 @@ export const ValueViewString = ({value, isExpanded}: ValueViewStringProps) => {
</Column>
);
}
return (
<Collapsed hasScrolling={hasScrolling} onClick={onClick}>
{content}
</Collapsed>
);
return <Collapsed onClick={onClick}>{content}</Collapsed>;
};
Loading

0 comments on commit 3e3d604

Please sign in to comment.