Skip to content

Results and errors

What the frozen Session methods return, and the two exceptions a caller is expected to catch. The names and fields on this page are frozen at 1.0 (API stability) unless the stability page lists them as tier 2.

Method Returns
ingest() IngestSummary
audit(), scan_pixel_content() PhiReport of PhiFinding
lock_identities(), lock_identities_batch() LockingResult, a list of Instance
recover_patient_identity() Dict[str, Dict[str, Any]]: SOP Instance UID to the values its token holds
export(format="dicom") ExportSummary
export(format="wfdb") List[str], the paths written
discover_redaction_zones() DiscoveryResult
get_cohort_report() pandas.DataFrame
phi_status_summary() Dict[str, Counter] of PhiStatus
redact(), reconcile_private_tags(), auto_remediate_config() int

Import the two exceptions from the package: from isocenter import RedactionError, ExportError. Both subclass RuntimeError.

Summaries

IngestSummary dataclass

What ingest() did with each file it found.

A file takes exactly one of four routes. A declined file is not recorded as imported, so offering it again declines it again.

Attributes:

Name Type Description
ingested int

Files read into the graph.

failures List[Tuple[str, str]]

(path, reason) per rejected file, the same pair its ERROR audit row carries.

declined int

Files refused because the session already holds their SOP Instance UID (as another instance's UID, or as a redacted instance's UID before redaction). Each has a WARNING audit row and is not read into the store.

skipped int

Files already in the store, not read again.

failed int

len(failures).

failed property

How many files were rejected.

ExportSummary dataclass

What export(format="dicom") wrote, and what it did not.

Attributes:

Name Type Description
written_uids List[str]

The SOP Instance UID of each instance that reached disk, and nothing else. An instance with no UID is not written and is in failures.

failures List[Tuple[str, str]]

(entity_uid, details) per instance that did not reach disk, each with an audit row.

written int

Files that reached disk, counted over distinct UIDs: two instances sharing a UID write one file.

failed int

len(failures).

failed property

How many instances did not.

written property

How many files reached disk.

Counted over the de-duplicated UIDs: two instances sharing a UID write one file, the second overwriting the first.

Returns:

Type Description
int

The number of distinct written UIDs.

Findings

PhiReport(findings, failures=None)

A container for PHI findings that supports analysis and export.

Iterates, indexes and measures like the list of findings it wraps (len(report), report[0], for finding in report), and adds DataFrame export.

Attributes:

Name Type Description
findings List[PhiFinding]

The findings, one per report line.

failures List[Tuple[str, str]]

(entity_uid, reason), one per instance a pixel scan could not read in full: its pixels could not be loaded, or OCR raised on at least one of its frames. scan_pixel_content() fills it; an instance that failed on some frames keeps the findings of the frames that were read. It is always a list, never None. audit()'s is always empty: a failure in its workers raises instead.

to_dataframe()

Convert the findings to a pandas DataFrame, one row each.

Returns:

Type Description
pd.DataFrame

A dataframe containing flattened finding details.

Raises:

Type Description
ImportError

If pandas is not installed.

PhiFinding dataclass

A potential PHI breach discovered during a scan: one report line.

Attributes:

Name Type Description
entity_uid str

Unique identifier of the entity (PatientID, SOPInstanceUID).

entity_type str

"Patient", "Study", "Series" or "Instance".

field_name str

The specific field or tag description.

value Any

The PHI value found.

reason str

Why this was flagged (e.g. "Safe Harbor Rules").

tag Optional[str]

The DICOM tag (e.g., "0010,0010").

patient_id Optional[str]

Linkage for context.

entity Any

The live object in session.store the finding names, or None when it cannot be found.

remediation_proposal Optional[PhiRemediation]

The suggested fix, which anonymize() applies.

metadata Dict[str, Any]

Context carried with the finding.

entity_path Tuple

Route from the Instance to the item this was raised against, as (sequence_tag, index) steps. Empty means the Instance itself. The only way to rebind a finding to its sequence item after it crosses a process boundary.

PhiRemediation dataclass

Proposed action to fix a PHI finding.

Attributes:

Name Type Description
action_type str

REMOVE_TAG, REPLACE_TAG or SHIFT_DATE.

target_attr str

The attribute or tag to modify.

new_value Any

The proposed new value (if known).

original_value Any

The original value for audit/reversion.

metadata Dict[str, Any]

Context metadata (e.g. patient linkage for date shifting).

Identity locks

LockingResult

Bases: list

What lock_identities() returns: a list of the Instance objects that received an identity token, whose repr is one line (<LockingResult: N instances secured>) rather than every instance.

Exceptions

RedactionError(failures, attempted)

Bases: RuntimeError

Redaction did not remove what it was asked to remove.

Raised after the whole pass, not at the first failure: the instances that could be redacted are redacted, and the failures are already in the audit log, so a caller that catches this still gets a compliance report that grades REVIEW_REQUIRED.

A RuntimeError subclass, so except RuntimeError catches it; its own class tells it from the export path's bare RuntimeErrors, which mean nothing was written, where this means something unsafe is still in the graph.

Parameters:

Name Type Description Default
failures list

(entity_uid, details) pairs, kept as self.failures.

required
attempted int

How many instances the pass targeted, kept as self.attempted.

required

ExportError(failures, attempted, folder=None)

Bases: RuntimeError

The export delivered nothing.

Raised by session.export() when zero of N planned instances reached disk and at least one failed, in both formats: the DICOM path, and WfdbExporter.export, where N is the waveform records attempted. The message says "instances" in both: a WFDB record is written from one waveform instance, and its failure is named by that instance's UID, as the DICOM one is. Not raised on a partial export.

Raised last, after every record the run produces, so a caller who catches this still holds a correct graph, a complete audit trail and a compliance report grading REVIEW_REQUIRED. The DICOM path raises after the collision report, the recoverable-identity disclosure, the delivery counters, the EXPORT audit row and Done.. The WFDB path has none of the first three; it raises after each record's ERROR or DATA_LOSS row and its own EXPORT row.

A RuntimeError subclass, so except RuntimeError catches it. write_tree raises a bare RuntimeError instead, for "this serializer could not write".

Parameters:

Name Type Description Default
failures list

(entity_uid, details) per instance that failed; kept as self.failures.

required
attempted int

How many instances were planned; kept as self.attempted.

required
folder str

The output folder, named in the message.

None

Building a graph by hand

isocenter.Builder is the frozen name of the class below; only start_patient() is frozen, and the chain it starts is tier 2.

Builder

Build a Patient graph by hand, with no files behind it.

Import it as from isocenter import Builder:

patient = (Builder.start_patient("P123", "Doe^John")
           .add_study("1.2.3", "20240101")
           .add_series("1.2.3.1", "CT", 1)
           .end_series().end_study().build())

start_patient(patient_id, name) staticmethod

Begin building a Patient.

Parameters:

Name Type Description Default
patient_id str

The Patient ID. There is no id keyword: start_patient(id=...) raises TypeError.

required
name str

The Patient's Name.

required

Returns:

Type Description
PatientBuilder

A builder for the new patient.