From 80c3c485a301bc20116cf9a3ab83c5219b2d85d3 Mon Sep 17 00:00:00 2001 From: Ray Chiang Date: Sun, 26 Jul 2026 21:54:15 -0700 Subject: [PATCH 1/2] docs: Add error handling to "Processing helpers" section (#2263) Added section on error handling. Also adjusted the header and some of the text in the map() section to improve searchability. --- .../processing_component.mdx | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/docs/src/content/docs/programming_guide/processing_component.mdx b/docs/src/content/docs/programming_guide/processing_component.mdx index ec7d89175..5f1ec3e80 100644 --- a/docs/src/content/docs/programming_guide/processing_component.mdx +++ b/docs/src/content/docs/programming_guide/processing_component.mdx @@ -57,7 +57,7 @@ And two sugar APIs that simplify common patterns: - **`mount_each()`** — mounts one component per item in a keyed iterable - **`mount_target()`** — mounts a target without an explicit subpath -See also [`map()`](#map) for a utility API that operates within a component without creating new ones. +See also [`map()`](#Using CocoIndex map to apply transformations) for a utility API that operates within a component without creating new ones. ### Automatic subpath derivation `mount()`, `use_mount()`, and `mount_each()` all accept an optional `ComponentSubpath` as their first argument. When omitted, the subpath is **auto-derived** from the function name using `Symbol(fn.__name__)`. @@ -297,8 +297,8 @@ This pattern ensures that CocoIndex can track component relationships and target ## Processing helpers -### `map()` -`map()` applies an async function to each item in a collection, running all calls concurrently within the current processing component. Unlike [`mount()`](#mount) and [`mount_each()`](#mount_each), it does **not** create child processing components — it's purely concurrent execution (similar to `asyncio.gather()`). +### Using CocoIndex `map()` to apply transformations +The `map()` handler (also known as `coco.map()`) applies an async function to each item in a collection, running all calls concurrently within the current processing component. Unlike [`mount()`](#mount) and [`mount_each()`](#mount_each), it does **not** create child processing components — it's purely concurrent execution (similar to `asyncio.gather()`). ```python @coco.fn(memo=True) @@ -308,9 +308,35 @@ async def process_file(file: FileLike, table: postgres.TableTarget[DocEmbedding] await coco.map(process_chunk, chunks, file.file_path.path, id_gen, table) ``` -The first argument to the function receives each item; additional arguments are passed through to every call. `map()` returns a `list` of the results, in the same order as the input items. +The first argument to the function receives each item; additional arguments are passed through to every call. The `coco.map()` handler returns a `list` of the results, in the same order as the input items. -#### When to use `map()` vs `mount_each()` +#### When to use the `map()` processor vs `mount_each()` - Use **`mount_each()`** when each item should be its own processing component — with its own component path, target state ownership, and target states sync boundary. -- Use **`map()`** when you want to process items concurrently *within* the current component, without creating new component boundaries. This is common for sub-item work like processing chunks within a file — the same within-component chunk work the [chunk-embedding pipeline in Core Concepts](./core_concepts#processing-component) walks through. +- Use the **`map()`** handler when you want to process items concurrently *within* the current component, without creating new component boundaries. This is common for sub-item work like processing chunks within a file — the same within-component chunk work the [chunk-embedding pipeline in Core Concepts](./core_concepts#processing-component) walks through. + +#### Error handling with the `map()` processor + +The `coco.map()` handler allows for two patterns of error handling. The async function called by the `map()` handler can raise an exception. This applies when a single error is sufficient for the error case. + +```python +@coco.fn +async def disallow_word(item: str) -> str: + if item == "bad_word": + raise ValueError(f"Found bad word item={item!r}") + result = item + return result + +try: + await coco.map(disallow_word, TEXT) +except Exception as e: + error_found = e +``` + +To handle multiple errors, any code must use the `list[ReturnT]` return value from the `coco.map()` handler. + +```python +check = await coco.map(disallow_word, TEXT) +failures = [c for c in check if not c.ok] +``` + From d940d837cb266f7abc4c9246040068509b8b5bf3 Mon Sep 17 00:00:00 2001 From: Ray Chiang Date: Mon, 24 Aug 2026 15:50:33 -0700 Subject: [PATCH 2/2] docs: Further documentation cleanup and fixes to "Processing helpers" - Remove error handling section - Fix some text to avoid confusion - The doc changes are now just the title changes and the additional references to `coco.map()` to improve section ranking for search. --- .../processing_component.mdx | 38 +++---------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/docs/src/content/docs/programming_guide/processing_component.mdx b/docs/src/content/docs/programming_guide/processing_component.mdx index 5f1ec3e80..76a11a695 100644 --- a/docs/src/content/docs/programming_guide/processing_component.mdx +++ b/docs/src/content/docs/programming_guide/processing_component.mdx @@ -57,7 +57,7 @@ And two sugar APIs that simplify common patterns: - **`mount_each()`** — mounts one component per item in a keyed iterable - **`mount_target()`** — mounts a target without an explicit subpath -See also [`map()`](#Using CocoIndex map to apply transformations) for a utility API that operates within a component without creating new ones. +See also [`map()`](#using-cocoindex-map-to-apply-transformations) for a utility API that operates within a component without creating new ones. ### Automatic subpath derivation `mount()`, `use_mount()`, and `mount_each()` all accept an optional `ComponentSubpath` as their first argument. When omitted, the subpath is **auto-derived** from the function name using `Symbol(fn.__name__)`. @@ -143,7 +143,7 @@ handle = await coco.mount_each(process_file, files.items(), target) await handle.ready() # waits until every per-item component is ready ``` -If you want per-item results without creating components, use [`map()`](#map). +If you want per-item results without creating components, use [`map()`](#using-cocoindex-map-to-apply-transformations). You can provide an explicit subpath as the first argument: @@ -298,7 +298,7 @@ This pattern ensures that CocoIndex can track component relationships and target ## Processing helpers ### Using CocoIndex `map()` to apply transformations -The `map()` handler (also known as `coco.map()`) applies an async function to each item in a collection, running all calls concurrently within the current processing component. Unlike [`mount()`](#mount) and [`mount_each()`](#mount_each), it does **not** create child processing components — it's purely concurrent execution (similar to `asyncio.gather()`). +The `map()` API (also known as `coco.map()`) applies an async function to each item in a collection, running all calls concurrently within the current processing component. Unlike [`mount()`](#mount) and [`mount_each()`](#mount_each), it does **not** create child processing components — it's purely concurrent execution (similar to `asyncio.gather()`). ```python @coco.fn(memo=True) @@ -308,35 +308,9 @@ async def process_file(file: FileLike, table: postgres.TableTarget[DocEmbedding] await coco.map(process_chunk, chunks, file.file_path.path, id_gen, table) ``` -The first argument to the function receives each item; additional arguments are passed through to every call. The `coco.map()` handler returns a `list` of the results, in the same order as the input items. +The first argument to the function receives each item; additional arguments are passed through to every call. The `coco.map()` API returns a `list` of the results, in the same order as the input items. -#### When to use the `map()` processor vs `mount_each()` +#### When to use the `map()` API vs `mount_each()` - Use **`mount_each()`** when each item should be its own processing component — with its own component path, target state ownership, and target states sync boundary. -- Use the **`map()`** handler when you want to process items concurrently *within* the current component, without creating new component boundaries. This is common for sub-item work like processing chunks within a file — the same within-component chunk work the [chunk-embedding pipeline in Core Concepts](./core_concepts#processing-component) walks through. - -#### Error handling with the `map()` processor - -The `coco.map()` handler allows for two patterns of error handling. The async function called by the `map()` handler can raise an exception. This applies when a single error is sufficient for the error case. - -```python -@coco.fn -async def disallow_word(item: str) -> str: - if item == "bad_word": - raise ValueError(f"Found bad word item={item!r}") - result = item - return result - -try: - await coco.map(disallow_word, TEXT) -except Exception as e: - error_found = e -``` - -To handle multiple errors, any code must use the `list[ReturnT]` return value from the `coco.map()` handler. - -```python -check = await coco.map(disallow_word, TEXT) -failures = [c for c in check if not c.ok] -``` - +- Use the **`map()`** API when you want to process items concurrently *within* the current component, without creating new component boundaries. This is common for sub-item work like processing chunks within a file — the same within-component chunk work the [chunk-embedding pipeline in Core Concepts](./core_concepts#processing-component) walks through.