Show More
@@ -50,7 +50,7 b' Backward latex completion' | |||
|
50 | 50 | |
|
51 | 51 | It is sometime challenging to know how to type a character, if you are using |
|
52 | 52 | IPython, or any compatible frontend you can prepend backslash to the character |
|
53 |
and press |
|
|
53 | and press :kbd:`Tab` to expand it to its latex form. | |
|
54 | 54 | |
|
55 | 55 | .. code:: |
|
56 | 56 | |
@@ -59,7 +59,7 b' and press ``<tab>`` to expand it to its latex form.' | |||
|
59 | 59 | |
|
60 | 60 | |
|
61 | 61 | Both forward and backward completions can be deactivated by setting the |
|
62 |
|
|
|
62 | :any:`Completer.backslash_combining_completions` option to ``False``. | |
|
63 | 63 | |
|
64 | 64 | |
|
65 | 65 | Experimental |
@@ -95,7 +95,7 b' having to execute any code:' | |||
|
95 | 95 | ... myvar[1].bi<tab> |
|
96 | 96 | |
|
97 | 97 | Tab completion will be able to infer that ``myvar[1]`` is a real number without |
|
98 |
executing any code unlike the |
|
|
98 | executing almost any code unlike the deprecated :any:`IPCompleter.greedy` | |
|
99 | 99 | option. |
|
100 | 100 | |
|
101 | 101 | Be sure to update :any:`jedi` to the latest stable version or to try the |
@@ -972,29 +972,38 b' class Completer(Configurable):' | |||
|
972 | 972 | help="""Activate greedy completion. |
|
973 | 973 | |
|
974 | 974 | .. deprecated:: 8.8 |
|
975 | Use :any:`evaluation` and :any:`auto_close_dict_keys` instead. | |
|
975 | Use :any:`Completer.evaluation` and :any:`Completer.auto_close_dict_keys` instead. | |
|
976 | 976 | |
|
977 | When enabled in IPython 8.8+ activates following settings for compatibility: | |
|
978 | - ``evaluation = 'unsafe'`` | |
|
979 | - ``auto_close_dict_keys = True`` | |
|
977 | When enabled in IPython 8.8 or newer, changes configuration as follows: | |
|
978 | ||
|
979 | - ``Completer.evaluation = 'unsafe'`` | |
|
980 | - ``Completer.auto_close_dict_keys = True`` | |
|
980 | 981 | """, |
|
981 | 982 | ).tag(config=True) |
|
982 | 983 | |
|
983 | 984 | evaluation = Enum( |
|
984 | 985 | ("forbidden", "minimal", "limited", "unsafe", "dangerous"), |
|
985 | 986 | default_value="limited", |
|
986 |
help=""" |
|
|
987 | help="""Policy for code evaluation under completion. | |
|
987 | 988 | |
|
988 |
Successive options allow to enable more eager evaluation for |
|
|
989 | including for nested dictionaries, nested lists, or even results of function calls. Setting `unsafe` | |
|
990 | or higher can lead to evaluation of arbitrary user code on TAB with potentially dangerous side effects. | |
|
989 | Successive options allow to enable more eager evaluation for better | |
|
990 | completion suggestions, including for nested dictionaries, nested lists, | |
|
991 | or even results of function calls. | |
|
992 | Setting ``unsafe`` or higher can lead to evaluation of arbitrary user | |
|
993 | code on :kbd:`Tab` with potentially unwanted or dangerous side effects. | |
|
991 | 994 | |
|
992 | 995 | Allowed values are: |
|
993 | - `forbidden`: no evaluation at all | |
|
994 | - `minimal`: evaluation of literals and access to built-in namespaces; no item/attribute evaluation nor access to locals/globals | |
|
995 | - `limited` (default): access to all namespaces, evaluation of hard-coded methods (``keys()``, ``__getattr__``, ``__getitems__``, etc) on allow-listed objects (e.g. ``dict``, ``list``, ``tuple``, ``pandas.Series``) | |
|
996 | - `unsafe`: evaluation of all methods and function calls but not of syntax with side-effects like `del x`, | |
|
997 | - `dangerous`: completely arbitrary evaluation | |
|
996 | ||
|
997 | - ``forbidden``: no evaluation of code is permitted, | |
|
998 | - ``minimal``: evaluation of literals and access to built-in namespace; | |
|
999 | no item/attribute evaluation nor access to locals/globals, | |
|
1000 | - ``limited``: access to all namespaces, evaluation of hard-coded methods | |
|
1001 | (for example: :any:`dict.keys`, :any:`object.__getattr__`, | |
|
1002 | :any:`object.__getitem__`) on allow-listed objects (for example: | |
|
1003 | :any:`dict`, :any:`list`, :any:`tuple`, ``pandas.Series``), | |
|
1004 | - ``unsafe``: evaluation of all methods and function calls but not of | |
|
1005 | syntax with side-effects like `del x`, | |
|
1006 | - ``dangerous``: completely arbitrary evaluation. | |
|
998 | 1007 | """, |
|
999 | 1008 | ).tag(config=True) |
|
1000 | 1009 | |
@@ -1019,7 +1028,15 b' class Completer(Configurable):' | |||
|
1019 | 1028 | "unicode characters back to latex commands.").tag(config=True) |
|
1020 | 1029 | |
|
1021 | 1030 | auto_close_dict_keys = Bool( |
|
1022 | False, help="""Enable auto-closing dictionary keys.""" | |
|
1031 | False, | |
|
1032 | help=""" | |
|
1033 | Enable auto-closing dictionary keys. | |
|
1034 | ||
|
1035 | When enabled string keys will be suffixed with a final quote | |
|
1036 | (matching the opening quote), tuple keys will also receive a | |
|
1037 | separating comma if needed, and keys which are final will | |
|
1038 | receive a closing bracket (``]``). | |
|
1039 | """, | |
|
1023 | 1040 | ).tag(config=True) |
|
1024 | 1041 | |
|
1025 | 1042 | def __init__(self, namespace=None, global_namespace=None, **kwargs): |
@@ -1157,8 +1174,8 b' class Completer(Configurable):' | |||
|
1157 | 1174 | obj = guarded_eval( |
|
1158 | 1175 | expr, |
|
1159 | 1176 | EvaluationContext( |
|
1160 |
globals |
|
|
1161 |
locals |
|
|
1177 | globals=self.global_namespace, | |
|
1178 | locals=self.namespace, | |
|
1162 | 1179 | evaluation=self.evaluation, |
|
1163 | 1180 | ), |
|
1164 | 1181 | ) |
@@ -1183,7 +1200,7 b' def get__all__entries(obj):' | |||
|
1183 | 1200 | return [w for w in words if isinstance(w, str)] |
|
1184 | 1201 | |
|
1185 | 1202 | |
|
1186 | class DictKeyState(enum.Flag): | |
|
1203 | class _DictKeyState(enum.Flag): | |
|
1187 | 1204 | """Represent state of the key match in context of other possible matches. |
|
1188 | 1205 | |
|
1189 | 1206 | - given `d1 = {'a': 1}` completion on `d1['<tab>` will yield `{'a': END_OF_ITEM}` as there is no tuple. |
@@ -1199,6 +1216,7 b' class DictKeyState(enum.Flag):' | |||
|
1199 | 1216 | |
|
1200 | 1217 | |
|
1201 | 1218 | def _parse_tokens(c): |
|
1219 | """Parse tokens even if there is an error.""" | |
|
1202 | 1220 | tokens = [] |
|
1203 | 1221 | token_generator = tokenize.generate_tokens(iter(c.splitlines()).__next__) |
|
1204 | 1222 | while True: |
@@ -1257,7 +1275,7 b' def match_dict_keys(' | |||
|
1257 | 1275 | prefix: str, |
|
1258 | 1276 | delims: str, |
|
1259 | 1277 | extra_prefix: Optional[Tuple[Union[str, bytes], ...]] = None, |
|
1260 | ) -> Tuple[str, int, Dict[str, DictKeyState]]: | |
|
1278 | ) -> Tuple[str, int, Dict[str, _DictKeyState]]: | |
|
1261 | 1279 | """Used by dict_key_matches, matching the prefix to a list of keys |
|
1262 | 1280 | |
|
1263 | 1281 | Parameters |
@@ -1307,8 +1325,8 b' def match_dict_keys(' | |||
|
1307 | 1325 | return True |
|
1308 | 1326 | |
|
1309 | 1327 | filtered_key_is_final: Dict[ |
|
1310 | Union[str, bytes, int, float], DictKeyState | |
|
1311 | ] = defaultdict(lambda: DictKeyState.BASELINE) | |
|
1328 | Union[str, bytes, int, float], _DictKeyState | |
|
1329 | ] = defaultdict(lambda: _DictKeyState.BASELINE) | |
|
1312 | 1330 | |
|
1313 | 1331 | for k in keys: |
|
1314 | 1332 | # If at least one of the matches is not final, mark as undetermined. |
@@ -1319,9 +1337,9 b' def match_dict_keys(' | |||
|
1319 | 1337 | if filter_prefix_tuple(k): |
|
1320 | 1338 | key_fragment = k[prefix_tuple_size] |
|
1321 | 1339 | filtered_key_is_final[key_fragment] |= ( |
|
1322 | DictKeyState.END_OF_TUPLE | |
|
1340 | _DictKeyState.END_OF_TUPLE | |
|
1323 | 1341 | if len(k) == prefix_tuple_size + 1 |
|
1324 | else DictKeyState.IN_TUPLE | |
|
1342 | else _DictKeyState.IN_TUPLE | |
|
1325 | 1343 | ) |
|
1326 | 1344 | elif prefix_tuple_size > 0: |
|
1327 | 1345 | # we are completing a tuple but this key is not a tuple, |
@@ -1329,7 +1347,7 b' def match_dict_keys(' | |||
|
1329 | 1347 | pass |
|
1330 | 1348 | else: |
|
1331 | 1349 | if isinstance(k, text_serializable_types): |
|
1332 | filtered_key_is_final[k] |= DictKeyState.END_OF_ITEM | |
|
1350 | filtered_key_is_final[k] |= _DictKeyState.END_OF_ITEM | |
|
1333 | 1351 | |
|
1334 | 1352 | filtered_keys = filtered_key_is_final.keys() |
|
1335 | 1353 | |
@@ -1367,7 +1385,7 b' def match_dict_keys(' | |||
|
1367 | 1385 | token_start = token_match.start() |
|
1368 | 1386 | token_prefix = token_match.group() |
|
1369 | 1387 | |
|
1370 | matched: Dict[str, DictKeyState] = {} | |
|
1388 | matched: Dict[str, _DictKeyState] = {} | |
|
1371 | 1389 | |
|
1372 | 1390 | str_key: Union[str, bytes] |
|
1373 | 1391 | |
@@ -2503,8 +2521,8 b' class IPCompleter(Completer):' | |||
|
2503 | 2521 | tuple_prefix = guarded_eval( |
|
2504 | 2522 | prior_tuple_keys, |
|
2505 | 2523 | EvaluationContext( |
|
2506 |
globals |
|
|
2507 |
locals |
|
|
2524 | globals=self.global_namespace, | |
|
2525 | locals=self.namespace, | |
|
2508 | 2526 | evaluation=self.evaluation, |
|
2509 | 2527 | in_subscript=True, |
|
2510 | 2528 | ), |
@@ -2569,7 +2587,7 b' class IPCompleter(Completer):' | |||
|
2569 | 2587 | |
|
2570 | 2588 | results = [] |
|
2571 | 2589 | |
|
2572 | end_of_tuple_or_item = DictKeyState.END_OF_TUPLE | DictKeyState.END_OF_ITEM | |
|
2590 | end_of_tuple_or_item = _DictKeyState.END_OF_TUPLE | _DictKeyState.END_OF_ITEM | |
|
2573 | 2591 | |
|
2574 | 2592 | for k, state_flag in matches.items(): |
|
2575 | 2593 | result = leading + k |
@@ -2584,7 +2602,7 b' class IPCompleter(Completer):' | |||
|
2584 | 2602 | |
|
2585 | 2603 | if state_flag in end_of_tuple_or_item and can_close_bracket: |
|
2586 | 2604 | result += "]" |
|
2587 | if state_flag == DictKeyState.IN_TUPLE and can_close_tuple_item: | |
|
2605 | if state_flag == _DictKeyState.IN_TUPLE and can_close_tuple_item: | |
|
2588 | 2606 | result += ", " |
|
2589 | 2607 | results.append(result) |
|
2590 | 2608 | return results |
@@ -17,6 +17,7 b' from functools import cached_property' | |||
|
17 | 17 | from dataclasses import dataclass, field |
|
18 | 18 | |
|
19 | 19 | from IPython.utils.docs import GENERATING_DOCUMENTATION |
|
20 | from IPython.utils.decorators import undoc | |
|
20 | 21 | |
|
21 | 22 | |
|
22 | 23 | if TYPE_CHECKING or GENERATING_DOCUMENTATION: |
@@ -26,21 +27,25 b' else:' | |||
|
26 | 27 | Protocol = object # requires Python >=3.8 |
|
27 | 28 | |
|
28 | 29 | |
|
30 | @undoc | |
|
29 | 31 | class HasGetItem(Protocol): |
|
30 | 32 | def __getitem__(self, key) -> None: |
|
31 | 33 | ... |
|
32 | 34 | |
|
33 | 35 | |
|
36 | @undoc | |
|
34 | 37 | class InstancesHaveGetItem(Protocol): |
|
35 | 38 | def __call__(self, *args, **kwargs) -> HasGetItem: |
|
36 | 39 | ... |
|
37 | 40 | |
|
38 | 41 | |
|
42 | @undoc | |
|
39 | 43 | class HasGetAttr(Protocol): |
|
40 | 44 | def __getattr__(self, key) -> None: |
|
41 | 45 | ... |
|
42 | 46 | |
|
43 | 47 | |
|
48 | @undoc | |
|
44 | 49 | class DoesNotHaveGetAttr(Protocol): |
|
45 | 50 | pass |
|
46 | 51 | |
@@ -49,7 +54,7 b' class DoesNotHaveGetAttr(Protocol):' | |||
|
49 | 54 | MayHaveGetattr = Union[HasGetAttr, DoesNotHaveGetAttr] |
|
50 | 55 | |
|
51 | 56 | |
|
52 | def unbind_method(func: Callable) -> Union[Callable, None]: | |
|
57 | def _unbind_method(func: Callable) -> Union[Callable, None]: | |
|
53 | 58 | """Get unbound method for given bound method. |
|
54 | 59 | |
|
55 | 60 | Returns None if cannot get unbound method.""" |
@@ -69,8 +74,11 b' def unbind_method(func: Callable) -> Union[Callable, None]:' | |||
|
69 | 74 | return None |
|
70 | 75 | |
|
71 | 76 | |
|
77 | @undoc | |
|
72 | 78 | @dataclass |
|
73 | 79 | class EvaluationPolicy: |
|
80 | """Definition of evaluation policy.""" | |
|
81 | ||
|
74 | 82 | allow_locals_access: bool = False |
|
75 | 83 | allow_globals_access: bool = False |
|
76 | 84 | allow_item_access: bool = False |
@@ -92,12 +100,12 b' class EvaluationPolicy:' | |||
|
92 | 100 | if func in self.allowed_calls: |
|
93 | 101 | return True |
|
94 | 102 | |
|
95 | owner_method = unbind_method(func) | |
|
103 | owner_method = _unbind_method(func) | |
|
96 | 104 | if owner_method and owner_method in self.allowed_calls: |
|
97 | 105 | return True |
|
98 | 106 | |
|
99 | 107 | |
|
100 | def has_original_dunder_external( | |
|
108 | def _has_original_dunder_external( | |
|
101 | 109 | value, |
|
102 | 110 | module_name, |
|
103 | 111 | access_path, |
@@ -121,7 +129,7 b' def has_original_dunder_external(' | |||
|
121 | 129 | return False |
|
122 | 130 | |
|
123 | 131 | |
|
124 | def has_original_dunder( | |
|
132 | def _has_original_dunder( | |
|
125 | 133 | value, allowed_types, allowed_methods, allowed_external, method_name |
|
126 | 134 | ): |
|
127 | 135 | # note: Python ignores `__getattr__`/`__getitem__` on instances, |
@@ -141,12 +149,13 b' def has_original_dunder(' | |||
|
141 | 149 | return True |
|
142 | 150 | |
|
143 | 151 | for module_name, *access_path in allowed_external: |
|
144 | if has_original_dunder_external(value, module_name, access_path, method_name): | |
|
152 | if _has_original_dunder_external(value, module_name, access_path, method_name): | |
|
145 | 153 | return True |
|
146 | 154 | |
|
147 | 155 | return False |
|
148 | 156 | |
|
149 | 157 | |
|
158 | @undoc | |
|
150 | 159 | @dataclass |
|
151 | 160 | class SelectivePolicy(EvaluationPolicy): |
|
152 | 161 | allowed_getitem: Set[InstancesHaveGetItem] = field(default_factory=set) |
@@ -155,14 +164,14 b' class SelectivePolicy(EvaluationPolicy):' | |||
|
155 | 164 | allowed_getattr_external: Set[Tuple[str, ...]] = field(default_factory=set) |
|
156 | 165 | |
|
157 | 166 | def can_get_attr(self, value, attr): |
|
158 | has_original_attribute = has_original_dunder( | |
|
167 | has_original_attribute = _has_original_dunder( | |
|
159 | 168 | value, |
|
160 | 169 | allowed_types=self.allowed_getattr, |
|
161 | 170 | allowed_methods=self._getattribute_methods, |
|
162 | 171 | allowed_external=self.allowed_getattr_external, |
|
163 | 172 | method_name="__getattribute__", |
|
164 | 173 | ) |
|
165 | has_original_attr = has_original_dunder( | |
|
174 | has_original_attr = _has_original_dunder( | |
|
166 | 175 | value, |
|
167 | 176 | allowed_types=self.allowed_getattr, |
|
168 | 177 | allowed_methods=self._getattr_methods, |
@@ -182,7 +191,7 b' class SelectivePolicy(EvaluationPolicy):' | |||
|
182 | 191 | |
|
183 | 192 | def can_get_item(self, value, item): |
|
184 | 193 | """Allow accessing `__getiitem__` of allow-listed instances unless it was not modified.""" |
|
185 | return has_original_dunder( | |
|
194 | return _has_original_dunder( | |
|
186 | 195 | value, |
|
187 | 196 | allowed_types=self.allowed_getitem, |
|
188 | 197 | allowed_methods=self._getitem_methods, |
@@ -211,34 +220,50 b' class SelectivePolicy(EvaluationPolicy):' | |||
|
211 | 220 | } |
|
212 | 221 | |
|
213 | 222 | |
|
214 | class DummyNamedTuple(NamedTuple): | |
|
223 | class _DummyNamedTuple(NamedTuple): | |
|
215 | 224 | pass |
|
216 | 225 | |
|
217 | 226 | |
|
218 | 227 | class EvaluationContext(NamedTuple): |
|
219 | locals_: dict | |
|
220 |
|
|
|
228 | #: Local namespace | |
|
229 | locals: dict | |
|
230 | #: Global namespace | |
|
231 | globals: dict | |
|
232 | #: Evaluation policy identifier | |
|
221 | 233 | evaluation: Literal[ |
|
222 | 234 | "forbidden", "minimal", "limited", "unsafe", "dangerous" |
|
223 | 235 | ] = "forbidden" |
|
236 | #: Whether the evalution of code takes place inside of a subscript. | |
|
237 | #: Useful for evaluating ``:-1, 'col'`` in ``df[:-1, 'col']``. | |
|
224 | 238 | in_subscript: bool = False |
|
225 | 239 | |
|
226 | 240 | |
|
227 | class IdentitySubscript: | |
|
241 | class _IdentitySubscript: | |
|
242 | """Returns the key itself when item is requested via subscript.""" | |
|
243 | ||
|
228 | 244 | def __getitem__(self, key): |
|
229 | 245 | return key |
|
230 | 246 | |
|
231 | 247 | |
|
232 | IDENTITY_SUBSCRIPT = IdentitySubscript() | |
|
248 | IDENTITY_SUBSCRIPT = _IdentitySubscript() | |
|
233 | 249 | SUBSCRIPT_MARKER = "__SUBSCRIPT_SENTINEL__" |
|
234 | 250 | |
|
235 | 251 | |
|
236 |
class GuardRejection( |
|
|
252 | class GuardRejection(Exception): | |
|
253 | """Exception raised when guard rejects evaluation attempt.""" | |
|
254 | ||
|
237 | 255 | pass |
|
238 | 256 | |
|
239 | 257 | |
|
240 | 258 | def guarded_eval(code: str, context: EvaluationContext): |
|
241 | locals_ = context.locals_ | |
|
259 | """Evaluate provided code in the evaluation context. | |
|
260 | ||
|
261 | If evaluation policy given by context is set to ``forbidden`` | |
|
262 | no evaluation will be performed; if it is set to ``dangerous`` | |
|
263 | standard :func:`eval` will be used; finally, for any other, | |
|
264 | policy :func:`eval_node` will be called on parsed AST. | |
|
265 | """ | |
|
266 | locals_ = context.locals | |
|
242 | 267 | |
|
243 | 268 | if context.evaluation == "forbidden": |
|
244 | 269 | raise GuardRejection("Forbidden mode") |
@@ -256,10 +281,10 b' def guarded_eval(code: str, context: EvaluationContext):' | |||
|
256 | 281 | locals_ = locals_.copy() |
|
257 | 282 | locals_[SUBSCRIPT_MARKER] = IDENTITY_SUBSCRIPT |
|
258 | 283 | code = SUBSCRIPT_MARKER + "[" + code + "]" |
|
259 |
context = EvaluationContext(**{**context._asdict(), **{"locals |
|
|
284 | context = EvaluationContext(**{**context._asdict(), **{"locals": locals_}}) | |
|
260 | 285 | |
|
261 | 286 | if context.evaluation == "dangerous": |
|
262 |
return eval(code, context.globals |
|
|
287 | return eval(code, context.globals, context.locals) | |
|
263 | 288 | |
|
264 | 289 | expression = ast.parse(code, mode="eval") |
|
265 | 290 | |
@@ -267,14 +292,12 b' def guarded_eval(code: str, context: EvaluationContext):' | |||
|
267 | 292 | |
|
268 | 293 | |
|
269 | 294 | def eval_node(node: Union[ast.AST, None], context: EvaluationContext): |
|
270 | """ | |
|
271 | Evaluate AST node in provided context. | |
|
295 | """Evaluate AST node in provided context. | |
|
272 | 296 | |
|
273 | Applies evaluation restrictions defined in the context. | |
|
297 | Applies evaluation restrictions defined in the context. Currently does not support evaluation of functions with keyword arguments. | |
|
274 | 298 | |
|
275 | Currently does not support evaluation of functions with keyword arguments. | |
|
299 | Does not evaluate actions that always have side effects: | |
|
276 | 300 | |
|
277 | Does not evaluate actions which always have side effects: | |
|
278 | 301 | - class definitions (``class sth: ...``) |
|
279 | 302 | - function definitions (``def sth: ...``) |
|
280 | 303 | - variable assignments (``x = 1``) |
@@ -282,13 +305,15 b' def eval_node(node: Union[ast.AST, None], context: EvaluationContext):' | |||
|
282 | 305 | - deletions (``del x``) |
|
283 | 306 | |
|
284 | 307 | Does not evaluate operations which do not return values: |
|
308 | ||
|
285 | 309 | - assertions (``assert x``) |
|
286 | 310 | - pass (``pass``) |
|
287 | 311 | - imports (``import x``) |
|
288 | - control flow | |
|
289 | - conditionals (``if x:``) except for ternary IfExp (``a if x else b``) | |
|
290 | - loops (``for`` and `while``) | |
|
291 | - exception handling | |
|
312 | - control flow: | |
|
313 | ||
|
314 | - conditionals (``if x:``) except for ternary IfExp (``a if x else b``) | |
|
315 | - loops (``for`` and `while``) | |
|
316 | - exception handling | |
|
292 | 317 | |
|
293 | 318 | The purpose of this function is to guard against unwanted side-effects; |
|
294 | 319 | it does not give guarantees on protection from malicious code execution. |
@@ -376,10 +401,10 b' def eval_node(node: Union[ast.AST, None], context: EvaluationContext):' | |||
|
376 | 401 | f" not allowed in {context.evaluation} mode", |
|
377 | 402 | ) |
|
378 | 403 | if isinstance(node, ast.Name): |
|
379 |
if policy.allow_locals_access and node.id in context.locals |
|
|
380 |
return context.locals |
|
|
381 |
if policy.allow_globals_access and node.id in context.globals |
|
|
382 |
return context.globals |
|
|
404 | if policy.allow_locals_access and node.id in context.locals: | |
|
405 | return context.locals[node.id] | |
|
406 | if policy.allow_globals_access and node.id in context.globals: | |
|
407 | return context.globals[node.id] | |
|
383 | 408 | if policy.allow_builtins_access and hasattr(builtins, node.id): |
|
384 | 409 | # note: do not use __builtins__, it is implementation detail of Python |
|
385 | 410 | return getattr(builtins, node.id) |
@@ -439,8 +464,8 b' BUILTIN_GETITEM: Set[InstancesHaveGetItem] = {' | |||
|
439 | 464 | collections.UserDict, |
|
440 | 465 | collections.UserList, |
|
441 | 466 | collections.UserString, |
|
442 | DummyNamedTuple, | |
|
443 | IdentitySubscript, | |
|
467 | _DummyNamedTuple, | |
|
468 | _IdentitySubscript, | |
|
444 | 469 | } |
|
445 | 470 | |
|
446 | 471 | |
@@ -537,3 +562,12 b' EVALUATION_POLICIES = {' | |||
|
537 | 562 | allow_any_calls=True, |
|
538 | 563 | ), |
|
539 | 564 | } |
|
565 | ||
|
566 | ||
|
567 | __all__ = [ | |
|
568 | "guarded_eval", | |
|
569 | "eval_node", | |
|
570 | "GuardRejection", | |
|
571 | "EvaluationContext", | |
|
572 | "_unbind_method", | |
|
573 | ] |
@@ -68,94 +68,22 b' class ConfigMagics(Magics):' | |||
|
68 | 68 | To view what is configurable on a given class, just pass the class |
|
69 | 69 | name:: |
|
70 | 70 | |
|
71 |
In [2]: %config |
|
|
72 | IPCompleter(Completer) options | |
|
73 |
--------------------------- |
|
|
74 | IPCompleter.backslash_combining_completions=<Bool> | |
|
75 | Enable unicode completions, e.g. \\alpha<tab> . Includes completion of latex | |
|
76 | commands, unicode names, and expanding unicode characters back to latex | |
|
77 | commands. | |
|
78 | Current: True | |
|
79 | IPCompleter.debug=<Bool> | |
|
80 | Enable debug for the Completer. Mostly print extra information for | |
|
81 | experimental jedi integration. | |
|
71 | In [2]: %config LoggingMagics | |
|
72 | LoggingMagics(Magics) options | |
|
73 | --------------------------- | |
|
74 | LoggingMagics.quiet=<Bool> | |
|
75 | Suppress output of log state when logging is enabled | |
|
82 | 76 | Current: False |
|
83 | IPCompleter.disable_matchers=<list-item-1>... | |
|
84 | List of matchers to disable. | |
|
85 | The list should contain matcher identifiers (see | |
|
86 | :any:`completion_matcher`). | |
|
87 | Current: [] | |
|
88 | IPCompleter.greedy=<Bool> | |
|
89 | Activate greedy completion | |
|
90 | PENDING DEPRECATION. this is now mostly taken care of with Jedi. | |
|
91 | This will enable completion on elements of lists, results of function calls, etc., | |
|
92 | but can be unsafe because the code is actually evaluated on TAB. | |
|
93 | Current: False | |
|
94 | IPCompleter.jedi_compute_type_timeout=<Int> | |
|
95 | Experimental: restrict time (in milliseconds) during which Jedi can compute types. | |
|
96 | Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt | |
|
97 | performance by preventing jedi to build its cache. | |
|
98 | Current: 400 | |
|
99 | IPCompleter.limit_to__all__=<Bool> | |
|
100 | DEPRECATED as of version 5.0. | |
|
101 | Instruct the completer to use __all__ for the completion | |
|
102 | Specifically, when completing on ``object.<tab>``. | |
|
103 | When True: only those names in obj.__all__ will be included. | |
|
104 | When False [default]: the __all__ attribute is ignored | |
|
105 | Current: False | |
|
106 | IPCompleter.merge_completions=<Bool> | |
|
107 | Whether to merge completion results into a single list | |
|
108 | If False, only the completion results from the first non-empty | |
|
109 | completer will be returned. | |
|
110 | As of version 8.6.0, setting the value to ``False`` is an alias for: | |
|
111 | ``IPCompleter.suppress_competing_matchers = True.``. | |
|
112 | Current: True | |
|
113 | IPCompleter.omit__names=<Enum> | |
|
114 | Instruct the completer to omit private method names | |
|
115 | Specifically, when completing on ``object.<tab>``. | |
|
116 | When 2 [default]: all names that start with '_' will be excluded. | |
|
117 | When 1: all 'magic' names (``__foo__``) will be excluded. | |
|
118 | When 0: nothing will be excluded. | |
|
119 | Choices: any of [0, 1, 2] | |
|
120 | Current: 2 | |
|
121 | IPCompleter.profile_completions=<Bool> | |
|
122 | If True, emit profiling data for completion subsystem using cProfile. | |
|
123 | Current: False | |
|
124 | IPCompleter.profiler_output_dir=<Unicode> | |
|
125 | Template for path at which to output profile data for completions. | |
|
126 | Current: '.completion_profiles' | |
|
127 | IPCompleter.suppress_competing_matchers=<Union> | |
|
128 | Whether to suppress completions from other *Matchers*. | |
|
129 | When set to ``None`` (default) the matchers will attempt to auto-detect | |
|
130 | whether suppression of other matchers is desirable. For example, at the | |
|
131 | beginning of a line followed by `%` we expect a magic completion to be the | |
|
132 | only applicable option, and after ``my_dict['`` we usually expect a | |
|
133 | completion with an existing dictionary key. | |
|
134 | If you want to disable this heuristic and see completions from all matchers, | |
|
135 | set ``IPCompleter.suppress_competing_matchers = False``. To disable the | |
|
136 | heuristic for specific matchers provide a dictionary mapping: | |
|
137 | ``IPCompleter.suppress_competing_matchers = {'IPCompleter.dict_key_matcher': | |
|
138 | False}``. | |
|
139 | Set ``IPCompleter.suppress_competing_matchers = True`` to limit completions | |
|
140 | to the set of matchers with the highest priority; this is equivalent to | |
|
141 | ``IPCompleter.merge_completions`` and can be beneficial for performance, but | |
|
142 | will sometimes omit relevant candidates from matchers further down the | |
|
143 | priority list. | |
|
144 | Current: None | |
|
145 | IPCompleter.use_jedi=<Bool> | |
|
146 | Experimental: Use Jedi to generate autocompletions. Default to True if jedi | |
|
147 | is installed. | |
|
148 | Current: True | |
|
149 | 77 | |
|
150 | 78 | but the real use is in setting values:: |
|
151 | 79 | |
|
152 |
In [3]: %config |
|
|
80 | In [3]: %config LoggingMagics.quiet = True | |
|
153 | 81 | |
|
154 | 82 | and these values are read from the user_ns if they are variables:: |
|
155 | 83 | |
|
156 |
In [4]: feeling_ |
|
|
84 | In [4]: feeling_quiet=False | |
|
157 | 85 | |
|
158 |
In [5]: %config |
|
|
86 | In [5]: %config LoggingMagics.quiet = feeling_quiet | |
|
159 | 87 | |
|
160 | 88 | """ |
|
161 | 89 | from traitlets.config.loader import Config |
@@ -3,18 +3,18 b' from IPython.core.guarded_eval import (' | |||
|
3 | 3 | EvaluationContext, |
|
4 | 4 | GuardRejection, |
|
5 | 5 | guarded_eval, |
|
6 | unbind_method, | |
|
6 | _unbind_method, | |
|
7 | 7 | ) |
|
8 | 8 | from IPython.testing import decorators as dec |
|
9 | 9 | import pytest |
|
10 | 10 | |
|
11 | 11 | |
|
12 | 12 | def limited(**kwargs): |
|
13 |
return EvaluationContext(locals |
|
|
13 | return EvaluationContext(locals=kwargs, globals={}, evaluation="limited") | |
|
14 | 14 | |
|
15 | 15 | |
|
16 | 16 | def unsafe(**kwargs): |
|
17 |
return EvaluationContext(locals |
|
|
17 | return EvaluationContext(locals=kwargs, globals={}, evaluation="unsafe") | |
|
18 | 18 | |
|
19 | 19 | |
|
20 | 20 | @dec.skip_without("pandas") |
@@ -206,7 +206,7 b' def test_access_builtins():' | |||
|
206 | 206 | |
|
207 | 207 | def test_subscript(): |
|
208 | 208 | context = EvaluationContext( |
|
209 |
locals |
|
|
209 | locals={}, globals={}, evaluation="limited", in_subscript=True | |
|
210 | 210 | ) |
|
211 | 211 | empty_slice = slice(None, None, None) |
|
212 | 212 | assert guarded_eval("", context) == tuple() |
@@ -221,8 +221,8 b' def test_unbind_method():' | |||
|
221 | 221 | return "CUSTOM" |
|
222 | 222 | |
|
223 | 223 | x = X() |
|
224 | assert unbind_method(x.index) is X.index | |
|
225 | assert unbind_method([].index) is list.index | |
|
224 | assert _unbind_method(x.index) is X.index | |
|
225 | assert _unbind_method([].index) is list.index | |
|
226 | 226 | |
|
227 | 227 | |
|
228 | 228 | def test_assumption_instance_attr_do_not_matter(): |
General Comments 0
You need to be logged in to leave comments.
Login now