##// END OF EJS Templates
some more typechecking (#14535)
M Bussonnier -
r28895:a49046c7 merge
parent child Browse files
Show More
@@ -32,7 +32,7 b' def test_full_path_posix():'
32 spath = "/foo"
32 spath = "/foo"
33 result = tt.full_path(spath, ["a.txt", "b.txt"])
33 result = tt.full_path(spath, ["a.txt", "b.txt"])
34 assert result, ["/a.txt" == "/b.txt"]
34 assert result, ["/a.txt" == "/b.txt"]
35 result = tt.full_path(spath, "a.txt")
35 result = tt.full_path(spath, ["a.txt"])
36 assert result == ["/a.txt"]
36 assert result == ["/a.txt"]
37
37
38
38
@@ -44,7 +44,7 b' def test_full_path_win32():'
44 spath = "c:\\foo"
44 spath = "c:\\foo"
45 result = tt.full_path(spath, ["a.txt", "b.txt"])
45 result = tt.full_path(spath, ["a.txt", "b.txt"])
46 assert result, ["c:\\a.txt" == "c:\\b.txt"]
46 assert result, ["c:\\a.txt" == "c:\\b.txt"]
47 result = tt.full_path(spath, "a.txt")
47 result = tt.full_path(spath, ["a.txt"])
48 assert result == ["c:\\a.txt"]
48 assert result == ["c:\\a.txt"]
49
49
50
50
@@ -36,7 +36,7 b' from . import skipdoctest'
36 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
36 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
37
37
38 @doctest_deco
38 @doctest_deco
39 def full_path(startPath,files):
39 def full_path(startPath: str, files: list[str]) -> list[str]:
40 """Make full paths for all the listed files, based on startPath.
40 """Make full paths for all the listed files, based on startPath.
41
41
42 Only the base part of startPath is kept, since this routine is typically
42 Only the base part of startPath is kept, since this routine is typically
@@ -49,7 +49,7 b' def full_path(startPath,files):'
49 Initial path to use as the base for the results. This path is split
49 Initial path to use as the base for the results. This path is split
50 using os.path.split() and only its first component is kept.
50 using os.path.split() and only its first component is kept.
51
51
52 files : string or list
52 files : list
53 One or more files.
53 One or more files.
54
54
55 Examples
55 Examples
@@ -61,13 +61,8 b' def full_path(startPath,files):'
61 >>> full_path('/foo',['a.txt','b.txt'])
61 >>> full_path('/foo',['a.txt','b.txt'])
62 ['/a.txt', '/b.txt']
62 ['/a.txt', '/b.txt']
63
63
64 If a single file is given, the output is still a list::
65
66 >>> full_path('/foo','a.txt')
67 ['/a.txt']
68 """
64 """
69
65 assert isinstance(files, list)
70 files = list_strings(files)
71 base = os.path.split(startPath)[0]
66 base = os.path.split(startPath)[0]
72 return [ os.path.join(base,f) for f in files ]
67 return [ os.path.join(base,f) for f in files ]
73
68
@@ -16,7 +16,20 b' import warnings'
16 from string import Formatter
16 from string import Formatter
17 from pathlib import Path
17 from pathlib import Path
18
18
19 from typing import List, Dict, Tuple, Optional, cast, Sequence, Mapping, Any
19 from typing import (
20 List,
21 Dict,
22 Tuple,
23 Optional,
24 cast,
25 Sequence,
26 Mapping,
27 Any,
28 Union,
29 Callable,
30 Iterator,
31 TypeVar,
32 )
20
33
21 if sys.version_info < (3, 12):
34 if sys.version_info < (3, 12):
22 from typing_extensions import Self
35 from typing_extensions import Self
@@ -138,8 +151,13 b' class SList(list):'
138
151
139 p = paths = property(get_paths)
152 p = paths = property(get_paths)
140
153
141 def grep(self, pattern, prune = False, field = None):
154 def grep(
142 """ Return all strings matching 'pattern' (a regex or callable)
155 self,
156 pattern: Union[str, Callable[[Any], re.Match[str] | None]],
157 prune: bool = False,
158 field: Optional[int] = None,
159 ) -> Self:
160 """Return all strings matching 'pattern' (a regex or callable)
143
161
144 This is case-insensitive. If prune is true, return all items
162 This is case-insensitive. If prune is true, return all items
145 NOT matching the pattern.
163 NOT matching the pattern.
@@ -154,7 +172,7 b' class SList(list):'
154 a.grep('chm', field=-1)
172 a.grep('chm', field=-1)
155 """
173 """
156
174
157 def match_target(s):
175 def match_target(s: str) -> str:
158 if field is None:
176 if field is None:
159 return s
177 return s
160 parts = s.split()
178 parts = s.split()
@@ -169,12 +187,12 b' class SList(list):'
169 else:
187 else:
170 pred = pattern
188 pred = pattern
171 if not prune:
189 if not prune:
172 return SList([el for el in self if pred(match_target(el))])
190 return type(self)([el for el in self if pred(match_target(el))])
173 else:
191 else:
174 return SList([el for el in self if not pred(match_target(el))])
192 return type(self)([el for el in self if not pred(match_target(el))])
175
193
176 def fields(self, *fields):
194 def fields(self, *fields: List[str]) -> List[List[str]]:
177 """ Collect whitespace-separated fields from string list
195 """Collect whitespace-separated fields from string list
178
196
179 Allows quick awk-like usage of string lists.
197 Allows quick awk-like usage of string lists.
180
198
@@ -209,8 +227,12 b' class SList(list):'
209
227
210 return res
228 return res
211
229
212 def sort(self,field= None, nums = False):
230 def sort( # type:ignore[override]
213 """ sort by specified fields (see fields())
231 self,
232 field: Optional[List[str]] = None,
233 nums: bool = False,
234 ) -> Self:
235 """sort by specified fields (see fields())
214
236
215 Example::
237 Example::
216
238
@@ -236,7 +258,7 b' class SList(list):'
236
258
237
259
238 dsu.sort()
260 dsu.sort()
239 return SList([t[1] for t in dsu])
261 return type(self)([t[1] for t in dsu])
240
262
241
263
242 # FIXME: We need to reimplement type specific displayhook and then add this
264 # FIXME: We need to reimplement type specific displayhook and then add this
@@ -255,7 +277,7 b' class SList(list):'
255 # print_slist = result_display.register(SList)(print_slist)
277 # print_slist = result_display.register(SList)(print_slist)
256
278
257
279
258 def indent(instr,nspaces=4, ntabs=0, flatten=False):
280 def indent(instr: str, nspaces: int = 4, ntabs: int = 0, flatten: bool = False) -> str:
259 """Indent a string a given number of spaces or tabstops.
281 """Indent a string a given number of spaces or tabstops.
260
282
261 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
283 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
@@ -275,7 +297,7 b' def indent(instr,nspaces=4, ntabs=0, flatten=False):'
275
297
276 Returns
298 Returns
277 -------
299 -------
278 str|unicode : string indented by ntabs and nspaces.
300 str : string indented by ntabs and nspaces.
279
301
280 """
302 """
281 if instr is None:
303 if instr is None:
@@ -292,7 +314,7 b' def indent(instr,nspaces=4, ntabs=0, flatten=False):'
292 return outstr
314 return outstr
293
315
294
316
295 def list_strings(arg):
317 def list_strings(arg: Union[str, List[str]]) -> List[str]:
296 """Always return a list of strings, given a string or list of strings
318 """Always return a list of strings, given a string or list of strings
297 as input.
319 as input.
298
320
@@ -316,7 +338,7 b' def list_strings(arg):'
316 return arg
338 return arg
317
339
318
340
319 def marquee(txt='',width=78,mark='*'):
341 def marquee(txt: str = "", width: int = 78, mark: str = "*") -> str:
320 """Return the input string centered in a 'marquee'.
342 """Return the input string centered in a 'marquee'.
321
343
322 Examples
344 Examples
@@ -343,7 +365,8 b" def marquee(txt='',width=78,mark='*'):"
343
365
344 ini_spaces_re = re.compile(r'^(\s+)')
366 ini_spaces_re = re.compile(r'^(\s+)')
345
367
346 def num_ini_spaces(strng):
368
369 def num_ini_spaces(strng: str) -> int:
347 """Return the number of initial spaces in a string"""
370 """Return the number of initial spaces in a string"""
348 warnings.warn(
371 warnings.warn(
349 "`num_ini_spaces` is Pending Deprecation since IPython 8.17."
372 "`num_ini_spaces` is Pending Deprecation since IPython 8.17."
@@ -359,7 +382,7 b' def num_ini_spaces(strng):'
359 return 0
382 return 0
360
383
361
384
362 def format_screen(strng):
385 def format_screen(strng: str) -> str:
363 """Format a string for screen printing.
386 """Format a string for screen printing.
364
387
365 This removes some latex-type format codes."""
388 This removes some latex-type format codes."""
@@ -396,7 +419,7 b' def dedent(text: str) -> str:'
396 return '\n'.join([first, rest])
419 return '\n'.join([first, rest])
397
420
398
421
399 def wrap_paragraphs(text, ncols=80):
422 def wrap_paragraphs(text: str, ncols: int = 80) -> List[str]:
400 """Wrap multiple paragraphs to fit a specified width.
423 """Wrap multiple paragraphs to fit a specified width.
401
424
402 This is equivalent to textwrap.wrap, but with support for multiple
425 This is equivalent to textwrap.wrap, but with support for multiple
@@ -428,7 +451,7 b' def wrap_paragraphs(text, ncols=80):'
428 return out_ps
451 return out_ps
429
452
430
453
431 def strip_email_quotes(text):
454 def strip_email_quotes(text: str) -> str:
432 """Strip leading email quotation characters ('>').
455 """Strip leading email quotation characters ('>').
433
456
434 Removes any combination of leading '>' interspersed with whitespace that
457 Removes any combination of leading '>' interspersed with whitespace that
@@ -478,7 +501,7 b' def strip_email_quotes(text):'
478 return text
501 return text
479
502
480
503
481 def strip_ansi(source):
504 def strip_ansi(source: str) -> str:
482 """
505 """
483 Remove ansi escape codes from text.
506 Remove ansi escape codes from text.
484
507
@@ -519,7 +542,8 b' class EvalFormatter(Formatter):'
519 In [3]: f.format("{greeting[slice(2,4)]}", greeting="Hello")
542 In [3]: f.format("{greeting[slice(2,4)]}", greeting="Hello")
520 Out[3]: 'll'
543 Out[3]: 'll'
521 """
544 """
522 def get_field(self, name, args, kwargs):
545
546 def get_field(self, name: str, args: Any, kwargs: Any) -> Tuple[Any, str]:
523 v = eval(name, kwargs)
547 v = eval(name, kwargs)
524 return v, name
548 return v, name
525
549
@@ -606,11 +630,15 b' class DollarFormatter(FullEvalFormatter):'
606 In [4]: f.format('$a or {b}', a=1, b=2)
630 In [4]: f.format('$a or {b}', a=1, b=2)
607 Out[4]: '1 or 2'
631 Out[4]: '1 or 2'
608 """
632 """
609 _dollar_pattern_ignore_single_quote = re.compile(r"(.*?)\$(\$?[\w\.]+)(?=([^']*'[^']*')*[^']*$)")
633
610 def parse(self, fmt_string):
634 _dollar_pattern_ignore_single_quote = re.compile(
611 for literal_txt, field_name, format_spec, conversion \
635 r"(.*?)\$(\$?[\w\.]+)(?=([^']*'[^']*')*[^']*$)"
612 in Formatter.parse(self, fmt_string):
636 )
613
637
638 def parse(self, fmt_string: str) -> Iterator[Tuple[Any, Any, Any, Any]]: # type: ignore
639 for literal_txt, field_name, format_spec, conversion in Formatter.parse(
640 self, fmt_string
641 ):
614 # Find $foo patterns in the literal text.
642 # Find $foo patterns in the literal text.
615 continue_from = 0
643 continue_from = 0
616 txt = ""
644 txt = ""
@@ -627,14 +655,17 b' class DollarFormatter(FullEvalFormatter):'
627 # Re-yield the {foo} style pattern
655 # Re-yield the {foo} style pattern
628 yield (txt + literal_txt[continue_from:], field_name, format_spec, conversion)
656 yield (txt + literal_txt[continue_from:], field_name, format_spec, conversion)
629
657
630 def __repr__(self):
658 def __repr__(self) -> str:
631 return "<DollarFormatter>"
659 return "<DollarFormatter>"
632
660
633 #-----------------------------------------------------------------------------
661 #-----------------------------------------------------------------------------
634 # Utils to columnize a list of string
662 # Utils to columnize a list of string
635 #-----------------------------------------------------------------------------
663 #-----------------------------------------------------------------------------
636
664
637 def _col_chunks(l, max_rows, row_first=False):
665
666 def _col_chunks(
667 l: List[int], max_rows: int, row_first: bool = False
668 ) -> Iterator[List[int]]:
638 """Yield successive max_rows-sized column chunks from l."""
669 """Yield successive max_rows-sized column chunks from l."""
639 if row_first:
670 if row_first:
640 ncols = (len(l) // max_rows) + (len(l) % max_rows > 0)
671 ncols = (len(l) // max_rows) + (len(l) % max_rows > 0)
@@ -646,7 +677,7 b' def _col_chunks(l, max_rows, row_first=False):'
646
677
647
678
648 def _find_optimal(
679 def _find_optimal(
649 rlist: List[str], row_first: bool, separator_size: int, displaywidth: int
680 rlist: List[int], row_first: bool, separator_size: int, displaywidth: int
650 ) -> Dict[str, Any]:
681 ) -> Dict[str, Any]:
651 """Calculate optimal info to columnize a list of string"""
682 """Calculate optimal info to columnize a list of string"""
652 for max_rows in range(1, len(rlist) + 1):
683 for max_rows in range(1, len(rlist) + 1):
@@ -662,7 +693,10 b' def _find_optimal('
662 }
693 }
663
694
664
695
665 def _get_or_default(mylist, i, default=None):
696 T = TypeVar("T")
697
698
699 def _get_or_default(mylist: List[T], i: int, default: T) -> T:
666 """return list item number, or default if don't exist"""
700 """return list item number, or default if don't exist"""
667 if i >= len(mylist):
701 if i >= len(mylist):
668 return default
702 return default
@@ -740,9 +774,31 b' def compute_item_matrix('
740 )
774 )
741 nrow, ncol = info["max_rows"], info["num_columns"]
775 nrow, ncol = info["max_rows"], info["num_columns"]
742 if row_first:
776 if row_first:
743 return ([[_get_or_default(items, r * ncol + c, default=empty) for c in range(ncol)] for r in range(nrow)], info)
777 return (
778 [
779 [
780 _get_or_default(
781 items, r * ncol + c, default=empty
782 ) # type:ignore[misc]
783 for c in range(ncol)
784 ]
785 for r in range(nrow)
786 ],
787 info,
788 )
744 else:
789 else:
745 return ([[_get_or_default(items, c * nrow + r, default=empty) for c in range(ncol)] for r in range(nrow)], info)
790 return (
791 [
792 [
793 _get_or_default(
794 items, c * nrow + r, default=empty
795 ) # type:ignore[misc]
796 for c in range(ncol)
797 ]
798 for r in range(nrow)
799 ],
800 info,
801 )
746
802
747
803
748 def columnize(
804 def columnize(
@@ -795,7 +851,9 b' def columnize('
795 return "\n".join(map(sjoin, fmatrix)) + "\n"
851 return "\n".join(map(sjoin, fmatrix)) + "\n"
796
852
797
853
798 def get_text_list(list_, last_sep=' and ', sep=", ", wrap_item_with=""):
854 def get_text_list(
855 list_: List[str], last_sep: str = " and ", sep: str = ", ", wrap_item_with: str = ""
856 ) -> str:
799 """
857 """
800 Return a string with a natural enumeration of items
858 Return a string with a natural enumeration of items
801
859
@@ -150,12 +150,22 b' warn_redundant_casts = true'
150 module = [
150 module = [
151 "IPython.utils.text",
151 "IPython.utils.text",
152 ]
152 ]
153 disallow_untyped_defs = true
154 check_untyped_defs = false
155 disallow_untyped_decorators = true
156
157 [[tool.mypy.overrides]]
158 module = [
159 ]
153 disallow_untyped_defs = false
160 disallow_untyped_defs = false
161 ignore_errors = true
162 ignore_missing_imports = true
163 disallow_untyped_calls = false
164 disallow_incomplete_defs = false
154 check_untyped_defs = false
165 check_untyped_defs = false
155 disallow_untyped_decorators = false
166 disallow_untyped_decorators = false
156
167
157
168 # gloabl ignore error
158 # global ignore error
159 [[tool.mypy.overrides]]
169 [[tool.mypy.overrides]]
160 module = [
170 module = [
161 "IPython",
171 "IPython",
General Comments 0
You need to be logged in to leave comments. Login now