baml.csv.Reader

A streaming CSV reader. Create one with `baml.csv.open` or `baml.csv.reader`.

Reference version

Signature

class baml.csv.Reader

A streaming CSV reader. Create one with baml.csv.open or baml.csv.reader.

A Reader is a lazy iterator over Record values, so a multi-gigabyte file parses in constant memory and every baml.iter adapter and default method (map, filter, collect, ...) works on it. There is one cursor: raw iteration, rows<T>(), and headers() all draw from the same stream.

A thrown record error has already consumed the offending record. The parser resynchronizes at the next record boundary, so the next call to next() continues and one corrupt cell costs exactly one record.

on_error governs record-scoped failures for every read on this handle. Under the default "throw" they propagate. Under "skip" they are counted, handed to ReaderOptions.on_skip, and stepped over. Options and Header failures are never record-scoped and throw either way — a header that cannot serve T will not start serving it on the next row.

Every read throws Error { kind: Closed } after close(); skipped(), skipped_count(), and position() stay valid. A baml.errors.Io failure from the source is stream-scoped and final: the reader is marked exhausted before the throw, so a caller that swallows it gets baml.iter.Done rather than an infinite retry.

Source:<builtin>/baml/ns_csv/csv.bamlbytes 14905–23246

Fields

_handle

$rust_type

_owns_file

bool

Instance methods

function

_feed

(self, chunk: uint8array) -> null throws never

(internal) Append a chunk of source bytes to the parse buffer.

function

_feed_eof

(self) -> null throws never

(internal) Mark the source as exhausted.

function

_mark_closed

(self) -> null throws never

(internal) Mark the reader closed (idempotent).

function

_mark_exhausted

(self) -> null throws never

(internal) Mark the iterator exhausted: subsequent polls return Done.

function

_read_chunk

(self) -> null throws baml.errors.Io

(internal) Pull the next chunk from the backing file, or mark EOF for in-memory sources.

The reader is marked exhausted before an IO error is thrown, so subsequent next() calls return baml.iter.Done. A closed handle arrives as an IO error, because baml.io.Read has no separate closed-handle error channel.

function

close

(self) -> null throws baml.errors.Io

Releases the reader. Idempotent.

The underlying file handle is closed only when the reader owns it (created by open); a handle passed to reader(file) stays open, since its lifecycle belongs to the caller. Closing is optional, as with baml.fs.File — the GC reclaims unreferenced readers.

Throws

  • baml.errors.Io if closing an owned file handle fails. The reader is already marked closed by then, so a retry will not reopen it.
function

headers

(self) -> string[] | null throws baml.csv.Error | baml.errors.Io

The column names: the headers option when set, the file's header row when has_header = true (consumed on first call), and null otherwise.

Idempotent. The header is resolved once and cached, so calling this before iterating costs nothing and consumes no data record. An empty input has no header row, and reads as the headers option or null.

A malformed header record surfaces from whichever call reads the header first, and it exhausts the reader rather than resynchronizing: without a trustworthy header every later name-to-column mapping would be silently wrong. on_error does not apply, because there is no next header to resume at.

Throws

  • Error { kind: Quote } or Error { kind: Encoding } if the header record itself is malformed. Every later call rethrows the same error.
  • baml.errors.Io if the source cannot be read.
function

position

(self) -> baml.csv.Position throws never

The position of the start of the next unread record. Its record field counts all data records consumed so far, including skipped ones.

function

rows

