Skip to content

zimscraperlib.zim.metadata

Classes:

Functions:

  • allow_duplicates

    Whether list input can accept duplicate values

  • allow_empty

    Whether input can be blank

  • clean_str

    Clean a string value for unwanted control characters and strip white chars

  • deduplicate

    Whether duplicates in list inputs should be reduced

  • mandatory

    Marks a Metadata mandatory: must be set to please Creator and cannot be empty

  • nb_grapheme_for

    Number of graphemes (visually perceived characters) in a given string

  • only_lang_codes

    Whether list input should be checked to only accept ISO-639-1 codes

  • x_prefixed

    Whether metadata names should be automatically X-Prefixed

  • x_protected

    Whether metadata name should be checked for collision with reserved names

Attributes:

APPLY_RECOMMENDATIONS module-attribute

APPLY_RECOMMENDATIONS: bool = True

AnyMetadata module-attribute

AnyMetadata = MetadataBase[Any]

DEFAULT_DEV_ZIM_METADATA module-attribute

DEFAULT_DEV_ZIM_METADATA = StandardMetadataList(
    Name=NameMetadata("Test Name"),
    Title=TitleMetadata("Test Title"),
    Creator=CreatorMetadata("Test Creator"),
    Publisher=PublisherMetadata("Test Publisher"),
    Date=DateMetadata(date(2023, 1, 1)),
    Description=DescriptionMetadata("Test Description"),
    Language=LanguageMetadata("fra"),
    Illustration_48x48_at_1=DefaultIllustrationMetadata(
        b64decode(
            "iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAANQTFRFR3BMgvrS0gAAAAF0Uk5TAEDm2GYAAAANSURBVBjTY2AYBdQEAAFQAAGn4toWAAAAAElFTkSuQmCC"
        )
    ),
)

MANDATORY_ZIM_METADATA_KEYS module-attribute

MANDATORY_ZIM_METADATA_KEYS: list[str] = (
    get_reserved_names()
)

T module-attribute

T = TypeVar('T')

UNWANTED_CONTROL_CHARACTERS_REGEX module-attribute

UNWANTED_CONTROL_CHARACTERS_REGEX = compile(
    "(?![\\n\\t\\r])\\p{C}"
)

CreatorMetadata

CreatorMetadata(value: str, name: str | None = None)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Creator'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

CustomMetadata

CustomMetadata(name: str, value: bytes | IOBase | BytesIO)

Bases: Metadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
501
502
503
def __init__(self, name: str, value: bytes | io.IOBase | io.BytesIO) -> None:
    self.meta_name = name
    super().__init__(value=value)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name instance-attribute

meta_name = name

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding: bool = False

value instance-attribute

value: T = get_cleaned_value(value)

get_binary_from

get_binary_from(
    value: bytes
    | SupportsRead[bytes]
    | SupportsSeekableRead[bytes]
    | BytesIO,
) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
def get_binary_from(
    self,
    value: bytes | SupportsRead[bytes] | SupportsSeekableRead[bytes] | io.BytesIO,
) -> bytes:
    bvalue: bytes = b""
    if isinstance(value, io.BytesIO):
        bvalue = value.getvalue()
    elif isinstance(value, bytes):
        bvalue = value
    else:
        last_pos: int = 0
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            last_pos = value.tell()
        bvalue = value.read()
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            value.seek(last_pos)
    if not self.empty_allowed and not value:
        raise ValueError("Missing value (empty not allowed)")
    return bvalue

get_cleaned_value

get_cleaned_value(value: bytes | IOBase | BytesIO) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
246
247
def get_cleaned_value(self, value: bytes | io.IOBase | io.BytesIO) -> bytes:
    return self.get_binary_from(value)

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
249
250
def get_libzim_value(self) -> bytes:
    return self.value

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

CustomTextMetadata

CustomTextMetadata(name: str, value: str)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
508
509
510
def __init__(self, name: str, value: str) -> None:
    self.meta_name = name
    super().__init__(name=name, value=value)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name instance-attribute

