Skip to content

Commit 149177c

Browse files
committed
Updating type hints.
1 parent c011c49 commit 149177c

File tree

12 files changed

+101
-69
lines changed

12 files changed

+101
-69
lines changed

domdf_python_tools/bases.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __getstate__(self) -> Dict[str, Any]:
5252
return self.__dict__
5353

5454
def __setstate__(self, state):
55-
self.__init__(**state)
55+
self.__init__(**state) # type: ignore
5656

5757
def __copy__(self):
5858
return self.__class__(**self.__dict__)

domdf_python_tools/doctools.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
F = TypeVar('F', bound=Callable[..., Any])
3535

3636

37-
def deindent_string(string: str) -> str:
37+
def deindent_string(string: Optional[str]) -> str:
3838
"""
3939
Removes all indentation from the given string.
4040
@@ -45,6 +45,10 @@ def deindent_string(string: str) -> str:
4545
:rtype: str
4646
"""
4747

48+
if not string:
49+
# Short circuit if empty string or None
50+
return ''
51+
4852
split_string = string.split("\n")
4953
deindented_string = [line.lstrip("\t ") for line in split_string]
5054
return "\n".join(deindented_string)

domdf_python_tools/paths.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ class PathPlus(pathlib.Path):
282282
def __new__(cls, *args, **kwargs):
283283
if cls is PathPlus:
284284
cls = WindowsPathPlus if os.name == 'nt' else PosixPathPlus
285-
self = cls._from_parts(args, init=False)
285+
self = cls._from_parts(args, init=False) # type: ignore
286286
if not self._flavour.is_supported:
287287
raise NotImplementedError(f"cannot instantiate {cls.__name__!r} on your system")
288288
self._init()

domdf_python_tools/terminal.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,8 @@
6767
import shlex
6868
import struct
6969
import subprocess
70-
import sys
7170
import textwrap
72-
from typing import Optional, Tuple
71+
from typing import Any, Optional, Tuple
7372

7473

7574
def clear() -> None:
@@ -208,13 +207,15 @@ def _get_terminal_size_posix() -> Optional[Tuple[int, int]]: # pragma: no cover
208207
import fcntl
209208
import termios
210209

