Skip to content

Commit e493474

Browse files
committed
fix: XmlPart._rel_ref_count
`.rel_ref_count()` as implemented was only applicable to `XmlPart` where references to a related part could be present in the XML. Longer term it probably makes sense to override `Part.drop_rel()` in `XmlPart` and not have a `_rel_ref_count()` method in `part` at all, but this works and is less potentially disruptive.
1 parent 3f56b7d commit e493474

File tree

2 files changed

+38
-20
lines changed

2 files changed

+38
-20
lines changed

src/docx/opc/part.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from typing import TYPE_CHECKING, Callable, Dict, Type
5+
from typing import TYPE_CHECKING, Callable, Dict, Type, cast
66

77
from docx.opc.oxml import serialize_part_xml
88
from docx.opc.packuri import PackURI
@@ -149,11 +149,12 @@ def target_ref(self, rId: str) -> str:
149149
rel = self.rels[rId]
150150
return rel.target_ref
151151

152-
def _rel_ref_count(self, rId):
153-
"""Return the count of references in this part's XML to the relationship
154-
identified by `rId`."""
155-
rIds = self._element.xpath("//@r:id")
156-
return len([_rId for _rId in rIds if _rId == rId])
152+
def _rel_ref_count(self, rId: str) -> int:
153+
"""Return the count of references in this part to the relationship identified by `rId`.
154+
155+
Only an XML part can contain references, so this is 0 for `Part`.
156+
"""
157+
return 0
157158

158159

159160
class PartFactory:
@@ -231,3 +232,9 @@ def part(self):
231232
That chain of delegation ends here for child objects.
232233
"""
233234
return self
235+
236+
def _rel_ref_count(self, rId: str) -> int:
237+
"""Return the count of references in this part's XML to the relationship
238+
identified by `rId`."""
239+
rIds = cast("list[str]", self._element.xpath("//@r:id"))
240+
return len([_rId for _rId in rIds if _rId == rId])

tests/opc/test_part.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -169,24 +169,13 @@ def it_can_establish_an_external_relationship(self, rels_prop_: Mock, rels_: Moc
169169
rels_.get_or_add_ext_rel.assert_called_once_with("http://rel/type", "https://hyper/link")
170170
assert rId == "rId27"
171171

172-
@pytest.mark.parametrize(
173-
("part_cxml", "rel_should_be_dropped"),
174-
[
175-
("w:p", True),
176-
("w:p/r:a{r:id=rId42}", True),
177-
("w:p/r:a{r:id=rId42}/r:b{r:id=rId42}", False),
178-
],
179-
)
180-
def it_can_drop_a_relationship(
181-
self, part_cxml: str, rel_should_be_dropped: bool, rels_prop_: Mock
182-
):
172+
def it_can_drop_a_relationship(self, rels_prop_: Mock):
183173
rels_prop_.return_value = {"rId42": None}
184-
part = Part("partname", "content_type")
185-
part._element = element(part_cxml) # pyright: ignore[reportAttributeAccessIssue]
174+
part = Part(PackURI("/partname"), "content_type")
186175

187176
part.drop_rel("rId42")
188177

189-
assert ("rId42" not in part.rels) is rel_should_be_dropped
178+
assert "rId42" not in part.rels
190179

191180
def it_can_find_a_related_part_by_reltype(
192181
self, rels_prop_: Mock, rels_: Mock, other_part_: Mock
@@ -411,6 +400,24 @@ def it_knows_its_the_part_for_its_child_objects(self, part_fixture):
411400
xml_part = part_fixture
412401
assert xml_part.part is xml_part
413402

403+
@pytest.mark.parametrize(
404+
("part_cxml", "rel_should_be_dropped"),
405+
[
406+
("w:p", True),
407+
("w:p/r:a{r:id=rId42}", True),
408+
("w:p/r:a{r:id=rId42}/r:b{r:id=rId42}", False),
409+
],
410+
)
411+
def it_only_drops_a_relationship_with_zero_reference_count(
412+
self, part_cxml: str, rel_should_be_dropped: bool, rels_prop_: Mock, package_: Mock
413+
):
414+
rels_prop_.return_value = {"rId42": None}
415+
part = XmlPart(PackURI("/partname"), "content_type", element(part_cxml), package_)
416+
417+
part.drop_rel("rId42")
418+
419+
assert ("rId42" not in part.rels) is rel_should_be_dropped
420+
414421
# fixtures -------------------------------------------------------
415422

416423
@pytest.fixture
@@ -452,6 +459,10 @@ def parse_xml_(self, request, element_):
452459
def partname_(self, request):
453460
return instance_mock(request, PackURI)
454461

462+
@pytest.fixture
463+
def rels_prop_(self, request: FixtureRequest):
464+
return property_mock(request, XmlPart, "rels")
465+
455466
@pytest.fixture
456467
def serialize_part_xml_(self, request):
457468
return function_mock(request, "docx.opc.part.serialize_part_xml")

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy