|
import sublime |
|
import sublime_plugin |
|
|
|
import sys |
|
import os |
|
import functools |
|
|
|
|
|
|
|
class TemporaryStorage(object): |
|
settings = {} |
|
markers = [] |
|
|
|
LastRun = TemporaryStorage() |
|
|
|
class Settings(object): |
|
def __init__(self, name): |
|
self.name = name |
|
|
|
@property |
|
def global_(self): |
|
return sublime.load_settings(self.name + '.sublime-settings') |
|
|
|
@property |
|
def user(self): |
|
try: |
|
return (sublime.active_window().active_view() |
|
.settings().get(self.name, {})) |
|
except: |
|
return {} |
|
|
|
def get(self, key, default=None): |
|
return self.user.get(key, self.global_.get(key, default)) |
|
|
|
Settings = Settings(__name__) |
|
|
|
|
|
|
|
class PytestSetAndRunCommand(sublime_plugin.WindowCommand): |
|
def run(self, options=None): |
|
"""""" |
|
settings = self.get_settings() |
|
if options: |
|
settings['options'] = options |
|
else: |
|
settings['options'] = Settings.get('first') |
|
|
|
self.window.run_command("pytest_run", settings) |
|
LastRun.settings = settings |
|
|
|
|
|
def get_settings(self): |
|
rv = {} |
|
for key in ['pytest', 'working_dir', 'file_regex']: |
|
rv[key] = Settings.get(key) |
|
|
|
view = self.window.active_view() |
|
env = environment(view) |
|
try: |
|
filename = env['file_base'] |
|
if "_test" in filename or "test_" in filename: |
|
rv['target'] = env['file'] |
|
else: |
|
rv['target'] = Settings.get('tests_dir').format(**env) |
|
except KeyError: |
|
rv['target'] = Settings.get('tests_dir').format(**env) |
|
|
|
return rv |
|
|
|
|
|
class PytestRerunCommand(sublime_plugin.WindowCommand): |
|
def run(self, options=None): |
|
"""""" |
|
settings = LastRun.settings |
|
if not settings: |
|
self.window.run_command("pytest_set_and_run") |
|
return |
|
|
|
if options: |
|
settings['options'] = options |
|
else: |
|
settings['options'] = Settings.get("then") |
|
|
|
self.window.run_command("pytest_run", settings) |
|
|
|
|
|
def environment(view): |
|
window = view.window() |
|
|
|
rv = {} |
|
|
|
filename = view.file_name() |
|
if filename: |
|
rv['file'] = filename |
|
rv['file_path'] = os.path.dirname(filename) |
|
rv['file_base'] = os.path.basename(filename) |
|
|
|
|
|
if window and window.folders(): |
|
rv['project_path'] = window.folders()[0] |
|
elif filename: |
|
rv['project_path'] = rv['file_path'] |
|
|
|
if 'project_path' in rv: |
|
rv['project_base'] = os.path.basename(rv['project_path']) |
|
|
|
return rv |
|
|
|
|
|
|
|
class PytestRunCommand(sublime_plugin.WindowCommand): |
|
def run(self, **kwargs): |
|
""" |
|
kwargs: pytest, options, target, working_dir, file_regex |
|
""" |
|
args = self.make_args(kwargs) |
|
sublime.status_message("Running %s" % args['cmd'][0]) |
|
|
|
save = Settings.get('save_before_test') |
|
if save is True: |
|
av = self.window.active_view() |
|
if av and av.is_dirty(): |
|
self.window.run_command("save") |
|
elif save == 'all': |
|
selfs.window.run_command("save_all") |
|
|
|
output_view = Settings.get('output') |
|
if output_view == 'panel': |
|
self.window.run_command("test_exec", args) |
|
if Settings.get('hide_panel_unless_failures'): |
|
self.window.run_command("hide_panel", {"panel": "output.exec"}) |
|
|
|
elif output_view == 'view': |
|
args['title'] = "Test Results" |
|
self.window.run_command("test_xexec", args) |
|
|
|
|
|
def make_args(self, kwargs): |
|
env = environment(self.window.active_view()) |
|
for key in ['pytest', 'target', 'working_dir']: |
|
kwargs[key] = kwargs[key].format(**env) |
|
|
|
command = "{pytest} {options} {target}".format(**kwargs) |
|
|
|
return { |
|
"file_regex": kwargs['file_regex'], |
|
"cmd": [command], |
|
"shell": True, |
|
"working_dir": kwargs['working_dir'], |
|
"quiet": True |
|
} |
|
|
|
|
|
|
|
|
|
|
|
def annotate_view(view, markers): |
|
filename = view.file_name() |
|
if not filename: |
|
return |
|
|
|
view.erase_regions('PyTestRunner') |
|
|
|
regions = [] |
|
for marker in markers: |
|
fn, line, h = marker |
|
if sys.platform == 'win32': |
|
# we have a cygwin like path e.g. "/c/users" instead of "c:\" |
|
fn = os.path.normpath(fn) |
|
fn = fn[2:] |
|
filename = os.path.splitdrive(filename)[1] |
|
|
|
if fn == filename: |
|
region = view.full_line(view.text_point(line-1, h)) |
|
regions.append(region) |
|
|
|
view.add_regions('PyTestRunner', regions, |
|
'markup.deleted.diff', |
|
'bookmark', |
|
sublime.DRAW_OUTLINED) |
|
|
|
|
|
class PytestSetMarkersCommand(sublime_plugin.WindowCommand): |
|
def run(self, markers=[]): |
|
LastRun.markers = markers |
|
|
|
# immediately paint the visible tabs |
|
window = sublime.active_window() |
|
views = [window.active_view_in_group(group) |
|
for group in range(window.num_groups())] |
|
|
|
# print markers |
|
for view in views: |
|
annotate_view(view, markers) |
|
|
|
class PytestMarkCurrentViewCommand(sublime_plugin.EventListener): |
|
def on_activated(self, view): |
|
markers = LastRun.markers |
|
# print markers |
|
annotate_view(view, markers) |
|
|
|
|
|
|
|
standard_exec = __import__('exec') |
|
import xexec |
|
|
|
class TestExecCommand(standard_exec.ExecCommand): |
|
|
|
def run(self, **kw): |
|
self.dots = "" |
|
return super(TestExecCommand, self).run(**kw) |
|
|
|
def finish(self, proc): |
|
super(TestExecCommand, self).finish(proc) |
|
sublime.status_message("Ran %s tests." % len(self.dots)) |
|
|
|
markers = self.output_view.find_all_results() |
|
# we can't serialize a tuple in the settings, so we listify each marker |
|
markers = [list(marker) for marker in markers] |
|
|
|
sublime.active_window().run_command("pytest_set_markers", |
|
{"markers": markers}) |
|
|
|
def append_dots(self, dot): |
|
self.dots += dot |
|
sublime.status_message("Testing " + self.dots[-400:]) |
|
|
|
if dot in 'FX': |
|
sublime.active_window().run_command( |
|
"show_panel", {"panel": "output.exec"}) |
|
|
|
def on_data(self, proc, data): |
|
# print ">>", proc, ">>", data |
|
if data in '.FxXs': |
|
sublime.set_timeout(functools.partial(self.append_dots, data), 0) |
|
super(TestExecCommand, self).on_data(proc, data) |
|
|
|
class TestXexecCommand(xexec.ExecCommand): |
|
|
|
def finish(self, proc): |
|
super(TestXexecCommand, self).finish(proc) |
|
|
|
markers = self.output_view.find_all_results() |
|
# we can't serialize a tuple in the settings, so we listify each marker |
|
markers = [list(marker) for marker in markers] |
|
|
|
sublime.active_window().run_command("pytest_set_markers", |
|
{"markers": markers}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|