8000 rfctr: Run type-checks clean · python-openxml/python-docx@ac26854 · GitHub
[go: up one dir, main page]

Skip to content

Commit ac26854

Browse files
committed
rfctr: Run type-checks clean
1 parent b61b63b commit ac26854

File tree

16 files changed

+322
-179
lines changed

16 files changed

+322
-179
lines changed

src/docx/image/image.py

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,31 @@
44
them in a document.
55
"""
66

7+
from __future__ import annotations
8+
79
import hashlib
810
import io
911
import os
12+
from typing import IO, Tuple
13+
14+
from typing_extensions import Self
1015

1116
from docx.image.exceptions import UnrecognizedImageError
12-
from docx.shared import Emu, Inches, lazyproperty
17+
from docx.shared import Emu, Inches, Length, lazyproperty
1318

1419

15-
class Image(object):
20+
class Image:
1621
"""Graphical image stream such as JPEG, PNG, or GIF with properties and methods
1722
required by ImagePart."""
1823

19-
def __init__(self, blob, filename, image_header):
24+
def __init__(self, blob: bytes, filename: str, image_header: BaseImageHeader):
2025
super(Image, self).__init__()
2126
self._blob = blob
2227
self._filename = filename
2328
self._image_header = image_header
2429

2530
@classmethod
26-
def from_blob(cls, blob):
31+
def from_blob(cls, blob: bytes) -> Self:
2732
"""Return a new |Image| subclass instance parsed from the image binary contained
2833
in `blob`."""
2934
stream = io.BytesIO(blob)
@@ -73,60 +78,66 @@ def filename(self):
7378
return self._filename
7479

7580
@property
76-
def px_width(self):
81+
def px_width(self) -> int:
7782
"""The horizontal pixel dimension of the image."""
7883
return self._image_header.px_width
7984

8085
@property
81-
def px_height(self):
86+
def px_height(self) -> int:
8287
"""The vertical pixel dimension of the image."""
8388
return self._image_header.px_height
8489

8590
@property
86-
def horz_dpi(self):
91+
def horz_dpi(self) -> int:
8792
"""Integer dots per inch for the width of this image.
8893
8994
Defaults to 72 when not present in the file, as is often the case.
9095
"""
9196
return self._image_header.horz_dpi
9297

9398
@property
94-
def vert_dpi(self):
99+
def vert_dpi(self) -> int:
95100
"""Integer dots per inch for the height of this image.
96101
97102
Defaults to 72 when not present in the file, as is often the case.
98103
"""
99104
return self._image_header.vert_dpi
100105

101106
@property
102-
def width(self):
107+
def width(self) -> Inches:
103108
"""A |Length| value representing the native width of the image, calculated from
104109
the values of `px_width` and `horz_dpi`."""
105110
return Inches(self.px_width / self.horz_dpi)
106111

107112
@property
108-
def height(self):
113+
def height(self) -> Inches:
109114
"""A |Length| value representing the native height of the image, calculated from
110115
the values of `px_height` and `vert_dpi`."""
111116
return Inches(self.px_height / self.vert_dpi)
112117

113-
def scaled_dimensions(self, width=None, height=None):
114-
"""Return a (cx, cy) 2-tuple representing the native dimensions of this image
115-
scaled by applying the following rules to `width` and `height`.
116-
117-
If both `width` and `height` are specified, the return value is (`width`,
118-
`height`); no scaling is performed. If only one is specified, it is used to
119-
compute a scaling factor that is then applied to the unspecified dimension,
120-
preserving the aspect ratio of the image. If both `width` and `height` are
121-
|None|, the native dimensions are returned. The native dimensions are calculated
122-
using the dots-per-inch (dpi) value embedded in the image, defaulting to 72 dpi
123-
if no value is specified, as is often the case. The returned values are both
124-
|Length| objects.
118+
def scaled_dimensions(
119+
self, width: int | None = None, height: int | None = None
120+
) -> Tuple[Length, Length]:
121+
"""(cx, cy) pair representing scaled dimensions of this image.
122+
123+
The native dimensions of the i 10000 mage are scaled by applying the following rules to
124+
the `width` and `height` arguments.
125+
126+
* If both `width` and `height` are specified, the return value is (`width`,
127+
`height`); no scaling is performed.
128+
* If only one is specified, it is used to compute a scaling factor that is then
129+
applied to the unspecified dimension, preserving the aspect ratio of the image.
130+
* If both `width` and `height` are |None|, the native dimensions are returned.
131+
132+
The native dimensions are calculated using the dots-per-inch (dpi) value
133+
embedded in the image, defaulting to 72 dpi if no value is specified, as is
134+
often the case. The returned values are both |Length| objects.
125135
"""
126136
if width is None and height is None:
127137
return self.width, self.height
128138

