Skill Tracer
Skills › Scientific Agent Skills › vaex › io_operations.md

io_operations.md

154 lines · skills/vaex/references/io_operations.md at 5f2bc03

Open on GitHub
1# File I/O and remote data
2
3Targets core 4.19.0 / HDF5 0.15.0. [Official I/O guide](https://vaex.io/docs/guides/io.html)
4and released readers/writers define these contracts.
5

File I/O and remote data

Targets core 4.19.0 / HDF5 0.15.0. Official I/O guide and released readers/writers define these contracts.

Raw lines 1 to 5
6## Local format round trips
7
8This small fixture uses a temporary directory. Real exports overwrite existing paths
9by default: choose a new destination, verify it, then manage replacement explicitly.
11```python
12from pathlib import Path
13from tempfile import TemporaryDirectory
14import csv
15import numpy as np
16import pyarrow as pa
17import pyarrow.csv as pacsv
18import vaex
20workspace = TemporaryDirectory()
21root = Path(workspace.name)
22df = vaex.from_arrays(id=np.array(['001', '002', '003']), x=np.array([1., 2., 3.]))
23df['twice'] = 2 * df.x
24paths = {ext: root / ('data.' + ext) for ext in ['hdf5', 'arrow', 'feather', 'parquet', 'csv']}
25df.export_hdf5(str(paths['hdf5']), chunk_size=2)
26df.export_arrow(str(paths['arrow']), chunk_size=2) # Arrow IPC stream by default
27df.export_feather(str(paths['feather']), compression='lz4')
28df.export_parquet(str(paths['parquet']), compression='snappy', chunk_size=2)
29df.export_csv(str(paths['csv']), index=False, chunk_size=2)
30for ext in ['hdf5', 'arrow', 'feather', 'parquet']:
31 reopened = vaex.open(str(paths[ext]))
32 assert reopened.id.tolist() == ['001', '002', '003']
33 assert reopened.twice.tolist() == [2., 4., 6.]
34# Arrow stream and Arrow file readers differ:
35with pa.input_stream(str(paths['arrow'])) as source:
36 table = pa.ipc.open_stream(source).read_all() # this small fixture fits in RAM
37assert table.num_rows == 3
38```
40HDF5 means the Vaex tabular layout, not arbitrary HDF5. `export_hdf5` has no
41`compression=` keyword. `mode='a'` appends a **different group**, not rows to the same
42table. Do not implement incremental row export by repeatedly writing `/table` in append
43mode. For compression use a tested Parquet/Feather format and verify type/null fidelity.
44Nested Arrow structures and multidimensional columns have format-specific limits;
45round-trip a representative fixture before a full conversion.
47`export_arrow` defaults to a stream (`as_stream=True`); request `as_stream=False`
48when an Arrow IPC file is required. `export_feather` uses its own Feather writer and
49can materialize a table; do not assume its memory profile matches chunked Arrow export.
50Compressed buffers cannot provide the same memory-map behavior as uncompressed columns.

Local format round trips

This small fixture uses a temporary directory. Real exports overwrite existing paths by default: choose a new destination, verify it, then manage replacement explicitly.

from pathlib import Path
from tempfile import TemporaryDirectory
import csv
import numpy as np
import pyarrow as pa
import pyarrow.csv as pacsv
import vaex

workspace = TemporaryDirectory()
root = Path(workspace.name)
df = vaex.from_arrays(id=np.array(['001', '002', '003']), x=np.array([1., 2., 3.]))
df['twice'] = 2 * df.x
paths = {ext: root / ('data.' + ext) for ext in ['hdf5', 'arrow', 'feather', 'parquet', 'csv']}
df.export_hdf5(str(paths['hdf5']), chunk_size=2)
df.export_arrow(str(paths['arrow']), chunk_size=2)  # Arrow IPC stream by default
df.export_feather(str(paths['feather']), compression='lz4')
df.export_parquet(str(paths['parquet']), compression='snappy', chunk_size=2)
df.export_csv(str(paths['csv']), index=False, chunk_size=2)
for ext in ['hdf5', 'arrow', 'feather', 'parquet']:
    reopened = vaex.open(str(paths[ext]))
    assert reopened.id.tolist() == ['001', '002', '003']
    assert reopened.twice.tolist() == [2., 4., 6.]
# Arrow stream and Arrow file readers differ:
with pa.input_stream(str(paths['arrow'])) as source:
    table = pa.ipc.open_stream(source).read_all()  # this small fixture fits in RAM
assert table.num_rows == 3

HDF5 means the Vaex tabular layout, not arbitrary HDF5. export_hdf5 has no compression= keyword. mode='a' appends a different group, not rows to the same table. Do not implement incremental row export by repeatedly writing /table in append mode. For compression use a tested Parquet/Feather format and verify type/null fidelity. Nested Arrow structures and multidimensional columns have format-specific limits; round-trip a representative fixture before a full conversion.

export_arrow defaults to a stream (as_stream=True); request as_stream=False when an Arrow IPC file is required. export_feather uses its own Feather writer and can materialize a table; do not assume its memory profile matches chunked Arrow export. Compressed buffers cannot provide the same memory-map behavior as uncompressed columns.

Raw lines 6 to 51
52## CSV types, chunking and conversion
54```python
55# Check raw column names before a CSV parser silently renames duplicates.
56with paths['csv'].open(newline='', encoding='utf-8') as handle:
57 headers = next(csv.reader(handle))
58assert len(headers) == len(set(headers))
59options = pacsv.ConvertOptions(column_types={'id': pa.string(), 'x': pa.float64(), 'twice': pa.float64()})
60lazy = vaex.from_csv_arrow(str(paths['csv']), lazy=True, convert_options=options,
61 chunk_size='1MiB')
62assert lazy.id.tolist() == ['001', '002', '003']
63# pandas-backed reader is eager unless chunk_size or conversion is requested.
64eager = vaex.from_csv(str(paths['csv']), dtype={'id': str})
65assert eager.id.tolist() == ['001', '002', '003']
66part_paths = []
67for index, chunk in enumerate(vaex.from_csv(str(paths['csv']), chunk_size=2, dtype={'id': str})):
68 chunk['offset'] = chunk.x + 10
69 path = root / f'part-{index:04d}.hdf5'
70 chunk.export_hdf5(str(path))
71 part_paths.append(str(path))
72combined = vaex.open_many(part_paths)
73assert combined.offset.tolist() == [11., 12., 13.]
74converted = vaex.from_csv(str(paths['csv']), convert=str(root / 'converted.hdf5'),
75 chunk_size=2, dtype={'id': str})
76assert converted.id.tolist() == ['001', '002', '003']
77```
79Use `vaex.from_csv(..., chunk_size=...)` for the iterator; there is no public
80`from_csv_chunked` function. `from_csv(..., convert=...)` writes intermediate parts
81and a combined file, so budget temporary disk space as well as the final output.
82Lazy CSV does schema/index work and does not support compressed CSV files in this
83release. `convert_options` is the correct parameter for Arrow column type hints.
84Inspect null spellings, delimiter, quoting, encoding and units. The metadata cache and
85conversion-reuse logic are conveniences, not content-addressed provenance: record source
86checksums and use a fresh destination when inputs change.
88For SQL, use a bounded pandas/SQLAlchemy chunk iterator and export each chunk to a
89separate file, then `vaex.open_many`. Collecting all chunks in a list retains all data
90in RAM. SQL import/export is not a native Vaex database endpoint; parameter binding,
91transactions and schema belong to the chosen database client. Never interpolate user
92values into SQL or put passwords in examples/logs.

CSV types, chunking and conversion

# Check raw column names before a CSV parser silently renames duplicates.
with paths['csv'].open(newline='', encoding='utf-8') as handle:
    headers = next(csv.reader(handle))
assert len(headers) == len(set(headers))
options = pacsv.ConvertOptions(column_types={'id': pa.string(), 'x': pa.float64(), 'twice': pa.float64()})
lazy = vaex.from_csv_arrow(str(paths['csv']), lazy=True, convert_options=options,
                           chunk_size='1MiB')
assert lazy.id.tolist() == ['001', '002', '003']
# pandas-backed reader is eager unless chunk_size or conversion is requested.
eager = vaex.from_csv(str(paths['csv']), dtype={'id': str})
assert eager.id.tolist() == ['001', '002', '003']
part_paths = []
for index, chunk in enumerate(vaex.from_csv(str(paths['csv']), chunk_size=2, dtype={'id': str})):
    chunk['offset'] = chunk.x + 10
    path = root / f'part-{index:04d}.hdf5'
    chunk.export_hdf5(str(path))
    part_paths.append(str(path))
combined = vaex.open_many(part_paths)
assert combined.offset.tolist() == [11., 12., 13.]
converted = vaex.from_csv(str(paths['csv']), convert=str(root / 'converted.hdf5'),
                          chunk_size=2, dtype={'id': str})
assert converted.id.tolist() == ['001', '002', '003']

Use vaex.from_csv(..., chunk_size=...) for the iterator; there is no public from_csv_chunked function. from_csv(..., convert=...) writes intermediate parts and a combined file, so budget temporary disk space as well as the final output. Lazy CSV does schema/index work and does not support compressed CSV files in this release. convert_options is the correct parameter for Arrow column type hints. Inspect null spellings, delimiter, quoting, encoding and units. The metadata cache and conversion-reuse logic are conveniences, not content-addressed provenance: record source checksums and use a fresh destination when inputs change.

For SQL, use a bounded pandas/SQLAlchemy chunk iterator and export each chunk to a separate file, then vaex.open_many. Collecting all chunks in a list retains all data in RAM. SQL import/export is not a native Vaex database endpoint; parameter binding, transactions and schema belong to the chosen database client. Never interpolate user values into SQL or put passwords in examples/logs.

Raw lines 52 to 93
94## State is separate from data
96```python
97state_path = root / 'expressions.json'
98df.state_write(str(state_path))
99fresh = vaex.from_arrays(id=np.array(['001', '002', '003']), x=np.array([1., 2., 3.]))
100fresh.state_load(str(state_path), set_filter=False, trusted=True)
101assert fresh.twice.tolist() == [2., 4., 6.]
102workspace.cleanup()
103```
105A state file stores definitions, variables, selections and serialized functions; it is
106not a data backup. Loading it can alter filters/columns and execute deserialized Python
107objects. Use only trusted state plus matching schema/units/software versions.
108`set_filter=False` prevents importing the training filter; validate target row count
109and identities after transfer. Models appear only after their prediction transform is
110attached to the saved DataFrame. See [ML](machine_learning.md).

State is separate from data

state_path = root / 'expressions.json'
df.state_write(str(state_path))
fresh = vaex.from_arrays(id=np.array(['001', '002', '003']), x=np.array([1., 2., 3.]))
fresh.state_load(str(state_path), set_filter=False, trusted=True)
assert fresh.twice.tolist() == [2., 4., 6.]
workspace.cleanup()

A state file stores definitions, variables, selections and serialized functions; it is not a data backup. Loading it can alter filters/columns and execute deserialized Python objects. Use only trusted state plus matching schema/units/software versions. set_filter=False prevents importing the training filter; validate target row count and identities after transfer. Models appear only after their prediction transform is attached to the saved DataFrame. See ML.

Raw lines 94 to 111
112## Remote/cloud I/O: source-verified, not service-tested
114Core has native S3 handling through PyArrow with an s3fs fallback and GCS handling
115through gcsfs. `fs_options` keys are backend-specific; an explicit `fs` object and
116`fs_options` should not be combined. Remote reads may create a local file cache.
117Examples below are illustrative and require an accessible object plus credentials
118configured outside the code. They were checked against source, not run against accounts.
120```python
121s3 = vaex.open('s3://example-bucket/measurements.parquet',
122 fs_options={'profile': 'research', 'region': 'us-east-1'})
123gcs = vaex.open('gs://example-bucket/measurements.parquet',
124 fs_options={'project': 'research-project'})
125```
127Do not assume installing `adlfs` makes an `az://` URI understood by every Vaex reader.
128For another backend, configure its filesystem and verify a representative read with
129`fs=` using that backend's current documentation. Native HDF5 writer is path/h5py based;
130it does not offer `fs`/`fs_options` and should not be advertised as a cloud writer.
131Stage locally, verify, and upload with the authorized storage client. Arrow/Parquet
132writers expose filesystem options, but authenticated writes were not tested in this review.

Remote/cloud I/O: source-verified, not service-tested

Core has native S3 handling through PyArrow with an s3fs fallback and GCS handling through gcsfs. fs_options keys are backend-specific; an explicit fs object and fs_options should not be combined. Remote reads may create a local file cache. Examples below are illustrative and require an accessible object plus credentials configured outside the code. They were checked against source, not run against accounts.

s3 = vaex.open('s3://example-bucket/measurements.parquet',
               fs_options={'profile': 'research', 'region': 'us-east-1'})
gcs = vaex.open('gs://example-bucket/measurements.parquet',
                fs_options={'project': 'research-project'})

Do not assume installing adlfs makes an az:// URI understood by every Vaex reader. For another backend, configure its filesystem and verify a representative read with fs= using that backend's current documentation. Native HDF5 writer is path/h5py based; it does not offer fs/fs_options and should not be advertised as a cloud writer. Stage locally, verify, and upload with the authorized storage client. Arrow/Parquet writers expose filesystem options, but authenticated writes were not tested in this review.

Raw lines 112 to 133
134## Vaex server: separate optional package
136The current server guide and vaex-server 0.10.0 source use `vaex server`:
138```bash
139# Illustrative: requires vaex-server and a compatible file; local interface only.
140vaex server --host 127.0.0.1 --port 9000 measurements=measurements.hdf5
141```
143```python
144# Illustrative: server must already be running.
145remote = vaex.open('ws://127.0.0.1:9000/measurements')
146remote_mean = remote.mean('x')
147```
149The Python client uses the WebSocket protocol, not a guessed REST `/data` endpoint.
150The name here is the explicit `measurements=` alias. Use the server's schema/docs
151for REST clients; the skill does not define custom endpoints or pagination. External
152access needs deployment-specific authentication and TLS; the basic CLI is not a
153production authentication setup. Server startup/client compatibility and authenticated
154remote operations were not executed here. [Server guide](https://vaex.io/docs/guides/server.html).

Vaex server: separate optional package

The current server guide and vaex-server 0.10.0 source use vaex server:

# Illustrative: requires vaex-server and a compatible file; local interface only.
vaex server --host 127.0.0.1 --port 9000 measurements=measurements.hdf5
# Illustrative: server must already be running.
remote = vaex.open('ws://127.0.0.1:9000/measurements')
remote_mean = remote.mean('x')

The Python client uses the WebSocket protocol, not a guessed REST /data endpoint. The name here is the explicit measurements= alias. Use the server's schema/docs for REST clients; the skill does not define custom endpoints or pagination. External access needs deployment-specific authentication and TLS; the basic CLI is not a production authentication setup. Server startup/client compatibility and authenticated remote operations were not executed here. Server guide.

Raw lines 134 to 154