Skip to content

Commit 5a22c52

Browse files
committed
rfctr: improve typing for tables
1 parent 630ecbf commit 5a22c52

17 files changed

+480
-425
lines changed

pyrightconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"ignore": [
77
],
88
"include": [
9-
"src/docx/",
9+
"src/docx",
1010
"tests"
1111
],
1212
"pythonPlatform": "All",

requirements-dev.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
-r requirements-test.txt
22
build
3+
ruff
34
setuptools>=61.0.0
45
tox
56
twine
7+
types-lxml

requirements-test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
behave>=1.2.3
33
pyparsing>=2.0.1
44
pytest>=2.5
5+
pytest-xdist
56
ruff

src/docx/opc/oxml.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# pyright: reportPrivateUsage=false
2+
13
"""Temporary stand-in for main oxml module.
24
35
This module came across with the PackageReader transplant. Probably much will get
@@ -27,7 +29,7 @@
2729
# ===========================================================================
2830

2931

30-
def parse_xml(text: str) -> etree._Element: # pyright: ignore[reportPrivateUsage]
32+
def parse_xml(text: str) -> etree._Element:
3133
"""`etree.fromstring()` replacement that uses oxml parser."""
3234
return etree.fromstring(text, oxml_parser)
3335

@@ -44,7 +46,7 @@ def qn(tag):
4446
return "{%s}%s" % (uri, tagroot)
4547

4648

47-
def serialize_part_xml(part_elm):
49+
def serialize_part_xml(part_elm: etree._Element):
4850
"""Serialize `part_elm` etree element to XML suitable for storage as an XML part.
4951
5052
That is to say, no insignificant whitespace added for readability, and an

src/docx/oxml/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@
149149
CT_TblGridCol,
150150
CT_TblLayoutType,
151151
CT_TblPr,
152+
CT_TblPrEx,
152153
CT_TblWidth,
153154
CT_Tc,
154155
CT_TcPr,
@@ -164,6 +165,7 @@
164165
register_element_cls("w:tblGrid", CT_TblGrid)
165166
register_element_cls("w:tblLayout", CT_TblLayoutType)
166167
register_element_cls("w:tblPr", CT_TblPr)
168+
register_element_cls("w:tblPrEx", CT_TblPrEx)
167169
register_element_cls("w:tblStyle", CT_String)
168170
register_element_cls("w:tc", CT_Tc)
169171
register_element_cls("w:tcPr", CT_TcPr)

src/docx/oxml/document.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class CT_Body(BaseOxmlElement):
4444

4545
p = ZeroOrMore("w:p", successors=("w:sectPr",))
4646
tbl = ZeroOrMore("w:tbl", successors=("w:sectPr",))
47-
sectPr: CT_SectPr | None = ZeroOrOne( # pyright: ignore[reportGeneralTypeIssues]
47+
sectPr: CT_SectPr | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
4848
"w:sectPr", successors=()
4949
)
5050

src/docx/oxml/parser.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# pyright: reportImportCycles=false
2+
13
"""XML parser for python-docx."""
24

