From 60b1e35e9865e3064aeb8ad76b614c28ad91a9ee Mon Sep 17 00:00:00 2001 From: Wolfgang Mehner Date: Tue, 12 Jan 2016 18:26:47 +0100 Subject: [PATCH 1/8] Fix issue with updating buffers The append method of buffer causes an error (Vim 7.3 with Python 2.7.3) if the supplied list is empty. This case is now handled explicitly. --- autoload/python/buffer.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/autoload/python/buffer.py b/autoload/python/buffer.py index ef2fa60..a669331 100644 --- a/autoload/python/buffer.py +++ b/autoload/python/buffer.py @@ -18,8 +18,13 @@ def write(self, msg, overwrite): else: to_write = str(msg).split('\n') - if len(to_write) == 1 and to_write[0] == "": - return (last_line, last_line) + if len(to_write) == 0 or len(to_write) == 1 and to_write[0] == "": + # nothing to write, check overwrite + if overwrite: + self._buffer[:] = None + return (1, 1) + else: + return (last_line, last_line) if overwrite or self.is_empty(): self._buffer[:] = to_write @@ -131,4 +136,4 @@ def contents(self): def is_empty(self): return not self._buffer - +# vim: expandtab: tabstop=4: shiftwidth=4 From 504d5e557b23093341f189c60265899d340c5a12 Mon Sep 17 00:00:00 2001 From: Wolfgang Mehner Date: Tue, 12 Jan 2016 18:29:12 +0100 Subject: [PATCH 2/8] Fix issue with handling new buffers The previous implementation causes a problem (Vim 7.3 with Python 2.7.3) with obtaining the buffer object of a newly generated buffer. This is fixed by a more straightforward approach. --- autoload/python/window.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/autoload/python/window.py b/autoload/python/window.py index 1d9101c..7b05916 100644 --- a/autoload/python/window.py +++ b/autoload/python/window.py @@ -56,7 +56,8 @@ def create(self, open_cmd): vim.command("setlocal buftype=nofile modifiable "+ \ "winfixheight winfixwidth") existing_content = self._buffer.contents() - self._buffer = VimBuffer(vim.buffers[self.getbuffernr()]) + self._buffer = VimBuffer(vim.current.buffer) + self._buffernr = vim.current.buffer.number self._buffer.replace(existing_content) self.is_open = True self.creation_count += 1 @@ -116,3 +117,5 @@ def on_create(self): self.command('setlocal syntax=do_command_window') self.command('nnoremap '+\ ':call do#ShowProcessFromCommandWindow()') + +# vim: expandtab: tabstop=4: shiftwidth=4 From 8c11a83b92ce8aa5b1e8b23c399b4233510cc0f6 Mon Sep 17 00:00:00 2001 From: Wolfgang Mehner Date: Tue, 12 Jan 2016 18:30:29 +0100 Subject: [PATCH 3/8] Add tab-completion of filenames to commands The commands ':Do' and ':DoQuietly' now tab-complete filenames, which is essential when dealing with shell commands. --- plugin/do.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/do.vim b/plugin/do.vim index fbaf9b2..70f63f3 100644 --- a/plugin/do.vim +++ b/plugin/do.vim @@ -18,8 +18,8 @@ if !has("python") finish endif -command! -nargs=* Do call do#Execute() -command! -nargs=* DoQuietly call do#Execute(, 1) +command! -complete=file -nargs=* Do call do#Execute() +command! -complete=file -nargs=* DoQuietly call do#Execute(, 1) command! -range DoThis call do#ExecuteSelection() command! DoAgain call do#ExecuteAgain() command! Doing call do#ToggleCommandWindow() From 165de2b6556ec464ea33bc13a857c4d60b538cc1 Mon Sep 17 00:00:00 2001 From: Wolfgang Mehner Date: Wed, 13 Jan 2016 18:42:32 +0100 Subject: [PATCH 4/8] Fix incomplete output buffers Fix Issue #1 concerning missing lines in the output buffer. We simply have to continue to read from the streams (after the process has terminated) until we hit the end-of-file. --- autoload/python/async.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/autoload/python/async.py b/autoload/python/async.py index 5f1929e..aa6e396 100644 --- a/autoload/python/async.py +++ b/autoload/python/async.py @@ -28,9 +28,12 @@ def _readfds(self): fds = [self.__process.stdout.fileno(), self.__process.stderr.fileno()] streams = [self.__process.stdout, self.__process.stderr] + # while the process is still alive ... while self.__process.poll() is None: + # wait for one of the file descriptors to be ready for reading fdsin, _, _ = select.select(fds, [], []) for fd in fdsin: + # read a line from the file descriptor output = [None, None] ind = fds.index(fd) stream = streams[ind] @@ -38,6 +41,17 @@ def _readfds(self): if len(s) > 0: output[ind] = s yield output + # after the process has finished ... + for ind, stream in enumerate( streams ): + # read the rest of the output from the file descriptor + output = [None, None] + while True: + s = stream.readline() + if len(s) > 0: + output[ind] = s + yield output + else: + break class ProcessPool: @@ -79,3 +93,4 @@ def stop(self): for t in self.__threads: t.join(1000) +# vim: expandtab: tabstop=4: shiftwidth=4 From 694b046028ecd8d7b686ffd05f5b540edacf0458 Mon Sep 17 00:00:00 2001 From: Wolfgang Mehner Date: Tue, 14 Jun 2016 22:45:32 +0200 Subject: [PATCH 5/8] Clean up and Python 3 preparation Remove some obsolete lines, which searched for the Python sources in the wrong place. Prepare to use the Python 3 interface, the code still has to be updated in other places. --- autoload/do.vim | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/autoload/do.vim b/autoload/do.vim index 29ba1ab..0d1f1ab 100644 --- a/autoload/do.vim +++ b/autoload/do.vim @@ -15,20 +15,20 @@ let s:do_refresh_key = "" let s:do_update_time = 500 let s:do_auto_show_process_window = 1 +"" " Load Python script -if filereadable($VIMRUNTIME."/plugin/python/do.py") - pyfile $VIMRUNTIME/plugin/do.py -elseif filereadable($HOME."/.vim/plugin/python/do.py") - pyfile $HOME/.vim/plugin/python/do.py +" +" Search relative to this file. +let $CUR_DIRECTORY=expand(":p:h") + +if filereadable($CUR_DIRECTORY."/python/do.py") + if has("python") + pyfile $CUR_DIRECTORY/python/do.py + elseif has("python3") + py3file $CUR_DIRECTORY/python/do.py + endif else - " when we use pathogen for instance - let $CUR_DIRECTORY=expand(":p:h") - - if filereadable($CUR_DIRECTORY."/python/do.py") - pyfile $CUR_DIRECTORY/python/do.py - else - call confirm('vdebug.vim: Unable to find do.py. Place it in either your home vim directory or in the Vim runtime directory.', 'OK') - endif + call confirm('do.vim: Unable to find autoload/python/do.py. Place it in either your home vim directory or in the Vim runtime directory.', 'OK') endif "" @@ -121,9 +121,7 @@ function! do#Execute(command, ...) call do#error("Supplied command is empty") else let s:previous_command = l:command -python <<_EOF_ -do_async.execute(vim.eval("l:command"), int(vim.eval("l:quiet")) == 1) -_EOF_ + python do_async.execute(vim.eval("l:command"), int(vim.eval("l:quiet")) == 1) endif endfunction @@ -144,9 +142,7 @@ endfunction " @param string file_path The path to the file to write log information " function! do#EnableLogger(file_path) -python <<_EOF_ -do_async.enable_logger(vim.eval("a:file_path")) -_EOF_ + python do_async.enable_logger(vim.eval("a:file_path")) endfunction "" @@ -249,3 +245,5 @@ endfunction " Initialize do python do_async = Do() autocmd VimLeavePre * python do_async.stop() + +" vim: expandtab: tabstop=4: shiftwidth=4 From d52f6fa009d2c0edfa1163f0729d135d4094e3f5 Mon Sep 17 00:00:00 2001 From: Wolfgang Mehner Date: Tue, 23 Aug 2016 17:21:10 +0200 Subject: [PATCH 6/8] Python 3 preparation Make scripts compliant to Python 3, the code still has to be updated in other places. --- autoload/python/do.py | 2 +- autoload/python/utils.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/autoload/python/do.py b/autoload/python/do.py index be19da0..494153c 100644 --- a/autoload/python/do.py +++ b/autoload/python/do.py @@ -45,7 +45,7 @@ def mark_command_window_as_closed(self): def mark_process_window_as_closed(self): try: self.__process_renderer.destroy_process_window() - except Exception, e: + except Exception as e: log("Error: %s" % str(e)) def show_process_from_command_window(self): diff --git a/autoload/python/utils.py b/autoload/python/utils.py index ff7bd00..2d63abe 100644 --- a/autoload/python/utils.py +++ b/autoload/python/utils.py @@ -95,7 +95,7 @@ def __init__(self, debug_level, filename): def __open(self): try: self.f = open(self.filename,'w') - except IOError, e: + except IOError as e: raise LogError("Invalid file name '%s' for log file: %s" \ %(self.filename, str(e))) except: @@ -141,7 +141,7 @@ def remove_logger(cls, type): cls.loggers[type].shutdown() return True else: - print "Failed to find logger %s in list of loggers" % type + print ( "Failed to find logger %s in list of loggers" % type ) return False @classmethod From ff5a1c2cf69f1c86e9dc3037989172ab7a10e05f Mon Sep 17 00:00:00 2001 From: Wolfgang Mehner Date: Tue, 23 Aug 2016 17:35:06 +0200 Subject: [PATCH 7/8] Add an API to start processes from another plug-in Extend the handling of processes in Python: - Allow to split the output. - Processes can be marked as 'external', - ... and trigger the new hook 'do#HookProcessFinished' upon completion. - Move 'Process' creation from 'ProcessCollection' into the 'Do' class. Add an API, so that 'do.vim' can be triggered by other plug-ins: - Processes can be started via 'do#ExecuteExternal', ... which support a callback executed upon the completion of the background process. - Information about them can be retrieved via 'do#GetExternal'. --- autoload/do.vim | 128 ++++++++++++++++++++++++++++++++++++++++++ autoload/python/do.py | 61 +++++++++++++++++--- 2 files changed, 181 insertions(+), 8 deletions(-) diff --git a/autoload/do.vim b/autoload/do.vim index 0d1f1ab..6c14dc4 100644 --- a/autoload/do.vim +++ b/autoload/do.vim @@ -136,6 +136,134 @@ function! do#ExecuteSelection() call do#Execute(l:command) endfunction +"" +" Keeps records on external processes started via do#ExecuteExternal . +" +let s:external_processes = { + \ 'by_id' : {}, + \ 'by_pid' : {}, + \ } + +"" +" Default callback for external processes +" +" This is the default callback for external processes. It always excepts all +" parameters and does nothing. +" +" @param string a:1 The ID of the external process +" @param number or string a:2 The exit code of the external process +" +function! s:EmptyCallback(...) +endfunction + +"" +" Start an external process +" +" Start an external process with the following options, which are given in a +" Dict with fields: +" - id (string): a user-defined ID +" - split_output (integer): whether the output is to be split into stdout and +" stderr, the default is not to split the output +" - callback (Funcref): a function to be called after the process is finished: +" function s:Callback(pid,exit_code) +" " ... +" endfunction +" options.callback = Function("s:Callback") +" +" @param string command The command to run +" @param dict options The options as a dictionary +" +function! do#ExecuteExternal(command, options) + let record = { + \ 'id' : get ( a:options, 'id', '' ), + \ 'command' : a:command, + \ 'callback' : get ( a:options, 'callback', function('s:EmptyCallback') ), + \ 'split_output' : get ( a:options, 'split_output', 0 ), + \ 'status' : 'new', + \ 'pid' : -1, + \ 'exit_code' : -1, + \ } + if record.id != '' + let s:external_processes.by_id[record.id] = record + endif + + let l:command = a:command + let l:pid = -1 + let l:split = record.split_output + if empty(l:command) + "TODO: log + return 0 + endif + let l:command = Strip(l:command) + if empty(l:command) + "TODO: log + return 0 + else + let l:pid = pyeval ( 'do_async.execute(vim.eval("l:command"), external = True, split_output = vim.eval("l:split") == 1 )' ) + let record.status = 'running' + let record.pid = l:pid + let s:external_processes.by_pid[record.pid] = record + endif +endfunction + +"" +" Get a previously started external process +" +" Returns the record of the last external process with the given ID. The +" record is a Dict with fields: +" - id (string): the user-defined ID +" - command (string): the command +" - split_output (integer): whether the output is split +" - status (string): "new", "running", "finished", or "failed" +" - pid (number): only valid while the status is "running" +" - exit_code (number): only valid if the status is "finished" +" +" If a record with this ID does not exist, a record with the field 'status' +" set to "failed" is returned. +" +" @param string id The ID of the process +" +function! do#GetExternal(id) + if ! has_key ( s:external_processes.by_id, a:id ) + return { 'status' : 'failed', } + endif + return s:external_processes.by_id[a:id] +endfunction + +"" +" Internal use: An external process is finished +" +" This function is called by Python after an external process finished. It +" should not be called by a user. +" +" @param number pid The PID of the process, for identification +" @param number exit_code The exit code +" +function! do#HookProcessFinished(pid,exit_code) + if has_key ( s:external_processes.by_pid, a:pid ) + let record = s:external_processes.by_pid[a:pid] + let record.status = 'finished' + let record.exit_code = a:exit_code + call remove ( s:external_processes.by_pid, a:pid ) + + call call ( record.callback, [ record.id, record.exit_code ] ) + + if record.split_output + " :TODO:14.07.2016 19:03:WM: only get the output when requested, + " this runs during an autocmd and takes to much time + let l = pyeval ( 'do_async.get_by_pid('.record.pid.').output().all_std()' ) + let record.output_std = join ( l, "" ) + let l = pyeval ( 'do_async.get_by_pid('.record.pid.').output().all_err()' ) + let record.output_err = join ( l, "" ) + else + " :TODO:14.07.2016 19:03:WM: only get the output when requested, + " this runs during an autocmd and takes to much time + let l = pyeval ( 'do_async.get_by_pid('.record.pid.').output().all()' ) + let record.output = join ( l, "" ) + endif + endif +endfunction + "" " Enable the file logger for debugging purposes. " diff --git a/autoload/python/do.py b/autoload/python/do.py index 494153c..6cebd40 100644 --- a/autoload/python/do.py +++ b/autoload/python/do.py @@ -24,15 +24,21 @@ def __init__(self): def __del__(self): self.stop() - def execute(self, cmd, quiet = False): + def execute(self, cmd, quiet = False, external = False, split_output = False): pid = self.__process_pool.execute(cmd) log("Started command with pid %i: %s" %(pid, cmd)) - process = self.__processes.add(cmd, pid) - self.__process_renderer.add_process(process, quiet) + process = Process(cmd, pid = pid, external = external, split_output = split_output) + self.__processes.add(process, pid) + self.__process_renderer.add_process(process, quiet or external) self.__assign_autocommands() self.check() + return pid + + def get_by_pid(self, pid): + return self.__processes.get_by_pid(str(pid)) + def reload_options(self): Options.reload() @@ -108,10 +114,8 @@ class ProcessCollection: def __init__(self): self.__processes = {} - def add(self, command, pid): - process = Process(command, pid) + def add(self, process, pid): self.__processes[pid] = process - return process def get_by_pid(self, pid): return next((p for p in self.__processes.values() if p.get_pid() == pid), None) @@ -136,11 +140,15 @@ def kill_all(self): process.kill() class Process: - def __init__(self, command, pid): + def __init__(self, command, pid, external = False, split_output = False): self.__command = command self.__pid = str(pid) self.__start_time = time.time() - self.__output = Output() + self.__external = external + if split_output: + self.__output = SplitOutput() + else: + self.__output = Output() self.__exit_code = None self.__time = None @@ -148,6 +156,9 @@ def mark_as_complete(self, exit_code): self.__exit_code = str(exit_code) self.__time = round((time.time() - self.__start_time) * 1000) + if self.__external: + vim.command('call do#HookProcessFinished(%s,%s)' % ( self.__pid, self.__exit_code )) + def has_finished(self): return self.__exit_code is not None @@ -178,6 +189,9 @@ def output(self): def name(self): return "DoOutput(%s)" % self.__pid + def is_external(self): + return self.__external + def kill(self): try: os.kill(int(self.__pid), signal.SIGTERM) @@ -203,3 +217,34 @@ def append(self, stdout, stderr): self.__output.append(stdout) if stderr is not None: self.__output.append("E> %s" % stderr) + +class SplitOutput: + def __init__(self): + self.__output_std = [] + self.__output_err = [] + + def all(self): + if len(self.__output_err) == 0: + return self.__output_std + else: + return self.__output_std + [ 'E> Errors:' ] + self.__output_err + + def all_std(self): + return self.__output_std + + def all_err(self): + return self.__output_err + + def __len__(self): + return len(self.__output_std) + + def from_line(self, line): + return self.__output_std[line:] + + def append(self, stdout, stderr): + if stdout is not None: + self.__output_std.append(stdout) + if stderr is not None: + self.__output_err.append(stderr) + +# vim: expandtab: tabstop=4: shiftwidth=4 From 1cf84cbda70195108771781b8133647797c03524 Mon Sep 17 00:00:00 2001 From: Sankhesh Jhaveri Date: Fri, 23 Sep 2016 14:10:20 -0400 Subject: [PATCH 8/8] Add full Python3 support Support Vim compiled with either +python or +python3. Incorporates the pull request WolfgangMehner#1 by @sankhesh . --- autoload/do.vim | 72 ++++++++++++++++++++++++++++-------- autoload/python/async.py | 13 ++++--- autoload/python/do.py | 4 +- autoload/python/rendering.py | 2 +- autoload/python/utils.py | 4 +- plugin/do.vim | 2 +- 6 files changed, 71 insertions(+), 26 deletions(-) diff --git a/autoload/do.vim b/autoload/do.vim index 6c14dc4..0b211a7 100644 --- a/autoload/do.vim +++ b/autoload/do.vim @@ -90,7 +90,11 @@ endfunction " function will reload them. " function! do#ReloadOptions() - python do_async.reload_options() + if has("python") + python do_async.reload_options() + elseif has("python3") + python3 do_async.reload_options() + endif endfunction "" @@ -121,7 +125,11 @@ function! do#Execute(command, ...) call do#error("Supplied command is empty") else let s:previous_command = l:command - python do_async.execute(vim.eval("l:command"), int(vim.eval("l:quiet")) == 1) + if has("python") + python do_async.execute(vim.eval("l:command"), int(vim.eval("l:quiet")) == 1) + elseif has("python3") + python3 do_async.execute(vim.eval("l:command"), int(vim.eval("l:quiet")) == 1) + endif endif endfunction @@ -270,7 +278,11 @@ endfunction " @param string file_path The path to the file to write log information " function! do#EnableLogger(file_path) - python do_async.enable_logger(vim.eval("a:file_path")) + if has("python") + python do_async.enable_logger(vim.eval("a:file_path")) + elseif has("python3") + python3 do_async.enable_logger(vim.eval("a:file_path")) + endif endfunction "" @@ -279,7 +291,11 @@ endfunction " The command window details currently running and finished processes. " function! do#ToggleCommandWindow() - python do_async.toggle_command_window() + if has("python") + python do_async.toggle_command_window() + elseif has("python3") + python3 do_async.toggle_command_window() + endif endfunction "" @@ -288,7 +304,11 @@ endfunction " Executed automatically via an autocommand. " function! do#MarkCommandWindowAsClosed() - python do_async.mark_command_window_as_closed() + if has("python") + python do_async.mark_command_window_as_closed() + elseif has("python3") + python3 do_async.mark_command_window_as_closed() + endif endfunction "" @@ -297,14 +317,22 @@ endfunction " Executed automatically via an autocommand. " function! do#MarkProcessWindowAsClosed() - python do_async.mark_process_window_as_closed() + if has("python") + python do_async.mark_process_window_as_closed() + elseif has("python3") + python3 do_async.mark_process_window_as_closed() + endif endfunction "" " Trigger selection of a process in the command window. " function! do#ShowProcessFromCommandWindow() - python do_async.show_process_from_command_window() + if has("python") + python do_async.show_process_from_command_window() + elseif has("python3") + python3 do_async.show_process_from_command_window() + endif endfunction "" @@ -328,12 +356,21 @@ function! do#AssignAutocommands() execute "nnoremap " . do#get("do_refresh_key") . " :call do#nop()" execute "inoremap " . do#get("do_refresh_key") . ' :call do#nop()' augroup vim_do - au CursorHold * python do_async.check() - au CursorHoldI * python do_async.check() - au CursorMoved * python do_async.check() - au CursorMovedI * python do_async.check() - au FocusGained * python do_async.check() - au FocusLost * python do_async.check() + if has("python") + au CursorHold * python do_async.check() + au CursorHoldI * python do_async.check() + au CursorMoved * python do_async.check() + au CursorMovedI * python do_async.check() + au FocusGained * python do_async.check() + au FocusLost * python do_async.check() + elseif has("python3") + au CursorHold * python3 do_async.check() + au CursorHoldI * python3 do_async.check() + au CursorMoved * python3 do_async.check() + au CursorMovedI * python3 do_async.check() + au FocusGained * python3 do_async.check() + au FocusLost * python3 do_async.check() + endif augroup END let &updatetime=do#get("do_update_time") endfunction @@ -371,7 +408,12 @@ function! s:getVisualSelection() endfunction " Initialize do -python do_async = Do() -autocmd VimLeavePre * python do_async.stop() +if has("python") + python do_async = Do() + autocmd VimLeavePre * python do_async.stop() +elseif has("python3") + python3 do_async = Do() + autocmd VimLeavePre * python3 do_async.stop() +endif " vim: expandtab: tabstop=4: shiftwidth=4 diff --git a/autoload/python/async.py b/autoload/python/async.py index aa6e396..a1194f9 100644 --- a/autoload/python/async.py +++ b/autoload/python/async.py @@ -1,10 +1,13 @@ -import Queue import threading import subprocess -import shlex import select +import sys from utils import log -import os + +if sys.version[0] == '2': + import Queue as queue +else: + import queue as queue class AsyncProcessReader(threading.Thread): def __init__(self, process, output_q): @@ -57,7 +60,7 @@ def _readfds(self): class ProcessPool: def __init__(self): self.__threads = [] - self.__output_q = Queue.Queue(0) + self.__output_q = queue.Queue(0) def execute(self, cmd): subproc = subprocess.Popen(cmd, shell=True, @@ -80,7 +83,7 @@ def get_outputs(self): try: for result in iter(self.__output_q.get_nowait, None): results.append(result) - except Queue.Empty: + except queue.Empty: pass return results diff --git a/autoload/python/do.py b/autoload/python/do.py index 6cebd40..4721e90 100644 --- a/autoload/python/do.py +++ b/autoload/python/do.py @@ -118,7 +118,7 @@ def add(self, process, pid): self.__processes[pid] = process def get_by_pid(self, pid): - return next((p for p in self.__processes.values() if p.get_pid() == pid), None) + return next((p for p in list(self.__processes.values()) if p.get_pid() == pid), None) def update(self, pid, exit_status, stdout, stderr): process = self.__processes[pid] @@ -133,7 +133,7 @@ def all_finished(self): return len(self.get_running()) == 0 def get_running(self): - return filter(lambda p: p.is_running(), self.__processes.values()) + return [p for p in list(self.__processes.values()) if p.is_running()] def kill_all(self): for process in self.get_running(): diff --git a/autoload/python/rendering.py b/autoload/python/rendering.py index 717cc8f..b479f78 100644 --- a/autoload/python/rendering.py +++ b/autoload/python/rendering.py @@ -75,7 +75,7 @@ def __str__(self): self.__process.get_status(), self.__formatted_time(), self.__process.get_pid()) - max_length = max(map(len, values)) + 12 + max_length = max(list(map(len, values))) + 12 title = "=" * max_length + "\n" title += " [command] %s\n" % values[0] diff --git a/autoload/python/utils.py b/autoload/python/utils.py index 2d63abe..4c04b3a 100644 --- a/autoload/python/utils.py +++ b/autoload/python/utils.py @@ -125,7 +125,7 @@ def __init__(self,string,level = Logger.INFO): @classmethod def log(cls, string, level = Logger.INFO): - for k, l in cls.loggers.iteritems(): + for k, l in cls.loggers.items(): l.log(string,level) @classmethod @@ -146,7 +146,7 @@ def remove_logger(cls, type): @classmethod def shutdown(cls): - for k, l in cls.loggers.iteritems(): + for k, l in cls.loggers.items(): l.shutdown() cls.loggers = {} diff --git a/plugin/do.vim b/plugin/do.vim index 70f63f3..e308c90 100644 --- a/plugin/do.vim +++ b/plugin/do.vim @@ -14,7 +14,7 @@ "============================================================================= " }}} -if !has("python") +if !has("python") && !has("python3") finish endif