129139
if width is None:
140+
assert height is not None
130141
scaling_factor = float(height) / float(self.height)
131142
width = round(self.width * scaling_factor)
132143

@@ -142,7 +153,12 @@ def sha1(self):
142153
return hashlib.sha1(self._blob).hexdigest()
143154

144155
@classmethod
145-
def _from_stream(cls, stream, blob, filename=None):
156+
def _from_stream(
157+
cls,
158+
stream: IO[bytes],
159+
blob: bytes,
160+
filename: str | None = None,
161+
) -> Image:
146162
"""Return an instance of the |Image| subclass corresponding to the format of the
147163
image in `stream`."""
148164
image_header = _ImageHeaderFactory(stream)

src/docx/opc/part.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from docx.oxml.parser import parse_xml
1212

1313
if TYPE_CHECKING:
14-
from docx.opc.package import OpcPackage
14+
from docx.package import Package
1515

1616

1717
class Part(object):
@@ -26,7 +26,7 @@ def __init__(
2626
partname: str,
2727
content_type: str,
2828
blob: bytes | None = None,
29-
package: OpcPackage | None = None,
29+
package: Package | None = None,
3030
):
3131
super(Part, self).__init__()
3232
self._partname = partname

src/docx/oxml/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from docx.oxml.drawing import CT_Drawing
99
from docx.oxml.parser import register_element_cls
1010
from docx.oxml.shape import (
11+
CT_Anchor,
1112
CT_Blip,
1213
CT_BlipFillProperties,
1314
CT_GraphicalObject,
@@ -48,6 +49,7 @@
4849
register_element_cls("pic:pic", CT_Picture)
4950
register_element_cls("pic:spPr", CT_ShapeProperties)
5051
register_element_cls("w:drawing", CT_Drawing)
52+
register_element_cls("wp:anchor", CT_Anchor)
5153
register_element_cls("wp:docPr", CT_NonVisualDrawingProps)
5254
register_element_cls("wp:extent", CT_PositiveSize2D)
5355
register_element_cls("wp:inline", CT_Inline)

src/docx/oxml/shape.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from __future__ import annotations
44

5+
from typing import TYPE_CHECKING
6+
57
from docx.oxml.ns import nsdecls
68
from docx.oxml.parser import parse_xml
79
from docx.oxml.simpletypes import (
@@ -20,6 +22,13 @@
2022
ZeroOrOne,
2123
)
2224

25+
if TYPE_CHECKING:
26+
from docx.shared import Length
27+
28+
29+
class CT_Anchor(BaseOxmlElement):
30+
"""`<wp:anchor>` element, container for a "floating" shape."""
31+
2332

2433
class CT_Blip(BaseOxmlElement):
2534
"""``<a:blip>`` element, specifies image source and adjustments such as alpha and
@@ -49,14 +58,14 @@ class CT_GraphicalObjectData(BaseOxmlElement):
4958

5059

5160
class CT_Inline(BaseOxmlElement):
52-
"""``<w:inline>`` element, container for an inline shape."""
61+
"""`<wp:inline>` element, container for an inline shape."""
5362

5463
extent = OneAndOnlyOne("wp:extent")
5564
docPr = OneAndOnlyOne("wp:docPr")
5665
graphic = OneAndOnlyOne("a:graphic")
5766

5867
@classmethod
59-
def new(cls, cx, cy, shape_id, pic):
68+
def new(cls, cx: Length, cy: Length, shape_id: int, pic: CT_Picture) -> CT_Inline:
6069
"""Return a new ``<wp:inline>`` element populated with the values passed as
6170
parameters."""
6271
inline = parse_xml(cls._inline_xml())
@@ -71,9 +80,13 @@ def new(cls, cx, cy, shape_id, pic):
7180
return inline
7281

7382
@classmethod
74-
def new_pic_inline(cls, shape_id, rId, filename, cx, cy):
75-
"""Return a new `wp:inline` element containing the `pic:pic` element specified
76-
by the argument values."""
83+
def new_pic_inline(
84+
cls, shape_id: int, rId: str, filename: str, cx: Length, cy: Length
85+
) -> CT_Inline:
86+
"""Create `wp:inline` element containing a `pic:pic` element.
87+
88+
The contents of the `pic:pic` element is taken from the argument values.
89+
"""
7790
pic_id = 0 # Word doesn't seem to use this, but does not omit it
7891
pic = CT_Picture.new(pic_id, filename, rId, cx, cy)
7992
inline = cls.new(cx, cy, shape_id, pic)

src/docx/oxml/simpletypes.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,34 @@
55
schema.
66
"""
77

8-
from ..exceptions import InvalidXmlError
9-
from ..shared import Emu, Pt, RGBColor, Twips
8+
from __future__ import annotations
9+
10+
from typing import TYPE_CHECKING, Any
11+
12+
from docx.exceptions import InvalidXmlError
13+
from docx.shared import Emu, Pt, RGBColor, Twips
14+
15+
if TYPE_CHECKING:
16+
from docx import types as t
1017

1118

1219
class BaseSimpleType(object):
20+
"""Base class for simple-types."""
21+
1322
@classmethod
14-
def from_xml(cls, str_value):
15-
return cls.convert_from_xml(str_value)
23+
def from_xml(cls, xml_value: str):
24+
return cls.convert_from_xml(xml_value)
1625

1726
@classmethod
1827
def to_xml(cls, value):
1928
cls.validate(value)
2029
str_value = cls.convert_to_xml(value)
2130
return str_value
2231

32+
@classmethod
33+
def convert_from_xml(cls, str_value: str) -> t.AbstractSimpleTypeMember:
34+
return int(str_value)
35+
2336
@classmethod
2437
def validate_int(cls, value):
2538
if not isinstance(value, int):
@@ -35,15 +48,10 @@ def validate_int_in_range(cls, value, min_inclusive, max_inclusive):
3548
)
3649

