Import measurement data as DataCreationDTO into OpenSILEX via the AddList API
(POST /core/data), driven by a CSV file and a YAML configuration. Data is sent in
batches (default 5000) and a full report is produced for every row.
The data import script processes a CSV file to create OpenSILEX data points. For each row, it:
- Parses the CSV — auto-detects the header row and comment lines, applies the configured encoding
- Maps columns — resolves CSV columns to
DataCreationDTOfields (date, value, variable, target, device) - Resolves URIs — looks up variable, device and target URIs from the name → URI mappings (or uses URIs as-is)
- Builds DTOs — one
DataCreationDTOper measurement (long format) or per measurement column (wide format) - Sends in batches — POSTs batches to
POST /core/data, re-sending failed batches row by row - Writes a report — one report line per produced DTO, plus an errors file for failed/skipped rows
# download the example files (config + CSV, long and wide formats)
opensilex-py-download-data-config-example --dest ./data_examples
# import data
opensilex-py-run-data-import \
--host http://localhost:8666/rest \
--identifier admin@opensilex.org \
--password secret \
--csv data.csv \
--config config.yaml \
--verboseQuick test with the wide-format fixtures downloaded by the command above
(test_data_wide.csv + test_config_wide.yaml in the current directory):
opensilex-py-download-data-config-example
opensilex-py-run-data-import \
--host http://localhost:8666/rest \
--identifier admin@opensilex.org \
--password admin \
--csv test_data_wide.csv \
--config test_config_wide.yaml \
--verbose| Argument | Meaning | Default value | Notes |
|---|---|---|---|
--host |
Base URL of the OpenSILEX REST API (must include /rest). |
http://localhost:8666/rest |
Also via OPENSILEX_HOST. |
--identifier |
Email of the OpenSILEX account. | admin@opensilex.org |
Also via OPENSILEX_IDENTIFIER. |
--password |
Password of the OpenSILEX account. | None (required) | Also via OPENSILEX_PASSWORD. Avoid passing the password in clear text on the command line; prefer the environment variable. |
--csv |
Path to the CSV input file. | – | Required. |
--config |
Path to the YAML configuration file. | – | Required. |
--verbose / -v |
Print detailed logs and tracebacks. | False |
| Argument | Meaning | Default value | Notes |
|---|---|---|---|
--dest |
Destination directory where example files will be copied. | . (current directory) |
Directory is created automatically if it does not exist; can be relative or absolute path. |
# default – copies files into the current directory
opensilex-py-download-data-config-example
# specify a custom destination
opensilex-py-download-data-config-example --dest ./data_examplesGenerate a starter YAML configuration from a CSV file. The header row and comment lines are auto-detected, column roles (date, value, variable, target, device) are guessed from the column names, and the distinct values found in the variable/target/device columns are pre-filled as mapping keys (the URIs are left empty for the user to fill in).
# long format (default) – 1 row = 1 measurement
opensilex-py-generate-data-config --csv data.csv
# wide format – 1 row = N measurements (one column per measurement)
opensilex-py-generate-data-config --csv data.csv --format wide
# explicit output path and header line
opensilex-py-generate-data-config --csv data.csv --config config.yaml --header-row 4
# overwrite an existing config without being prompted
opensilex-py-generate-data-config --csv data.csv --force| Argument | Meaning | Default value | Notes |
|---|---|---|---|
--csv |
Path to the CSV file to analyze. | – | Required – the file must exist and be readable. |
--config |
Output YAML path. | <csv_stem>_config.yaml next to the CSV |
|
--format |
Data format: long (1 row = 1 measurement) or wide (1 row = N measurements). |
long |
|
--header-row |
1-indexed header line. | auto-detected | |
--force |
Overwrite an existing config without confirmation. | False |
Otherwise a prompt asks before overwriting. |
The config maps CSV columns to the DataCreationDTO fields, including the nested
provenance sub-object. Three name → existing URI mappings are provided
(variable_mapping, device_mapping, target_mapping); a value that is not in the
mapping but already looks like a URI is used as-is.
data:
format: long # long (1 line = 1 measurement) | wide (1 line = N measurements)
batch_size: 5000
csv:
encoding: utf-8-sig
header_row: 4 # 1-indexed header line (InfluxDB files start with '#' lines)
skip_comment_rows: true
metadata_rows: # optional: extract global constants from lines above the header
- { row: 1, column: 2, pattern: "Nom de la parcelle:{name}", assign_to: target }
variable_mapping:
soil_water_potential: "http://.../id/variable/soil_water_potential"
device_mapping:
WM_09: "https://.../device/WM_09"
target_mapping:
AVD: "opensilex-sandbox:id/scientific-object/so-vitadapt"
fields:
date: { column: "_time" }
value: { column: "_value", type: auto } # auto | float | int | bool | str
variable: { column: "_field" }
target: { column: "site" }
provenance:
uri: "https://.../provenance/WM_09_Tensiometer" # constant
experiments: ["http://.../experiment/crops-life-2026"] # constant list
prov_was_associated_with:
- { column: "device" } # per-row device -> device_mapping
# - { value: "HSTI" } # or a constant device
# wide format only:
# date_column: "Date et Heure"
# measurements: { hum1: "soil_humidity_1", temp1: "soil_temperature_1" }format: long– one CSV line produces oneDataCreationDTO.format: wide– one CSV line (a timestamp) is melted into NDataCreationDTO, one permeasurementscolumn (each with its own variable).- The device
rdf_typeis resolved from the OpenSILEX API (OntologyApi.get_uri_types,POST /ontology/uri_types) in batch; if it cannot be resolved it falls back tovocabulary:SensingDevice. - Rows that fail validation (missing value, unknown name, invalid date…) are not sent
and are reported as
skipped.
A report CSV <csv>_data_report.csv is written next to the input file with one line per
produced DTO: row (1-based data row, excluding header/comment lines), variable, status
(success | failed | skipped), reason, error, and timestamp (ISO 8601 UTC time the
import was run). When there are any failed or skipped rows, a second CSV
<csv>_data_errors.csv containing only those rows (with the same timestamp) is written next
to the input file and its path is printed to the console.
Failure isolation. When a whole batch is rejected, it is re-sent row by row so each
failing row is identified individually. When a batch is only partially created, the
already-created rows are not re-sent (to avoid duplicates): if the API returns an
ordered list of created items, the remaining rows are re-sent row by row; if it returns an
unordered count, the unconfirmed rows are reported as failed (not re-sent) so they can be
re-imported safely. A timestamped log file is also written in the CSV directory.
Size limit. The CSV is fully loaded into memory (a pandas DataFrame) before processing. This is fine for typical InfluxDB exports (tens of thousands of rows) but for very large exports (millions of rows / several GB) consider splitting the file into smaller chunks.
from opensilex_python_client.auth import connect
from opensilex_python_client.data import import_from_csv
client = connect.connect_to_opensilex({
"host": "http://localhost:8666/rest",
"identifier": "admin@opensilex.org",
"password": "secret",
})
import_from_csv.run(client, "data.csv", "config.yaml", debug=True)