]> crepu.dev Git - config.git/blob - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/jedi/inference/flow_analysis.py
Actualizado el Readme
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / jedi / inference / flow_analysis.py
1 from typing import Dict, Optional
2
3 from jedi.parser_utils import get_flow_branch_keyword, is_scope, get_parent_scope
4 from jedi.inference.recursion import execution_allowed
5 from jedi.inference.helpers import is_big_annoying_library
6
7
8 class Status:
9 lookup_table: Dict[Optional[bool], 'Status'] = {}
10
11 def __init__(self, value: Optional[bool], name: str) -> None:
12 self._value = value
13 self._name = name
14 Status.lookup_table[value] = self
15
16 def invert(self):
17 if self is REACHABLE:
18 return UNREACHABLE
19 elif self is UNREACHABLE:
20 return REACHABLE
21 else:
22 return UNSURE
23
24 def __and__(self, other):
25 if UNSURE in (self, other):
26 return UNSURE
27 else:
28 return REACHABLE if self._value and other._value else UNREACHABLE
29
30 def __repr__(self):
31 return '<%s: %s>' % (type(self).__name__, self._name)
32
33
34 REACHABLE = Status(True, 'reachable')
35 UNREACHABLE = Status(False, 'unreachable')
36 UNSURE = Status(None, 'unsure')
37
38
39 def _get_flow_scopes(node):
40 while True:
41 node = get_parent_scope(node, include_flows=True)
42 if node is None or is_scope(node):
43 return
44 yield node
45
46
47 def reachability_check(context, value_scope, node, origin_scope=None):
48 if is_big_annoying_library(context) \
49 or not context.inference_state.flow_analysis_enabled:
50 return UNSURE
51
52 first_flow_scope = get_parent_scope(node, include_flows=True)
53 if origin_scope is not None:
54 origin_flow_scopes = list(_get_flow_scopes(origin_scope))
55 node_flow_scopes = list(_get_flow_scopes(node))
56
57 branch_matches = True
58 for flow_scope in origin_flow_scopes:
59 if flow_scope in node_flow_scopes:
60 node_keyword = get_flow_branch_keyword(flow_scope, node)
61 origin_keyword = get_flow_branch_keyword(flow_scope, origin_scope)
62 branch_matches = node_keyword == origin_keyword
63 if flow_scope.type == 'if_stmt':
64 if not branch_matches:
65 return UNREACHABLE
66 elif flow_scope.type == 'try_stmt':
67 if not branch_matches and origin_keyword == 'else' \
68 and node_keyword == 'except':
69 return UNREACHABLE
70 if branch_matches:
71 break
72
73 # Direct parents get resolved, we filter scopes that are separate
74 # branches. This makes sense for autocompletion and static analysis.
75 # For actual Python it doesn't matter, because we're talking about
76 # potentially unreachable code.
77 # e.g. `if 0:` would cause all name lookup within the flow make
78 # unaccessible. This is not a "problem" in Python, because the code is
79 # never called. In Jedi though, we still want to infer types.
80 while origin_scope is not None:
81 if first_flow_scope == origin_scope and branch_matches:
82 return REACHABLE
83 origin_scope = origin_scope.parent
84
85 return _break_check(context, value_scope, first_flow_scope, node)
86
87
88 def _break_check(context, value_scope, flow_scope, node):
89 reachable = REACHABLE
90 if flow_scope.type == 'if_stmt':
91 if flow_scope.is_node_after_else(node):
92 for check_node in flow_scope.get_test_nodes():
93 reachable = _check_if(context, check_node)
94 if reachable in (REACHABLE, UNSURE):
95 break
96 reachable = reachable.invert()
97 else:
98 flow_node = flow_scope.get_corresponding_test_node(node)
99 if flow_node is not None:
100 reachable = _check_if(context, flow_node)
101 elif flow_scope.type in ('try_stmt', 'while_stmt'):
102 return UNSURE
103
104 # Only reachable branches need to be examined further.
105 if reachable in (UNREACHABLE, UNSURE):
106 return reachable
107
108 if value_scope != flow_scope and value_scope != flow_scope.parent:
109 flow_scope = get_parent_scope(flow_scope, include_flows=True)
110 return reachable & _break_check(context, value_scope, flow_scope, node)
111 else:
112 return reachable
113
114
115 def _check_if(context, node):
116 with execution_allowed(context.inference_state, node) as allowed:
117 if not allowed:
118 return UNSURE
119
120 types = context.infer_node(node)
121 values = set(x.py__bool__() for x in types)
122 if len(values) == 1:
123 return Status.lookup_table[values.pop()]
124 else:
125 return UNSURE