<T>(
self

A typed iterator over the remaining records, decoding each into T.

Validates eagerly. It reads the header if necessary and checks that every non-optional field of T is satisfiable, so an unusable T throws Error { kind: Header } at the call site rather than on the millionth row.

The decode rules are Record.decode<T>'s, under this reader's on_error policy. "Remaining" is literal: this shares the reader's one cursor, so records already pulled by next() are gone.

Throws

  • Error { kind: Header } if a required field of T has no column, or its column name is duplicated.
  • Error { kind: Options } if T is not a flat class of cell-decodable fields.
  • Anything headers() throws, since it is called first.
function

skipped

(self) -> baml.csv.Error[] throws never

The first max_skipped (default 1,000) Error values skipped under on_error = "skip".

Retention is bounded so a pathological file cannot turn a constant-memory stream into an unbounded error log. It keeps the first errors rather than the last, because the first ones usually explain the rest. Use ReaderOptions.on_skip to observe every skip, and skipped_count() for the true total.

function

skipped_count

(self) -> int throws never

Exact count of records skipped under on_error = "skip".

Unaffected by max_skipped — the counter is kept even once retention stops.

Implementations

baml.Concrete for T

Source:<builtin>/baml/core.bamlbytes 763–795

baml.iter.Iterator for baml.csv.Reader

Instance methods

function

chain

<E2>(
self,
other: baml.iter.Iterable<Error = E2, Item = (Self as baml.iter.Iterator).Item>
) -> baml.iter.Iterator<Error = (Self as baml.iter.Iterator).Error | E2, Item = (Self as baml.iter.Iterator).Item> throws never

Returns an iterator over all of self's elements followed by all of other's.

other.iter() is called right away, when the chain is built; only the advancing is deferred. The two sides may have different error types, and the result throws either.

Returns

A baml.iter.Chain.

function

collect

(self) -> (Self as baml.iter.Iterator).Item[] throws (Self as baml.iter.Iterator).Error

Consumes the rest of this iterator into an array, in order.

The rest: elements already pulled from a partly-consumed iterator are not included, and an already-exhausted iterator collects to [].

Throws

  • Self.Error if advancing the iterator fails. The elements gathered so far are lost, since the array is only returned on success.
function

count

(self) -> int throws (Self as baml.iter.Iterator).Error

Consumes the rest of this iterator and returns how many elements there were, 0 if it was already exhausted.

Every element is actually pulled — there is no size hint to short circuit with — so counting a chain runs the whole chain, callbacks included.

Throws

  • Self.Error if advancing the iterator fails.
function

every

<E2>(
self,
predicate: ((Self as baml.iter.Iterator).Item) -> bool throws E2
) -> bool throws (Self as baml.iter.Iterator).Error | E2

Whether predicate holds for every remaining element — Python's all, JavaScript's every.

Short circuits at the first false. An empty iterator gives true — the empty conjunction — which is worth remembering when the iterator may have been exhausted already.

Throws

  • Self.Error if advancing the iterator fails.
  • E2 if predicate throws.

ALIASES: all

function

filter

<E2>(
self,
predicate: ((Self as baml.iter.Iterator).Item) -> bool throws E2
) -> baml.iter.Iterator<Error = (Self as baml.iter.Iterator).Error | E2, Item = (Self as baml.iter.Iterator).Item> throws never

Returns an iterator over the elements for which predicate is true, in order.

A rejected element is skipped, not a stopping point — use baml.iter.Iterator.take_while to stop at the first failure instead.

Returns

A baml.iter.Filter yielding the kept elements.

function

filter_map

<R, E2>(
self,
fn: ((Self as baml.iter.Iterator).Item) -> R | null throws E2
) -> baml.iter.Iterator<Error = (Self as baml.iter.Iterator).Error | E2, Item = R> throws never

Returns an iterator over the non-null results of fn: map and filter in one pass.

null is the skip signal, so the produced item type R is the non-optional one. An iterator whose own items you want to keep as null cannot be expressed this way — filter and map it in two steps instead.

Returns

A baml.iter.FilterMap yielding the non-null results, in order.

function

find

<E2>(
self,
predicate: ((Self as baml.iter.Iterator).Item) -> bool throws E2
) -> (Self as baml.iter.Iterator).Item | null throws (Self as baml.iter.Iterator).Error | E2

The first remaining element for which predicate is true, or null if the iterator runs out first.

Short circuits: the matching element is consumed, and the iterator is left positioned just after it.

The result is Self.Item?, so — unlike next, which uses the distinct baml.iter.Done sentinel — an iterator whose items are themselves nullable cannot tell a found null from no match. Use baml.iter.Iterator.filter followed by next when that distinction matters.

Throws

  • Self.Error if advancing the iterator fails.
  • E2 if predicate throws.
function

flat_map

<R, E2, E3>(
self,
fn: ((Self as baml.iter.Iterator).Item) -> baml.iter.Iterable<Error = E3, Item = R> throws E2
) -> baml.iter.Iterator<Error = (Self as baml.iter.Iterator).Error | E2 | E3, Item = R> throws never

Returns an iterator over the elements of the iterables fn produces, laid end to end.

Each inner sequence is drained before the next outer element is pulled, and one that is empty contributes nothing. Three error types meet here — the source's, fn's E2, and the inner iterables' E3 — and the result throws all of them.

Returns

A baml.iter.FlatMap yielding R.

function

for_each

<E2>(
self,
fn: ((Self as baml.iter.Iterator).Item) -> null throws E2
) -> null throws (Self as baml.iter.Iterator).Error | E2

Calls fn on each remaining element, in order, for its side effects.

A for (.. in ..) loop is generally preferable; this is for the end of a long chain of calls. It runs to exhaustion — there is no way for fn to stop it early. Use baml.iter.Iterator.some or a for loop with a break when you need to.

Throws

  • Self.Error if advancing the iterator fails.
  • E2 if fn throws, which ends the traversal at that element.
function

map

<R, E2>(
self,
fn: ((Self as baml.iter.Iterator).Item) -> R throws E2
) -> baml.iter.Iterator<Error = (Self as baml.iter.Iterator).Error | E2, Item = R> throws never

Returns an iterator that applies fn to each element — Python's map, JavaScript's Iterator.prototype.map.

fn is applied exactly once per element that is actually pulled, in order, so a chain that ends early never touches the elements it skipped.

Returns

A baml.iter.Map yielding R, of the same length as self.

Yields the next raw Record, pumping input from the source as the parser needs it.

A skipped record is not a result, so the loop runs until one survives or the stream ends. Under "throw" the error propagates instead — but the record has already been consumed, so calling next() again resumes cleanly at the following record.

function

peekable

(
self
) -> baml.iter.Peekable<(Self as baml.iter.Iterator).Item, (Self as baml.iter.Iterator).Error> throws never

Returns an iterator with one element of look-ahead.

Unlike the other adapters this returns the concrete baml.iter.Peekable class rather than the Iterator interface, because peek lives on the class: an existential would hide it.

Returns

A baml.iter.Peekable yielding exactly what self yields, plus a peek that reads the next element without consuming it.

function

reduce

<A, E2>(
self,
fn: (A, (Self as baml.iter.Iterator).Item) -> A throws E2,
initial: A
) -> A throws (Self as baml.iter.Iterator).Error | E2

Folds every remaining element into an accumulator, left to right.

The accumulator starts at initial and each call to fn replaces it with the result; initial is what comes back for an empty iterator. Because the seed is required and its type A is independent of the item type, this is the operation Rust calls Iterator::fold and Python calls functools.reduce — not Rust's reduce.

Parameters

  • fn: combines the accumulator so far with the next element.
  • initial: the starting accumulator, and the result for an empty iterator.

Throws

  • Self.Error if advancing the iterator fails.
  • E2 if fn throws. The fold stops there; the partial accumulator is not recoverable.

ALIASES: fold

function

skip

(
self,
n: int
) -> baml.iter.Iterator<Error = (Self as baml.iter.Iterator).Error, Item = (Self as baml.iter.Iterator).Item> throws never

Returns an iterator over everything after the first n elements.

For n <= 0 every element is yielded; a source with fewer than n elements yields nothing. The skipped elements are pulled from the source and discarded — they are not free, and they can still throw. A skip is counted only once the source has actually yielded, so a throw the caller retries does not consume part of the count.

Parameters

  • n: how many leading elements to discard.

Returns

A baml.iter.Skip.

Examples

baml.iter.Range.new(0, 5).skip(2).collect() // [2, 3, 4]
function

skip_while

<E2>(
self,
predicate: ((Self as baml.iter.Iterator).Item) -> bool throws E2
) -> baml.iter.Iterator<Error = (Self as baml.iter.Iterator).Error | E2, Item = (Self as baml.iter.Iterator).Item> throws never

Returns an iterator over everything from the first element predicate rejects onwards.

That first rejected element is itself yielded — it is the start of the kept run, not a discarded boundary. The predicate is not consulted again afterwards, so later elements it would have matched are still yielded.

Returns

A baml.iter.SkipWhile.

Examples

// stops skipping at 3, so the trailing 1 and 2 are kept
[1, 2, 3, 1, 2].iter().skip_while((x: int) -> bool { x < 3 }).collect() // [3, 1, 2]
function

some

<E2>(
self,
predicate: ((Self as baml.iter.Iterator).Item) -> bool throws E2
) -> bool throws (Self as baml.iter.Iterator).Error | E2

Whether predicate holds for any remaining element — Python's any, JavaScript's some.

Short circuits at the first true, leaving the iterator positioned just after the matching element so it can be inspected further. An empty iterator gives false, the empty disjunction.

Throws

  • Self.Error if advancing the iterator fails.
  • E2 if predicate throws.

ALIASES: any

function

step_by

(
self,
n: int
) -> baml.iter.Iterator<Error = (Self as baml.iter.Iterator).Error, Item = (Self as baml.iter.Iterator).Item> throws never

Returns an iterator over every nth element, starting with the first.

The elements kept are those at positions 0, n, 2n, and so on. The skipped ones are still pulled from the source — and so may still throw — they are simply discarded.

Parameters

  • n: how far to advance between yielded elements. Values below 1 mean "advance by one", i.e. yield everything.

Returns

A baml.iter.StepBy.

function

take

(
self,
n: int
) -> baml.iter.Iterator<Error = (Self as baml.iter.Iterator).Error, Item = (Self as baml.iter.Iterator).Item> throws never

Returns an iterator over at most the first n elements.

Once n elements have been yielded the source is no longer advanced, and if the source ends first this ends with it. For n <= 0 it yields nothing. A slot is spent only once the source has actually yielded an element, so a source that throws and is then retried does not silently lose one.

This is the usual way to bound an unbounded iterator such as Repeat.new(v) or a wide Range.

Parameters

  • n: the greatest number of elements to yield.

Returns

A baml.iter.Take yielding at most n elements.

Examples

baml.iter.Repeat.new(0).take(5).collect()   // [0, 0, 0, 0, 0]
baml.iter.Range.new(0, 10).take(3).collect() // [0, 1, 2]
function

take_while

<E2>(
self,
predicate: ((Self as baml.iter.Iterator).Item) -> bool throws E2
) -> baml.iter.Iterator<Error = (Self as baml.iter.Iterator).Error | E2, Item = (Self as baml.iter.Iterator).Item> throws never

Returns an iterator over the leading run of elements for which predicate is true.

The element that fails the predicate is consumed from the source and is not yielded. Unlike filter, iteration stops at the first failure rather than skipping it, and the stop latches: the source is never advanced again, however often next is called.

Returns

A baml.iter.TakeWhile.

Examples

// stops at 5, so 6 and 8 are never yielded
[2, 4, 5, 6, 8].iter().take_while((x: int) -> bool { x % 2 == 0 }).collect() // [2, 4]

Source:<builtin>/baml/ns_csv/csv.bamlbytes 15581–16952