From 607f66c974246e2c1a54326484d2f91a2cc86f82 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sun, 28 Jul 2013 11:43:19 -0500 Subject: [PATCH 1/8] Print the location and the completions for sith.py run --- sith.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/sith.py b/sith.py index a27197f8..ba15a866 100755 --- a/sith.py +++ b/sith.py @@ -95,12 +95,16 @@ class TestCase(object): column = random.randint(0, len(lines[line - 1])) return cls(operation, path, line, column) - def run(self, debugger, record=None): + def run(self, debugger, record=None, print_completions=False): try: with open(self.path) as f: - script = jedi.Script(f.read(), self.line, self.column, - self.path) - getattr(script, self.operation)() + self.file = f.read() + self.script = jedi.Script(self.file, self.line, self.column, + self.path) + self.completions = getattr(self.script, self.operation)() + if print_completions: + self.show_location() + self.show_completions() except jedi.NotFoundError: pass except Exception: @@ -108,7 +112,7 @@ class TestCase(object): if record is not None: with open(record, 'w') as f: json.dump(self.__dict__, f) - self.show() + self.show_errors() if debugger: einfo = sys.exc_info() pdb = __import__(debugger) @@ -118,7 +122,20 @@ class TestCase(object): pdb.post_mortem(einfo[2]) exit(1) - def show(self): + def show_location(self): + # Three lines ought to be enough + show = 3 + lower = self.line - show if self.line - show > 0 else 0 + for i, line in enumerate(self.file.split('\n')[lower:self.line]): + print(lower + i + 1, line) + print(' '*(self.column + len(str(self.line))), '^') + + def show_completions(self): + print("Completions:") + for completion in self.completions: + print(completion.name) + + def show_errors(self): print(self.traceback) print(("Error with running Script(...).{operation}() with\n" "\tpath: {path}\n" @@ -138,13 +155,13 @@ def main(arguments): if arguments['redo'] or arguments['show']: t = TestCase.from_cache(record) if arguments['show']: - t.show() + t.show_errors() else: t.run(debugger) elif arguments['run']: TestCase(arguments[''], arguments[''], int(arguments['']), int(arguments['']) - ).run(debugger) + ).run(debugger, print_completions=True) else: for _ in range(int(arguments['--maxtries'])): t = TestCase.generate(arguments[''] or '.') From 8af28bef2d02a826d274c5c756a9ad39ca690f12 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sun, 28 Jul 2013 14:14:46 -0500 Subject: [PATCH 2/8] Extra line for readability --- sith.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sith.py b/sith.py index ba15a866..2cae57be 100755 --- a/sith.py +++ b/sith.py @@ -132,6 +132,7 @@ class TestCase(object): def show_completions(self): print("Completions:") + print() for completion in self.completions: print(completion.name) From 40dec0c2c69774edb0b93790ab9926925f0573f5 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sun, 28 Jul 2013 14:31:21 -0500 Subject: [PATCH 3/8] Fix a typo in the sith.py usage --- sith.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sith.py b/sith.py index 2cae57be..d150386c 100755 --- a/sith.py +++ b/sith.py @@ -17,7 +17,7 @@ Show recorded exception:: ./sith.py show Usage: - sith.py [--pdb|--ipdb|--pudb] [-d] [-m=] [-f] [--record=] random [] + sith.py [--pdb|--ipdb|--pudb] [-d] [-n=] [-f] [--record=] random [] sith.py [--pdb|--ipdb|--pudb] [-d] [-f] [--record=] redo sith.py [--pdb|--ipdb|--pudb] [-d] [-f] run sith.py show [--record=] From 78f7ff6760b9220c5a98e284a6e36bb94a178e1a Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sun, 28 Jul 2013 14:31:40 -0500 Subject: [PATCH 4/8] Document sith.py run --- sith.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sith.py b/sith.py index d150386c..2cbf4122 100755 --- a/sith.py +++ b/sith.py @@ -16,6 +16,16 @@ Show recorded exception:: ./sith.py show +Run a specific operation + + ./sith.py run operation /path/to/source/file.py line col + +Where operation is one of completions, goto_assignments, goto_definitions, +usages, or call_signatures. + +Note: Line numbers start at 1; columns start at 0 (this is consistent with +many text editors, including Emacs). + Usage: sith.py [--pdb|--ipdb|--pudb] [-d] [-n=] [-f] [--record=] random [] sith.py [--pdb|--ipdb|--pudb] [-d] [-f] [--record=] redo From ae09a2d0a497ce569c48e56db9ce6200ee4b3ccf Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sun, 28 Jul 2013 14:31:47 -0500 Subject: [PATCH 5/8] Define the operations in the class, not in the function I was originally going to try to automatically include these in the docstring using format, but they would have to be defined before the docstring for that to work. But I think it's still useful to have these defined in the class. --- sith.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sith.py b/sith.py index 2cbf4122..eabf5179 100755 --- a/sith.py +++ b/sith.py @@ -87,12 +87,13 @@ class TestCase(object): dct = json.load(f) return cls(**dct) + operations = [ + 'completions', 'goto_assignments', 'goto_definitions', 'usages', + 'call_signatures'] + @classmethod def generate(cls, file_path): - operations = [ - 'completions', 'goto_assignments', 'goto_definitions', 'usages', - 'call_signatures'] - operation = random.choice(operations) + operation = random.choice(cls.operations) path = random.choice(SourceFinder.files(file_path)) with open(path) as f: From 47bed4a30dabded92fc595a65d6e265c7e1af8e9 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sun, 28 Jul 2013 15:12:51 -0500 Subject: [PATCH 6/8] Add type checking for sith.py run --- sith.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sith.py b/sith.py index eabf5179..31c97e33 100755 --- a/sith.py +++ b/sith.py @@ -75,6 +75,8 @@ class SourceFinder(object): class TestCase(object): def __init__(self, operation, path, line, column, traceback=None): + if operation not in self.operations: + raise ValueError("%s is not a valid operation" % operation) self.operation = operation self.path = path self.line = line From fe63e3bc9796950d27af0167f632ddbd15824c83 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sun, 28 Jul 2013 15:13:09 -0500 Subject: [PATCH 7/8] Add printing for all the different kinds of completions in sith.py run This kind of printing should probably go in the objects themselves, but I was too disgusted by the completion APIs to even begin to start extending the code for that (it needs to be cleaned up first). --- sith.py | 59 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/sith.py b/sith.py index 31c97e33..f75c81d3 100755 --- a/sith.py +++ b/sith.py @@ -108,16 +108,16 @@ class TestCase(object): column = random.randint(0, len(lines[line - 1])) return cls(operation, path, line, column) - def run(self, debugger, record=None, print_completions=False): + def run(self, debugger, record=None, print_result=False): try: with open(self.path) as f: self.file = f.read() self.script = jedi.Script(self.file, self.line, self.column, self.path) self.completions = getattr(self.script, self.operation)() - if print_completions: - self.show_location() - self.show_completions() + if print_result: + self.show_location(self.line, self.column) + self.show_operation() except jedi.NotFoundError: pass except Exception: @@ -135,20 +135,55 @@ class TestCase(object): pdb.post_mortem(einfo[2]) exit(1) - def show_location(self): + def show_location(self, lineno, column, show=3): # Three lines ought to be enough - show = 3 - lower = self.line - show if self.line - show > 0 else 0 - for i, line in enumerate(self.file.split('\n')[lower:self.line]): + lower = lineno - show if lineno - show > 0 else 0 + for i, line in enumerate(self.file.split('\n')[lower:lineno]): print(lower + i + 1, line) - print(' '*(self.column + len(str(self.line))), '^') + print(' '*(column + len(str(lineno))), '^') + + def show_operation(self): + print("%s:\n" % self.operation.capitalize()) + if self.operation == 'completions': + self.show_completions() + elif self.operation == 'goto_assignments': + self.show_goto_assignments() + elif self.operation == 'goto_definitions': + self.show_goto_definitions() + elif self.operation == 'usages': + self.show_usages() + elif self.operation == 'call_signatures': + self.show_call_signatures() def show_completions(self): - print("Completions:") - print() for completion in self.completions: print(completion.name) + # TODO: Support showing the location in other files + + # TODO: Move this printing to the completion objects themselves + def show_usages(self): + for completion in self.completions: + print(completion.description) + if os.path.abspath(completion.module_path) == os.path.abspath(self.path): + self.show_location(completion.line, completion.column) + + def show_call_signatures(self): + for completion in self.completions: + # This is too complicated to print. It really should be + # implemented in str() anyway. + print(completion) + # Can't print the location here because we don't have the module path + + + def show_goto_definitions(self): + for completion in self.completions: + print(completion.desc_with_module) + if os.path.abspath(completion.module_path) == os.path.abspath(self.path): + self.show_location(completion.line, completion.column) + + show_goto_assignments = show_goto_definitions + def show_errors(self): print(self.traceback) print(("Error with running Script(...).{operation}() with\n" @@ -175,7 +210,7 @@ def main(arguments): elif arguments['run']: TestCase(arguments[''], arguments[''], int(arguments['']), int(arguments['']) - ).run(debugger, print_completions=True) + ).run(debugger, print_result=True) else: for _ in range(int(arguments['--maxtries'])): t = TestCase.generate(arguments[''] or '.') From 2b5f53d1d4e5ac52c3309061d37a6f1b5e904888 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 29 Jul 2013 11:55:09 -0500 Subject: [PATCH 8/8] Minor fixes --- sith.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/sith.py b/sith.py index f75c81d3..049f6178 100755 --- a/sith.py +++ b/sith.py @@ -140,20 +140,11 @@ class TestCase(object): lower = lineno - show if lineno - show > 0 else 0 for i, line in enumerate(self.file.split('\n')[lower:lineno]): print(lower + i + 1, line) - print(' '*(column + len(str(lineno))), '^') + print(' ' * (column + len(str(lineno))), '^') def show_operation(self): print("%s:\n" % self.operation.capitalize()) - if self.operation == 'completions': - self.show_completions() - elif self.operation == 'goto_assignments': - self.show_goto_assignments() - elif self.operation == 'goto_definitions': - self.show_goto_definitions() - elif self.operation == 'usages': - self.show_usages() - elif self.operation == 'call_signatures': - self.show_call_signatures() + getattr(self, 'show_' + self.operation)() def show_completions(self): for completion in self.completions: @@ -175,7 +166,6 @@ class TestCase(object): print(completion) # Can't print the location here because we don't have the module path - def show_goto_definitions(self): for completion in self.completions: print(completion.desc_with_module)