Skip to content

Commit 3f62ffc

Browse files
committed
hdr: extract _Header.is_linked_to_previous
_Header can now rely on _BaseHeaderFooter for this behavior.
1 parent c16e55e commit 3f62ffc

File tree

2 files changed

+25
-98
lines changed

2 files changed

+25
-98
lines changed

docx/section.py

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -270,38 +270,13 @@ def _has_definition(self):
270270
class _Header(_BaseHeaderFooter):
271271
"""Page header."""
272272

273-
@property
274-
def is_linked_to_previous(self):
275-
"""True if this header uses the header definition of the preceding section.
276-
277-
False if this header has an explicit definition.
278-
279-
Assigning ``True`` to this property removes any header definition for this
280-
section, causing it to "inherit" the header definition of the prior section.
281-
Assigning ``False`` causes a new, empty header definition to be added for this
282-
section, but only if no existing definition is present.
283-
"""
284-
# ---absence of a header (definition) part indicates "linked" behavior---
285-
return not self._has_header_part
286-
287-
@is_linked_to_previous.setter
288-
def is_linked_to_previous(self, value):
289-
new_state = bool(value)
290-
# ---do nothing when value is not being changed---
291-
if new_state == self.is_linked_to_previous:
292-
return
293-
if new_state is True:
294-
self._drop_header_part()
295-
else:
296-
self._add_header_part()
297-
298-
def _add_header_part(self):
273+
def _add_definition(self):
299274
"""Return newly-added header part."""
300275
header_part, rId = self._document_part.add_header_part()
301276
self._sectPr.add_headerReference(WD_HEADER_FOOTER.PRIMARY, rId)
302277
return header_part
303278