211-
def ioctl_GWINSZ(fd):
210+
def ioctl_GWINSZ(fd: int) -> Optional[Tuple[Any, ...]]:
212211
try:
213-
cr = struct.unpack("hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, "1234"))
212+
cr = struct.unpack("hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, b"1234"))
214213
return cr
215214
except Exception:
216215
pass
217216

217+
return None
218+
218219
cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
219220

220221
if not cr:
@@ -252,10 +253,15 @@ def __init__(self, indent: str = " "):
252253
self.parent_frame = inspect.currentframe().f_back # type: ignore # TODO
253254

254255
def __enter__(self):
255-
self.locals_on_entry = self.parent_frame.f_locals.copy()
256+
self.locals_on_entry = self.parent_frame.f_locals.copy() # type: ignore
256257

257258
def __exit__(self, exc_t, exc_v, tb):
258-
new_locals = {k: v for k, v in self.parent_frame.f_locals.items() if k not in self.locals_on_entry}
259+
new_locals = {
260+
k: v
261+
for k, v in self.parent_frame.f_locals.items() # type: ignore
262+
if k not in self.locals_on_entry
263+
}
264+
259265
print(textwrap.indent(pprint.pformat(new_locals), self.indent))
260266

261267

domdf_python_tools/typing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
PathLike = Union[str, pathlib.Path, os.PathLike]
3232

3333

34-
def check_membership(obj: Any, type_: Type) -> bool:
34+
def check_membership(obj: Any, type_: Union[Type, object]) -> bool:
3535
"""
3636
Check if the type of ``obj`` is one of the types in a :class:`typing.Union`, Sequence etc.
3737

setup.cfg

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,12 @@ exclude =
4949
tests
5050
tests.*
5151
doc-source
52+
53+
54+
55+
56+
[mypy]
57+
python_version = 3.6
58+
ignore_missing_imports = True
59+
namespace_packages = True
60+
check_untyped_defs = True

tests/test_dates.py

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
test_date = datetime.datetime(1996, 10, 13, 2, 20).replace(tzinfo=pytz.utc)
2020
today = datetime.datetime.utcnow().replace(tzinfo=pytz.utc) # make sure UTC
2121

22+
2223
# TODO: travis matrix to test without pytz installed
2324
# TODO: test get_timezone
2425

@@ -78,13 +79,21 @@ def test_set_timezone():
7879

7980
if dates.get_utc_offset(tz, today): # otherwise the timezone stayed as UTC
8081
# ensure timestamp did change
81-
assert dates.set_timezone(today, dates.get_timezone(tz, today)).timestamp() != today.timestamp()
82+
target_tz = dates.get_timezone(tz, today)
83+
assert target_tz is not None
84+
85+
assert dates.set_timezone(today, target_tz).timestamp() != today.timestamp()
8286

8387
# Difference between "today" and the new timezone should be the timezone difference
84-
assert (
85-
dates.set_timezone(today, dates.get_timezone(tz, today)).timestamp()
86-
+ dates.get_utc_offset(tz, today).total_seconds()
87-
) == today.timestamp()
88+
target_tz = dates.get_timezone(tz, today)
89+
assert target_tz is not None
90+
91+
utc_offset = dates.get_utc_offset(tz, today)
92+
assert utc_offset is not None
93+
94+
as_seconds = dates.set_timezone(today, target_tz).timestamp() + utc_offset.total_seconds()
95+
96+
assert as_seconds == today.timestamp()
8897

8998
if tz in {
9099
"America/Punta_Arenas",
@@ -110,10 +119,14 @@ def test_set_timezone():
110119
# get_utc_offset(tz, test_date).total_seconds()
111120
#
112121
# )
113-
assert (
114-
dates.set_timezone(test_date, dates.get_timezone(tz, test_date)).timestamp()
115-
+ dates.get_utc_offset(tz, test_date).total_seconds()
116-
) == test_date.timestamp()
122+
target_tz = dates.get_timezone(tz, test_date)
123+
assert target_tz is not None
124+
125+
offset = dates.get_utc_offset(tz, test_date)
126+
assert offset is not None
127+
128+
as_seconds = dates.set_timezone(test_date, target_tz).timestamp() + offset.total_seconds()
129+
assert as_seconds == test_date.timestamp()
117130

118131

119132
months = [
@@ -146,31 +159,39 @@ def test_parse_month():
146159

147160
for value in ["abc", 0, '0', -1, "-1", 13, "13"]:
148161
with pytest.raises(ValueError, match="Unrecognised month value"):
149-
dates.parse_month(value)
162+
dates.parse_month(value) # type: ignore
150163

151164

152-
def test_get_month_number():
153-
for month_idx, month in enumerate(months):
165+
@pytest.mark.parametrize("month_idx, month", enumerate(months))
166+
def test_get_month_number_from_name(month_idx, month):
167+
month_idx += 1 # to make 1-indexed
154168

155-
month_idx += 1 # to make 1-indexed
169+
for i in range(3, len(month)):
170+
assert dates.get_month_number(month.lower()[:i]) == month_idx
171+
assert dates.get_month_number(month.upper()[:i]) == month_idx
172+
assert dates.get_month_number(month.capitalize()[:i]) == month_idx
156173

157-
for i in range(3, len(month)):
158-
assert dates.get_month_number(month.lower()[:i]) == month_idx
159-
assert dates.get_month_number(month.upper()[:i]) == month_idx
160-
assert dates.get_month_number(month.capitalize()[:i]) == month_idx
174+
assert dates.get_month_number(month) == month_idx
161175

162-
assert dates.get_month_number(month) == month_idx
163176

177+
@pytest.mark.parametrize("month_idx", range(1, 13))
178+
def test_get_month_number_from_no(month_idx):
164179
for month_idx in range(1, 13):
165180
assert dates.get_month_number(month_idx) == month_idx
166181

167-
for value in [0, -1, 13]:
168-
with pytest.raises(ValueError, match="The given month is not recognised."):
169-
dates.get_month_number(value)
170182

171-
for value in ["abc", '0', "-1" "13"]:
172-
with pytest.raises(ValueError, match="Unrecognised month value"):
173-
dates.get_month_number(value)
183+
@pytest.mark.parametrize("value, match", [
184+
(0, "The given month is not recognised."),
185+
(-1, "The given month is not recognised."),
186+
(13, "The given month is not recognised."),
187+
("abc", "Unrecognised month value"),
188+
('0', "Unrecognised month value"),
189+
("-1", "Unrecognised month value"),
190+
("13", "Unrecognised month value"),
191+
])
192+
def test_get_month_number_errors(value, match):
193+
with pytest.raises(ValueError, match=match):
194+
dates.get_month_number(value)
174195

175196

176197
def test_check_date():

tests/test_import_tools.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
sys.path.append("tests")
1414

1515
# 3rd party
16-
import discover_demo_module
16+
import discover_demo_module # type: ignore
1717

1818

1919
def test_discover():

tests/test_paths.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,8 @@ def test_maybe_make_parents_pathplus():
147147

148148

149149
def test_parent_path():
150-
with TemporaryDirectory() as tmpdir:
151-
tmpdir = pathlib.Path(tmpdir)
150+
with TemporaryDirectory() as tmpdir_:
151+
tmpdir = pathlib.Path(tmpdir_)
152152

153153
dir1 = tmpdir / "dir1"
154154
dir2 = dir1 / "dir2"

tests/test_paths_stdlib.py

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,17 @@
88
#
99

1010
# stdlib
11-
import collections.abc
1211
import errno
13-
import io
1412
import os
1513
import pathlib
1614
import pickle
17-
import platform
1815
import socket
1916
import stat
2017
import sys
21-
import tempfile
2218
import unittest
2319
from test import support # type: ignore
2420
from test.support import TESTFN # type: ignore
21+
from typing import Set
2522
from unittest import mock
2623

2724
# 3rd party
@@ -44,7 +41,7 @@
4441

4542

4643
def symlink_skip_reason():
47-
if not pathlib.supports_symlinks:
44+
if not pathlib.supports_symlinks: # type: ignore
4845
return "no system support for symlinks"
4946
try:
5047
os.symlink(__file__, BASE)
@@ -243,7 +240,7 @@ def test_unlink(self):
243240
def test_unlink_missing_ok(self): # pragma: no cover (<py37)
244241
p = PathPlus(BASE) / 'fileAAA'
245242
self.assertFileNotFound(p.unlink)
246-
p.unlink(missing_ok=True)
243+
p.unlink(missing_ok=True) # type: ignore
247244

248245
def test_rmdir(self):
249246
p = PathPlus(BASE) / 'dirA'
@@ -262,15 +259,15 @@ def test_link_to(self): # pragma: no cover (<py37)
262259
# linking to another path.
263260
q = P / 'dirA' / 'fileAA'
264261
try:
265-
p.link_to(q)
262+
p.link_to(q) # type: ignore
266263
except PermissionError as e:
267264
self.skipTest('os.link(): %s' % e)
268265
self.assertEqual(q.stat().st_size, size)
269266
self.assertEqual(os.path.samefile(p, q), True)
270267
self.assertTrue(p.stat)
271268
# Linking to a str of a relative path.
272269
r = rel_join('fileAAA')
273-
q.link_to(r)
270+
q.link_to(r) # type: ignore
274271
self.assertEqual(os.stat(r).st_size, size)
275272
self.assertTrue(q.stat)
276273

@@ -281,7 +278,7 @@ def test_link_to_not_implemented(self):
281278
# linking to another path.
282279
q = P / 'dirA' / 'fileAA'
283280
with self.assertRaises(NotImplementedError):
284-
p.link_to(q)
281+
p.link_to(q) # type: ignore
285282

286283
def test_rename(self):
287284
P = PathPlus(BASE)
@@ -347,11 +344,11 @@ def test_replace(self):
347344
@with_symlinks
348345
def test_readlink(self): # pragma: no cover (<py39)
349346
P = PathPlus(BASE)
350-
self.assertEqual((P / 'linkA').readlink(), PathPlus('fileA'))
351-
self.assertEqual((P / 'brokenLink').readlink(), PathPlus('non-existing'))
352-
self.assertEqual((P / 'linkB').readlink(), PathPlus('dirB'))
347+
self.assertEqual((P / 'linkA').readlink(), PathPlus('fileA')) # type: ignore
348+
self.assertEqual((P / 'brokenLink').readlink(), PathPlus('non-existing')) # type: ignore
349+
self.assertEqual((P / 'linkB').readlink(), PathPlus('dirB')) # type: ignore
353350
with self.assertRaises(OSError):
354-
(P / 'fileA').readlink()
351+
(P / 'fileA').readlink() # type: ignore
355352

356353
def test_touch_common(self):
357354
P = PathPlus(BASE)
@@ -507,7 +504,7 @@ def my_mkdir(path, mode=0o777):
507504
os.mkdir(path, mode) # Our real call.
508505

509506
pattern = [bool(pattern_num & (1 << n)) for n in range(5)]
510-
concurrently_created = set()
507+
concurrently_created: Set = set()
511508
p12 = p / 'dir1' / 'dir2'
512509
try:
513510
with mock.patch("pathlib._normal_accessor.mkdir", my_mkdir):
@@ -569,13 +566,13 @@ def test_is_file(self):
569566
def test_is_mount(self): # pragma: no cover (<py37)
570567
P = PathPlus(BASE)
571568
R = PathPlus('/') # TODO: Work out Windows.
572-
self.assertFalse((P / 'fileA').is_mount())
573-
self.assertFalse((P / 'dirA').is_mount())
574-
self.assertFalse((P / 'non-existing').is_mount())
575-
self.assertFalse((P / 'fileA' / 'bah').is_mount())
576-
self.assertTrue(R.is_mount())
569+
self.assertFalse((P / 'fileA').is_mount()) # type: ignore
570+
self.assertFalse((P / 'dirA').is_mount()) # type: ignore
571+
self.assertFalse((P / 'non-existing').is_mount()) # type: ignore
572+
self.assertFalse((P / 'fileA' / 'bah').is_mount()) # type: ignore
573+
self.assertTrue(R.is_mount()) # type: ignore
577574
if support.can_symlink():
578-
self.assertFalse((P / 'linkA').is_mount())
575+
self.assertFalse((P / 'linkA').is_mount()) # type: ignore
579576

580577
def test_is_symlink(self):
581578
P = PathPlus(BASE)

0 commit comments

Comments
 (0)