Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jedi/inference/utils.py: 60%

43 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

1""" A universal module with functions / classes without dependencies. """ 

2import functools 

3import re 

4import os 

5 

6 

7_sep = os.path.sep 

8if os.path.altsep is not None: 

9 _sep += os.path.altsep 

10_path_re = re.compile(r'(?:\.[^{0}]+|[{0}]__init__\.py)$'.format(re.escape(_sep))) 

11del _sep 

12 

13 

14def to_list(func): 

15 def wrapper(*args, **kwargs): 

16 return list(func(*args, **kwargs)) 

17 return wrapper 

18 

19 

20def to_tuple(func): 

21 def wrapper(*args, **kwargs): 

22 return tuple(func(*args, **kwargs)) 

23 return wrapper 

24 

25 

26def unite(iterable): 

27 """Turns a two dimensional array into a one dimensional.""" 

28 return set(typ for types in iterable for typ in types) 

29 

30 

31class UncaughtAttributeError(Exception): 

32 """ 

33 Important, because `__getattr__` and `hasattr` catch AttributeErrors 

34 implicitly. This is really evil (mainly because of `__getattr__`). 

35 Therefore this class originally had to be derived from `BaseException` 

36 instead of `Exception`. But because I removed relevant `hasattr` from 

37 the code base, we can now switch back to `Exception`. 

38 

39 :param base: return values of sys.exc_info(). 

40 """ 

41 

42 

43def safe_property(func): 

44 return property(reraise_uncaught(func)) 

45 

46 

47def reraise_uncaught(func): 

48 """ 

49 Re-throw uncaught `AttributeError`. 

50 

51 Usage: Put ``@rethrow_uncaught`` in front of the function 

52 which does **not** suppose to raise `AttributeError`. 

53 

54 AttributeError is easily get caught by `hasattr` and another 

55 ``except AttributeError`` clause. This becomes problem when you use 

56 a lot of "dynamic" attributes (e.g., using ``@property``) because you 

57 can't distinguish if the property does not exist for real or some code 

58 inside of the "dynamic" attribute through that error. In a well 

59 written code, such error should not exist but getting there is very 

60 difficult. This decorator is to help us getting there by changing 

61 `AttributeError` to `UncaughtAttributeError` to avoid unexpected catch. 

62 This helps us noticing bugs earlier and facilitates debugging. 

63 """ 

64 @functools.wraps(func) 

65 def wrapper(*args, **kwds): 

66 try: 

67 return func(*args, **kwds) 

68 except AttributeError as e: 

69 raise UncaughtAttributeError(e) from e 

70 return wrapper 

71 

72 

73class PushBackIterator: 

74 def __init__(self, iterator): 

75 self.pushes = [] 

76 self.iterator = iterator 

77 self.current = None 

78 

79 def push_back(self, value): 

80 self.pushes.append(value) 

81 

82 def __iter__(self): 

83 return self 

84 

85 def __next__(self): 

86 if self.pushes: 

87 self.current = self.pushes.pop() 

88 else: 

89 self.current = next(self.iterator) 

90 return self.current