##// END OF EJS Templates
Polish documentation, hide private functions
krassowski -
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 ``<tab>`` to expand it to its latex form.
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 ``Completer.backslash_combining_completions`` option to ``False``.
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 previously available ``IPCompleter.greedy``
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="""Code evaluation under completion.
987 help="""Policy for code evaluation under completion.
987 988
988 Successive options allow to enable more eager evaluation for more accurate completion suggestions,
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_=self.global_namespace,
1161 locals_=self.namespace,
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_=self.global_namespace,
2507 locals_=self.namespace,
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 globals_: dict
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(ValueError):
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_": locals_}})
284 context = EvaluationContext(**{**context._asdict(), **{"locals": locals_}})
260 285
261 286 if context.evaluation == "dangerous":
262 return eval(code, context.globals_, context.locals_)
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,10 +305,12 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
312 - control flow:
313
289 314 - conditionals (``if x:``) except for ternary IfExp (``a if x else b``)
290 315 - loops (``for`` and `while``)
291 316 - exception handling
@@ -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_[node.id]
381 if policy.allow_globals_access and node.id in context.globals_:
382 return context.globals_[node.id]
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 IPCompleter
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 IPCompleter.greedy = True
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_greedy=False
84 In [4]: feeling_quiet=False
157 85
158 In [5]: %config IPCompleter.greedy = feeling_greedy
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_=kwargs, globals_={}, evaluation="limited")
13 return EvaluationContext(locals=kwargs, globals={}, evaluation="limited")
14 14
15 15
16 16 def unsafe(**kwargs):
17 return EvaluationContext(locals_=kwargs, globals_={}, evaluation="unsafe")
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_={}, globals_={}, evaluation="limited", in_subscript=True
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