35
from __future__ import annotations
@@ -43,7 +45,7 @@ def OxmlElement(
4345
nsptag_str: str,
4446
attrs: Dict[str, str] | None = None,
4547
nsdecls: Dict[str, str] | None = None,
46-
) -> BaseOxmlElement:
48+
) -> BaseOxmlElement | etree._Element: # pyright: ignore[reportPrivateUsage]
4749
"""Return a 'loose' lxml element having the tag specified by `nsptag_str`.
4850
4951
The tag in `nsptag_str` must contain the standard namespace prefix, e.g. `a:tbl`.

src/docx/oxml/section.py

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -51,55 +51,49 @@ def inner_content_elements(self) -> List[CT_P | CT_Tbl]:
5151
class CT_HdrFtrRef(BaseOxmlElement):
5252
"""`w:headerReference` and `w:footerReference` elements."""
5353

54-
type_: WD_HEADER_FOOTER = (
55-
RequiredAttribute( # pyright: ignore[reportGeneralTypeIssues]
56-
"w:type", WD_HEADER_FOOTER
57-
)
58-
)
59-
rId: str = RequiredAttribute( # pyright: ignore[reportGeneralTypeIssues]
60-
"r:id", XsdString
54+
type_: WD_HEADER_FOOTER = RequiredAttribute( # pyright: ignore[reportAssignmentType]
55+
"w:type", WD_HEADER_FOOTER
6156
)
57+
rId: str = RequiredAttribute("r:id", XsdString) # pyright: ignore[reportAssignmentType]
6258

6359

6460
class CT_PageMar(BaseOxmlElement):
6561
"""``<w:pgMar>`` element, defining page margins."""
6662

67-
top: Length | None = OptionalAttribute( # pyright: ignore[reportGeneralTypeIssues]
63+
top: Length | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
6864
"w:top", ST_SignedTwipsMeasure
6965
)
70-
right: Length | None = OptionalAttribute( # pyright: ignore
66+
right: Length | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
7167
"w:right", ST_TwipsMeasure
7268
)
73-
bottom: Length | None = OptionalAttribute( # pyright: ignore
69+
bottom: Length | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
7470
"w:bottom", ST_SignedTwipsMeasure
7571
)
76-
left: Length | None = OptionalAttribute( # pyright: ignore[reportGeneralTypeIssues]
72+
left: Length | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
7773
"w:left", ST_TwipsMeasure
7874
)
79-
header: Length | None = OptionalAttribute( # pyright: ignore
75+
header: Length | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
8076
"w:header", ST_TwipsMeasure
8177
)
82-
footer: Length | None = OptionalAttribute( # pyright: ignore
78+
footer: Length | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
8379
"w:footer", ST_TwipsMeasure
8480
)
85-
gutter: Length | None = OptionalAttribute( # pyright: ignore
81+
gutter: Length | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
8682
"w:gutter", ST_TwipsMeasure
8783
)
8884

8985

9086
class CT_PageSz(BaseOxmlElement):
9187
"""``<w:pgSz>`` element, defining page dimensions and orientation."""
9288

93-
w: Length | None = OptionalAttribute( # pyright: ignore[reportGeneralTypeIssues]
89+
w: Length | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
9490
"w:w", ST_TwipsMeasure
9591
)
96-
h: Length | None = OptionalAttribute( # pyright: ignore[reportGeneralTypeIssues]
92+
h: Length | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
9793
"w:h", ST_TwipsMeasure
9894
)
99-
orient: WD_ORIENTATION = (
100-
OptionalAttribute( # pyright: ignore[reportGeneralTypeIssues]
101-
"w:orient", WD_ORIENTATION, default=WD_ORIENTATION.PORTRAIT
102-
)
95+
orient: WD_ORIENTATION = OptionalAttribute( # pyright: ignore[reportAssignmentType]
96+
"w:orient", WD_ORIENTATION, default=WD_ORIENTATION.PORTRAIT
10397
)
10498

10599

@@ -139,16 +133,16 @@ class CT_SectPr(BaseOxmlElement):
139133
)
140134
headerReference = ZeroOrMore("w:headerReference", successors=_tag_seq)
141135
footerReference = ZeroOrMore("w:footerReference", successors=_tag_seq)
142-
type: CT_SectType | None = ZeroOrOne( # pyright: ignore[reportGeneralTypeIssues]
136+
type: CT_SectType | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
143137
"w:type", successors=_tag_seq[3:]
144138
)
145-
pgSz: CT_PageSz | None = ZeroOrOne( # pyright: ignore[reportGeneralTypeIssues]
139+
pgSz: CT_PageSz | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
146140
"w:pgSz", successors=_tag_seq[4:]
147141
)
148-
pgMar: CT_PageMar | None = ZeroOrOne( # pyright: ignore[reportGeneralTypeIssues]
142+
pgMar: CT_PageMar | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
149143
"w:pgMar", successors=_tag_seq[5:]
150144
)
151-
titlePg: CT_OnOff | None = ZeroOrOne( # pyright: ignore[reportGeneralTypeIssues]
145+
titlePg: CT_OnOff | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
152146
"w:titlePg", successors=_tag_seq[14:]
153147
)
154148
del _tag_seq
@@ -187,9 +181,7 @@ def bottom_margin(self) -> Length | None:
187181
@bottom_margin.setter
188182
def bottom_margin(self, value: int | Length | None):
189183
pgMar = self.get_or_add_pgMar()
190-
pgMar.bottom = (
191-
value if value is None or isinstance(value, Length) else Length(value)
192-
)
184+
pgMar.bottom = value if value is None or isinstance(value, Length) else Length(value)
193185

194186
def clone(self) -> CT_SectPr:
195187
"""Return an exact duplicate of this ``<w:sectPr>`` element tree suitable for
@@ -217,9 +209,7 @@ def footer(self) -> Length | None:
217209
@footer.setter
218210
def footer(self, value: int | Length | None):
219211
pgMar = self.get_or_add_pgMar()
220-
pgMar.footer = (
221-
value if value is None or isinstance(value, Length) else Length(value)
222-
)
212+
pgMar.footer = value if value is None or isinstance(value, Length) else Length(value)
223213