meta_name = name

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

DateBasedMetadata

DateBasedMetadata(
    value: date | datetime, name: str | None = None
)

Bases: MetadataBase[date]

Expects a Date (date | datetime) input. Will be UTF-8 encoded as YYYY-MM-DD

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
327
328
329
330
def __init__(
    self, value: datetime.date | datetime.datetime, name: str | None = None
) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name instance-attribute

meta_name: str

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: date

get_cleaned_value

get_cleaned_value(value: date) -> date
Source code in src/zimscraperlib/zim/metadata.py
333
334
335
336
def get_cleaned_value(self, value: datetime.date) -> datetime.date:
    if isinstance(value, datetime.datetime):
        value = value.date()
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
338
339
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value.strftime("%Y-%m-%d"))

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

DateMetadata

DateMetadata(
    value: date | datetime, name: str | None = None
)

Bases: DateBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
327
328
329
330
def __init__(
    self, value: datetime.date | datetime.datetime, name: str | None = None
) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Date'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: date

get_cleaned_value

get_cleaned_value(value: date) -> date
Source code in src/zimscraperlib/zim/metadata.py
333
334
335
336
def get_cleaned_value(self, value: datetime.date) -> datetime.date:
    if isinstance(value, datetime.datetime):
        value = value.date()
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
338
339
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value.strftime("%Y-%m-%d"))

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

DefaultIllustrationMetadata

DefaultIllustrationMetadata(
    value: bytes | IOBase | BytesIO, name: str | None = None
)

Bases: IllustrationBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
350
351
352
353
def __init__(
    self, value: bytes | io.IOBase | io.BytesIO, name: str | None = None
) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = DEFAULT_ZIM_ILLLUSTRATION_SCALE

illustration_size class-attribute instance-attribute

illustration_size: int = DEFAULT_ZIM_ILLLUSTRATION_SIZE

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype class-attribute instance-attribute

meta_mimetype = 'image/png'

meta_name class-attribute instance-attribute

meta_name = 'Illustration_48x48@1'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding: bool = False

value instance-attribute

value: bytes

get_binary_from

get_binary_from(
    value: bytes
    | SupportsRead[bytes]
    | SupportsSeekableRead[bytes]
    | BytesIO,
) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
def get_binary_from(
    self,
    value: bytes | SupportsRead[bytes] | SupportsSeekableRead[bytes] | io.BytesIO,
) -> bytes:
    bvalue: bytes = b""
    if isinstance(value, io.BytesIO):
        bvalue = value.getvalue()
    elif isinstance(value, bytes):
        bvalue = value
    else:
        last_pos: int = 0
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            last_pos = value.tell()
        bvalue = value.read()
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            value.seek(last_pos)
    if not self.empty_allowed and not value:
        raise ValueError("Missing value (empty not allowed)")
    return bvalue

get_cleaned_value

get_cleaned_value(value: bytes | IOBase | BytesIO) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
356
357
358
359
360
361
362
363
364
365
366
367
def get_cleaned_value(self, value: bytes | io.IOBase | io.BytesIO) -> bytes:
    value = self.get_binary_from(value)
    if not is_valid_image(
        image=value,
        imformat="PNG",
        size=(self.illustration_size, self.illustration_size),
    ):
        raise ValueError(
            f"{self.name} is not a valid "
            f"{self.illustration_size}x{self.illustration_size} PNG Image"
        )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
369
370
def get_libzim_value(self) -> bytes:
    return self.value

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

DescriptionMetadata

DescriptionMetadata(value: str, name: str | None = None)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Description'

mimetype property

mimetype: str

name property

name: str

oz_max_length class-attribute instance-attribute

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

FlavourMetadata

FlavourMetadata(value: str, name: str | None = None)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Flavour'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

IllustrationBasedMetadata

IllustrationBasedMetadata(
    value: bytes | IOBase | BytesIO, name: str | None = None
)

Bases: Metadata

Expects a Square PNG Illustration (bytes-like) input.