3750
@classmethod
38-
def validate_string(cls, value):
39-
if isinstance(value, str):
40-
return value
41-
try:
42-
if isinstance(value, basestring):
43-
return value
44-
except NameError: # means we're on Python 3
45-
pass
46-
raise TypeError("value must be a string, got %s" % type(value))
51+
def validate_string(cls, value: Any) -> str:
52+
if not isinstance(value, str):
53+
raise TypeError("value must be a string, got %s" % type(value))
54+
return value
4755

4856

4957
class BaseIntType(BaseSimpleType):
@@ -62,15 +70,15 @@ def validate(cls, value):
6270

6371
class BaseStringType(BaseSimpleType):
6472
@classmethod
65-
def convert_from_xml(cls, str_value):
73+
def convert_from_xml(cls, str_value: str) -> str:
6674
return str_value
6775

6876
@classmethod
69-
def convert_to_xml(cls, value):
77+
def convert_to_xml(cls, value: str) -> str:
7078
return value
7179

7280
@classmethod
73-
def validate(cls, value):
81+
def validate(cls, value: str):
7482
cls.validate_string(value)
7583

7684

@@ -160,7 +168,7 @@ def validate(cls, value):
160168

161169
class ST_BrClear(XsdString):
162170
@classmethod
163-
def validate(cls, value):
171+
def validate(cls, value: str) -> None:
164172
cls.validate_string(value)
165173
valid_values = ("none", "left", "right", "all")
166174
if value not in valid_values:

0 commit comments

Comments
 (0)
0