Skip to content

Add CSV Inventory import to python client#55

Merged
tilorspace merged 3 commits into
masterfrom
feature/inventory-csv-import-32
Jul 14, 2026
Merged

Add CSV Inventory import to python client#55
tilorspace merged 3 commits into
masterfrom
feature/inventory-csv-import-32

Conversation

@tilorspace

Copy link
Copy Markdown
Contributor

Support importing Inventory CSV files (samples, subsamples, containers)

Closes #32

Summary

Adds client support for the Inventory API's CSV import endpoints, so users can bulk import samples, subsamples and containers from CSV files instead of building records one at a time. The client previously had no way to drive CSV import.

What's new

New InventoryClient methods:

Method Purpose
parse_csv_import_file(file, record_type) Analyse a CSV before importing: returns its columns, the server's suggested field mappings, and (for samples) a suggested Sample Template. Creates nothing.
import_csv_files(import_settings, containers_file=, samples_file=, subsamples_file=) Low-level import that mirrors the API: submit one or more CSVs in a single operation with full settings.
import_samples_csv(samples_file, field_mappings, template_id=, template_info=) Convenience wrapper for importing samples.
import_containers_csv(containers_file, field_mappings) Convenience wrapper for importing LIST containers.
import_subsamples_csv(subsamples_file, field_mappings) Convenience wrapper for importing subsamples into existing samples (referenced by Global Id).

Plus a new ImportRecordType enum (SAMPLES, SUBSAMPLES, CONTAINERS).

A field_mappings dict maps each CSV column name to an RSpace field name, for example "name", "description", "quantity", "expiry date", "identifier", "import identifier", "parent container import id", "parent container global id", "parent sample import id", "parent sample global id". Map a column to None to ignore it.

Usage

inv = rspace_client.utils.createInventoryClient()

# Optional: inspect columns and suggested mappings first
parse = inv.parse_csv_import_file(open("antibodies.csv", "rb"), "SAMPLES")

# Import samples, creating a new template from the CSV columns
result = inv.import_samples_csv(
    open("antibodies.csv", "rb"),
    field_mappings={"Name": "name", "Comment": "description"},
    template_info={"name": "Antibodies imported from CSV"},
)
print(result["status"], result["sampleResults"]["successCount"])

See the runnable examples/import_inventory_csv.py for samples, containers, and subsamples.

Scope and behaviour notes

  • Instruments and Instrument Templates cannot be imported from CSV. This is an API limitation, not a client one, so it is documented on ImportRecordType and in the changelog rather than silently omitted.
  • Container support is limited to simple LIST containers, matching the API.
  • The convenience methods validate inputs client-side and raise ValueError early (before any network call) when a required mapping is missing: samples/containers/subsamples must map a column to "name", samples require a template (template_id or template_info), and subsamples require a "parent sample global id" mapping.
  • A rejected import (prevalidation error or full rollback) is returned by the server as HTTP 200 with a status of PREVALIDATION_ERROR or REVERTED_ON_ERROR, so these methods return the result dict without raising. Callers should check result["status"].
  • Request settings are serialised with json.dumps, so field mappings and template info cannot break the request structure.

Endpoints used

  • POST /api/inventory/v1/import/parseFile (multipart file + recordType)
  • POST /api/inventory/v1/import/importFiles (multipart containersFile / samplesFile / subSamplesFile + importSettings)

Tests

Added integration tests in rspace_client/tests/invapi_test.py following the existing pattern (skipped automatically without API credentials): parse, import for each record type, subsample import into a pre-existing sample, and the client-side validation guards.

Changelog

Added an Unreleased entry.

tilorspace and others added 2 commits July 13, 2026 13:48
The import prevalidation requires the number of unmapped CSV columns to
exactly equal the number of custom fields in the target template. The test
used a zero-field template but left the 'Comment' column unmapped, so the
server returned PREVALIDATION_ERROR. Map 'Comment' to the built-in
'description' field so no template field is required. Also document this
column/template-field rule on import_samples_csv.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Python client support for Inventory CSV import workflows by introducing parse/import methods on InventoryClient, an enum for supported record types, an example script, and integration tests to exercise the new endpoints.

Changes:

  • Added ImportRecordType and new InventoryClient methods to parse CSVs and import samples/containers/subsamples via multipart endpoints.
  • Added integration tests covering parse + import flows and client-side validation guards.
  • Added a runnable example script and documented the feature in the changelog.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
rspace_client/inv/inv.py Adds CSV import enum + multipart parse/import methods and convenience wrappers for samples/containers/subsamples.
rspace_client/tests/invapi_test.py Adds integration tests for CSV parse/import and validation error cases.
examples/import_inventory_csv.py Adds a runnable example demonstrating parse + import for all supported record types.
CHANGELOG.md Documents the new CSV import support under Unreleased.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rspace_client/inv/inv.py
Comment thread rspace_client/inv/inv.py
…review)

Addresses Copilot review on PR #55: the docstrings state exactly one column
must map to 'name' (and, for subsamples, to 'parent sample global id'), but the
validation only checked presence. Multiple mappings are silently resolved by
the server (last wins), so fail fast client-side instead.

Adds a generic _require_single_mapping helper enforcing a count of exactly one,
used for 'name' across all import types and for 'parent sample global id' in
import_subsamples_csv, plus tests for the duplicate-mapping cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@nebay-abraha nebay-abraha left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good 👍

@tilorspace tilorspace merged commit c941dfc into master Jul 14, 2026
7 checks passed
@tilorspace tilorspace deleted the feature/inventory-csv-import-32 branch July 14, 2026 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support import of CSV files

3 participants