304-
def _drop_header_part(self):
279+
def _drop_definition(self):
305280
"""Remove header definition associated with this section."""
306281
rId = self._sectPr.remove_headerReference(WD_HEADER_FOOTER.PRIMARY)
307282
self._document_part.drop_header_part(rId)
@@ -321,17 +296,17 @@ def _get_or_add_header_part(self):
321296
"""
322297
# ---note this method is called recursively to access inherited headers---
323298
# ---case-1: header does not inherit---
324-
if self._has_header_part:
299+
if self._has_definition:
325300
return self._header_part
326301
prior_header = self._prior_header
327302
# ---case-2: header inherits and belongs to second-or-later section---
328303
if prior_header is not None:
329304
return prior_header._get_or_add_header_part()
330305
# ---case-3: header inherits, but is first header---
331-
return self._add_header_part()
306+
return self._add_definition()
332307

333308
@property
334-
def _has_header_part(self):
309+
def _has_definition(self):
335310
"""True if a header is explicitly defined for this section."""
336311
headerReference = self._sectPr.get_headerReference(WD_HEADER_FOOTER.PRIMARY)
337312
return False if headerReference is None else True

tests/test_section.py

Lines changed: 20 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -446,39 +446,12 @@ def has_definition_fixture(self, request):
446446

447447
class Describe_Header(object):
448448

449-
def it_knows_when_its_linked_to_the_previous_header(
450-
self, is_linked_get_fixture, _has_header_part_prop_
451-
):
452-
has_header_part, expected_value = is_linked_get_fixture
453-
_has_header_part_prop_.return_value = has_header_part
454-
header = _Header(None, None)
455-
456-
is_linked = header.is_linked_to_previous
457-
458-
assert is_linked is expected_value
459-
460-
def it_can_change_whether_it_is_linked_to_previous_header(
461-
self,
462-
is_linked_set_fixture,
463-
_has_header_part_prop_,
464-
_drop_header_part_,
465-
_add_header_part_,
466-
):
467-
has_header_part, new_value, drop_calls, add_calls = is_linked_set_fixture
468-
_has_header_part_prop_.return_value = has_header_part
469-
header = _Header(None, None)
470-
471-
header.is_linked_to_previous = new_value
472-
473-
assert _drop_header_part_.call_args_list == [call(header)] * drop_calls
474-
assert _add_header_part_.call_args_list == [call(header)] * add_calls
475-
476449
def it_can_add_a_header_part_to_help(self, document_part_, header_part_):
477450
sectPr = element("w:sectPr{r:a=b}")
478451
document_part_.add_header_part.return_value = header_part_, "rId3"
479452
header = _Header(sectPr, document_part_)
480453

481-
header_part = header._add_header_part()
454+
header_part = header._add_definition()
482455

483456
document_part_.add_header_part.assert_called_once_with()
484457
assert sectPr.xml == xml(
@@ -490,7 +463,7 @@ def it_can_drop_the_related_header_part_to_help(self, document_part_):
490463
sectPr = element("w:sectPr{r:a=b}/w:headerReference{w:type=default,r:id=rId42}")
491464
header = _Header(sectPr, document_part_)
492465

493-
header._drop_header_part()
466+
header._drop_definition()
494467

495468
assert sectPr.xml == xml("w:sectPr{r:a=b}")
496469
document_part_.drop_header_part.assert_called_once_with("rId42")
@@ -509,9 +482,9 @@ def it_provides_access_to_the_hdr_element_to_help(
509482
assert hdr_elm is hdr
510483

511484
def it_gets_the_header_part_when_it_has_one(
512-
self, _has_header_part_prop_, _header_part_prop_, header_part_
485+
self, _has_definition_prop_, _header_part_prop_, header_part_
513486
):
514-
_has_header_part_prop_.return_value = True
487+
_has_definition_prop_.return_value = True
515488
_header_part_prop_.return_value = header_part_
516489
header = _Header(None, None)
517490

@@ -520,9 +493,9 @@ def it_gets_the_header_part_when_it_has_one(
520493
assert header_part is header_part_
521494

522495
def but_it_gets_the_prior_header_part_when_it_is_linked(
523-
self, _has_header_part_prop_, _prior_header_prop_, prior_header_, header_part_
496+
self, _has_definition_prop_, _prior_header_prop_, prior_header_, header_part_
524497
):
525-
_has_header_part_prop_.return_value = False
498+
_has_definition_prop_.return_value = False
526499
_prior_header_prop_.return_value = prior_header_
527500
prior_header_._get_or_add_header_part.return_value = header_part_
528501
header = _Header(None, None)
@@ -534,28 +507,28 @@ def but_it_gets_the_prior_header_part_when_it_is_linked(
534507

535508
def and_it_adds_the_header_part_when_it_is_linked_and_the_first_section(
536509
self,
537-
_has_header_part_prop_,
510+
_has_definition_prop_,
538511
_prior_header_prop_,
539-
_add_header_part_,
512+
_add_definition_,
540513
header_part_
541514
):
542-
_has_header_part_prop_.return_value = False
515+
_has_definition_prop_.return_value = False
543516
_prior_header_prop_.return_value = None
544-
_add_header_part_.return_value = header_part_
517+
_add_definition_.return_value = header_part_
545518
header = _Header(None, None)
546519

547520
header_part = header._get_or_add_header_part()
548521

549-
_add_header_part_.assert_called_once_with(header)
522+
_add_definition_.assert_called_once_with(header)
550523
assert header_part is header_part_
551524

552-
def it_knows_when_it_has_a_header_part_to_help(self, has_header_part_fixture):
553-
sectPr, expected_value = has_header_part_fixture
525+
def it_knows_when_it_has_a_header_part_to_help(self, has_definition_fixture):
526+
sectPr, expected_value = has_definition_fixture
554527
header = _Header(sectPr, None)
555528

556-
has_header_part = header._has_header_part
529+
has_definition = header._has_definition
557530

558-
assert has_header_part is expected_value
531+
assert has_definition is expected_value
559532

560533
def it_provides_access_to_its_header_part_to_help(
561534
self, document_part_, header_part_
@@ -599,49 +572,28 @@ def but_it_returns_None_when_its_the_first_header(self):
599572
("w:sectPr", False), ("w:sectPr/w:headerReference{w:type=default}", True)
600573
]
601574
)
602-
def has_header_part_fixture(self, request):
575+
def has_definition_fixture(self, request):
603576
sectPr_cxml, expected_value = request.param
604577
sectPr = element(sectPr_cxml)
605578
return sectPr, expected_value
606579

607-
@pytest.fixture(params=[(False, True), (True, False)])
608-
def is_linked_get_fixture(self, request):
609-
has_header_part, expected_value = request.param
610-
return has_header_part, expected_value
611-
612-
@pytest.fixture(
613-
params=[
614-
(False, True, 0, 0),
615-
(True, False, 0, 0),
616-
(True, True, 1, 0),
617-
(False, False, 0, 1),
618-
]
619-
)
620-
def is_linked_set_fixture(self, request):
621-
has_header_part, new_value, drop_calls, add_calls = request.param
622-
return has_header_part, new_value, drop_calls, add_calls
623-
624580
# fixture components ---------------------------------------------
625581

626582
@pytest.fixture
627-
def _add_header_part_(self, request):
628-
return method_mock(request, _Header, "_add_header_part")
583+
def _add_definition_(self, request):
584+
return method_mock(request, _Header, "_add_definition")
629585

630586
@pytest.fixture
631587
def document_part_(self, request):
632588
return instance_mock(request, DocumentPart)
633589

634-
@pytest.fixture
635-
def _drop_header_part_(self, request):
636-
return method_mock(request, _Header, "_drop_header_part")
637-
638590
@pytest.fixture
639591
def _get_or_add_header_part_(self, request):
640592
return method_mock(request, _Header, "_get_or_add_header_part")
641593

642594
@pytest.fixture
643-
def _has_header_part_prop_(self, request):
644-
return property_mock(request, _Header, "_has_header_part")
595+
def _has_definition_prop_(self, request):
596+
return property_mock(request, _Header, "_has_definition")
645597

646598
@pytest.fixture
647599
def header_(self, request):

0 commit comments

Comments
 (0)