224214
def get_footerReference(self, type_: WD_HEADER_FOOTER) -> CT_HdrFtrRef | None:
225215
"""Return footerReference element of `type_` or None if not present."""
@@ -251,9 +241,7 @@ def gutter(self) -> Length | None:
251241
@gutter.setter
252242
def gutter(self, value: int | Length | None):
253243
pgMar = self.get_or_add_pgMar()
254-
pgMar.gutter = (
255-
value if value is None or isinstance(value, Length) else Length(value)
256-
)
244+
pgMar.gutter = value if value is None or isinstance(value, Length) else Length(value)
257245

258246
@property
259247
def header(self) -> Length | None:
@@ -270,9 +258,7 @@ def header(self) -> Length | None:
270258
@header.setter
271259
def header(self, value: int | Length | None):
272260
pgMar = self.get_or_add_pgMar()
273-
pgMar.header = (
274-
value if value is None or isinstance(value, Length) else Length(value)
275-
)
261+
pgMar.header = value if value is None or isinstance(value, Length) else Length(value)
276262

277263
def iter_inner_content(self) -> Iterator[CT_P | CT_Tbl]:
278264
"""Generate all `w:p` and `w:tbl` elements in this section.
@@ -295,9 +281,7 @@ def left_margin(self) -> Length | None:
295281
@left_margin.setter
296282
def left_margin(self, value: int | Length | None):
297283
pgMar = self.get_or_add_pgMar()
298-
pgMar.left = (
299-
value if value is None or isinstance(value, Length) else Length(value)
300-
)
284+
pgMar.left = value if value is None or isinstance(value, Length) else Length(value)
301285

302286
@property
303287
def orientation(self) -> WD_ORIENTATION:
@@ -442,8 +426,8 @@ def top_margin(self, value: Length | None):
442426
class CT_SectType(BaseOxmlElement):
443427
"""``<w:sectType>`` element, defining the section start type."""
444428

445-
val: WD_SECTION_START | None = ( # pyright: ignore[reportGeneralTypeIssues]
446-
OptionalAttribute("w:val", WD_SECTION_START)
429+
val: WD_SECTION_START | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
430+
"w:val", WD_SECTION_START
447431
)
448432

449433

src/docx/oxml/shared.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class CT_DecimalNumber(BaseOxmlElement):
1515
containing a text representation of a decimal number (e.g. 42) in its ``val``
1616
attribute."""
1717

18-
val = RequiredAttribute("w:val", ST_DecimalNumber)
18+
val: int = RequiredAttribute("w:val", ST_DecimalNumber) # pyright: ignore[reportAssignmentType]
1919

2020
@classmethod
2121
def new(cls, nsptagname, val):
@@ -42,9 +42,7 @@ class CT_String(BaseOxmlElement):
4242
In those cases, it containing a style name in its `val` attribute.
4343
"""
4444

45-
val: str = RequiredAttribute( # pyright: ignore[reportGeneralTypeIssues]
46-
"w:val", ST_String
47-
)
45+
val: str = RequiredAttribute("w:val", ST_String) # pyright: ignore[reportGeneralTypeIssues]
4846

4947
@classmethod
5048
def new(cls, nsptagname: str, val: str):

0 commit comments

Comments
 (0)