# This file is part of pymarc. It is subject to the license terms in the
# LICENSE file found in the top-level directory of this distribution and at
# https://opensource.org/licenses/BSD-2-Clause. pymarc may be copied, modified,
# propagated, or distributed according to the terms contained in the LICENSE
# file.
"""The pymarc.leader file."""
from typing import Union
from pymarc.constants import LEADER_LEN
from pymarc.exceptions import BadLeaderValue, RecordLeaderInvalid
[docs]
class Leader(object):
"""Mutable leader.
A class to manipulate a `Record`'s leader.
You can use the properties (`status`, `bibliographic_level`, etc.) or their
slices/index equivalent (`leader[5]`, `leader[7]`, etc.) to read and write
values.
See `LoC's documentation
<https://www.loc.gov/marc/bibliographic/bdleader.html>`_
for more infos about those fields.
.. code-block:: python
leader = Leader("00475cas a2200169 i 4500")
leader[0:4] # returns "00475"
leader.status # returns "c"
leader.status = "a" # sets the status to "a"
leader[5] # returns the status "a"
leader[5] = "b" # sets the status to "b"
str(leader) # "00475bas a2200169 i 4500"
Usually the leader is accessed through the `leader` property of a record.
.. code-block:: python
from pymarc import MARCReader
with open('test/marc.dat', 'rb') as fh:
reader = MARCReader(fh)
for record in reader:
print(record.leader)
When creating/updating a `Record` please note that `record_length` and
`base_address` will only be generated in the marc21 output of
:func:`record.as_marc() <pymarc.record.Record.as_marc>`
"""
def __init__(self, leader: str) -> None:
"""Leader is initialized with a string."""
if len(leader) != LEADER_LEN:
raise RecordLeaderInvalid
self.leader = leader
def __getitem__(self, item: Union[str, int, slice]) -> str:
"""Get values using position, slice or properties.
leader[:4] == leader.length
"""
if isinstance(item, slice) or isinstance(item, int):
return self.leader[item]
return getattr(self, item)
def __setitem__(self, item: str, value: str) -> None:
"""Set values using position, slice or properties.
leader[5] = "a"
leader[0:4] = "0000"
leader.status = "a"
"""
if isinstance(item, slice):
self._replace_values(position=item.start, value=value)
elif isinstance(item, int):
self._replace_values(position=item, value=value)
else:
setattr(self, item, value)
def __str__(self) -> str:
"""A string representation of the leader."""
return self.leader
def _replace_values(self, position: int, value: str) -> None:
"""Replaces the values in the leader at `position` by `value`."""
if position < 0:
raise IndexError("Position must be positive")
after = position + len(value)
if after > LEADER_LEN:
raise BadLeaderValue(f"{value} is too long to be inserted at {position}")
self.leader = self.leader[:position] + value + self.leader[after:]
@property
def record_length(self) -> str:
"""Record length (00-04)."""
return self.leader[:5]
@record_length.setter
def record_length(self, value: str) -> None:
"""Record length (00-04)."""
if len(value) != 5:
raise BadLeaderValue(f"Record length is 4 chars field, got {value}")
self._replace_values(position=0, value=value)
@property
def record_status(self) -> str:
"""Record status (05)."""
return self.leader[5]
@record_status.setter
def record_status(self, value: str) -> None:
"""Record status (05)."""
if len(value) != 1:
raise BadLeaderValue(f"Record status is 1 char field, got {value}")
self._replace_values(position=5, value=value)
@property
def type_of_record(self) -> str:
"""Type of record (06)."""
return self.leader[6]
@type_of_record.setter
def type_of_record(self, value: str) -> None:
"""Type of record (06)."""
if len(value) != 1:
raise BadLeaderValue(f"Type of record is 1 char field, got {value}")
self._replace_values(position=6, value=value)
@property
def bibliographic_level(self) -> str:
"""Bibliographic level (07)."""
return self.leader[7]
@bibliographic_level.setter
def bibliographic_level(self, value: str) -> None:
"""Bibliographic level (07)."""
if len(value) != 1:
raise BadLeaderValue(f"Bibliographic level is 1 char field, got {value}")
self._replace_values(position=7, value=value)
@property
def type_of_control(self) -> str:
"""Type of control (08)."""
return self.leader[8]
@type_of_control.setter
def type_of_control(self, value: str) -> None:
"""Type of control (08)."""
if len(value) != 1:
raise BadLeaderValue(f"Type of control is 1 char field, got {value}")
self._replace_values(position=8, value=value)
@property
def coding_scheme(self) -> str:
"""Character coding scheme (09)."""
return self.leader[9]
@coding_scheme.setter
def coding_scheme(self, value: str) -> None:
"""Character coding scheme (09)."""
if len(value) != 1:
raise BadLeaderValue(
f"Character coding scheme is 1 char field, got {value}"
)
self._replace_values(position=9, value=value)
@property
def indicator_count(self) -> str:
"""Indicator count (10)."""
return self.leader[10]
@indicator_count.setter
def indicator_count(self, value: str) -> None:
"""Indicator count (10)."""
if len(value) != 1:
raise BadLeaderValue(f"Indicator count is 1 char field, got {value}")
self._replace_values(position=10, value=value)
@property
def subfield_code_count(self) -> str:
"""Subfield code count (11)."""
return self.leader[11]
@subfield_code_count.setter
def subfield_code_count(self, value: str) -> None:
"""Subfield code count (11)."""
if len(value) != 1:
raise BadLeaderValue(f"Subfield code count is 1 char field, got {value}")
self._replace_values(position=11, value=value)
@property
def base_address(self) -> str:
"""Base address of data (12-16)."""
return self.leader[12:17]
@base_address.setter
def base_address(self, value: str) -> None:
"""Base address of data (12-16)."""
if len(value) != 5:
raise BadLeaderValue(f"Base address of data is 4 chars field, got {value}")
self._replace_values(position=12, value=value)
@property
def encoding_level(self) -> str:
"""Encoding level (17)."""
return self.leader[17]
@encoding_level.setter
def encoding_level(self, value: str) -> None:
"""Encoding level (17)."""
if len(value) != 1:
raise BadLeaderValue(f"Encoding level is 1 char field, got {value}")
self._replace_values(position=17, value=value)
@property
def cataloging_form(self) -> str:
"""Descriptive cataloging form (18)."""
return self.leader[18]
@cataloging_form.setter
def cataloging_form(self, value: str) -> None:
"""Descriptive cataloging form (18)."""
if len(value) != 1:
raise BadLeaderValue(
f"Descriptive cataloging form is 1 char field, got {value}"
)
self._replace_values(position=18, value=value)
@property
def multipart_ressource(self) -> str:
"""Multipart resource record level (19)."""
return self.leader[19]
@multipart_ressource.setter
def multipart_ressource(self, value: str) -> None:
"""Multipart resource record level (19)."""
if len(value) != 1:
raise BadLeaderValue(
f"Multipart resource record level is 1 char field, got {value}"
)
self._replace_values(position=19, value=value)
@property
def length_of_field_length(self) -> str:
"""Length of the length-of-field portion (20)."""
return self.leader[20]
@length_of_field_length.setter
def length_of_field_length(self, value: str) -> None:
"""Length of the length-of-field portion (20)."""
if len(value) != 1:
raise BadLeaderValue(
f"Length of the length-of-field portion is 1 char field, got {value}"
)
self._replace_values(position=20, value=value)
@property
def starting_character_position_length(self) -> str:
"""Length of the starting-character-position portion (21)."""
return self.leader[21]
@starting_character_position_length.setter
def starting_character_position_length(self, value: str) -> None:
"""Length of the starting-character-position portion (21)."""
if len(value) != 1:
raise BadLeaderValue(
f"Length of the starting-character-position portion is 1 char field, got {value}"
)
self._replace_values(position=21, value=value)
@property
def implementation_defined_length(self) -> str:
"""Length of the implementation-defined portion (22)."""
return self.leader[22]
@implementation_defined_length.setter
def implementation_defined_length(self, value: str) -> None:
"""Length of the starting-character-position portion (22)."""
if len(value) != 1:
raise BadLeaderValue(
f"Length of the implementation-defined portion is 1 char field, got {value}"
)
self._replace_values(position=22, value=value)