PNG format and squareness will be checked

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
350
351
352
353
def __init__(
    self, value: bytes | io.IOBase | io.BytesIO, name: str | None = None
) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype class-attribute instance-attribute

meta_mimetype = 'image/png'

meta_name instance-attribute

meta_name: str

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding: bool = False

value instance-attribute

value: bytes

get_binary_from

get_binary_from(
    value: bytes
    | SupportsRead[bytes]
    | SupportsSeekableRead[bytes]
    | BytesIO,
) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
def get_binary_from(
    self,
    value: bytes | SupportsRead[bytes] | SupportsSeekableRead[bytes] | io.BytesIO,
) -> bytes:
    bvalue: bytes = b""
    if isinstance(value, io.BytesIO):
        bvalue = value.getvalue()
    elif isinstance(value, bytes):
        bvalue = value
    else:
        last_pos: int = 0
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            last_pos = value.tell()
        bvalue = value.read()
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            value.seek(last_pos)
    if not self.empty_allowed and not value:
        raise ValueError("Missing value (empty not allowed)")
    return bvalue

get_cleaned_value

get_cleaned_value(value: bytes | IOBase | BytesIO) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
356
357
358
359
360
361
362
363
364
365
366
367
def get_cleaned_value(self, value: bytes | io.IOBase | io.BytesIO) -> bytes:
    value = self.get_binary_from(value)
    if not is_valid_image(
        image=value,
        imformat="PNG",
        size=(self.illustration_size, self.illustration_size),
    ):
        raise ValueError(
            f"{self.name} is not a valid "
            f"{self.illustration_size}x{self.illustration_size} PNG Image"
        )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
369
370
def get_libzim_value(self) -> bytes:
    return self.value

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

IllustrationMetadata

IllustrationMetadata(
    value: bytes | IOBase | BytesIO,
    size: int,
    scale: int = 1,
)

Bases: IllustrationBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
411
412
413
414
415
416
def __init__(
    self, value: bytes | io.IOBase | io.BytesIO, size: int, scale: int = 1
) -> None:
    self.illustration_scale = scale
    self.illustration_size = size
    super().__init__(value=value)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = scale

illustration_size instance-attribute

illustration_size: int = size

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype class-attribute instance-attribute

meta_mimetype = 'image/png'

meta_name class-attribute instance-attribute

meta_name = 'Illustration_{size}x{size}@{scale}'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding: bool = False

value instance-attribute

value: bytes

get_binary_from

get_binary_from(
    value: bytes
    | SupportsRead[bytes]
    | SupportsSeekableRead[bytes]
    | BytesIO,
) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
def get_binary_from(
    self,
    value: bytes | SupportsRead[bytes] | SupportsSeekableRead[bytes] | io.BytesIO,
) -> bytes:
    bvalue: bytes = b""
    if isinstance(value, io.BytesIO):
        bvalue = value.getvalue()
    elif isinstance(value, bytes):
        bvalue = value
    else:
        last_pos: int = 0
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            last_pos = value.tell()
        bvalue = value.read()
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            value.seek(last_pos)
    if not self.empty_allowed and not value:
        raise ValueError("Missing value (empty not allowed)")
    return bvalue

get_cleaned_value

get_cleaned_value(value: bytes | IOBase | BytesIO) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
356
357
358
359
360
361
362
363
364
365
366
367
def get_cleaned_value(self, value: bytes | io.IOBase | io.BytesIO) -> bytes:
    value = self.get_binary_from(value)
    if not is_valid_image(
        image=value,
        imformat="PNG",
        size=(self.illustration_size, self.illustration_size),
    ):
        raise ValueError(
            f"{self.name} is not a valid "
            f"{self.illustration_size}x{self.illustration_size} PNG Image"
        )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
369
370
def get_libzim_value(self) -> bytes:
    return self.value

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

LanguageMetadata

LanguageMetadata(
    value: Iterable[str] | str, name: str | None = None
)

