init: 폴더구조 설계 및 인프라 설계
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
"""OPC-local oxml module to handle OPC-local concerns like relationship parsing."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Callable, cast
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from pptx.opc.constants import NAMESPACE as NS
|
||||
from pptx.opc.constants import RELATIONSHIP_TARGET_MODE as RTM
|
||||
from pptx.oxml import parse_xml, register_element_cls
|
||||
from pptx.oxml.simpletypes import (
|
||||
ST_ContentType,
|
||||
ST_Extension,
|
||||
ST_TargetMode,
|
||||
XsdAnyUri,
|
||||
XsdId,
|
||||
)
|
||||
from pptx.oxml.xmlchemy import (
|
||||
BaseOxmlElement,
|
||||
OptionalAttribute,
|
||||
RequiredAttribute,
|
||||
ZeroOrMore,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pptx.opc.packuri import PackURI
|
||||
|
||||
nsmap = {
|
||||
"ct": NS.OPC_CONTENT_TYPES,
|
||||
"pr": NS.OPC_RELATIONSHIPS,
|
||||
"r": NS.OFC_RELATIONSHIPS,
|
||||
}
|
||||
|
||||
|
||||
def oxml_to_encoded_bytes(
|
||||
element: BaseOxmlElement,
|
||||
encoding: str = "utf-8",
|
||||
pretty_print: bool = False,
|
||||
standalone: bool | None = None,
|
||||
) -> bytes:
|
||||
return etree.tostring(
|
||||
element, encoding=encoding, pretty_print=pretty_print, standalone=standalone
|
||||
)
|
||||
|
||||
|
||||
def oxml_tostring(
|
||||
elm: BaseOxmlElement,
|
||||
encoding: str | None = None,
|
||||
pretty_print: bool = False,
|
||||
standalone: bool | None = None,
|
||||
):
|
||||
return etree.tostring(elm, encoding=encoding, pretty_print=pretty_print, standalone=standalone)
|
||||
|
||||
|
||||
def serialize_part_xml(part_elm: BaseOxmlElement) -> bytes:
|
||||
"""Produce XML-file bytes for `part_elm`, suitable for writing directly to a `.xml` file.
|
||||
|
||||
Includes XML-declaration header.
|
||||
"""
|
||||
return etree.tostring(part_elm, encoding="UTF-8", standalone=True)
|
||||
|
||||
|
||||
class CT_Default(BaseOxmlElement):
|
||||
"""`<Default>` element.
|
||||
|
||||
Specifies the default content type to be applied to a part with the specified extension.
|
||||
"""
|
||||
|
||||
extension: str = RequiredAttribute( # pyright: ignore[reportAssignmentType]
|
||||
"Extension", ST_Extension
|
||||
)
|
||||
contentType: str = RequiredAttribute( # pyright: ignore[reportAssignmentType]
|
||||
"ContentType", ST_ContentType
|
||||
)
|
||||
|
||||
|
||||
class CT_Override(BaseOxmlElement):
|
||||
"""`<Override>` element.
|
||||
|
||||
Specifies the content type to be applied for a part with the specified partname.
|
||||
"""
|
||||
|
||||
partName: str = RequiredAttribute( # pyright: ignore[reportAssignmentType]
|
||||
"PartName", XsdAnyUri
|
||||
)
|
||||
contentType: str = RequiredAttribute( # pyright: ignore[reportAssignmentType]
|
||||
"ContentType", ST_ContentType
|
||||
)
|
||||
|
||||
|
||||
class CT_Relationship(BaseOxmlElement):
|
||||
"""`<Relationship>` element.
|
||||
|
||||
Represents a single relationship from a source to a target part.
|
||||
"""
|
||||
|
||||
rId: str = RequiredAttribute("Id", XsdId) # pyright: ignore[reportAssignmentType]
|
||||
reltype: str = RequiredAttribute("Type", XsdAnyUri) # pyright: ignore[reportAssignmentType]
|
||||
target_ref: str = RequiredAttribute( # pyright: ignore[reportAssignmentType]
|
||||
"Target", XsdAnyUri
|
||||
)
|
||||
targetMode: str = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
||||
"TargetMode", ST_TargetMode, default=RTM.INTERNAL
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def new(
|
||||
cls, rId: str, reltype: str, target_ref: str, target_mode: str = RTM.INTERNAL
|
||||
) -> CT_Relationship:
|
||||
"""Return a new `<Relationship>` element.
|
||||
|
||||
`target_ref` is either a partname or a URI.
|
||||
"""
|
||||
relationship = cast(CT_Relationship, parse_xml(f'<Relationship xmlns="{nsmap["pr"]}"/>'))
|
||||
relationship.rId = rId
|
||||
relationship.reltype = reltype
|
||||
relationship.target_ref = target_ref
|
||||
relationship.targetMode = target_mode
|
||||
return relationship
|
||||
|
||||
|
||||
class CT_Relationships(BaseOxmlElement):
|
||||
"""`<Relationships>` element, the root element in a .rels file."""
|
||||
|
||||
relationship_lst: list[CT_Relationship]
|
||||
_insert_relationship: Callable[[CT_Relationship], CT_Relationship]
|
||||
|
||||
relationship = ZeroOrMore("pr:Relationship")
|
||||
|
||||
def add_rel(
|
||||
self, rId: str, reltype: str, target: str, is_external: bool = False
|
||||
) -> CT_Relationship:
|
||||
"""Add a child `<Relationship>` element with attributes set as specified."""
|
||||
target_mode = RTM.EXTERNAL if is_external else RTM.INTERNAL
|
||||
relationship = CT_Relationship.new(rId, reltype, target, target_mode)
|
||||
return self._insert_relationship(relationship)
|
||||
|
||||
@classmethod
|
||||
def new(cls) -> CT_Relationships:
|
||||
"""Return a new `<Relationships>` element."""
|
||||
return cast(CT_Relationships, parse_xml(f'<Relationships xmlns="{nsmap["pr"]}"/>'))
|
||||
|
||||
@property
|
||||
def xml_file_bytes(self) -> bytes:
|
||||
"""Return XML bytes, with XML-declaration, for this `<Relationships>` element.
|
||||
|
||||
Suitable for saving in a .rels stream, not pretty printed and with an XML declaration at
|
||||
the top.
|
||||
"""
|
||||
return oxml_to_encoded_bytes(self, encoding="UTF-8", standalone=True)
|
||||
|
||||
|
||||
class CT_Types(BaseOxmlElement):
|
||||
"""`<Types>` element.
|
||||
|
||||
The container element for Default and Override elements in [Content_Types].xml.
|
||||
"""
|
||||
|
||||
default_lst: list[CT_Default]
|
||||
override_lst: list[CT_Override]
|
||||
|
||||
_add_default: Callable[..., CT_Default]
|
||||
_add_override: Callable[..., CT_Override]
|
||||
|
||||
default = ZeroOrMore("ct:Default")
|
||||
override = ZeroOrMore("ct:Override")
|
||||
|
||||
def add_default(self, ext: str, content_type: str) -> CT_Default:
|
||||
"""Add a child `<Default>` element with attributes set to parameter values."""
|
||||
return self._add_default(extension=ext, contentType=content_type)
|
||||
|
||||
def add_override(self, partname: PackURI, content_type: str) -> CT_Override:
|
||||
"""Add a child `<Override>` element with attributes set to parameter values."""
|
||||
return self._add_override(partName=partname, contentType=content_type)
|
||||
|
||||
@classmethod
|
||||
def new(cls) -> CT_Types:
|
||||
"""Return a new `<Types>` element."""
|
||||
return cast(CT_Types, parse_xml(f'<Types xmlns="{nsmap["ct"]}"/>'))
|
||||
|
||||
|
||||
register_element_cls("ct:Default", CT_Default)
|
||||
register_element_cls("ct:Override", CT_Override)
|
||||
register_element_cls("ct:Types", CT_Types)
|
||||
|
||||
register_element_cls("pr:Relationship", CT_Relationship)
|
||||
register_element_cls("pr:Relationships", CT_Relationships)
|
||||
Reference in New Issue
Block a user