Python API Reference¶
Complete Python API reference for MRRC.
Canonical Type Stubs
The file mrrc/_mrrc.pyi is the ground-truth type reference for the
Python extension module. IDEs use it for autocompletion and type checking.
If this page and the stub file disagree, the stub file is authoritative.
Core Classes¶
Record¶
A MARC bibliographic record containing a leader, control fields, and data fields.
from mrrc import Record, Field, Leader, Subfield
# Create a record with inline fields
record = Record(fields=[
Field("245", indicators=["1", "0"], subfields=[
Subfield("a", "Title"),
]),
])
# Or build incrementally
record = Record(Leader())
record.add_control_field("001", "123456789")
field = Field("245", "1", "0")
field.add_subfield("a", "Title")
record.add_field(field)
All record accessors (title, author, isbn, …) are read-only
properties, matching pymarc.
Enhanced Record wrapper with pymarc-compatible API.
physical_description
property
¶
Physical description from 300 field.
physicaldescription
property
¶
Physical description (pymarc-compatible name).
addedentries
property
¶
Added entries from 700/710/711/730 fields (pymarc compatibility).
__init__ ¶
Create a new Record.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
leader
|
Optional[Leader]
|
Optional Leader object (defaults to Leader()). |
None
|
fields
|
Optional[List[Field]]
|
Optional list of Field objects to add to the record. |
None
|
__getitem__ ¶
Get first field with given tag (pymarc compatibility).
Returns a Field instance for both control and data fields. Raises KeyError if the tag is not present in the record.
get_fields ¶
Get all fields with given tags.
If no tags provided, returns all fields (control + data). Supports multiple tags: record.get_fields('245', '260')
get ¶
Get first field with given tag, or default (pymarc compatibility).
get_field_or_err ¶
Get first field with given tag, raising :class:mrrc.FieldNotFound
(E105) when the tag is not present.
Strict-mode counterpart to :meth:get_field. Use this when an
absent field is a programming error worth the typed exception
and its diagnostic context (record_control_number,
field_tag); use :meth:get_field when None is the
expected sentinel.
remove_field ¶
Remove one or more fields from the record (pymarc compatibility).
A Field argument removes exactly that field: a live handle obtained from this record removes its precise occurrence; a detached field removes the first value-equal field, raising ValueError when nothing matches (as pymarc does). A tag string removes all fields with that tag, control tags included.
remove_fields ¶
Remove all fields with the given tags (pymarc compatibility).
add_ordered_field ¶
Add fields maintaining tag sort order (pymarc compatibility).
add_grouped_field ¶
Add fields after the last field with the same tag (pymarc compatibility).
fields ¶
Get all fields (control + data), as live handles.
Enumerates identically to no-arg :meth:get_fields: repeated
control tags (e.g. multiple 007s) yield one field per value.
get_linked_fields ¶
Find all 880 fields linked to a given field via subfield $6.
Given a non-880 field that has a $6 linkage subfield, returns all 880 fields whose $6 occurrence number matches. This is pymarc-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field
|
Field
|
A Field object with a $6 linkage subfield. |
required |
Returns:
| Type | Description |
|---|---|
List[Field]
|
List of linked 880 Field objects (empty if no linkage or no match). |
get_linked_field ¶
Find the single 880 field linked to a given field via subfield $6.
Like get_linked_fields() but returns only the first match.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field
|
Field
|
A Field object with a $6 linkage subfield. |
required |
Returns:
| Type | Description |
|---|---|
Optional[Field]
|
The linked 880 Field, or None. |
get_original_field ¶
Find the original field linked from a given 880 field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field_880
|
Field
|
An 880 Field object. |
required |
Returns:
| Type | Description |
|---|---|
Optional[Field]
|
The linked original Field, or None. |
get_field_pairs ¶
Get field pairs of original fields with their linked 880 counterparts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tag
|
str
|
The field tag to pair (e.g., '245', '100'). |
required |
Returns:
| Type | Description |
|---|---|
List[Tuple[Field, Optional[Field]]]
|
List of (original Field, linked 880 Field or None) tuples. |
fields_by_indicator ¶
fields_by_indicator(tag: str, *, indicator1: Optional[str] = None, indicator2: Optional[str] = None) -> List[Field]
Get fields matching indicator values.
This is a convenience method for filtering by indicators.
For more complex queries, use fields_matching() with a FieldQuery.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tag
|
str
|
The 3-character field tag to search. |
required |
indicator1
|
Optional[str]
|
Optional first indicator value (None = match any). |
None
|
indicator2
|
Optional[str]
|
Optional second indicator value (None = match any). |
None
|
Returns:
| Type | Description |
|---|---|
List[Field]
|
List of Field objects matching the criteria. |
fields_in_range ¶
Get fields within a tag range (inclusive).
Useful for querying groups of related fields, such as all subject fields (600-699) or all added entry fields (700-799).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_tag
|
str
|
Start of range (inclusive), e.g., "600". |
required |
end_tag
|
str
|
End of range (inclusive), e.g., "699". |
required |
Returns:
| Type | Description |
|---|---|
List[Field]
|
List of Field objects within the tag range. |
fields_matching ¶
Get fields matching a FieldQuery.
This method enables complex field matching using the Query DSL. A FieldQuery can combine tag, indicator, and subfield requirements.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
FieldQuery
|
A FieldQuery object with the matching criteria. |
required |
Returns:
| Type | Description |
|---|---|
List[Field]
|
List of Field objects matching all query criteria. |
fields_matching_range ¶
Get fields matching a TagRangeQuery.
This method finds fields within a tag range that also match indicator and subfield requirements.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
TagRangeQuery
|
A TagRangeQuery object with range and filter criteria. |
required |
Returns:
| Type | Description |
|---|---|
List[Field]
|
List of Field objects matching all query criteria. |
fields_matching_pattern ¶
Get fields matching a SubfieldPatternQuery (regex matching).
This method finds fields where a specific subfield's value matches a regular expression pattern.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
SubfieldPatternQuery
|
A SubfieldPatternQuery object with tag, subfield, and regex. |
required |
Returns:
| Type | Description |
|---|---|
List[Field]
|
List of Field objects where the subfield matches the pattern. |
fields_matching_value ¶
Get fields matching a SubfieldValueQuery (exact or partial string matching).
This method finds fields where a specific subfield's value matches a string exactly or as a substring.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
SubfieldValueQuery
|
A SubfieldValueQuery object with tag, subfield, value, and match type. |
required |
Returns:
| Type | Description |
|---|---|
List[Field]
|
List of Field objects where the subfield matches the value. |
Example
>>> # Find exact subject heading "History"
>>> query = SubfieldValueQuery("650", "a", "History")
>>> history_fields = record.fields_matching_value(query)
>>> # Find subjects containing "History" anywhere
>>> query = SubfieldValueQuery("650", "a", "History", partial=True)
>>> related_fields = record.fields_matching_value(query)
Dictionary access:
# record['xxx'] raises KeyError if tag is missing
field = record['245'] # Returns Field or raises KeyError
# Use record.get() for safe access (returns None if missing)
field = record.get('245') # Returns Field or None
Field handles: fields obtained from a record (record[tag],
get_field, get_field_or_err, get_fields, fields) are live
handles — every read and write goes through to the record, so in-place
edits persist, matching pymarc:
record["245"].indicator1 = "1" # persists
record["245"]["a"] = "New title /" # persists
record["005"].data = "20260603120000.0" # control fields too
Two caveats. Handles to the same field are distinct objects
(record["245"] is record["245"] is False) that share underlying
state — don't compare fields with is or id(). And removing fields
invalidates all outstanding handles for that record: any later use
raises StaleFieldError; re-fetch the field and retry.
Query results (fields_matching, fields_by_indicator,
fields_in_range, and related) are snapshots, not handles — edits to
them do not write back.
Field¶
A MARC field — both control fields and data fields use this class.
from mrrc import Field, Subfield
# Create a data field with indicators and subfields inline
field = Field("245", indicators=["1", "0"], subfields=[
Subfield("a", "Main title :"),
Subfield("b", "subtitle /"),
Subfield("c", "by Author."),
])
# Create a control field
field = Field("001", data="12345")
# Or build incrementally
field = Field("245", "1", "0")
field.add_subfield("a", "Main title :")
# Access subfields
print(field["a"]) # "Main title :"
for sf in field.subfields():
print(f"${sf.code} {sf.value}")
Enhanced Field wrapper with pymarc-compatible API.
Supports both control fields and data fields (like pymarc.Field).
Control fields are created with data=: Field('001', data='12345').
Data fields use indicators and subfields as before.
data
property
writable
¶
Control field data value (pymarc compatibility).
Returns the data string for control fields, None for data fields.
indicators
property
writable
¶
__init__ ¶
__init__(tag: str, indicator1: str = ' ', indicator2: str = ' ', *, subfields: Optional[List[Subfield]] = None, indicators: Optional[List[str]] = None, data: Optional[str] = None)
Create a new Field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tag
|
str
|
3-character field tag. |
required |
indicator1
|
str
|
First indicator (default ' '). |
' '
|
indicator2
|
str
|
Second indicator (default ' '). |
' '
|
subfields
|
Optional[List[Subfield]]
|
Optional list of Subfield objects to add. |
None
|
indicators
|
Optional[List[str]]
|
Optional list/tuple of [ind1, ind2], overrides indicator1/indicator2. |
None
|
data
|
Optional[str]
|
For control fields, the data string value. |
None
|
__getitem__ ¶
__setitem__ ¶
Set subfield value (replace first occurrence).
get ¶
Get first subfield value by code or return default.
value ¶
Return the field's value (pymarc compatibility). For control fields, returns the data content. For data fields, returns space-joined subfield values.
format_field ¶
Return human-readable text without indicators or subfield codes (pymarc compatibility).
is_control_field ¶
Check if this is a control field (pymarc compatibility).
__str__ ¶
MARC display format (pymarc compatibility).
Data fields: =TAG IND1IND2$aCONTENT$bCONTENT Control fields: =TAG CONTENT
get_subfields ¶
delete_subfield ¶
Delete first subfield with given code and return its value.
Matches pymarc's Field.delete_subfield() behavior: removes the
first subfield with the given code and returns its value, or None
if no subfield with that code exists.
subfields_as_dict ¶
Return subfields as dictionary mapping code to list of values.
add_subfield ¶
Add a subfield, optionally at a specific position (pymarc compatibility).
linkage_occurrence_num ¶
Extract the occurrence number from subfield $6 linkage (pymarc compatibility).
convert_legacy_subfields
classmethod
¶
Convert legacy pymarc subfield list to Subfield objects.
Converts the old format ['code', 'value', 'code', 'value', ...] to a list of Subfield objects.
ControlField¶
A backward-compatible subclass of Field for control fields. Prefer Field(tag, data=value) for new code.
from mrrc import ControlField
# Still works for backward compatibility
cf = ControlField("001", "12345")
print(cf.data) # "12345"
print(cf.is_control_field()) # True
print(isinstance(cf, Field)) # True
Subfield¶
A subfield within a MARC field.
from mrrc import Subfield
sf = Subfield("a", "value")
print(sf.code) # "a"
print(sf.value) # "value"
A subfield within a MARC field.
Subfields are named data elements within fields, consisting of a single-character code and a value.
Leader¶
The 24-byte MARC record header containing metadata.
from mrrc import Leader
leader = Leader()
leader.record_type = "a" # Language material
leader.bibliographic_level = "m" # Monograph
leader.character_coding = "a" # UTF-8
Properties:
| Property | Position | Description |
|---|---|---|
record_length |
00-04 | Record length (5 digits) |
record_status |
05 | Record status (n/c/d) |
record_type |
06 | Type of record (a=language, c=music, etc.) |
bibliographic_level |
07 | Bibliographic level (m=monograph, s=serial) |
control_record_type |
08 | Type of control |
character_coding |
09 | Character coding (space=MARC-8, a=UTF-8) |
indicator_count |
10 | Indicator count (usually 2) |
subfield_code_count |
11 | Subfield code count (usually 2) |
data_base_address |
12-16 | Base address of data |
encoding_level |
17 | Encoding level |
cataloging_form |
18 | Descriptive cataloging form |
multipart_level |
19 | Multipart resource record level |
reserved |
20-23 | Entry map (usually "4500") |
AuthorityRecord¶
A MARC authority record. Returned by AuthorityMARCReader.
from mrrc import AuthorityMARCReader, FieldNotFound
reader = AuthorityMARCReader("authorities.mrc")
record = next(reader)
print(record.heading_text()) # main heading string, or None
for tracing in record.see_from_tracings():
print("see from:", tracing)
Note: get_fields(tag) returns None when no fields match (unlike
Record.get_fields, which returns []).
A MARC authority record. Returned by AuthorityMARCReader.
try:
main = record.get_field_or_err("100")
except FieldNotFound as e:
print(f"missing {e.field_tag} on record {e.record_control_number}")
HoldingsRecord¶
A MARC holdings record. Returned by HoldingsMARCReader.
from mrrc import HoldingsMARCReader
reader = HoldingsMARCReader("holdings.mrc")
record = next(reader)
for location in record.locations(): # 852 fields
print(location)
for caption in record.captions_basic(): # 853 fields
print(caption)
Note: get_fields(tag) returns None when no fields match (unlike
Record.get_fields, which returns []).
A MARC holdings record. Returned by HoldingsMARCReader.
errors
property
¶
Non-fatal errors accumulated while parsing this record.
See :attr:Record.errors.
captions_supplements ¶
Supplementary-material caption and pattern fields (854).
enumeration_basic ¶
Basic enumeration and chronology fields (863).
enumeration_supplements ¶
Supplementary-material enumeration and chronology fields (864).
enumeration_indexes ¶
Index enumeration and chronology fields (865).
textual_holdings_basic ¶
Basic textual holdings fields (866).
textual_holdings_supplements ¶
Supplementary-material textual holdings fields (867).
textual_holdings_indexes ¶
Index textual holdings fields (868).
get_fields ¶
All fields matching tag, or None when none match.
get_field_or_err ¶
Get first field with given tag, raising mrrc.FieldNotFound
(E105) when the tag is not present.
Reader/Writer Classes¶
mrrc provides a dedicated reader per MARC record type. All three share the ISO 2709 binary format and the iteration protocol; they differ in the record type they yield and their constructor keywords.
| Reader | Yields | Use for |
|---|---|---|
MARCReader |
Record |
Bibliographic records |
AuthorityMARCReader |
AuthorityRecord |
Authority records |
HoldingsMARCReader |
HoldingsRecord |
Holdings records |
There are no dedicated authority/holdings writers; MARCWriter
serializes any record's fields to ISO 2709.
MARCReader¶
Reads MARC records from files with GIL-released I/O for parallelism.
from mrrc import MARCReader
# From file path (recommended for performance)
for record in MARCReader("records.mrc"):
print(record.title)
# From file object
with open("records.mrc", "rb") as f:
for record in MARCReader(f):
print(record.title)
# From bytes
data = open("records.mrc", "rb").read()
for record in MARCReader(data):
print(record.title)
Input Types:
| Type | Description |
|---|---|
str or Path |
File path (pure Rust I/O, best performance) |
bytes or bytearray |
In-memory data |
| File object | Python file-like object |
Keyword Arguments:
| Kwarg | Type | Default | Description |
|---|---|---|---|
to_unicode |
bool |
True |
Accepted for pymarc compatibility. mrrc always converts MARC-8 to UTF-8; passing False emits a warning but has no effect. |
permissive |
bool |
False |
When True, yields None for records that fail to parse instead of raising, matching pymarc's permissive behavior. |
recovery_mode |
str |
"strict" |
Controls how malformed records are handled (see below). Cannot be combined with permissive=True. |
Recovery Modes:
Instead of skipping bad records entirely (like permissive=True), recovery_mode attempts to salvage valid fields from damaged records:
| Mode | Behavior |
|---|---|
"strict" |
Raise on any malformation (default). |
"lenient" |
Attempt to recover, salvage valid fields from damaged records. |
"permissive" |
Very lenient — accept partial data even from severely malformed records. |
# Skip bad records (pymarc-compatible)
for record in MARCReader("bad.mrc", permissive=True):
if record is None:
continue
print(record.title)
# Salvage partial data from malformed records
for record in MARCReader("bad.mrc", recovery_mode="lenient"):
print(f"Got {len(record.get_fields())} fields")
Note: permissive=True and recovery_mode other than "strict" cannot be
combined — they represent different error-handling strategies. Use permissive=True
for pymarc-compatible "skip bad records" behavior, or recovery_mode for mrrc's
"salvage what you can" approach.
Thread Safety:
- NOT thread-safe - each thread needs its own reader
- GIL released during record parsing for parallelism
- Use
ThreadPoolExecutorwith separate readers per thread
MARCWriter¶
Writes MARC records to files.
MARC Writer wrapper.
AuthorityMARCReader¶
Reads MARC authority records, yielding AuthorityRecord. Same ISO 2709 binary format and iteration protocol as MARCReader, with a smaller keyword set. The record source (path, bytes, or file object) is positional; recovery_mode and validation_level are keyword-only and follow the MARCReader recovery modes, except recovery_mode defaults to "permissive" here rather than "strict".
from mrrc import AuthorityMARCReader
# From a path, bytes, or file object — like MARCReader
for record in AuthorityMARCReader("authorities.mrc"):
print(record.heading_text())
Reader for MARC authority records.
__new__ ¶
__new__(source: Any, *, recovery_mode: str = 'permissive', validation_level: str = 'structural') -> AuthorityMARCReader
HoldingsMARCReader¶
Reads MARC holdings records, yielding HoldingsRecord. Same shape and keyword semantics as AuthorityMARCReader (recovery_mode defaults to "permissive").
from mrrc import HoldingsMARCReader
for record in HoldingsMARCReader("holdings.mrc"):
for location in record.locations():
print(location)
Reader for MARC holdings records.
__new__ ¶
__new__(source: Any, *, recovery_mode: str = 'permissive', validation_level: str = 'structural') -> HoldingsMARCReader
Query DSL¶
Composable query objects passed to the Record.fields_matching* methods to
select fields by tag, indicators, tag range, or subfield value/pattern.
from mrrc import FieldQuery, SubfieldValueQuery
# Fields with tag 650 and indicator2 = "0"
q = FieldQuery().tag("650").indicator2("0")
for field in record.fields_matching(q):
print(field)
# Fields whose subfield $a equals "History"
for field in record.fields_matching_value(
SubfieldValueQuery("650", "a", "History")
):
print(field)
FieldQuery¶
Query builder for matching fields by tag, indicators, and subfields.
TagRangeQuery¶
Query for fields within a tag range.
__new__ ¶
__new__(start_tag: str, end_tag: str, *, indicator1: Optional[str] = None, indicator2: Optional[str] = None, required_subfields: Optional[List[str]] = None) -> TagRangeQuery
SubfieldPatternQuery¶
Query for fields where a subfield matches a regex pattern.
SubfieldValueQuery¶
Query for fields where a subfield matches a value.
Format Conversion¶
Record Methods¶
# JSON formats
json_str = record.to_json()
marcjson_str = record.to_marcjson()
# pymarc-compatible serialization
json_str = record.as_json() # pymarc MARC-in-JSON format
record_dict = record.as_dict() # pymarc-compatible dict
# MARCXML
xml_str = record.to_xml()
# Other XML-based formats
mods_str = record.to_mods()
dc_str = record.to_dublin_core()
# Binary (ISO 2709)
marc_bytes = record.as_marc() # returns bytes
marc_bytes = record.as_marc21() # alias
Module Functions¶
import mrrc
# Parse from JSON
record = mrrc.json_to_record(json_str)
# Parse from MARCXML
record = mrrc.xml_to_record(xml_str)
# Parse MARCXML collection (multiple records)
records = mrrc.xml_to_records(collection_xml_str)
# Parse from MODS XML
record = mrrc.mods_to_record(mods_xml)
# Parse MODS collection (multiple records)
records = mrrc.mods_collection_to_records(mods_collection_xml)
# Convert to CSV
csv_str = mrrc.record_to_csv(record)
csv_str = mrrc.records_to_csv(records)
# Convenience functions
records = mrrc.parse_xml_to_array(xml_str)
records = mrrc.parse_json_to_array(json_str)
mrrc.map_records(func, reader)
Constants¶
from mrrc import (
LEADER_LEN, # 24
DIRECTORY_ENTRY_LEN, # 12
END_OF_FIELD, # '\x1e'
END_OF_RECORD, # '\x1d'
SUBFIELD_INDICATOR, # '\x1f'
MARC_XML_NS, # MARCXML namespace URI
MARC_XML_SCHEMA, # MARCXML schema URI
)
BIBFRAME Conversion¶
Convert MARC to BIBFRAME 2.0 RDF.
from mrrc import marc_to_bibframe, BibframeConfig
# Basic conversion
config = BibframeConfig()
graph = marc_to_bibframe(record, config)
# With custom base URI
config.set_base_uri("http://library.example.org/")
graph = marc_to_bibframe(record, config)
# Serialize to different formats
turtle = graph.serialize("turtle")
rdfxml = graph.serialize("rdf-xml")
jsonld = graph.serialize("jsonld")
ntriples = graph.serialize("ntriples")
BibframeConfig¶
Configuration for BIBFRAME conversion.
Controls how MARC records are converted to BIBFRAME entities and how the resulting RDF graph is serialized.
Examples:
Default configuration::
config = mrrc.BibframeConfig()
Custom configuration::
config = mrrc.BibframeConfig()
config.set_base_uri("http://example.org/")
config.set_output_format("turtle")
config.set_authority_linking(True)
set_base_uri ¶
Set the base URI for generated resources.
When set, entities are given minted URIs like {base}/work/{id}.
When not set, blank nodes are used.
set_output_format ¶
Set the output format for RDF serialization.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
format
|
str
|
One of: "rdf-xml", "jsonld", "turtle", "ntriples" |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If format is not recognized |
set_authority_linking ¶
Enable or disable linking to external authority URIs.
RdfGraph¶
The RDF graph produced by marc_to_bibframe. Use len(graph) for the triple count and serialize(format) to emit RDF in "turtle", "rdf-xml", "jsonld", or "ntriples".
An RDF graph containing BIBFRAME triples.
Wraps the RDF graph produced by MARC-to-BIBFRAME conversion and provides serialization to various RDF formats.
Examples:
::
record = mrrc.Record(leader=mrrc.Leader())
config = mrrc.BibframeConfig()
graph = mrrc.marc_to_bibframe(record, config)
print(f"Graph has {len(graph)} triples")
turtle = graph.serialize("turtle")
serialize ¶
Serialize the graph to a string in the specified format.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
format
|
str
|
One of: "rdf-xml", "jsonld", "turtle", "ntriples" |
required |
Returns:
| Type | Description |
|---|---|
str
|
The serialized RDF as a string |
Raises:
| Type | Description |
|---|---|
ValueError
|
If format is not recognized or serialization fails |
parse
staticmethod
¶
Parse an RDF graph from a string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
str
|
The RDF data as a string |
required |
format
|
str
|
One of: "rdf-xml", "jsonld", "turtle", "ntriples" |
required |
Returns:
| Type | Description |
|---|---|
RdfGraph
|
A new RdfGraph instance |
Raises:
| Type | Description |
|---|---|
ValueError
|
If format is not recognized or parsing fails |
triples ¶
Get all triples as a list of (subject, predicate, object) tuples.
Parallel Processing¶
Lower-level utilities for splitting and parsing large MARC files across threads.
Most callers should use MARCReader with a ThreadPoolExecutor;
these are the building blocks underneath.
RecordBoundaryScanner¶
Scanner for finding record boundaries in MARC data.
ProducerConsumerPipeline¶
Exceptions¶
from mrrc import MrrcException, MarcError
try:
for record in MARCReader("bad.mrc"):
pass
except MrrcException as e:
print(f"MRRC error: {e}")
except MarcError as e:
print(f"MARC error: {e}")
The exception hierarchy:
MrrcException— base exception for all mrrc errorsMarcError— MARC-specific errors (parsing, validation)StaleFieldError— a live field handle was invalidated by field removal; re-fetch the field from the record and retry