1
1
# Copyright (c) 2010-2012 testtools developers. See LICENSE for details.
2
2
3
- import sys
3
+ from typing import Any , Callable , TypeVar
4
4
5
+ T = TypeVar ("T" )
6
+ K = TypeVar ("K" )
7
+ V = TypeVar ("V" )
8
+ R = TypeVar ("R" )
5
9
6
- def try_import (name , alternative = None , error_callback = None ):
7
- """Attempt to import a module, with a fallback.
8
10
9
- Attempt to import ``name``. If it fails, return ``alternative``. When
10
- supporting multiple versions of Python or optional dependencies, it is
11
- useful to be able to try to import a module.
12
-
13
- :param name: The name of the object to import, e.g. ``os.path`` or
14
- ``os.path.join``.
15
- :param alternative: The value to return if no module can be imported.
16
- Defaults to None.
17
- :param error_callback: If non-None, a callable that is passed the
18
- ImportError when the module cannot be loaded.
19
- """
20
- module_segments = name .split ("." )
21
- last_error = None
22
- remainder = []
23
-
24
- # module_name will be what successfully imports. We cannot walk from the
25
- # __import__ result because in import loops (A imports A.B, which imports
26
- # C, which calls try_import("A.B")) A.B will not yet be set.
27
- while module_segments :
28
- module_name = "." .join (module_segments )
29
- try :
30
- __import__ (module_name )
31
- except ImportError :
32
- last_error = sys .exc_info ()[1 ]
33
- remainder .append (module_segments .pop ())
34
- continue
35
- else :
36
- break
37
- else :
38
- if last_error is not None and error_callback is not None :
39
- error_callback (last_error )
40
- return alternative
41
-
42
- module = sys .modules [module_name ]
43
- nonexistent = object ()
44
- for segment in reversed (remainder ):
45
- module = getattr (module , segment , nonexistent )
46
- if module is nonexistent :
47
- if last_error is not None and error_callback is not None :
48
- error_callback (last_error )
49
- return alternative
50
-
51
- return module
52
-
53
-
54
- def map_values (function , dictionary ):
11
+ def map_values (function : Callable [[V ], R ], dictionary : dict [K , V ]) -> dict [K , R ]:
55
12
"""Map ``function`` across the values of ``dictionary``.
56
13
57
14
:return: A dict with the same keys as ``dictionary``, where the value
@@ -60,17 +17,17 @@ def map_values(function, dictionary):
60
17
return {k : function (dictionary [k ]) for k in dictionary }
61
18
62
19
63
- def filter_values (function , dictionary ) :
20
+ def filter_values (function : Callable [[ V ], bool ], dictionary : dict [ K , V ]) -> dict [ K , V ] :
64
21
"""Filter ``dictionary`` by its values using ``function``."""
65
22
return {k : v for k , v in dictionary .items () if function (v )}
66
23
67
24
68
- def dict_subtract (a , b ) :
25
+ def dict_subtract (a : dict [ K , V ], b : dict [ K , Any ]) -> dict [ K , V ] :
69
26
"""Return the part of ``a`` that's not in ``b``."""
70
27
return {k : a [k ] for k in set (a ) - set (b )}
71
28
72
29
73
- def list_subtract (a , b ) :
30
+ def list_subtract (a : list [ T ] , b : list [ T ]) -> list [ T ] :
74
31
"""Return a list ``a`` without the elements of ``b``.
75
32
76
33
If a particular value is in ``a`` twice and ``b`` once then the returned
0 commit comments