To reproduce create a repro.py file with:
class StringMethods:
def a():
pass
class Test:
def __init__(self):
self.str = StringMethods()
def __getattr__(self, name):
raise AttributeError(f"{name} not found")
Then in IPython:
%config Completer.use_jedi = False
from repro import Test
r = Test()
r.str.# <tab>
This will show all methods of str, but none of StringMethods.
This is because:
- the custom
__getattr__ leads the default guarded evaluation policy to reject evaluation of r.str, which raises GuardRejection
- IPython then tries to recover from any
Exception by trimming the r. part away, even though it might be sufficient to trim on SyntaxError and related exceptions:
|
def _evaluate_expr(self, expr): |
|
obj = not_found |
|
done = False |
|
while not done and expr: |
|
try: |
|
obj = guarded_eval( |
|
expr, |
|
EvaluationContext( |
|
globals=self.global_namespace, |
|
locals=self.namespace, |
|
evaluation=self.evaluation, |
|
auto_import=self._auto_import, |
|
policy_overrides=self.policy_overrides, |
|
), |
|
) |
|
done = True |
|
except Exception as e: |
|
if self.debug: |
|
print("Evaluation exception", e) |
|
# trim the expression to remove any invalid prefix |
|
# e.g. user starts `(d[`, so we get `expr = '(d'`, |
|
# where parenthesis is not closed. |
|
# TODO: make this faster by reusing parts of the computation? |
|
expr = self._trim_expr(expr) |
|
return obj |
To reproduce create a
repro.pyfile with:Then in IPython:
This will show all methods of
str, but none ofStringMethods.This is because:
__getattr__leads the default guarded evaluation policy to reject evaluation ofr.str, which raisesGuardRejectionExceptionby trimming ther.part away, even though it might be sufficient to trim onSyntaxErrorand related exceptions:ipython/IPython/core/completer.py
Lines 1300 to 1324 in d47970f