Commits

ZyX_I committed 22700a0

@%aurum/drivers/common/utils: Added pyeval() emulation
@%aurum/drivers/mercurial: Moved some code from python/aurum/aumercurial to python/aurum/auutils
Moved ansi_esc_echo registration to @%aurum/drivers/common/utils
@%aurum/repository, @%aurum/drivers/mercurial: Made repeatedcmd work without pyeval()

  • Participants
  • Parent commits 2d5eea1

Comments (0)

Files changed (10)

 test/*repo
 test/svntestreposerver
 testother
+.ropeproject

autoload/aurum/drivers/common/utils.vim

 "▶1
 scriptencoding utf-8
-execute frawor#Setup('1.0', {'@/resources': '0.0',
+execute frawor#Setup('1.1', {'@/resources': '0.0',
             \                       '@/os': '0.2'})
 let s:utils={}
+"▶1 _unload
+function s:._unload()
+python <<EOF
+try :
+    reload(aurum.auutils)
+except Exception :
+    pass
+EOF
+endfunction
 "▶1 utils.kwargstolst :: kwargs → [str]
 function s:utils.kwargstolst(kwargs)
     let r=[]
     try
         " This way is much faster
         python import aurum.utils
+        " No need in using pyeval emulation: it will degrade performance a lot
         function s:F.readsystem(...)
             return pyeval('aurum.utils.readsystem(*vim.eval("a:000"))')
         endfunction
         return call(s:_r.ansi_esc.echo, [a:str]+a:000, {})
     endfunction
     let s:utils.using_ansi_esc_echo=1
+    if exists('*pyeval')
+        python import aurum.auutils
+        execute 'python aurum.auutils.register_ansi_esc_echo_func('.
+                    \               'vim.bindeval("s:utils.printm"))'
+    endif
 else
     function s:utils.printm(m, ...)
         let prevempty=0
     endfunction
     let s:utils.using_ansi_esc_echo=0
 endif
+"▶1 utils.pyeval
+if exists('*pyeval')
+    let s:utils.pyeval=function('pyeval')
+else
+    python import aurum.auutils
+    function s:utils.pyeval(e)
+        python vim.command('return '+
+                    \aurum.auutils.nonutf_dumps(eval(vim.eval('a:e'))))
+    endfunction
+endif
+"▶1 utils.pystring
+" Only works with numbers and strings
+function s:utils.pystring(v)
+    return type(a:v)==type(0) ? string(a:v)
+                \             : '"'.substitute(escape(a:v, '\"'),
+                \                              "\n", '\\n', '').'"'
+endfunction
 "▶1 utils.emptystatdct
 let s:utils.emptystatdct={
             \'modified': [],

autoload/aurum/drivers/mercurial.vim

         "       not do this either, but it will be necessary to review these 
         "       lines after python3 support in mercurial will be finished.
         execute s:py 'reload('.s:pp.')'
-        if s:_r.utils.using_ansi_esc_echo
-            if exists('*pyeval')
-                execute s:pya.'register_ansi_esc_echo_func('.
-                            \               'vim.bindeval("s:_r.utils.printm"))'
-            endif
-        endif
     endif
 endif
 let s:nullrev=repeat('0', 40)
     endif
 endfunction
 "▶1 hg.ignore :: repo, file → +FS
+"▶2 determine s:usepython value
 let s:usepython=0
 if has_key(s:_r, 'py')
     try
     endtry
 endif
 if s:usepython "▶2
-if exists('*pyeval')
-function s:hg.ignore(repo, file)
-    let hgignore=s:_r.os.path.join(a:repo.path, '.hgignore')
-    let reline='^'.pyeval('re.escape(vim.bindeval("a:file"))').'$'
-    return s:F.addtosection(a:repo, hgignore, 'regexp', reline)
-endfunction
-else
-function s:hg.ignore(repo, file)
-    let d={}
-    execute s:py 'vim.eval("extend(d, {''pattern'': "+'.
-                \              'json.dumps(re.escape(vim.eval("a:file")))+"})")'
-    let hgignore=s:_r.os.path.join(a:repo.path, '.hgignore')
-    let reline='^'.d.pattern.'$'
-    return s:F.addtosection(a:repo, hgignore, 'regexp', reline)
-endfunction
-endif
-else "▶2
-function s:hg.ignore(repo, file)
-    let hgignore=s:_r.os.path.join(a:repo.path, '.hgignore')
-    return s:F.addtosection(a:repo, hgignore, 'glob', escape(a:file, '\*[{}]?'))
-endfunction
+    function s:hg.ignore(repo, file)
+        let hgignore=s:_r.os.path.join(a:repo.path, '.hgignore')
+        let re='^'.s:_r.utils.pyeval('re.escape('.
+                    \                       s:_r.utils.pystring(a:file).')').'$'
+        return s:F.addtosection(a:repo, hgignore, 'regexp', re)
+    endfunction
+else           "▶2
+    function s:hg.ignore(repo, file)
+        let hgignore=s:_r.os.path.join(a:repo.path, '.hgignore')
+        " According to the documentation, re.escape escapes all non-alphanumeric 
+        " characters, we just do the same here.
+        let re='^'.substitute(a:file, '\W', '\\\0', '').'$'
+        return s:F.addtosection(a:repo, hgignore, 'regexp', re)
+    endfunction
 endif
 "▶1 hg.ignoreglob :: repo, glob → + FS
 function s:hg.ignoreglob(repo, glob)
 "▶1 astatus, agetcs, agetrepoprop
 if s:_r.repo.userepeatedcmd
     if s:usepythondriver
-        function s:hg.astatus(repo, interval, ...)
-            let args = string(a:interval).', '.s:pp.'._get_status, '.
-                        \'vim.eval("a:repo.path"), '
-            let args.= join(map(copy(a:000), s:revargsexpr), ',')
-            return pyeval('aurum.repeatedcmd.new('.args.')')
-        endfunction
+        if exists('*pyeval')
+            function s:hg.astatus(repo, interval, ...)
+                let args = string(a:interval).', '.s:pp.'._get_status, '.
+                            \'vim.eval("a:repo.path"), '
+                let args.= join(map(copy(a:000), s:revargsexpr), ',')
+                return s:_r.utils.pyeval('aurum.repeatedcmd.new('.args.')')
+            endfunction
+        else
+            function s:hg.astatus(repo, interval, ...)
+                let args = string(a:interval).', '.s:pp.'._get_status, '.
+                            \'vim.eval("a:repo.path"), '
+                let args.= join(map(copy(a:000), s:revargsexpr), ',')
+                execute 'python vim.command("return "+'.
+                            \       'aurum.auutils.nonutf_dumps('.
+                            \               'aurum.repeatedcmd.new('.args.')))'
+            endfunction
+        endif
         function s:hg.agetcs(repo, interval, rev)
-            return pyeval('aurum.repeatedcmd.new('.string(a:interval).', '.
-                        \                        s:pp.'._get_cs, '.
-                        \                       'vim.eval("a:repo.path"), '.
-                        \                       'vim.eval("a:rev"))')
+            return s:_r.utils.pyeval('aurum.repeatedcmd.new('.
+                        \                 string(a:interval).', '.
+                        \                 s:pp.'._get_cs, '.
+                        \                 s:_r.utils.pystring(a:repo.path).', '.
+                        \                 s:_r.utils.pystring(a:rev).')')
         endfunction
         function s:hg.agetrepoprop(repo, interval, prop)
-            return pyeval('aurum.repeatedcmd.new('.string(a:interval).', '.
-                        \                        s:pp.'.get_one_prop, '.
-                        \                       'vim.eval("a:repo.path"), '.
-                        \                       'vim.eval("a:prop"))')
+            return s:_r.utils.pyeval('aurum.repeatedcmd.new('.
+                        \                 string(a:interval).', '.
+                        \                 s:pp.'.get_one_prop, '.
+                        \                 s:_r.utils.pystring(a:repo.path).', '.
+                        \                 s:_r.utils.pystring(a:prop).')')
         endfunction
     else
         try
             function s:hg.astatus(repo, interval, ...)
                 let [args, kwargs, reverse]=call(s:F.statargs, a:000, {})
                 let arglist=s:_r.utils.kwargstolst(kwargs)+args
-                return pyeval('aurum.repeatedcmd.new('.string(a:interval).', '.
+                return s:_r.utils.pyeval('aurum.repeatedcmd.new('.
+                            \        string(a:interval).', '.
                             \       'aurum.rcdriverfuncs.hg_status, '.
                             \       'vim.eval("a:repo.path"), '.
                             \       'vim.eval("arglist"), '.
                 if a:prop isnot# 'branch'
                     call s:_f.throw('anbnimp')
                 endif
-                return pyeval('aurum.repeatedcmd.new('.string(a:interval).', '.
+                return s:_r.utils.pyeval('aurum.repeatedcmd.new('.
+                            \        string(a:interval).', '.
                             \       'aurum.rcdriverfuncs.hg_branch, '.
                             \       'vim.eval("a:repo.path"))')
             endfunction

autoload/aurum/repo.vim

 "▶1
-execute frawor#Setup('5.5', {'@/resources': '0.0',
-            \                       '@/os': '0.0',
-            \                  '@/options': '0.0',
-            \          '@%aurum/lineutils': '0.0',
-            \            '@%aurum/bufvars': '0.0',
-            \                     '@aurum': '1.0',})
+execute frawor#Setup('5.5', { '@/resources': '0.0',
+            \                        '@/os': '0.0',
+            \                   '@/options': '0.0',
+            \           '@%aurum/lineutils': '0.0',
+            \             '@%aurum/bufvars': '0.0',
+            \                      '@aurum': '1.0',
+            \'@%aurum/drivers/common/utils': '1.1',})
 let s:drivers={}
 let s:repos={}
 let s:bufrepos={}
 function s:deffuncs.checkremote(...)
     return 0
 endfunction
-"▶1 aget, aremove
+"▶1 aget, aremove, XXX _unload
 let s:userepeatedcmd=0
-if has('python') && exists('*pyeval')
+if has('python')
     try
         python import aurum.repeatedcmd
-        python reload(aurum.repeatedcmd)
         let s:userepeatedcmd=1
+        function s:._unload()
+            python reload(aurum.repeatedcmd)
+        endfunction
     catch
     endtry
 endif
     augroup END
     let s:_augroups+=['AuRCFinish']
     function s:deffuncs.aget(repo, rcid, ...)
-        return pyeval('aurum.repeatedcmd.get(vim.bindeval("a:rcid"), '.
-                    \                        (a:0 && a:1? 'True': 'False').')')
+        return s:_r.utils.pyeval(
+                    \'aurum.repeatedcmd.get('.string(a:rcid).', '.
+                    \                       (a:0 && a:1? 'True': 'False').
+                    \                     ')')
     endfunction
-    function s:deffuncs.apause(repo, rcid)
-        python aurum.repeatedcmd.pause(vim.bindeval("a:rcid"))
-    endfunction
-    function s:deffuncs.aresume(repo, rcid)
-        python aurum.repeatedcmd.resume(vim.bindeval("a:rcid"))
-    endfunction
-    function s:deffuncs.aremove(repo, rcid)
-        python aurum.repeatedcmd.remove(vim.bindeval("a:rcid"))
-    endfunction
+    for s:f in ['pause', 'resume', 'remove']
+        execute      'function s:deffuncs.a'.s:f."(repo, rcid)\n".
+                    \'    execute "python '.
+                    \     'aurum.repeatedcmd.'.s:f.'(".string(a:rcid).")"'."\n".
+                    \'endfunction'
+    endfor
+    unlet s:f
 endif
 "▶1 iterfuncs: cs generators
 " startfunc (here)  :: repo, opts → d
     1.0: Made _r.utils.getcmd return a list,
          replaced _r.utils.kwargstostr with _r.utils.kwargstolst,
          made _r.utils.run return a pair (output, exit_code)
+    1.1: Added _r.utils.pyeval and _r.utils.pystring
 @%aurum/file:
     0.1: Added |:AuFile| prompt option.
 @%aurum/hyperlink:

python/aurum/aumercurial.py

 import json
 import re
 import sys
+from aurum.auutils import AurumError, outermethodgen, autoexportmethodgen, vim_extend, \
+                          vim_throw, echoe, echom, get_repo_prop_gen
 
 if hasattr(error, 'RepoLookupError'):
     RepoLookupError=error.RepoLookupError
 else:
     RepoLookupError=error.RepoError
 
-def outermethod(func):
-    """
-        Decorator used to make functions omit showing python traceback in case vim_throw was used.
-        Also transforms first argument (which is a path) to an repository object
-    """
-    def f(path, *args, **kwargs):
-        try:
-            repo=g_repo(path)
-            try:
-                return func(repo, *args, **kwargs)
-            finally:
-                repo.ui.flush()
-        except AurumError:
-            pass
-        except vim.error:
-            pass
-    return f
+def flush(repo):
+    repo.ui.flush()
 
-def autoexportmethod(*extargs, **extkwargs):
-    def autoexportmethoddec(func):
-        def f2(path, *args, **kwargs):
-            return func(g_repo(path), *args, **kwargs)
-        globals()['_'+func.__name__]=f2
-        def f(*args, **kwargs):
-            vim_extend(val=func(*args, **kwargs), *extargs, **extkwargs)
-        return f
-    return autoexportmethoddec
+def g_repo(path):
+    try:
+        return hg.repository(PrintUI(), path)
+    except error.RepoError:
+        vim_throw('norepo', path)
 
-def nonutf_dumps(obj):
-    todump=[('dump', obj)]
-    r=''
-    while todump:
-        t, obj = todump.pop(0)
-        if t == 'inject':
-            r+=obj
-        else:
-            tobj=type(obj)
-            if tobj is int:
-                r+=str(obj)
-            elif tobj is float:
-                r += "%1.1e" % obj
-            elif tobj is list or tobj is tuple:
-                r+='['
-                todump.insert(0, ('inject', ']'))
-                for value in reversed(obj):
-                    todump[:0]=[('dump', value), ('inject', ',')]
-            elif tobj is dict:
-                r+='{'
-                todump.insert(0, ('inject', '}'))
-                for key, value in obj.items():
-                    todump[:0]=[('dump', key),
-                                ('inject', ':'),
-                                ('dump', value),
-                                ('inject', ',')]
-            else:
-                r+='"'+str(obj).replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n')+'"'
-    return r
-
-def pyecho(o, error=False):
-    try:
-        return (sys.stderr if error else sys.stdout).write(str(o))
-    except UnicodeDecodeError:
-        if error:
-            vim.command('echohl ErrorMsg')
-        for line in str(o).split("\n"):
-            if not line:
-                line=' '
-            vim.command('echomsg '+utf_dumps(line))
-        if error:
-            vim.command('echohl None')
-
-if hasattr(vim, 'bindeval'):
-    ansi_esc_echo_func=None
-    def register_ansi_esc_echo_func(func):
-        global ansi_esc_echo_func
-        ansi_esc_echo_func=func
-        global echom
-        echom=ansi_esc_echo
-
-    def ansi_esc_echo(o, colinfo):
-        if colinfo is None:
-            return ansi_esc_echo_func(str(o), self={})
-        else:
-            return ansi_esc_echo_func(str(o), colinfo, self={})
-
-echoe=lambda o, colinfo: pyecho(o, True )
-echom=lambda o, colinfo: pyecho(o, False)
-
-def utf_dumps(obj):
-    return json.dumps(obj, encoding='utf8')
-
-class AurumError(Exception):
-    pass
-
-class VIMEncode(json.JSONEncoder):
-    def encode(self, obj, *args, **kwargs):
-        if isinstance(obj, (dict, list, int)):
-            return super(VIMEncode, self).encode(obj, *args, **kwargs)
-        return '"'+str(obj).replace('\\', '\\\\').replace('"', '\\"')+'"'
+outermethod      = outermethodgen(g_repo, flush)
+autoexportmethod = autoexportmethodgen(g_repo, globals())
 
 class PrintUI(ui.ui):
     def __init__(self, *args, **kwargs):
             for line in lines:
                 target.append(line)
 
-def vim_throw(*args):
-    vim.command('call s:_f.throw('+nonutf_dumps(args)[1:-1]+')')
-    raise AurumError()
-
-def g_repo(path):
-    try:
-        return hg.repository(PrintUI(), path)
-    except error.RepoError:
-        vim_throw('norepo', path)
-
 def g_cs(repo, rev):
     try:
         return repo[rev]
         vim_throw('nofile', filepath, cs.hex(), cs._repo.path)
 
 def set_rev_dict(cs, cs_vim):
-    cs_vim['hex']=cs.hex()
-    cs_vim['time']=int(cs.date()[0])
-    cs_vim['description']=cs.description()
-    cs_vim['user']=cs.user()
-    cs_vim['parents']=[parent.hex() for parent in cs.parents()]
+    cs_vim['hex']         = cs.hex()
+    cs_vim['time']        = int(cs.date()[0])
+    cs_vim['description'] = cs.description()
+    cs_vim['user']        = cs.user()
+    cs_vim['parents']     = [parent.hex() for parent in cs.parents()]
     try:
         branch=cs.branch()
         cs_vim['branch']=branch
     r=[set_rev_dict(g_cs(repo, i), {'rev': i,}) for i in range(startrev, cscount+1)]
     return r
 
-if hasattr(vim, 'bindeval'):
-    def vim_extend(val, var='d', utf=True, list=False):
-        d_vim = vim.bindeval(var)
-        if list:
-            d_vim.extend(val)
-        else:
-            for key in val:
-                d_vim[key] = val[key]
-else:
-    def vim_extend(val, var='d', utf=True, list=False):
-        vim.eval('extend('+var+', '+((utf_dumps if utf else nonutf_dumps)(val))+')')
-
 @outermethod
 def get_updates(repo, oldtip=None):
     tipcs=repo['tip']
                                      repo.ui.config('paths', 'default'),
               'branch': lambda repo: repo.dirstate.branch(),
         }
-@outermethod
-@autoexportmethod()
-def get_repo_prop(repo, prop):
-    if prop in repo_props:
-        r=repo_props[prop](repo)
-        if r is None:
-            vim_throw('failcfg', prop, repo.path)
-        else:
-            return {prop : r}
-    else:
-        vim_throw('nocfg', repo.path, prop)
+
+get_repo_prop = outermethod(autoexportmethod()(get_repo_prop_gen(repo_props)))
 
 def get_one_prop(path, prop):
     return _get_repo_prop(path, prop)[prop]

python/aurum/auutils.py

+import vim, sys
+
+def emptystatdct():
+    return {
+            'modified': [],
+            'added'   : [],
+            'removed' : [],
+            'deleted' : [],
+            'unknown' : [],
+            'ignored' : [],
+            'clean'   : [],
+            }
+
+def outermethodgen(g_repo, flush):
+    def outermethod(func):
+        """
+            Decorator used to make functions omit showing python traceback in 
+            case vim_throw was used.
+            Also transforms first argument (which is a path) to an repository 
+            object
+        """
+        def f(path, *args, **kwargs):
+            try:
+                repo=g_repo(path)
+                try:
+                    return func(repo, *args, **kwargs)
+                finally:
+                    flush(repo)
+            except AurumError:
+                pass
+            except vim.error:
+                pass
+        return f
+    return outermethod
+
+def autoexportmethodgen(g_repo, g):
+    def autoexportmethod(*extargs, **extkwargs):
+        def autoexportmethoddec(func):
+            def f2(path, *args, **kwargs):
+                return func(g_repo(path), *args, **kwargs)
+            g['_'+func.__name__]=f2
+            def f(*args, **kwargs):
+                vim_extend(val=func(*args, **kwargs), *extargs, **extkwargs)
+            return f
+        return autoexportmethoddec
+    return autoexportmethod
+
+class AurumError(Exception):
+    pass
+
+def vim_throw(*args):
+    vim.command('call s:_f.throw('+nonutf_dumps(args)[1:-1]+')')
+    raise AurumError()
+
+def nonutf_dumps(obj):
+    todump=[('dump', obj)]
+    r=''
+    while todump:
+        t, obj = todump.pop(0)
+        if t == 'inject':
+            r+=obj
+        else:
+            tobj=type(obj)
+            if tobj is int:
+                r+=str(obj)
+            elif tobj is float:
+                r += "%1.1e" % obj
+            elif tobj is list or tobj is tuple:
+                r+='['
+                todump.insert(0, ('inject', ']'))
+                for value in reversed(obj):
+                    todump[:0]=[('dump', value), ('inject', ',')]
+            elif tobj is dict:
+                r+='{'
+                todump.insert(0, ('inject', '}'))
+                for key, value in obj.items():
+                    todump[:0]=[('dump', key),
+                                ('inject', ':'),
+                                ('dump', value),
+                                ('inject', ',')]
+            else:
+                r+='"'+str(obj).replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n')+'"'
+    return r
+
+def utf_dumps(obj):
+    return json.dumps(obj, encoding='utf8')
+
+if hasattr(vim, 'bindeval'):
+    def vim_extend(val, var='d', utf=True, list=False):
+        d_vim = vim.bindeval(var)
+        if list:
+            d_vim.extend(val)
+        else:
+            for key in val:
+                d_vim[key] = val[key]
+else:
+    def vim_extend(val, var='d', utf=True, list=False):
+        vim.eval('extend('+var+', '+((utf_dumps if utf else nonutf_dumps)(val))+')')
+
+if hasattr(vim, 'bindeval'):
+    ansi_esc_echo_func=None
+    def register_ansi_esc_echo_func(func):
+        global ansi_esc_echo_func
+        ansi_esc_echo_func=func
+        global echom
+        echom=ansi_esc_echo
+
+    def ansi_esc_echo(o, colinfo):
+        if colinfo is None:
+            return ansi_esc_echo_func(str(o), self={})
+        else:
+            return ansi_esc_echo_func(str(o), colinfo, self={})
+
+def pyecho(o, error=False):
+    try:
+        return (sys.stderr if error else sys.stdout).write(str(o))
+    except UnicodeDecodeError:
+        if error:
+            vim.command('echohl ErrorMsg')
+        for line in str(o).split("\n"):
+            if not line:
+                line=' '
+            vim.command('echomsg '+utf_dumps(line))
+        if error:
+            vim.command('echohl None')
+
+echoe=lambda o, colinfo: pyecho(o, True )
+echom=lambda o, colinfo: pyecho(o, False)
+
+def get_repo_prop_gen(repo_props):
+    def get_repo_prop(repo, prop):
+        if prop in repo_props:
+            r=repo_props[prop](repo)
+            if r is None:
+                vim_throw('failcfg', prop, repo.path)
+            else:
+                return {prop : r}
+        else:
+            vim_throw('nocfg', repo.path, prop)
+    return get_repo_prop
+
+# vim: ft=python ts=4 sw=4 sts=4 et tw=100

python/aurum/rcdriverfuncs.py

-from aurum.utils import readlines
-from copy import deepcopy
+from aurum.utils   import readlines
+from aurum.auutils import emptystatdct
 
 hgstatchars={
     'M': 'modified',
     'I': 'ignored',
     'C': 'clean',
 }
-emptystatdct={
-    'modified': [],
-    'added'   : [],
-    'removed' : [],
-    'deleted' : [],
-    'unknown' : [],
-    'ignored' : [],
-    'clean'   : [],
-}
 
 def hg_status(path, args, reverse=False):
-    r=deepcopy(emptystatdct)
-    for line in readlines(['hg']+args, cwd=path):
+    r=emptystatdct()
+    for line in readlines(['hg', 'status']+args, cwd=path):
         r[hgstatchars[line[0]]].append(line[2:])
     if reverse:
         r['deleted'], r['unknown'] = r['unknown'], r['deleted']
     return readlines(['hg', 'branch'], cwd=path).next()
 
 def git_status(path, fname):
-    r=deepcopy(emptystatdct)
+    r=emptystatdct()
     try:
         line=readlines(['git', 'status', '--porcelain', '--', fname],
                        cwd=path).next()
     },
 ]
 def svn_status(path, fname):
-    r=deepcopy(emptystatdct)
+    r=emptystatdct()
     try:
         line=readlines(['svn', 'status', '--', fname], cwd=path).next()
         status=line[:7]
 }
 
 def bzr_status(path, fname):
-    r=deepcopy(emptystatdct)
+    r=emptystatdct()
     try:
         line=readlines(['bzr', 'status', '--', fname], cwd=path).next()
         if line[-1] != ':':

python/aurum/repeatedcmd.py

 
     def getvalue(self):
         if not self.alive():
-            return self.getcurrentvalue()
+            result = self.getcurrentvalue()
+            self.start()
+            return result
 
         self.qlock.acquire()
         if self.value is None or not self.queue.empty():

python/aurum/utils.py

     return lines, exit_code
 
 def readlines(cmd, cwd=None):
-    p=Popen(cmd, shell=False, stdout=PIPE, stderr=None, cwd=cwd)
+    p=Popen(cmd, shell=False, stdout=PIPE, stderr=PIPE, cwd=cwd)
+    p.stderr.close()
     for line in p.stdout:
         yield line[:-1]