11"""Objects that implement reading and writing OPC packages."""
22
3+ from __future__ import annotations
4+
5+ from typing import IO , TYPE_CHECKING , Iterator
6+
37from docx .opc .constants import RELATIONSHIP_TYPE as RT
48from docx .opc .packuri import PACKAGE_URI , PackURI
59from docx .opc .part import PartFactory
610from docx .opc .parts .coreprops import CorePropertiesPart
711from docx .opc .pkgreader import PackageReader
812from docx .opc .pkgwriter import PackageWriter
913from docx .opc .rel import Relationships
10- from docx .opc .shared import lazyproperty
14+ from docx .shared import lazyproperty
15+
16+ if TYPE_CHECKING :
17+ from docx .opc .part import Part
1118
1219
1320class OpcPackage :
@@ -56,7 +63,7 @@ def walk_rels(source, visited=None):
5663 for rel in walk_rels (self ):
5764 yield rel
5865
59- def iter_parts (self ):
66+ def iter_parts (self ) -> Iterator [ Part ] :
6067 """Generate exactly one reference to each of the parts in the package by
6168 performing a depth-first traversal of the rels graph."""
6269
@@ -76,7 +83,7 @@ def walk_parts(source, visited=[]):
7683 for part in walk_parts (self ):
7784 yield part
7885
79- def load_rel (self , reltype , target , rId , is_external = False ):
86+ def load_rel (self , reltype : str , target : Part | str , rId : str , is_external : bool = False ):
8087 """Return newly added |_Relationship| instance of `reltype` between this part
8188 and `target` with key `rId`.
8289
@@ -111,14 +118,14 @@ def next_partname(self, template):
111118 return PackURI (candidate_partname )
112119
113120 @classmethod
114- def open (cls , pkg_file ) :
121+ def open (cls , pkg_file : str | IO [ bytes ]) -> OpcPackage :
115122 """Return an |OpcPackage| instance loaded with the contents of `pkg_file`."""
116123 pkg_reader = PackageReader .from_file (pkg_file )
117124 package = cls ()
118125 Unmarshaller .unmarshal (pkg_reader , package , PartFactory )
119126 return package
120127
121- def part_related_by (self , reltype ) :
128+ def part_related_by (self , reltype : str ) -> Part :
122129 """Return part to which this package has a relationship of `reltype`.
123130
124131 Raises |KeyError| if no such relationship is found and |ValueError| if more than
@@ -127,13 +134,16 @@ def part_related_by(self, reltype):
127134 return self .rels .part_with_reltype (reltype )
128135
129136 @property
130- def parts (self ):
137+ def parts (self ) -> list [ Part ] :
131138 """Return a list containing a reference to each of the parts in this package."""
132139 return list (self .iter_parts ())
133140
134- def relate_to (self , part , reltype ):
135- """Return rId key of relationship to `part`, from the existing relationship if
136- there is one, otherwise a newly created one."""
141+ def relate_to (self , part : Part , reltype : str ):
142+ """Return rId key of new or existing relationship to `part`.
143+
144+ If a relationship of `reltype` to `part` already exists, its rId is returned. Otherwise a
145+ new relationship is created and that rId is returned.
146+ """
137147 rel = self .rels .get_or_add (reltype , part )
138148 return rel .rId
139149
@@ -143,9 +153,11 @@ def rels(self):
143153 relationships for this package."""
144154 return Relationships (PACKAGE_URI .baseURI )
145155
146- def save (self , pkg_file ):
147- """Save this package to `pkg_file`, where `file` can be either a path to a file
148- (a string) or a file-like object."""
156+ def save (self , pkg_file : str | IO [bytes ]):
157+ """Save this package to `pkg_file`.
158+
159+ `pkg_file` can be either a file-path or a file-like object.
160+ """
149161 for part in self .parts :
150162 part .before_marshal ()
151163 PackageWriter .write (pkg_file , self .rels , self .parts )
@@ -190,9 +202,7 @@ def _unmarshal_parts(pkg_reader, package, part_factory):
190202 """
191203 parts = {}
192204 for partname , content_type , reltype , blob in pkg_reader .iter_sparts ():
193- parts [partname ] = part_factory (
194- partname , content_type , reltype , blob , package
195- )
205+ parts [partname ] = part_factory (partname , content_type , reltype , blob , package )
196206 return parts
197207
198208 @staticmethod
@@ -202,7 +212,5 @@ def _unmarshal_relationships(pkg_reader, package, parts):
202212 in `parts`."""
203213 for source_uri , srel in pkg_reader .iter_srels ():
204214 source = package if source_uri == "/" else parts [source_uri ]
205- target = (
206- srel .target_ref if srel .is_external else parts [srel .target_partname ]
207- )
215+ target = srel .target_ref if srel .is_external else parts [srel .target_partname ]
208216 source .load_rel (srel .reltype , target , srel .rId , srel .is_external )
0 commit comments