samples¶
samples
¶
CRUD wrapper for the samples table.
Same call style as the other table modules: cursor first, dict returns,
writes audit-logged via _LoggingCursor.
sample_name is globally unique (not scoped to a visit), so the
natural-key lookup is get_by_name
and get_or_create keys on
sample_name alone.
Two independent coordinate systems live on this table and must not be
confused — they were, until 004_ip_and_sequencing_coords:
IPR / IPRP
Immunoprecipitation run and plate, from columns N (IP run #)
and O (Plate #) of the lab's "Overview of IP runs" sheet. The
RxxPxx in the sample name is not a reliable source: plates were
relabelled on some files, so the name is never read for this.
Plate-based control linking keys on this pair, because controls
occupy wells 81-96 of the IP plate.
SQR / SQRP
Sequencing run and its plate, from the run sheet. Unrelated to the
name: R14P02_77_.. was sequenced as SQR 07, plate 02.
The same run sheet gives each sequenced sample its barcodes
(007_sample_barcodes): i7_index / i5_index are the index
sequences, i7_index_id / i5_index_id the kit's names for them.
NULL means not known. set_sequencing
sets these and SQR / SQRP on a sample that already exists.
canonical_plate_id
¶
Return the canonical form of a run or plate identifier.
Strips surrounding whitespace, collapses the "absent" sentinels
("", "NA", "N/A", case-insensitive) to a single
canonical empty string, and zero-pads a purely numeric identifier
to two characters. Anything non-numeric is returned stripped but
otherwise verbatim.
The padding matters: matching is by exact string, so "5" and
"05" used to describe one physical plate as two, which left
whole projects with no controls. Normalizing here means every write
path agrees on one spelling.
This is the one normalization chokepoint for both coordinate pairs;
create / update
call it on every write and the importer reuses it so the value the
DB stores is always canonical and coordinate matching is reliable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str | None
|
Raw IPR / IPRP / SQR / SQRP cell (may be |
required |
Returns:
| Type | Description |
|---|---|
str
|
The canonical identifier (possibly |
Source code in src/noxdb/samples.py
canonical_index
¶
Return the canonical form of an i7 / i5 index sequence.
Strips whitespace and upper-cases. The DB only accepts upper-case
A, C, G, T and N.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str | None
|
Raw index sequence (may be |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
The sequence, or |
Raises:
| Type | Description |
|---|---|
ValueError
|
If anything other than A, C, G, T or N remains. |
Source code in src/noxdb/samples.py
canonical_index_id
¶
Return an index's kit name (e.g. IDT10_i7_1) stripped, None if empty.
create
¶
create(cur, visit_id: int, sample_name: str, sample_type: str, sqr: str, sqrp: str, library: str, *, ipr: str, iprp: str, antibody_class: str | None = None, i7_index: str | None = None, i7_index_id: str | None = None, i5_index: str | None = None, i5_index_id: str | None = None) -> int
Insert a sample and return its new sample_id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
visit_id
|
int
|
Parent visit. Must already exist. |
required |
sample_name
|
str
|
Globally unique sample name. |
required |
sample_type
|
str
|
One of |
required |
sqr
|
str
|
Sequencing run, from the run sheet. Canonicalized via
|
required |
sqrp
|
str
|
Sequencing plate within that run. Canonicalized like
|
required |
library
|
str
|
Library identifier. |
required |
ipr
|
str
|
IP run, from the IP-runs overview sheet. Canonicalized via
|
required |
iprp
|
str
|
IP plate within that run, |
required |
antibody_class
|
str | None
|
Optional antibody class label. |
None
|
i7_index
|
str | None
|
i7 index sequence, from the run sheet. Canonicalized
via |
None
|
i7_index_id
|
str | None
|
The kit's name for the i7 index (e.g. |
None
|
i5_index
|
str | None
|
i5 index sequence. Canonicalized like |
None
|
i5_index_id
|
str | None
|
The kit's name for the i5 index. |
None
|
Returns:
| Type | Description |
|---|---|
int
|
The newly inserted |
Raises:
| Type | Description |
|---|---|
ValueError
|
If an index sequence has characters other than A, C, G, T and N. |
IntegrityError
|
If |
Source code in src/noxdb/samples.py
get
¶
Return the sample row for a given id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
sample_id
|
int
|
Primary key to look up. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
The row as |
Source code in src/noxdb/samples.py
get_by_name
¶
Return the sample row for a given name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
sample_name
|
str
|
Globally unique sample name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
The row as |
Source code in src/noxdb/samples.py
get_or_create
¶
get_or_create(cur, visit_id: int, sample_name: str, sample_type: str, sqr: str, sqrp: str, library: str, *, ipr: str, iprp: str, antibody_class: str | None = None, i7_index: str | None = None, i7_index_id: str | None = None, i5_index: str | None = None, i5_index_id: str | None = None) -> tuple[int, bool]
Idempotently return the sample id, inserting if needed.
Existing rows are returned as-is — the other columns are not used to update an existing row. Falls back to a re-fetch on the UNIQUE-violation race.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
visit_id
|
int
|
Parent visit (used only on insert). |
required |
sample_name
|
str
|
Globally unique sample name. |
required |
sample_type
|
str
|
Used only on insert. See
|
required |
sqr
|
str
|
Sequencing run. Used only on insert. |
required |
sqrp
|
str
|
Sequencing plate. Used only on insert. |
required |
library
|
str
|
Used only on insert. |
required |
ipr
|
str
|
IP run. Used only on insert. |
required |
iprp
|
str
|
IP plate. Used only on insert. |
required |
antibody_class
|
str | None
|
Used only on insert. |
None
|
i7_index
|
str | None
|
Used only on insert. |
None
|
i7_index_id
|
str | None
|
Used only on insert. |
None
|
i5_index
|
str | None
|
Used only on insert. |
None
|
i5_index_id
|
str | None
|
Used only on insert. |
None
|
Returns:
| Type | Description |
|---|---|
int
|
|
bool
|
call inserted the row. |
Raises:
| Type | Description |
|---|---|
IntegrityError
|
If the race-recovery fetch also misses. |
Source code in src/noxdb/samples.py
link_to_project
¶
Register sample_id under project_id in project_samples.
Idempotent: INSERT IGNORE so re-linking an already-linked
(project, sample) pair is a no-op. project_samples is the sole
source of truth for which samples belong to which project — a
sample may be linked to several projects (e.g. plate controls
shared across studies).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
project_id
|
int
|
Project to link the sample to. Must already exist. |
required |
sample_id
|
int
|
Sample to link. Must already exist. |
required |
Source code in src/noxdb/samples.py
list_for_visit
¶
Return all samples belonging to a visit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
visit_id
|
int
|
Visit to list. |
required |
order_by
|
str
|
Column name to order by. Must be a column of |
'sample_id'
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
All matching rows as |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/noxdb/samples.py
count_for_visit
¶
Return the number of samples for a visit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
visit_id
|
int
|
Visit to count. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of sample rows. |
Source code in src/noxdb/samples.py
update
¶
update(cur, sample_id: int, *, sample_name: str | None = None, sample_type: str | None = None, ipr: str | None = None, iprp: str | None = None, sqr: str | None = None, sqrp: str | None = None, library: str | None = None, antibody_class: str | None = None, i7_index: str | None = None, i7_index_id: str | None = None, i5_index: str | None = None, i5_index_id: str | None = None, manually_checked: bool | None = None) -> bool
Partial update of a sample row.
Only kwargs with non-None values are written. visit_id and
created_at are intentionally NOT updatable — re-parenting a
sample would corrupt downstream lineage. Setting antibody_class
or a barcode to NULL is also out of scope (the helper treats None
as "skip"); use raw SQL if you need that. To fill in sequencing
values without overwriting any by accident, use
set_sequencing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
sample_id
|
int
|
Row to update. |
required |
sample_name
|
str | None
|
New name (if not None). |
None
|
sample_type
|
str | None
|
New type (if not None). See
|
None
|
ipr
|
str | None
|
New IP run (if not None). Canonicalized via
|
None
|
iprp
|
str | None
|
New IP plate (if not None). Canonicalized like |
None
|
sqr
|
str | None
|
New sequencing run (if not None). Canonicalized like
|
None
|
sqrp
|
str | None
|
New sequencing plate (if not None). Canonicalized like
|
None
|
library
|
str | None
|
New library (if not None). |
None
|
antibody_class
|
str | None
|
New antibody class (if not None). |
None
|
i7_index
|
str | None
|
New i7 index sequence (if not None). Canonicalized
via |
None
|
i7_index_id
|
str | None
|
New i7 index name (if not None). |
None
|
i5_index
|
str | None
|
New i5 index sequence (if not None). Canonicalized
like |
None
|
i5_index_id
|
str | None
|
New i5 index name (if not None). |
None
|
manually_checked
|
bool | None
|
Whether the sample's metadata has been checked by hand (if not None). |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If an index sequence has characters other than A, C, G, T and N. |
Source code in src/noxdb/samples.py
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | |
sequencing_changes
¶
sequencing_changes(stored: dict[str, Any], *, sqr: str | None = None, sqrp: str | None = None, i7_index: str | None = None, i7_index_id: str | None = None, i5_index: str | None = None, i5_index_id: str | None = None) -> tuple[dict[str, Any], list[str]]
Work out what setting sequencing values on a stored sample would change.
Nothing is written. The values are canonicalized the way they would
be stored; an empty or None value means "leave as is".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stored
|
dict[str, Any]
|
The sample row, e.g. from |
required |
sqr
|
str | None
|
Sequencing run. |
None
|
sqrp
|
str | None
|
Sequencing plate. |
None
|
i7_index
|
str | None
|
i7 index sequence. |
None
|
i7_index_id
|
str | None
|
i7 index name. |
None
|
i5_index
|
str | None
|
i5 index sequence. |
None
|
i5_index_id
|
str | None
|
i5 index name. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
|
list[str]
|
would change to its new value. conflicts describes the changes |
tuple[dict[str, Any], list[str]]
|
that replace a value the sample already had (rather than fill in |
tuple[dict[str, Any], list[str]]
|
an empty one), e.g. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If an index sequence has characters other than A, C, G, T and N. |
Source code in src/noxdb/samples.py
set_sequencing
¶
set_sequencing(cur, sample_id: int, *, sqr: str | None = None, sqrp: str | None = None, i7_index: str | None = None, i7_index_id: str | None = None, i5_index: str | None = None, i5_index_id: str | None = None, overwrite: bool = False) -> bool
Set the sequencing run, plate and barcodes of an existing sample.
Only the values given are written. An empty column is filled in and one that already holds the same value is left alone. One that holds a different value is refused unless overwrite is set: a sample's sequencing values normally change only when it is re-sequenced, so a difference is more often a mismatched row than a correction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
sample_id
|
int
|
Sample to update. Must exist. |
required |
sqr
|
str | None
|
Sequencing run. Canonicalized via
|
None
|
sqrp
|
str | None
|
Sequencing plate. Canonicalized like |
None
|
i7_index
|
str | None
|
i7 index sequence. Canonicalized via
|
None
|
i7_index_id
|
str | None
|
i7 index name, e.g. |
None
|
i5_index
|
str | None
|
i5 index sequence. Canonicalized like |
None
|
i5_index_id
|
str | None
|
i5 index name. |
None
|
overwrite
|
bool
|
Replace values that differ instead of refusing. |
False
|
Returns:
| Type | Description |
|---|---|
bool
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the sample does not exist, if a value would replace a different stored one and overwrite is not set, or if an index sequence has characters other than A, C, G, T and N. |
Source code in src/noxdb/samples.py
delete
¶
Delete a sample.
sample_metadata.fk_sample_metadata_sample is ON DELETE
CASCADE, so this also removes every metadata row owned by the
sample. sample_files.fk_sample_files_sample is ON DELETE
RESTRICT and will block the delete instead — clean those up
first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
sample_id
|
int
|
Row to delete. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in src/noxdb/samples.py
exists
¶
Return whether a sample with the given id or name exists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
sample_id
|
int | None
|
Id to check (exclusive with |
None
|
name
|
str | None
|
Name to check (exclusive with |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If both or neither of |