From 738cb9951b611897222ee7610dd05bced6765e1c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 16 Dec 2015 15:21:20 +0100 Subject: [PATCH 1/6] Heuristic for better error messages --- IPython/core/ultratb.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index e8e1d2ec297..b083e1871f7 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -87,6 +87,7 @@ import inspect import keyword import linecache +import difflib import os import pydoc import re @@ -1028,7 +1029,33 @@ def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_con if records is None: return "" + + ### + # record heuristics + reg = re.compile("([a-zA-Z_]+)\(\) got an unexpected keyword argument '(.+)'") + # figure out what to do on len(args) > 1 + match = reg.match(evalue.args[0]) + if (etype == 'TypeError') and match: + last_record = records[-1] + function, kw = match.groups() + func = last_record[0].f_locals.get(function, None) + if not func: + func = last_record[0].f_globals.get(function, None) + signature = inspect.signature(func) + matches = difflib.get_close_matches(kw, signature.parameters.keys(), 3, 0.3) + if matches: + evalue.args = (evalue.args[0]+'. Did you meant one of %s ? ' % ', '.join(map(lambda x : "'"+x+"'",matches)), ) + else: + import pdb; pdb.set_trace() + else: + import pdb; pdb.set_trace() + + + + + + ### frames = self.format_records(records) formatted_exception = self.format_exception(etype, evalue) From 2db99cf1937fb42d01fc45cbf07a5e71f56b6c04 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 16 Dec 2015 23:26:54 +0100 Subject: [PATCH 2/6] Swallow exceptions when generating hints. --- IPython/core/ultratb.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index b083e1871f7..31f73668468 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -1036,20 +1036,18 @@ def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_con # figure out what to do on len(args) > 1 match = reg.match(evalue.args[0]) if (etype == 'TypeError') and match: - last_record = records[-1] - function, kw = match.groups() - func = last_record[0].f_locals.get(function, None) - if not func: - func = last_record[0].f_globals.get(function, None) - signature = inspect.signature(func) - matches = difflib.get_close_matches(kw, signature.parameters.keys(), 3, 0.3) - if matches: - evalue.args = (evalue.args[0]+'. Did you meant one of %s ? ' % ', '.join(map(lambda x : "'"+x+"'",matches)), ) - else: - import pdb; pdb.set_trace() - else: - import pdb; pdb.set_trace() - + try: + last_record = records[-1] + function, kw = match.groups() + func = last_record[0].f_locals.get(function, None) + if not func: + func = last_record[0].f_globals.get(function, None) + signature = inspect.signature(func) + matches = difflib.get_close_matches(kw, signature.parameters.keys(), 3, 0.3) + if matches: + evalue.args = (evalue.args[0]+'. Did you meant one of %s ? ' % ', '.join(map(lambda x : "'"+x+"'",matches)), ) + except Exception: + pass From 3bb664ba43aa2c3da83ba158fed2d1f2c197c95b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 16 Dec 2015 23:31:32 +0100 Subject: [PATCH 3/6] Swallow exceptions when generating hints even more --- IPython/core/ultratb.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 31f73668468..59660b4826f 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -1034,9 +1034,9 @@ def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_con # record heuristics reg = re.compile("([a-zA-Z_]+)\(\) got an unexpected keyword argument '(.+)'") # figure out what to do on len(args) > 1 - match = reg.match(evalue.args[0]) - if (etype == 'TypeError') and match: - try: + try: + match = reg.match(evalue.args[0]) + if (etype == 'TypeError') and match: last_record = records[-1] function, kw = match.groups() func = last_record[0].f_locals.get(function, None) @@ -1046,8 +1046,8 @@ def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_con matches = difflib.get_close_matches(kw, signature.parameters.keys(), 3, 0.3) if matches: evalue.args = (evalue.args[0]+'. Did you meant one of %s ? ' % ', '.join(map(lambda x : "'"+x+"'",matches)), ) - except Exception: - pass + except Exception: + pass From a12b818c5615ea4897361fbeb32af29c6cffd255 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 16 Dec 2015 23:35:58 +0100 Subject: [PATCH 4/6] correct pluralisation --- IPython/core/ultratb.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 59660b4826f..6dab8715bca 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -1044,8 +1044,10 @@ def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_con func = last_record[0].f_globals.get(function, None) signature = inspect.signature(func) matches = difflib.get_close_matches(kw, signature.parameters.keys(), 3, 0.3) - if matches: - evalue.args = (evalue.args[0]+'. Did you meant one of %s ? ' % ', '.join(map(lambda x : "'"+x+"'",matches)), ) + if len(matches) == 1: + evalue.args = (evalue.args[0]+". Did you mean '%s' ? " % matches[0]), ) + elif len(matches) > 1: + evalue.args = (evalue.args[0]+'. Did you mean one of %s ? ' % ', '.join(map(lambda x : "'"+x+"'",matches)), ) except Exception: pass From ab48066e26e9fdd23c3d19c24baa75d0ada02e59 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 17 Dec 2015 10:48:13 +0100 Subject: [PATCH 5/6] Oops SyntaxError --- IPython/core/ultratb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 6dab8715bca..7f1d57d9b57 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -1045,7 +1045,7 @@ def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_con signature = inspect.signature(func) matches = difflib.get_close_matches(kw, signature.parameters.keys(), 3, 0.3) if len(matches) == 1: - evalue.args = (evalue.args[0]+". Did you mean '%s' ? " % matches[0]), ) + evalue.args = (evalue.args[0]+". Did you mean '%s' ? " % matches[0], ) elif len(matches) > 1: evalue.args = (evalue.args[0]+'. Did you mean one of %s ? ' % ', '.join(map(lambda x : "'"+x+"'",matches)), ) except Exception: From 702ef8480a14574608fe094de435001489560aed Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 17 Dec 2015 15:45:41 +0100 Subject: [PATCH 6/6] try to hint on getattribute --- IPython/core/ultratb.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 7f1d57d9b57..788e0bd1bff 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -1033,6 +1033,7 @@ def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_con ### # record heuristics reg = re.compile("([a-zA-Z_]+)\(\) got an unexpected keyword argument '(.+)'") + reg2 = re.compile("'([a-zA-Z_]+)' object has no attribute '(.+)'") # figure out what to do on len(args) > 1 try: match = reg.match(evalue.args[0]) @@ -1047,7 +1048,28 @@ def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_con if len(matches) == 1: evalue.args = (evalue.args[0]+". Did you mean '%s' ? " % matches[0], ) elif len(matches) > 1: - evalue.args = (evalue.args[0]+'. Did you mean one of %s ? ' % ', '.join(map(lambda x : "'"+x+"'",matches)), ) + evalue.args = (evalue.args[0]+'. Did you mean one of %s ? ' % ', '.join(map(lambda x : "'"+x+"'", matches)), ) + match = reg2.match(evalue.args[0]) + except Exception: + pass + try: + if (etype == 'AttributeError') and match: + last_record = records[-1] + frame = last_record[0] + names = frame.f_code.co_names + typ, missing = match.groups() + for name in names: + obj = frame.f_locals.get(name, frame.f_globals.get(name, None)) + # likely no the right object, but likely the right type. + if obj and type(obj).__name__ == typ and (name in last_record[4][0]): + matches = difflib.get_close_matches(missing, dir(obj), 3, 0.3) + if len(matches) == 1: + evalue.args = (evalue.args[0]+". Did you mean '%s', which belong to '%s' ? " % (matches[0], name), ) + elif len(matches) > 1: + evalue.args = (evalue.args[0]+". Did you mean one of %s, which belong to '%s' ? " % ( ', '.join(map(lambda x : "'"+x+"'", matches)), name), ) + + + except Exception: pass