# single_file_extractor

## nominal.experimental.extractor.decorators.single_file_extractor(fn: Callable[[...], None], *, default_timestamp_column: str | None = None, default_timestamp_type: Iso8601 | Epoch | Relative | Custom | Literal['iso_8601', 'epoch_picoseconds', 'epoch_nanoseconds', 'epoch_microseconds', 'epoch_milliseconds', 'epoch_seconds', 'epoch_minutes', 'epoch_hours', 'epoch_days'] | None = None, output_format: FileOutputFormat | None = None) → Extractor[SingleFileExtractorContext]

## nominal.experimental.extractor.decorators.single_file_extractor(*, default_timestamp_column: str | None = None, default_timestamp_type: Iso8601 | Epoch | Relative | Custom | Literal['iso_8601', 'epoch_picoseconds', 'epoch_nanoseconds', 'epoch_microseconds', 'epoch_milliseconds', 'epoch_seconds', 'epoch_minutes', 'epoch_hours', 'epoch_days'] | None = None, output_format: FileOutputFormat | None = None) → Callable[[Callable[[...], None]], Extractor[SingleFileExtractorContext]]

Declare a single-file extractor with `ctx` followed by injected arguments.

Use `@error(ExceptionType, code="...", exit_code=64)` below this decorator to declare
structured failures handled automatically by `Extractor.run()`.
Declare inputs and parameters below this decorator with `@input` and `@parameter`;
they are passed as keyword arguments after `ctx`. Declare `default_timestamp_column`
and `default_timestamp_type` to generate `Extractor.registration_kwargs()`.

For images registered with a single-file output format (`PARQUET`, `CSV`, …): the ingest
pipeline ingests exactly one output file, parsed per the registered format. Declare it with
`SingleFileExtractorContext.set_output()`. If the image’s registered format turns out to be
`MANIFEST`, `Extractor.run()` fails at startup with a clear error.

Set `output_format` explicitly to generate registration metadata; it must then match
the registered format exactly. Omitting it preserves legacy runtime behavior.

This is the original output contract, kept for images already registered against it. New
extractors should use [`manifest_extractor()`](https://dev.nominal.io/python/ref/generated/nominal.experimental.extractor.decorators.manifest_extractor.md#nominal.experimental.extractor.decorators.manifest_extractor "nominal.experimental.extractor.decorators.manifest_extractor"), a strict superset: this mode has no per-output
timestamp, tag-column, or channel-prefix control, and changing an image’s output format later
requires registering a new image.

Example

```python
from pathlib import Path

from nominal.core.container_image import FileOutputFormat
from nominal.experimental.extractor import SingleFileExtractorContext, input, single_file_extractor

@single_file_extractor(
    output_format=FileOutputFormat.PARQUET,
    default_timestamp_column="time_us",
    default_timestamp_type="epoch_microseconds",
)
@input("source")
def convert(ctx: SingleFileExtractorContext, *, source: Path) -> None:
    table = read_input(source)
    out = ctx.output_dir / "converted.parquet"
    write_parquet(table, out)
    ctx.set_output(out)

if __name__ == "__main__":
    convert.run()
```

Return type:
:   [*Extractor*](https://dev.nominal.io/python/ref/generated/nominal.experimental.extractor.runner.Extractor.md#nominal.experimental.extractor.runner.Extractor "nominal.experimental.extractor.runner.Extractor")[[*SingleFileExtractorContext*](https://dev.nominal.io/python/ref/generated/nominal.experimental.extractor.context.SingleFileExtractorContext.md#nominal.experimental.extractor.context.SingleFileExtractorContext "nominal.experimental.extractor.context.SingleFileExtractorContext")] | [*Callable*](https://docs.python.org/3/library/typing.html#typing.Callable "(in Python v3.15)")[[[*Callable*](https://docs.python.org/3/library/typing.html#typing.Callable "(in Python v3.15)")[[…], *None*]], [*Extractor*](https://dev.nominal.io/python/ref/generated/nominal.experimental.extractor.runner.Extractor.md#nominal.experimental.extractor.runner.Extractor "nominal.experimental.extractor.runner.Extractor")[[*SingleFileExtractorContext*](https://dev.nominal.io/python/ref/generated/nominal.experimental.extractor.context.SingleFileExtractorContext.md#nominal.experimental.extractor.context.SingleFileExtractorContext "nominal.experimental.extractor.context.SingleFileExtractorContext")]]