Bases: TextListBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
292
293
def __init__(self, value: Iterable[str] | str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ','

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Language'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup = True

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: list[str]

get_cleaned_value

get_cleaned_value(value: Iterable[str] | str) -> list[str]
Source code in src/zimscraperlib/zim/metadata.py
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
def get_cleaned_value(self, value: Iterable[str] | str) -> list[str]:
    if isinstance(value, str):
        value = [value]
    else:
        value = list(value)
    if self.require_textlist_cleanup:
        value = [clean_str(item) for item in value]
    if not self.empty_allowed and (not value or not all(value)):
        raise ValueError("Missing value (empty not allowed)")
    if not self.duplicates_allowed and len(set(value)) != len(value):
        raise ValueError("Duplicate entries not allowed")
    elif self.require_deduplication:
        value = unique_values(value)
    if self.oz_only_iso636_3_allowed and APPLY_RECOMMENDATIONS:
        invalid_codes = list(filterfalse(is_valid_iso_639_3, value))
        if invalid_codes:
            raise ValueError(
                f"Following code(s) are not ISO-639-3: {','.join(invalid_codes)}"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
317
318
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.join_list_with.join(self.value))

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

LicenseMetadata

LicenseMetadata(value: str, name: str | None = None)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'License'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

LongDescriptionMetadata

LongDescriptionMetadata(
    value: str, name: str | None = None
)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'LongDescription'

mimetype property

mimetype: str

name property

name: str

oz_max_length class-attribute instance-attribute

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

Metadata

Metadata(
    value: Any,
    name: str | None = None,
    mimetype: str | None = None,
)

Bases: MetadataBase[bytes]

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
86
87
88
89
90
91
92
93
94
95
96
def __init__(
    self, value: Any, name: str | None = None, mimetype: str | None = None
) -> None:
    if name:
        self.meta_name = name
    if not getattr(self, "meta_name", ""):
        raise OSError("Metadata name missing")
    if mimetype:
        self.meta_mimetype = mimetype
    self.value = self.get_cleaned_value(value)
    self.validate()

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name instance-attribute

meta_name: str

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding: bool = False

value instance-attribute

value: T = get_cleaned_value(value)

get_binary_from

get_binary_from(
    value: bytes
    | SupportsRead[bytes]
    | SupportsSeekableRead[bytes]
    | BytesIO,
) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
def get_binary_from(
    self,
    value: bytes | SupportsRead[bytes] | SupportsSeekableRead[bytes] | io.BytesIO,
) -> bytes:
    bvalue: bytes = b""
    if isinstance(value, io.BytesIO):
        bvalue = value.getvalue()
    elif isinstance(value, bytes):
        bvalue = value
    else:
        last_pos: int = 0
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            last_pos = value.tell()
        bvalue = value.read()
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            value.seek(last_pos)
    if not self.empty_allowed and not value:
        raise ValueError("Missing value (empty not allowed)")
    return bvalue

get_cleaned_value

get_cleaned_value(value: bytes | IOBase | BytesIO) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
246
247
def get_cleaned_value(self, value: bytes | io.IOBase | io.BytesIO) -> bytes:
    return self.get_binary_from(value)

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
249
250
def get_libzim_value(self) -> bytes:
    return self.value

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

MetadataBase

MetadataBase(
    value: Any,
    name: str | None = None,
    mimetype: str | None = None,
)

Bases: ABC

Base class for metadata

Both generic (to accomodate any value type implemented in child classes) and abstract (because it has no idea how to compute the cleaned_value and libzim_value for any value type)

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
86
87
88
89
90
91
92
93
94
95
96
def __init__(
    self, value: Any, name: str | None = None, mimetype: str | None = None
) -> None:
    if name:
        self.meta_name = name
    if not getattr(self, "meta_name", ""):
        raise OSError("Metadata name missing")
    if mimetype:
        self.meta_mimetype = mimetype
    self.value = self.get_cleaned_value(value)
    self.validate()

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name instance-attribute

meta_name: str

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding: bool = False

value instance-attribute

value: T = get_cleaned_value(value)

get_cleaned_value abstractmethod

get_cleaned_value(value: Any) -> T
Source code in src/zimscraperlib/zim/metadata.py
152
153
@abstractmethod
def get_cleaned_value(self, value: Any) -> T: ...

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value abstractmethod

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
159
160
@abstractmethod
def get_libzim_value(self) -> bytes: ...

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

NameMetadata

NameMetadata(value: str, name: str | None = None)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Name'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

PublisherMetadata

PublisherMetadata(value: str, name: str | None = None)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Publisher'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

RelationMetadata

RelationMetadata(value: str, name: str | None = None)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Relation'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

ScraperMetadata

ScraperMetadata(value: str, name: str | None = None)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Scraper'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

SourceMetadata

SourceMetadata(value: str, name: str | None = None)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Source'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

StandardMetadataList dataclass

StandardMetadataList(
    Name: NameMetadata,
    Language: LanguageMetadata,
    Title: TitleMetadata,
    Creator: CreatorMetadata,
    Publisher: PublisherMetadata,
    Date: DateMetadata,
    Illustration_48x48_at_1: DefaultIllustrationMetadata,
    Description: DescriptionMetadata,
    LongDescription: LongDescriptionMetadata | None = None,
    Tags: TagsMetadata | None = None,
    Scraper: ScraperMetadata | None = None,
    Flavour: FlavourMetadata | None = None,
    Source: SourceMetadata | None = None,
    License: LicenseMetadata | None = None,
    Relation: RelationMetadata | None = None,
)

Methods:

Attributes:

Creator instance-attribute

Creator: CreatorMetadata

Date instance-attribute

Description instance-attribute

Description: DescriptionMetadata

Flavour class-attribute instance-attribute

Flavour: FlavourMetadata | None = None

Illustration_48x48_at_1 instance-attribute

Illustration_48x48_at_1: DefaultIllustrationMetadata

Language instance-attribute

Language: LanguageMetadata

License class-attribute instance-attribute

License: LicenseMetadata | None = None

LongDescription class-attribute instance-attribute

LongDescription: LongDescriptionMetadata | None = None

Name instance-attribute

Publisher instance-attribute

Publisher: PublisherMetadata

Relation class-attribute instance-attribute

Relation: RelationMetadata | None = None

Scraper class-attribute instance-attribute

Scraper: ScraperMetadata | None = None

Source class-attribute instance-attribute

Source: SourceMetadata | None = None

Tags class-attribute instance-attribute

Tags: TagsMetadata | None = None

Title instance-attribute

get_reserved_names classmethod

get_reserved_names() -> list[str]

list of mandatory metadata as per the spec.

computed from metadata using @mandatory decorator

Source code in src/zimscraperlib/zim/metadata.py
484
485
486
487
488
489
490
491
492
493
494
495
496
@classmethod
def get_reserved_names(cls) -> list[str]:
    """list of mandatory metadata as per the spec.

    computed from metadata using @mandatory decorator"""
    names: list[str] = []
    for field in fields(cls):
        if not isinstance(field.type, type):
            continue
        # field.type is a `type` only when expecting a single type
        # and is a string in case of None Union
        names.append(getattr(field.type, "meta_name", ""))
    return names

values

values() -> list[AnyMetadata]
Source code in src/zimscraperlib/zim/metadata.py
481
482
def values(self) -> list[AnyMetadata]:
    return list(filter(bool, asdict(self).values()))

TagsMetadata

TagsMetadata(
    value: Iterable[str] | str, name: str | None = None
)

Bases: TextListBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
292
293
def __init__(self, value: Iterable[str] | str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ';'

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Tags'

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup = True

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: list[str]

get_cleaned_value

get_cleaned_value(value: Iterable[str] | str) -> list[str]
Source code in src/zimscraperlib/zim/metadata.py
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
def get_cleaned_value(self, value: Iterable[str] | str) -> list[str]:
    if isinstance(value, str):
        value = [value]
    else:
        value = list(value)
    if self.require_textlist_cleanup:
        value = [clean_str(item) for item in value]
    if not self.empty_allowed and (not value or not all(value)):
        raise ValueError("Missing value (empty not allowed)")
    if not self.duplicates_allowed and len(set(value)) != len(value):
        raise ValueError("Duplicate entries not allowed")
    elif self.require_deduplication:
        value = unique_values(value)
    if self.oz_only_iso636_3_allowed and APPLY_RECOMMENDATIONS:
        invalid_codes = list(filterfalse(is_valid_iso_639_3, value))
        if invalid_codes:
            raise ValueError(
                f"Following code(s) are not ISO-639-3: {','.join(invalid_codes)}"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
317
318
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.join_list_with.join(self.value))

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

TextBasedMetadata

TextBasedMetadata(value: str, name: str | None = None)

Bases: MetadataBase[str]

Expects a Text (str) input. Will be cleaned-up and UTF-8 encoded

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name instance-attribute

meta_name: str

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

TextListBasedMetadata

TextListBasedMetadata(
    value: Iterable[str] | str, name: str | None = None
)

Bases: MetadataBase[list[str]]

Expects a Text List (list[str]) input. Each item will be cleaned-up.

List will be joined (see join_list_with) and UTF-8 encoded

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
292
293
def __init__(self, value: Iterable[str] | str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name instance-attribute

meta_name: str

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup = True

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: list[str]

get_cleaned_value

get_cleaned_value(value: Iterable[str] | str) -> list[str]
Source code in src/zimscraperlib/zim/metadata.py
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
def get_cleaned_value(self, value: Iterable[str] | str) -> list[str]:
    if isinstance(value, str):
        value = [value]
    else:
        value = list(value)
    if self.require_textlist_cleanup:
        value = [clean_str(item) for item in value]
    if not self.empty_allowed and (not value or not all(value)):
        raise ValueError("Missing value (empty not allowed)")
    if not self.duplicates_allowed and len(set(value)) != len(value):
        raise ValueError("Duplicate entries not allowed")
    elif self.require_deduplication:
        value = unique_values(value)
    if self.oz_only_iso636_3_allowed and APPLY_RECOMMENDATIONS:
        invalid_codes = list(filterfalse(is_valid_iso_639_3, value))
        if invalid_codes:
            raise ValueError(
                f"Following code(s) are not ISO-639-3: {','.join(invalid_codes)}"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
317
318
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.join_list_with.join(self.value))

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

TitleMetadata

TitleMetadata(value: str, name: str | None = None)

Bases: TextBasedMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
260
261
def __init__(self, value: str, name: str | None = None) -> None:
    super().__init__(value=value, name=name)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name class-attribute instance-attribute

meta_name: str = 'Title'

mimetype property

mimetype: str

name property

name: str

oz_max_length class-attribute instance-attribute

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

XCustomMetadata

XCustomMetadata(name: str, value: bytes | IOBase | BytesIO)

Bases: CustomMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
516
517
def __init__(self, name: str, value: bytes | io.IOBase | io.BytesIO) -> None:
    super().__init__(name=name, value=value)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name instance-attribute

meta_name = name

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup: bool = False

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding: bool = False

value instance-attribute

value: T = get_cleaned_value(value)

get_binary_from

get_binary_from(
    value: bytes
    | SupportsRead[bytes]
    | SupportsSeekableRead[bytes]
    | BytesIO,
) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
def get_binary_from(
    self,
    value: bytes | SupportsRead[bytes] | SupportsSeekableRead[bytes] | io.BytesIO,
) -> bytes:
    bvalue: bytes = b""
    if isinstance(value, io.BytesIO):
        bvalue = value.getvalue()
    elif isinstance(value, bytes):
        bvalue = value
    else:
        last_pos: int = 0
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            last_pos = value.tell()
        bvalue = value.read()
        if isinstance(value, SupportsSeekableRead) and value.seekable():
            value.seek(last_pos)
    if not self.empty_allowed and not value:
        raise ValueError("Missing value (empty not allowed)")
    return bvalue

get_cleaned_value

get_cleaned_value(value: bytes | IOBase | BytesIO) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
246
247
def get_cleaned_value(self, value: bytes | io.IOBase | io.BytesIO) -> bytes:
    return self.get_binary_from(value)

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
249
250
def get_libzim_value(self) -> bytes:
    return self.value

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

XCustomTextMetadata

XCustomTextMetadata(name: str, value: str)

Bases: CustomTextMetadata

Methods:

Attributes:

Source code in src/zimscraperlib/zim/metadata.py
523
524
def __init__(self, name: str, value: str) -> None:
    super().__init__(name=name, value=value)

duplicates_allowed class-attribute instance-attribute

duplicates_allowed: bool = False

empty_allowed class-attribute instance-attribute

empty_allowed: bool = False

illustration_scale class-attribute instance-attribute

illustration_scale: int = 1

illustration_size instance-attribute

illustration_size: int

is_required class-attribute instance-attribute

is_required: bool = False

join_list_with class-attribute instance-attribute

join_list_with: str = ' '

libzim_value property

libzim_value: bytes

meta_mimetype instance-attribute

meta_mimetype: str

meta_name instance-attribute

meta_name = name

mimetype property

mimetype: str

name property

name: str

oz_max_length instance-attribute

oz_max_length: int

oz_only_iso636_3_allowed class-attribute instance-attribute

oz_only_iso636_3_allowed: bool = False

oz_x_prefixed class-attribute instance-attribute

oz_x_prefixed: bool = False

oz_x_protected class-attribute instance-attribute

oz_x_protected: bool = False

require_deduplication class-attribute instance-attribute

require_deduplication: bool = False

require_text_cleanup class-attribute instance-attribute

require_text_cleanup = True

require_textlist_cleanup class-attribute instance-attribute

require_textlist_cleanup: bool = False

require_utf8_encoding class-attribute instance-attribute

require_utf8_encoding = True

value instance-attribute

value: str

get_cleaned_value

get_cleaned_value(value: str) -> str
Source code in src/zimscraperlib/zim/metadata.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def get_cleaned_value(self, value: str) -> str:
    if self.require_text_cleanup:
        value = clean_str(value)

    if not self.empty_allowed and not value.strip():
        raise ValueError("Missing value (empty not allowed)")

    # max-length is openZIM recommendation
    if getattr(self, "oz_max_length", 0) and APPLY_RECOMMENDATIONS:
        if nb_grapheme_for(value) > self.oz_max_length:
            raise ValueError(
                f"{self.name} value is too long ({self.oz_max_length})"
            )
    return value

get_encoded staticmethod

get_encoded(value: str) -> bytes
Source code in src/zimscraperlib/zim/metadata.py
144
145
146
@staticmethod
def get_encoded(value: str) -> bytes:
    return value.encode()

get_libzim_value

get_libzim_value() -> bytes
Source code in src/zimscraperlib/zim/metadata.py
279
280
def get_libzim_value(self) -> bytes:
    return self.get_encoded(self.value)

get_mimetype

get_mimetype() -> str
Source code in src/zimscraperlib/zim/metadata.py
 98
 99
100
def get_mimetype(self) -> str:
    # explicitly set first
    return getattr(self, "meta_mimetype", "text/plain;charset=UTF-8")

get_name

get_name() -> str
Source code in src/zimscraperlib/zim/metadata.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def get_name(self) -> str:
    if getattr(self, "illustration_size", 0) and getattr(
        self, "illustration_scale", 0
    ):
        return (
            f"Illustration_{self.illustration_size}x{self.illustration_size}"
            f"@{self.illustration_scale}"
        )

    # X- prefix is recommendation for custom
    if (
        self.oz_x_protected
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
        and self.matches_reserved_name(self.meta_name)
    ):
        raise ValueError("Custom metdata name must be X- prefixed")
    if (
        self.oz_x_prefixed
        and APPLY_RECOMMENDATIONS
        and not self.meta_name.startswith("X-")
    ):
        return f"X-{self.meta_name}"
    return self.meta_name

matches_reserved_name staticmethod

matches_reserved_name(name: str) -> bool
Source code in src/zimscraperlib/zim/metadata.py
106
107
108
109
110
111
112
113
@staticmethod
def matches_reserved_name(name: str) -> bool:
    if name in [field.name for field in fields(StandardMetadataList)]:
        return True
    # set by libzim
    if name == "Counter":
        return True
    return bool(ILLUSTRATIONS_METADATA_RE.match(name))

validate

validate() -> None
Source code in src/zimscraperlib/zim/metadata.py
148
149
150
def validate(self) -> None:
    _ = self.name
    _ = self.libzim_value

allow_duplicates

allow_duplicates(cls: type[U])

Whether list input can accept duplicate values

Source code in src/zimscraperlib/zim/metadata.py
190
191
192
193
def allow_duplicates[U: AnyMetadata](cls: type[U]):
    """Whether list input can accept duplicate values"""
    cls.duplicates_allowed = True
    return cls

allow_empty

allow_empty(cls: type[U])

Whether input can be blank

Source code in src/zimscraperlib/zim/metadata.py
184
185
186
187
def allow_empty[U: AnyMetadata](cls: type[U]):
    """Whether input can be blank"""
    cls.empty_allowed = True
    return cls

clean_str

clean_str(value: str) -> str

Clean a string value for unwanted control characters and strip white chars

Source code in src/zimscraperlib/zim/metadata.py
167
168
169
def clean_str(value: str) -> str:
    """Clean a string value for unwanted control characters and strip white chars"""
    return UNWANTED_CONTROL_CHARACTERS_REGEX.sub("", value).strip(" \r\n\t")

deduplicate

deduplicate(cls: type[U])

Whether duplicates in list inputs should be reduced

Source code in src/zimscraperlib/zim/metadata.py
196
197
198
199
200
def deduplicate[U: AnyMetadata](cls: type[U]):
    """Whether duplicates in list inputs should be reduced"""
    cls.duplicates_allowed = True
    cls.require_deduplication = True
    return cls

mandatory

mandatory(cls: type[U])

Marks a Metadata mandatory: must be set to please Creator and cannot be empty

Source code in src/zimscraperlib/zim/metadata.py
177
178
179
180
181
def mandatory[U: AnyMetadata](cls: type[U]):
    """Marks a Metadata mandatory: must be set to please Creator and cannot be empty"""
    cls.is_required = True
    cls.empty_allowed = False
    return cls

nb_grapheme_for

nb_grapheme_for(value: str) -> int

Number of graphemes (visually perceived characters) in a given string

Source code in src/zimscraperlib/zim/metadata.py
172
173
174
def nb_grapheme_for(value: str) -> int:
    """Number of graphemes (visually perceived characters) in a given string"""
    return len(regex.findall(r"\X", value))

only_lang_codes

only_lang_codes(cls: type[U])

Whether list input should be checked to only accept ISO-639-1 codes

Source code in src/zimscraperlib/zim/metadata.py
203
204
205
206
def only_lang_codes[U: AnyMetadata](cls: type[U]):
    """Whether list input should be checked to only accept ISO-639-1 codes"""
    cls.oz_only_iso636_3_allowed = True
    return cls

x_prefixed

x_prefixed(cls: type[U])

Whether metadata names should be automatically X-Prefixed

Source code in src/zimscraperlib/zim/metadata.py
217
218
219
220
221
def x_prefixed[U: AnyMetadata](cls: type[U]):
    """Whether metadata names should be automatically X-Prefixed"""
    cls.oz_x_protected = False
    cls.oz_x_prefixed = True
    return cls

x_protected

x_protected(cls: type[U])

Whether metadata name should be checked for collision with reserved names

when applying recommendations

Source code in src/zimscraperlib/zim/metadata.py
209
210
211
212
213
214
def x_protected[U: AnyMetadata](cls: type[U]):
    """Whether metadata name should be checked for collision with reserved names

    when applying recommendations"""
    cls.oz_x_protected = True
    return cls