Coder Social home page Coder Social logo

execnet's People

Contributors

alex avatar alfredodeza avatar asottile avatar benjaminp avatar bluetech avatar bmwiedemann avatar bubenkoff avatar ctheune avatar dependabot[bot] avatar fijal avatar graingert avatar hpk42 avatar hugovk avatar jaraco avatar mtelka avatar nicoddemus avatar olegpidsadnyi avatar pre-commit-ci[bot] avatar ronnypfannschmidt avatar scarabeusiv avatar skoslowski avatar stanislavlevin avatar tacaswell avatar the-compiler avatar tundish avatar vanadium23 avatar yili1992 avatar zac-hd avatar zejn avatar zmedico avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

execnet's Issues

Proxyed gateways not working over SSH

I am trying to run the "Simple Proxying" example with a master gw using SSH and get the following exception:

#!python

>>> import execnet
>>> group = execnet.Group()
>>> group.defaultspec = 'popen//via=master'
>>> master = group.makegateway('ssh=localhost//id=master')
>>> master
<Gateway id='master' receive-live, thread model, 0 active channels>
>>> slave = group.makegateway()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.3/site-packages/execnet/multi.py", line 122, in makegateway
    gw = gateway_bootstrap.bootstrap(proxy_io_master, spec)
  File "/usr/lib/python3.3/site-packages/execnet/gateway_bootstrap.py", line 86, in bootstrap
    bootstrap_popen(io, spec)
  File "/usr/lib/python3.3/site-packages/execnet/gateway_bootstrap.py", line 26, in bootstrap_popen
    s = io.read(1)
  File "/usr/lib/python3.3/site-packages/execnet/gateway_io.py", line 128, in read
    return self.iochan_file.read(nbytes)
  File "/usr/lib/python3.3/site-packages/execnet/gateway_base.py", line 855, in read
    self._buffer = self.channel.receive()
  File "/usr/lib/python3.3/site-packages/execnet/gateway_base.py", line 701, in receive
    raise self._getremoteerror() or EOFError()
execnet.gateway_base.RemoteError: Traceback (most recent call last):
  File "<string>", line 1029, in executetask
  File "<string>", line 1, in do_exec
  File "<remote exec>", line 210, in <module>
  File "<remote exec>", line 167, in serve_proxy_io
  File "<remote exec>", line 91, in create_io
  File "<remote exec>", line 17, in __init__
TypeError: __init__() got an unexpected keyword argument 'execmodel'


FYI: If I connect to a master without execnet installed it fails. That's not a problem I guess. I always liked it that execnet only needs be installed locally, though.

#!python

>>> slave = group.makegateway()
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 3, in <module>
ImportError: No module named execnet.gateway_base
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.3/site-packages/execnet/multi.py", line 122, in makegateway
    gw = gateway_bootstrap.bootstrap(proxy_io_master, spec)
  File "/usr/lib/python3.3/site-packages/execnet/gateway_bootstrap.py", line 86, in bootstrap
    bootstrap_popen(io, spec)
  File "/usr/lib/python3.3/site-packages/execnet/gateway_bootstrap.py", line 27, in bootstrap_popen
    assert s == "1".encode('ascii'), repr(s)
AssertionError: ''

new `TypeError` issues when closing the gateway

We are seeing new TypeError exceptions when the gateway closes. These are really hard to replicate but all too common now in the logs of our internal tests (that use the latest release of execnet, 1.2).

Unhandled exception in thread started by <function run_and_release at 0x7fa0becf3488>
Traceback (most recent call last):
File "/home/ubuntu/cephtest/ceph-deploy/ceph_deploy/lib/remoto/lib/execnet/gateway_base.py", line 245, in run_and_release
  with self._running_lock:
File "/usr/lib64/python2.6/threading.py", line 117, in acquire
  me = _get_ident()
TypeError: 'NoneType' object is not callable

On similar issues like this one, it was understood that the interpreter was shutting down so builtins would start being set to None, but this seems like is not the case even though the error is very similar (see Issue #22)

They appear when there is nothing else being executed remotely and the gateway is being closed.

sys.version_info is not serializable

When going through examples, I've got the DumpError on "Get information from remote ssh account" - http://codespeak.net/execnet/example/test_info.html#get-information-from-remote-ssh-account

The problem is that type of sys.version_info is not known to serializer, so can't be dumped. It would be easy to fix it by adding save_version_info to _Serializer class, however I doubt this is a reasonable approach. What is your opinion?

BTW: I suspect this is an easter bug in examples intended to encourage people to discover the problem with pdb and learn something about execnet :-)

Wrong license in the docs

doc/index.txt says:

The package is licensed under the GPL Version 2 or later, at your choice.

which is not correct anymore, as the package's license was changed to MIT recently.

On a related note, would it be possible to also change the license of doc/example/sysinfo.py to MIT - from a packager's pov it would be nice to have all files in the zipfile under the same license.

Redirecting stdout/stderr in the remote produces local warnings

Dear all,

I am using execnet to execute some code in a CPython 2.7 interpreter from a Java application running Jython. I am redirecting sys.stdout and sys.stderr in the remote with the following:

#!python
channel = gateway.remote_exec("""
import sys

outchan = channel.gateway.newchannel()
sys.stdout = outchan.makefile("w")
channel.send(outchan)
errchan = channel.gateway.newchannel()
sys.stderr = errchan.makefile("w")
channel.send(errchan)
""")
    
outchan = channel.receive()
errchan = channel.receive()
outchan.setcallback(lambda data: sys.stdout.write(str(data)))
errchan.setcallback(lambda data: sys.stderr.write(str(data)))

channel.waitclose()

When using this, what is printed by the remote is correctly redirected to the console of the local application. However, when the gateway is closed (with group.terminate() for example), I get the following warning:

close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr

This is not critical, but very annoying...
The warning message does not appear in the sys.stderr of the local application (nor in its sys.stdout) which is a special text window, but rather in the main console output of the application. So the 'close failed' seems to happen locally rather than on the remote.

Any idea ?

Thanks!

Test process hanging forever

We have a test job that uses pytest, xdist, execnet and it has been hanging forever on a regular basis.

Attaching in gdb it looks like it is waiting for a child but there is no child process. The relevant gdb python snippet:

threading.py: wait: 309
threading.py: wait: 603
execnet/gateway_base.py: waitall: 292
execnet/multi.py: safe_terminate: 277

In safe_terminate:

#!python
def safe_terminate(execmodel, timeout, list_of_paired_functions):
    # Snip some code
    workerpool.waitall()

If the timeout value that is passed into safe_terminate is passed into waitall then it will timeout and exit the pytest test run.

This is working for us.

pytest 2.6.4, xdist 1.11, execnet 1.2.0

We haven't used execnet 1.3.0 yet, but that version hasn't modified the above code.

test failures in execnet-1.2.0

under Python 2.7.8 and Python 3.3.5 and Python 3.4.0 and pypy;

================== test session starts =====================
doc/example/test_debug.txt .
doc/example/test_funcmultiplier.py .
doc/example/test_group.txt F
doc/example/test_multi.txt .
doc/example/test_proxy.txt F
doc/example/test_ssh_fileserver.txt .

========================= FAILURES ========================
_________________ [doctest] doc/example/test_group.txt __________
007 Use ``execnet.Group`` to manage membership and lifetime of
008 of multiple gateways::
009 
010     >>> import execnet
011     >>> group = execnet.Group(['popen'] * 2)
012     >>> len(group)
013     2
014     >>> group
015     <Group ['gw0', 'gw1']>
016     >>> list(group)
Expected:
    [<PopenGateway id='gw0' receive-live, 0 active channels>, <PopenGateway id='gw1' receive-live, 0 active channels>]
Got:
    [<Gateway id='gw0' receive-live, thread model, 0 active channels>, <Gateway id='gw1' receive-live, thread model, 0 active channels>]

/mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/doc/example/test_group.txt:16: DocTestFailure

_________________ [doctest] doc/example/test_proxy.txt ____________________
011 The simlest use case, is where one creates one master process
012 and uses it to controll new slaves and their environment
013 
014 ::
015 
016     >>> import execnet
017     >>> group = execnet.Group()
018     >>> group.defaultspec = 'popen//via=master'
019     >>> master = group.makegateway('popen//id=master')
020     >>> master
Expected:
    <Gateway id='master' receive-live, 0 active channels>
Got:
    <Gateway id='master' receive-live, thread model, 0 active channels>

/mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/doc/example/test_proxy.txt:20: DocTestFailure
============ short test summary info ==========================
XFAIL testing/test_multi.py::test_safe_terminate[thread]
  reason: execution model 'thread' does not support task count
XFAIL testing/test_multi.py::test_safe_terminate2[thread]
  reason: execution model 'thread' does not support task count
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[sys.executable-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python3.3-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python3.2-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python2.6-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python2.7-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[pypy-thread]
  reason: only os threading model supported
XFAIL testing/test_threadpool.py::test_limited_size[thread]
  WorkerPool does not implement limited size
SKIP [249] /mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/testing/conftest.py:177: could not import 'eventlet'
SKIP [53] /usr/lib64/pypy/site-packages/_pytest/config.py:835: no 'gspecs' option found
SKIP [1] /mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/testing/test_xspec.py:145: cpython2.5 not found
SKIP [12] /usr/lib64/pypy/site-packages/_pytest/skipping.py:143: condition: not hasattr(sys, 'getrefcount')
SKIP [17] /mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/testing/conftest.py:129: no jython found
SKIP [2] /usr/lib64/pypy/site-packages/_pytest/skipping.py:143: condition: sys.version<"3.0"
SKIP [5] /mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/testing/conftest.py:26: pypy tests skipped, use --pypy to run them.
SKIP [249] /mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/testing/conftest.py:177: could not import 'gevent'
======= 2 failed, 323 passed, 588 skipped, 9 xfailed in 52.42 seconds ==============

Py3.4 outputs these additional failures in test_channel.py

============================ FAILURES ==========================
______________________________ TestChannelBasicBehaviour.test_channel_error_reporting[popen-thread] ______________________________

self = <test_channel.TestChannelBasicBehaviour object at 0x7fc23c4d1f98>
gw = <Gateway id='popen' receive-live, thread model, 0 active channels>

    def test_channel_error_reporting(self, gw):
        channel = gw.remote_exec('def foo():\n  return foobar()\nfoo()\n')
        try:
            channel.receive()
        except channel.RemoteError:
            e = sys.exc_info()[1]
            assert str(e).startswith('Traceback (most recent call last):')
>           assert str(e).find('NameError: global name \'foobar\' '
                               'is not defined') > -1
E           assert -1 > -1
E            +  where -1 = <built-in method find of str object at 0x7fc23ebc8370>("NameError: global name 'foobar' is not defined")
E            +    where <built-in method find of str object at 0x7fc23ebc8370> = 'Traceback (most recent call last):\n  File "/mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0-pyth...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n'.find
E            +      where 'Traceback (most recent call last):\n  File "/mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0-pyth...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n' = str(RemoteError: Traceback (most recent call last):\n  File "/mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet...le "<remote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name 'foobar' is not defined\n)

testing/test_channel.py:76: AssertionError
_____________________________ TestChannelBasicBehaviour.test_channel_error_reporting[socket-thread] ______________________________

self = <test_channel.TestChannelBasicBehaviour object at 0x7fc23c4da320>
gw = <Gateway id='socket' receive-live, thread model, 0 active channels>

    def test_channel_error_reporting(self, gw):
        channel = gw.remote_exec('def foo():\n  return foobar()\nfoo()\n')
        try:
            channel.receive()
        except channel.RemoteError:
            e = sys.exc_info()[1]
            assert str(e).startswith('Traceback (most recent call last):')
>           assert str(e).find('NameError: global name \'foobar\' '
                               'is not defined') > -1
E           assert -1 > -1
E            +  where -1 = <built-in method find of str object at 0x7fc210028170>("NameError: global name 'foobar' is not defined")
E            +    where <built-in method find of str object at 0x7fc210028170> = 'Traceback (most recent call last):\n  File """"\nbase execnet gateway code send to the other side for bootstrapping.\...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n'.find
E            +      where 'Traceback (most recent call last):\n  File """"\nbase execnet gateway code send to the other side for bootstrapping.\...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n' = str(RemoteError: Traceback (most recent call last):\n  File """"\nbase execnet gateway code send to the other side for boots...le "<remote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name 'foobar' is not defined\n)

testing/test_channel.py:76: AssertionError
______________________________ TestChannelBasicBehaviour.test_channel_error_reporting[proxy-thread] ______________________________

self = <test_channel.TestChannelBasicBehaviour object at 0x7fc23c15beb8>
gw = <Gateway id='proxy' receive-live, thread model, 0 active channels>

    def test_channel_error_reporting(self, gw):
        channel = gw.remote_exec('def foo():\n  return foobar()\nfoo()\n')
        try:
            channel.receive()
        except channel.RemoteError:
            e = sys.exc_info()[1]
            assert str(e).startswith('Traceback (most recent call last):')
>           assert str(e).find('NameError: global name \'foobar\' '
                               'is not defined') > -1
E           assert -1 > -1
E            +  where -1 = <built-in method find of str object at 0x7fc23ebc8370>("NameError: global name 'foobar' is not defined")
E            +    where <built-in method find of str object at 0x7fc23ebc8370> = 'Traceback (most recent call last):\n  File "/mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0-pyth...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n'.find
E            +      where 'Traceback (most recent call last):\n  File "/mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0-pyth...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n' = str(RemoteError: Traceback (most recent call last):\n  File "/mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet...le "<remote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name 'foobar' is not defined\n)

testing/test_channel.py:76: AssertionError
===================== short test summary info =======================
XFAIL testing/test_multi.py::test_safe_terminate[thread]
  reason: execution model 'thread' does not support task count
XFAIL testing/test_multi.py::test_safe_terminate2[thread]
  reason: execution model 'thread' does not support task count
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[sys.executable-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python3.3-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python3.2-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python2.6-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python2.7-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[pypy-thread]
  reason: only os threading model supported
XFAIL testing/test_threadpool.py::test_limited_size[thread]
  WorkerPool does not implement limited size
SKIP [253] /mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/testing/conftest.py:177: could not import 'eventlet'
SKIP [54] /usr/lib64/python3.4/site-packages/_pytest/config.py:835: no 'gspecs' option found
SKIP [253] /mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/testing/conftest.py:177: could not import 'gevent'
SKIP [2] /usr/lib64/python3.4/site-packages/_pytest/skipping.py:143: condition: sys.version>="3.0"
SKIP [17] /mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/testing/conftest.py:129: no jython found
SKIP [5] /mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/testing/conftest.py:26: pypy tests skipped, use --pypy to run them.
SKIP [1] /mnt/gen2/TmpDir/portage/dev-python/execnet-1.2.0/work/execnet-1.2.0/testing/test_xspec.py:145: cpython2.5 not found
======== 3 failed, 323 passed, 585 skipped, 9 xfailed in 39.38 seconds =========

These are from a long established release. Can you replicate? Do you need any further info?

`import` changes to support vendorizing

We are kind of forced to include execnet in one of our tools to avoid packaging it for the wealth of distributions that we support, but execnet/__init__.py has some imports that
prevent its usage if it is not installed globally.

More specifically, these is the apipkg import that we had to modify so that it now looks like:

#!python

from . import apipkg

And then the call to init the modules becomes:

#!python

apipkg.initpkg(__name__, {

Would you consider making this change?

`HostNotFound` is raised when SSH reports a different problem

This is due to this line (gateway_bootstrap.py line 46) https://bitbucket.org/hpk42/execnet/src/9c14d7158790c3156c36ab720caa20273647967f/execnet/gateway_bootstrap.py?at=default#gateway_bootstrap.py-46

It tries to write and read back and catches the EOFError.

But trying to connect to SSH directly reports in:

#!

Permission denied (publickey).

Test failures with Python >=3.4

Execnet has 3 additional test failures with Python >=3.4.

$ PYTHONPATH="$(pwd)" py.test-3.4 testing
==================================================================== test session starts ====================================================================
platform linux -- Python 3.4.0 -- py-1.4.20 -- pytest-2.5.2
gateway test setup scope: session
execnet: /tmp/execnet/execnet/__init__.py -- 1.2.0
collected 916 items 

testing/test_basics.py ...................ss.....ss.....ss.......
testing/test_channel.py ..s...s...s...s...s...s...s...s...s.FFsF..s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s.
testing/test_gateway.py ..s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s......s.ss
testing/test_multi.py ..s.xx
testing/test_termination.py .....ss.xxxxxss
testing/test_threadpool.py ......x.......
testing/test_basics.py sssssssssssssssssssss
testing/test_channel.py ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
testing/test_gateway.py sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
testing/test_multi.py ssssss
testing/test_termination.py sssssssssssssss
testing/test_threadpool.py ssssssssssssss
testing/test_basics.py sssssssssssssssssssss
testing/test_channel.py ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
testing/test_gateway.py sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
testing/test_multi.py ssssss
testing/test_termination.py sssssssssssssss
testing/test_threadpool.py ssssssssssssss
testing/test_basics.py .....ss.....ss................ss..
testing/test_channel.py s.
testing/test_fixes.py ..
testing/test_gateway.py ............s.
testing/test_multi.py ..............
testing/test_rsync.py ...........
testing/test_serializer.py ...............
testing/test_termination.py ......ss
testing/test_xspec.py .....................ss.

========================================================================= FAILURES ==========================================================================
___________________________________________ TestChannelBasicBehaviour.test_channel_error_reporting[popen-thread] ____________________________________________

self = <test_channel.TestChannelBasicBehaviour object at 0x7f447787e6a0>, gw = <Gateway id='popen' receive-live, thread model, 0 active channels>

    def test_channel_error_reporting(self, gw):
        channel = gw.remote_exec('def foo():\n  return foobar()\nfoo()\n')
        try:
            channel.receive()
        except channel.RemoteError:
            e = sys.exc_info()[1]
            assert str(e).startswith('Traceback (most recent call last):')
>           assert str(e).find('NameError: global name \'foobar\' '
                               'is not defined') > -1
E           assert -1 > -1
E            +  where -1 = <built-in method find of str object at 0x7f447803ab30>("NameError: global name 'foobar' is not defined")
E            +    where <built-in method find of str object at 0x7f447803ab30> = 'Traceback (most recent call last):\n  File "/tmp/execnet/execnet/gateway_base.py", line 1029, in executetask\n    do_...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n'.find
E            +      where 'Traceback (most recent call last):\n  File "/tmp/execnet/execnet/gateway_base.py", line 1029, in executetask\n    do_...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n' = str(RemoteError: Traceback (most recent call last):\n  File "/tmp/execnet/execnet/gateway_base.py", line 1029, in executeta...le "<remote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name 'foobar' is not defined\n)

testing/test_channel.py:76: AssertionError
___________________________________________ TestChannelBasicBehaviour.test_channel_error_reporting[socket-thread] ___________________________________________

self = <test_channel.TestChannelBasicBehaviour object at 0x7f44746cc828>, gw = <Gateway id='socket' receive-live, thread model, 0 active channels>

    def test_channel_error_reporting(self, gw):
        channel = gw.remote_exec('def foo():\n  return foobar()\nfoo()\n')
        try:
            channel.receive()
        except channel.RemoteError:
            e = sys.exc_info()[1]
            assert str(e).startswith('Traceback (most recent call last):')
>           assert str(e).find('NameError: global name \'foobar\' '
                               'is not defined') > -1
E           assert -1 > -1
E            +  where -1 = <built-in method find of str object at 0x7f446c027240>("NameError: global name 'foobar' is not defined")
E            +    where <built-in method find of str object at 0x7f446c027240> = 'Traceback (most recent call last):\n  File """"\nbase execnet gateway code send to the other side for bootstrapping.\...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n'.find
E            +      where 'Traceback (most recent call last):\n  File """"\nbase execnet gateway code send to the other side for bootstrapping.\...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n' = str(RemoteError: Traceback (most recent call last):\n  File """"\nbase execnet gateway code send to the other side for boots...le "<remote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name 'foobar' is not defined\n)

testing/test_channel.py:76: AssertionError

self = <test_channel.TestChannelBasicBehaviour object at 0x7f447461df28>, gw = <Gateway id='proxy' receive-live, thread model, 0 active channels>

    def test_channel_error_reporting(self, gw):
        channel = gw.remote_exec('def foo():\n  return foobar()\nfoo()\n')
        try:
            channel.receive()
        except channel.RemoteError:
            e = sys.exc_info()[1]
            assert str(e).startswith('Traceback (most recent call last):')
>           assert str(e).find('NameError: global name \'foobar\' '
                               'is not defined') > -1
E           assert -1 > -1
E            +  where -1 = <built-in method find of str object at 0x7f447803adf0>("NameError: global name 'foobar' is not defined")
E            +    where <built-in method find of str object at 0x7f447803adf0> = 'Traceback (most recent call last):\n  File "/tmp/execnet/execnet/gateway_base.py", line 1029, in executetask\n    do_...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n'.find
E            +      where 'Traceback (most recent call last):\n  File "/tmp/execnet/execnet/gateway_base.py", line 1029, in executetask\n    do_...emote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name \'foobar\' is not defined\n' = str(RemoteError: Traceback (most recent call last):\n  File "/tmp/execnet/execnet/gateway_base.py", line 1029, in executeta...le "<remote exec>", line 3, in <module>\n  File "<remote exec>", line 2, in foo\nNameError: name 'foobar' is not defined\n)

testing/test_channel.py:76: AssertionError
================================================================== short test summary info ==================================================================
XFAIL testing/test_multi.py::test_safe_terminate[thread]
  reason: execution model 'thread' does not support task count
XFAIL testing/test_multi.py::test_safe_terminate2[thread]
  reason: execution model 'thread' does not support task count
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[sys.executable-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python3.3-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python3.2-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python2.6-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python2.7-thread]
  reason: only os threading model supported
XFAIL testing/test_threadpool.py::test_limited_size[thread]
  WorkerPool does not implement limited size
SKIP [249] /tmp/execnet/testing/conftest.py:177: could not import 'gevent'
SKIP [249] /tmp/execnet/testing/conftest.py:177: could not import 'eventlet'
SKIP [54] /tmp/execnet/testing/conftest.py:66: no 'gspecs' value found
SKIP [17] /tmp/execnet/testing/conftest.py:129: no jython found
SKIP [2] /usr/lib64/python3.4/site-packages/_pytest/skipping.py:132: condition: sys.version>="3.0"
SKIP [17] /tmp/execnet/testing/conftest.py:129: no pypy found
=============================================== 3 failed, 317 passed, 588 skipped, 8 xfailed in 47.23 seconds ===============================================

linux to window communication

I have installed Win32-OpenSSH on Windows VPS on aws using this steps. I am able to ssh into remote window machine from terminal. I have copied my .pub key into remote authorized_key file, and I am able ssh without password from terminal.

Now I want to do this using execnet.
My code is as follows.

#!python

import execnet
gw = execnet.makegateway("ssh=ipaddress")

Now the problem

  • Asks for password
  • Throws following error
#!python

buffer_get_ret: trying to get more bytes 1 than in buffer 0
buffer_get_char_ret: buffer_get_ret failed
buffer_get_char: buffer error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/execnet/multi.py", line 130, in makegateway
    gw = gateway_bootstrap.bootstrap(io, spec)
  File "/usr/local/lib/python2.7/dist-packages/execnet/gateway_bootstrap.py", line 94, in bootstrap
    bootstrap_exec(io, spec)
  File "/usr/local/lib/python2.7/dist-packages/execnet/gateway_bootstrap.py", line 46, in bootstrap_exec
    raise HostNotFound(io.remoteaddress)
execnet.gateway_bootstrap.HostNotFound: <IP ADDRESS HERE>

actual exception in bootstrap_exec function is

#!python

expected 1 bytes, got 0

allow positional arguments for remote_exec (?)

If I have a function with a few arguments, like:

def foo(arg1, arg2):
    ...

I cannot pass the arguments to remote_exec as (foo, arg1, arg2) because it insists in having them as keyword arguments:

TypeError: remote_exec() takes exactly 2 arguments (3 given)

It would be really nice to be able to pass in arguments as well as keyword arguments

Running pytest --pep8 raises "ValueError: invalid literal for long() with base 10"

Since upgrading to version 1.4.0, running "pytest --pep8" fails before even starting the tests, with the following error trace.

Note the sequence of weird symbols at the end of the trace.

I cannot use pytest --pep8 anymore since this issue. Reverting to version 1.3.0 solves the issue.

INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/home/me/venv/local/lib/python2.7/site-packages/_pytest/main.py", line 82, in wrap_session
INTERNALERROR>     config.hook.pytest_sessionstart(session=session)
INTERNALERROR>   File "/home/me/venv/local/lib/python2.7/site-packages/_pytest/core.py", line 521, in __call__
INTERNALERROR>     return self._docall(self.methods, kwargs)
INTERNALERROR>   File "/home/me/venv/local/lib/python2.7/site-packages/_pytest/core.py", line 528, in _docall
INTERNALERROR>     firstresult=self.firstresult).execute()
INTERNALERROR>   File "/home/me/venv/local/lib/python2.7/site-packages/_pytest/core.py", line 394, in execute
INTERNALERROR>     res = method(*args)
INTERNALERROR>   File "/home/me/venv/local/lib/python2.7/site-packages/pytest_flakes.py", line 37, in pytest_sessionstart
INTERNALERROR>     config._flakesmtimes = config.cache.get(HISTKEY, {})
INTERNALERROR>   File "/home/me/venv/local/lib/python2.7/site-packages/pytest_cache.py", line 87, in get
INTERNALERROR>     return loads(f.read())
INTERNALERROR>   File "/home/me/venv/local/lib/python2.7/site-packages/execnet/gateway_base.py", line 1332, in loads
INTERNALERROR>     py3str_as_py2str=py3str_as_py2str)
INTERNALERROR>   File "/home/me/venv/local/lib/python2.7/site-packages/execnet/gateway_base.py", line 1341, in load
INTERNALERROR>     return Unserializer(io, strconfig=strconfig).load(versioned=True)
INTERNALERROR>   File "/home/me/venv/local/lib/python2.7/site-packages/execnet/gateway_base.py", line 1161, in load
INTERNALERROR>     loader(self)
INTERNALERROR>   File "/home/me/venv/local/lib/python2.7/site-packages/execnet/gateway_base.py", line 1196, in load_longlong
INTERNALERROR>     self.stack.append(long(l))
INTERNALERROR> ValueError: invalid literal for long() with base 10: 'L/home/me/repos/Project/myproject/module/submodule/missing_stuff.pyDA\xd5r\xcb\xb3z\xac\x88O'

(project has been renamed)

Test failure with enabled warnings

Execnet has 1 additional test failure with Python >=3.2 and enabled warnings (using e.g. PYTHONWARNINGS="d,i::ImportWarning" environmental variable) due to unexpected ResourceWarning in stderr.

$ PYTHONPATH="$(pwd)" PYTHONWARNINGS="d,i::ImportWarning" py.test-3.3 testing
==================================================================== test session starts ====================================================================
platform linux -- Python 3.3.5 -- py-1.4.20 -- pytest-2.5.2
gateway test setup scope: session
execnet: /tmp/execnet/execnet/__init__.py -- 1.2.0
collected 916 items 

testing/test_basics.py ...................ss.....ss.....ss.F.....
testing/test_channel.py ..s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s.
testing/test_gateway.py ..s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s...s......s.ss
testing/test_multi.py ..s.xx
testing/test_termination.py .....ss.xxxxxss
testing/test_threadpool.py ......x.......
testing/test_basics.py sssssssssssssssssssss
testing/test_channel.py ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
testing/test_gateway.py sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
testing/test_multi.py ssssss
testing/test_termination.py sssssssssssssss
testing/test_threadpool.py ssssssssssssss
testing/test_basics.py sssssssssssssssssssss
testing/test_channel.py ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
testing/test_gateway.py sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
testing/test_multi.py ssssss
testing/test_termination.py sssssssssssssss
testing/test_threadpool.py ssssssssssssss
testing/test_basics.py .....ss.....ss................ss..
testing/test_channel.py s.
testing/test_fixes.py ..
testing/test_gateway.py ............s.
testing/test_multi.py ..............
testing/test_rsync.py ...........
testing/test_serializer.py ...............
testing/test_termination.py ......ss
testing/test_xspec.py .....................ss.

========================================================================= FAILURES ==========================================================================
_____________________________________________________________ test_stdouterrin_setnull[thread] ______________________________________________________________

execmodel = <ExecModel 'thread'>

    @pytest.mark.skipif("not hasattr(os, 'dup')")                                                                                                            
    def test_stdouterrin_setnull(execmodel):                                                                                                                 
        cap = py.io.StdCaptureFD()                                                                                                                           
        gateway_base.init_popen_io(execmodel)                                                                                                                
        os.write(1, "hello".encode('ascii'))                                                                                                                 
        if os.name == "nt":                                                                                                                                  
            os.write(2, "world")
        os.read(0, 1)
        out, err = cap.reset()
        assert not out
>       assert not err
E       assert not "/tmp/execnet/testing/test_basics.py:196: ResourceWarning: unclosed file <_io.TextIOWrapper name=13 mode='r' encoding=...file <_io.TextIOWrapper name=1 mode='w' encoding='UTF-8'>\n  setattr(sys, patchsysdict[self.targetfd], self._oldsys)\n"

testing/test_basics.py:203: AssertionError
---------------------------------------------------------------------- Captured stderr ----------------------------------------------------------------------
/usr/lib64/python3.3/site-packages/py/_io/capture.py:77: ResourceWarning: unclosed file <_io.TextIOWrapper name=0 mode='r' encoding='UTF-8'>
  setattr(sys, patchsysdict[self.targetfd], self._oldsys)
================================================================== short test summary info ==================================================================
XFAIL testing/test_multi.py::test_safe_terminate[thread]
  reason: execution model 'thread' does not support task count
XFAIL testing/test_multi.py::test_safe_terminate2[thread]
  reason: execution model 'thread' does not support task count
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[sys.executable-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python3.3-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python3.2-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python2.6-thread]
  reason: only os threading model supported
XFAIL testing/test_termination.py::test_terminate_implicit_does_trykill[python2.7-thread]
  reason: only os threading model supported
XFAIL testing/test_threadpool.py::test_limited_size[thread]
  WorkerPool does not implement limited size
SKIP [54] /tmp/execnet/testing/conftest.py:66: no 'gspecs' value found
SKIP [2] /usr/lib64/python3.3/site-packages/_pytest/skipping.py:132: condition: sys.version>="3.0"
SKIP [249] /tmp/execnet/testing/conftest.py:177: could not import 'eventlet'
SKIP [17] /tmp/execnet/testing/conftest.py:129: no pypy found
SKIP [17] /tmp/execnet/testing/conftest.py:129: no jython found
SKIP [249] /tmp/execnet/testing/conftest.py:177: could not import 'gevent'
=============================================== 1 failed, 319 passed, 588 skipped, 8 xfailed in 48.32 seconds ===============================================
sys:1: ResourceWarning: unclosed <socket.socket object, fd=17, family=2, type=1, proto=0>
sys:1: ResourceWarning: gc: 4 uncollectable objects at shutdown; use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list them

Rsync should be optional

Hi Holger Krekel,
I have been using pytest for last one month, and have explored lots of plugins, its really a great and easy framework to understand,but i have a concern that was unable to find any good plugin where i can test my directory mounted on NFS through a remote machine. I feel like rsync option should be optional, so the remote machine can be used for testing without any rsync option. Also it will be good if pytest-xdist distributes test per file based and not per function. Thanks

test_dont_write_bytecode assumes that bytecode writing is enabled

  • Bitbucket: https://bitbucket.org/hpk42/execnet/issue/10

  • Originally reported by: @mgorny

  • Originally created at: 2013-01-20T00:04:00.230

    @py.test.mark.skipif('sys.version_info < (2, 6)')
    def test_dont_write_bytecode(self, makegateway):
    check_sys_dont_write_bytecode = """
    import sys
    channel.send(sys.dont_write_bytecode)
    """

      gw = makegateway('popen')
      channel = gw.remote_exec(check_sys_dont_write_bytecode)
      ret = channel.receive()
      assert not ret
      gw = makegateway('popen//dont_write_bytecode')
      channel = gw.remote_exec(check_sys_dont_write_bytecode)
      ret = channel.receive()
      assert ret
    

Long story short, this test assumes that bytecode compiling is enabled unless explicitly disabled in the makegateway() call. Therefore, it fails when the tests are run with PYTHONDONTWRITEBYTECODE environment variable set and bytecode compiling is disabled in both cases.

I'm not sure how to fix this. I'm not sure if enabling bytecode compiling when user disabled it is a good idea. Another solution would be to skip the test if bytecode compiling is disabled in the parent process.

py33 tests break related to proxy on trunk

$ tox -e py32 testing/test_channel.py -- -k 'not(jython)' -v -x

gives:

#!python

GLOB sdist-make: /home/hpk/p/execnet/setup.py
py32 inst-nodeps: /home/hpk/p/execnet/.tox/dist/execnet-1.1.1dev5.zip
py32 runtests: commands[0] | py.test -rsfxX --junitxml=/home/hpk/p/execnet/.tox/py32/log/junit-py32.xml test_channel.py -k not(jython) -v -x
==================================== test session starts ====================================
platform linux2 -- Python 3.2.3 -- pytest-2.3.5 -- /home/hpk/p/execnet/.tox/py32/bin/python3.2
gateway test setup scope: session
execnet: /home/hpk/p/execnet/execnet/__init__.py -- 1.1.1dev5
plugins: timeout
collected 122 items 

test_channel.py:15: TestChannelBasicBehaviour.test_serialize_error[popen] PASSED
test_channel.py:15: TestChannelBasicBehaviour.test_serialize_error[socket] PASSED
test_channel.py:15: TestChannelBasicBehaviour.test_serialize_error[ssh] SKIPPED
test_channel.py:15: TestChannelBasicBehaviour.test_serialize_error[proxy] PASSED
test_channel.py:15: TestChannelBasicBehaviour.test_serialize_error[proxy] ERROR

========================================== ERRORS ===========================================
________ ERROR at teardown of TestChannelBasicBehaviour.test_serialize_error[proxy] _________

group = <Group ['proxy-transport']>

>   teardown=lambda group: group.terminate(timeout=1),
    extrakey="testgroup",
    scope=scope,
        )

../conftest.py:131: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <Group ['proxy-transport']>, timeout = 1

    def terminate(self, timeout=None):
        """ trigger exit of member gateways and wait for termination
            of member gateways and associated subprocesses.  After waiting
            timeout seconds try to to kill local sub processes of popen-
            and ssh-gateways.  Timeout defaults to None meaning
            open-ended waiting and no kill attempts.
            """
    
        while self:
            from execnet.threadpool import WorkerPool
            vias = {}
            for gw in self:
                if gw.spec.via:
                    vias[gw.spec.via] = True
            for gw in self:
                if gw.id not in vias:
                    gw.exit()
    
            def join_wait(gw):
                gw.join()
                gw._io.wait()
            def kill(gw):
                trace("Gateways did not come down after timeout: %r" % gw)
                gw._io.kill()
    
            safe_terminate(timeout, [
                (lambda: join_wait(gw), lambda: kill(gw))
>               for gw in self._gateways_to_join])

../execnet/multi.py:168: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

timeout = 1
list_of_paired_functions = [(<function <lambda> at 0x3184d10>, <function <lambda> at 0x3184d98>)]

    def safe_terminate(timeout, list_of_paired_functions):
        workerpool = WorkerPool(len(list_of_paired_functions)*2)
    
        def termkill(termfunc, killfunc):
            termreply = workerpool.dispatch(termfunc)
            try:
                termreply.get(timeout=timeout)
            except IOError:
                killfunc()
    
        replylist = []
        for termfunc, killfunc in list_of_paired_functions:
            reply = workerpool.dispatch(termkill, termfunc, killfunc)
            replylist.append(reply)
        for reply in replylist:
            reply.get()
        workerpool.shutdown()
>       workerpool.join()

../execnet/multi.py:256: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <execnet.threadpool.WorkerPool object at 0x318db90>, timeout = None

    def join(self, timeout=None):
        """ wait until all worker threads have terminated. """
        current = threading.currentThread()
        deadline = delta = None
        if timeout is not None:
            deadline = time.time() + timeout
        for thread in list(self._alive):
            if deadline:
                delta = deadline - time.time()
                if delta <= 0:
                    raise IOError("timeout while joining threads")
>           thread.join(timeout=delta)

../execnet/threadpool.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <WorkerThread(Thread-8, started daemon 140035077621504)>, timeout = None

    def join(self, timeout=None):
        if not self._initialized:
            raise RuntimeError("Thread.__init__() not called")
        if not self._started.is_set():
            raise RuntimeError("cannot join thread before it is started")
        if self is current_thread():
            raise RuntimeError("cannot join current thread")
    
        if __debug__:
            if not self._stopped:
                self._note("%s.join(): waiting until thread stops", self)
    
        self._block.acquire()
        try:
            if timeout is None:
                while not self._stopped:
>                   self._block.wait()

../../../.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py:854: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <Condition(<_thread.lock object at 0x3188890>, 1)>, timeout = None

    def wait(self, timeout=None):
        if not self._is_owned():
            raise RuntimeError("cannot wait on un-acquired lock")
        waiter = _allocate_lock()
        waiter.acquire()
        self._waiters.append(waiter)
        saved_state = self._release_save()
        try:    # restore state no matter what (e.g., KeyboardInterrupt)
            if timeout is None:
>               waiter.acquire()
E               Failed: Timeout >20s

../../../.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py:235: Failed
-------------------------------------- Captured stderr --------------------------------------
Exception in thread io-forward-proxy:
Traceback (most recent call last):
  File "/home/hpk/p/execnet/execnet/gateway_base.py", line 121, in from_io
    header = io.read(9) # type 1, channel 4, payload 4
  File "/home/hpk/p/execnet/execnet/gateway_base.py", line 93, in read
    raise EOFError("expected %d bytes, got %d" %(numbytes, len(buf)))
EOFError: expected 9 bytes, got 0

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 740, in _bootstrap_inner
    self.run()
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 693, in run
    self._target(*self._args, **self._kwargs)
  File "", line 149, in iothread
  File "/home/hpk/p/execnet/execnet/gateway_base.py", line 124, in from_io
    raise EOFError('couldnt load message header, ' + e.args[0])
EOFError: couldnt load message header, expected 9 bytes, got 0


+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++

~~~~~~~~~~~~~~~~~~~~~ Stack of Thread-8 (140035077621504) ~~~~~~~~~~~~~~~~~~~~~~
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 713, in _bootstrap
    self._bootstrap_inner()
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 740, in _bootstrap_inner
    self.run()
  File "/home/hpk/p/execnet/execnet/threadpool.py", line 84, in run
    while self._run_once():
  File "/home/hpk/p/execnet/execnet/threadpool.py", line 72, in _run_once
    result = func(*args, **kwargs)
  File "/home/hpk/p/execnet/execnet/multi.py", line 167, in <lambda>
    (lambda: join_wait(gw), lambda: kill(gw))
  File "/home/hpk/p/execnet/execnet/multi.py", line 160, in join_wait
    gw.join()
  File "/home/hpk/p/execnet/execnet/gateway_base.py", line 735, in join
    self._receiverthread.join(timeout)
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 854, in join
    self._block.wait()
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 235, in wait
    waiter.acquire()

~~~~~~~~~~~~~~~~~~~~~ Stack of receiver (140035086014208) ~~~~~~~~~~~~~~~~~~~~~~
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 713, in _bootstrap
    self._bootstrap_inner()
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 740, in _bootstrap_inner
    self.run()
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 693, in run
    self._target(*self._args, **self._kwargs)
  File "/home/hpk/p/execnet/execnet/gateway_base.py", line 674, in _thread_receiver
    msg = Message.from_io(io)
  File "/home/hpk/p/execnet/execnet/gateway_base.py", line 121, in from_io
    header = io.read(9) # type 1, channel 4, payload 4
  File "/home/hpk/p/execnet/execnet/gateway_io.py", line 111, in read
    return self.io.read(nbytes)
  File "/home/hpk/p/execnet/execnet/gateway_base.py", line 615, in read
    self._buffer += self.channel.receive()
  File "/home/hpk/p/execnet/execnet/gateway_base.py", line 445, in receive
    x = itemqueue.get(timeout=internal_timeout)
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/queue.py", line 194, in get
    self.not_empty.wait(remaining)
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 241, in wait
    gotit = waiter.acquire(True, timeout)

~~~~~~~~~~~~~~~~~~~~~ Stack of receiver (140035101587200) ~~~~~~~~~~~~~~~~~~~~~~
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 713, in _bootstrap
    self._bootstrap_inner()
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 740, in _bootstrap_inner
    self.run()
  File "/home/hpk/.pythonbrew/pythons/Python-3.2.3/lib/python3.2/threading.py", line 693, in run
    self._target(*self._args, **self._kwargs)
  File "/home/hpk/p/execnet/execnet/gateway_base.py", line 674, in _thread_receiver
    msg = Message.from_io(io)
  File "/home/hpk/p/execnet/execnet/gateway_base.py", line 121, in from_io
    header = io.read(9) # type 1, channel 4, payload 4
  File "/home/hpk/p/execnet/execnet/gateway_base.py", line 91, in read
    data = self._read(numbytes-len(buf))

+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++
----------- generated xml file: /home/hpk/p/execnet/.tox/py32/log/junit-py32.xml ------------
================================== short test summary info ==================================
SKIP [1] /home/hpk/p/execnet/conftest.py:64: no 'gspecs' value found
!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
======================= 3 passed, 1 skipped, 1 error in 20.21 seconds =======================
ERROR: InvocationError: '/home/hpk/p/execnet/.tox/py32/bin/py.test -rsfxX --junitxml=/home/hpk/p/execnet/.tox/py32/log/junit-py32.xml test_channel.py -k not(jython) -v -x'
___________________________________

Can we have alternative SSH commandline support?

I'm currently trying to make batou deploy to vagrant installations more smoothly, especially as their SSH config / key exchange procedure has improved (changed incompatibly) in the last versions.

Here's a monkeypatch I'm currently working with:

def new_ssh_args(spec):
    from execnet.gateway_io import popen_bootstrapline
    remotepython = spec.python or 'python'
    import pdb; pdb.set_trace()
    if spec.type == 'vagrant':
        args = ['vagrant', 'ssh', spec.ssh, '--', '-C']
    else:
        args = ['ssh', '-C']
    if spec.ssh_config is not None:
        args.extend(['-F', str(spec.ssh_config)])
    remotecmd = '%s -c "%s"' %(remotepython, popen_bootstrapline)
    if spec.type == 'vagrant':
        args.extend([remotecmd])
    else:
        args.extend([spec.ssh, remotecmd])
    print args
    return args

import execnet.gateway_io
execnet.gateway_io.ssh_args = new_ssh_args

This means I can now do:

execnet.makegateway(
            "ssh=default//python=python2.7//type=vagrant")

Which results in

$ vagrant ssh default -- -C python2.7 ...

Not sure which way you think might be the best integration to get this into execnet itself. Unfortunately a prefix isn't enough as we need to pass the '--' and the hostname at a different place.

I'd be willing to work on a patch if given some direction.

Execnet 1.4 not backward compatible

The latest execnet version is not backward compatible. It is breaking devpi which is using execnet to write data to its keyfs.

Bug report with reproducing script: https://bitbucket.org/hpk42/devpi/issues/263/cant-attach-new-replica-to-long-running (there are other ways to run into a similar error).

Expectation:

  • either execnet declares in its changelog that is is backwards incompatible
  • or the compatibility is restored in a bugfix release

AssertionError in taskserver.py (on Jython 2.7)

Dear all,

I am testing the use of execnet as a way to dispatch numerical computations from a Java application, where Jython is embedded, to a pool of CPython interpreters, where Numpy is available. taskserver.py, as found in the doc, seems to be the perfect starting point. Unfortunately, it randomly fails once in a while with the following exception:

Exception in thread Thread-316:Traceback (most recent call last):
File ".../Lib/threading.py", line 189, in _Thread__bootstrap
self.run()
File ".../Lib/site-packages/execnet/threadpool.py", line 84, in run
while self._run_once():
File ".../Lib/site-packages/execnet/threadpool.py", line 68, in _run_once
assert self not in self._pool._ready
AssertionError

This is with execnet 1.1, the remote python is CPython 2.6.1, the local python is Jython 2.7beta, from the git repository of a few weeks ago. I don't think it's related to Jython directly, but rather to the fact that there is no GIL in Jython, so this is likely a threading error that never appeared under CPython...

Any help will be greatly appreciated !

Best regards,

Timothรฉe

Unhandled error in sys.excepthook

After closing the connections we are seeing a few thread errors that seem impossible to get rid of. At the point where they are sent to stderr there is nothing left running and the code has closed the gateway.

Unhandled exception in thread started by
Error in sys.excepthook:

Original exception was:

Running execnet with debug show this:

[53488] gw0 [receiver-thread] RECEIVERTHREAD: starting to run
[53488] gw0 sent <Message.CHANNEL_EXEC channelid=1 len=6354>
[53488] gw0 sent <Message.CHANNEL_DATA channelid=1 'platform_information()'>
[53488] gw0 [receiver-thread] received <Message.CHANNEL_DATA channelid=1 ('Ubuntu', '12.04', 'precise')>
[53488] gw0 sent <Message.CHANNEL_DATA channelid=1 'machine_type()'>
[53488] gw0 [receiver-thread] received <Message.CHANNEL_DATA channelid=1 'x86_64'>
[53488] gw0 sent <Message.CHANNEL_DATA channelid=1 'shortname()'>
[53488] gw0 [receiver-thread] received <Message.CHANNEL_DATA channelid=1 'node1'>
[53488] gw0 sent <Message.CHANNEL_DATA channelid=1 len=324>
[53488] gw0 [receiver-thread] received <Message.CHANNEL_DATA channelid=1 None>
[53488] gw0 sent <Message.CHANNEL_DATA channelid=1 len=127>
[53488] gw0 [receiver-thread] received <Message.CHANNEL_DATA channelid=1 None>
[53488] gw0 gateway.exit() called
[53488] gw0 --> sending GATEWAY_TERMINATE
[53488] gw0 --> io.close_write
[53488] gw0 [receiver-thread] EOF without prior gateway termination message
[53488] gw0 [receiver-thread] entering finalization
[53488] gw0 finished receiving
[53488] gw0 [receiver-thread] terminating execution
[53488] gw0 [receiver-thread] closing read
[53488] gw0 [receiver-thread] closing write
[53488] gw0 [receiver-thread] leaving finalization
[53488] gw1 [receiver-thread] RECEIVERTHREAD: starting to run
[53488] gw1 sent <Message.CHANNEL_EXEC channelid=1 len=6354>
[53488] gw1 sent <Message.CHANNEL_DATA channelid=1 'platform_information()'>
[53488] gw1 [receiver-thread] received <Message.CHANNEL_DATA channelid=1 ('CentOS', '6.4', 'Final')>
[53488] gw1 sent <Message.CHANNEL_DATA channelid=1 'machine_type()'>
[53488] gw1 [receiver-thread] received <Message.CHANNEL_DATA channelid=1 'x86_64'>
[53488] gw1 sent <Message.CHANNEL_DATA channelid=1 'shortname()'>
[53488] gw1 [receiver-thread] received <Message.CHANNEL_DATA channelid=1 'node2'>
[53488] gw1 sent <Message.CHANNEL_DATA channelid=1 len=324>
[53488] gw1 [receiver-thread] received <Message.CHANNEL_DATA channelid=1 None>
[53488] gw1 sent <Message.CHANNEL_DATA channelid=1 len=127>
[53488] gw1 [receiver-thread] received <Message.CHANNEL_DATA channelid=1 None>
[53488] gw1 gateway.exit() called
[53488] gw1 --> sending GATEWAY_TERMINATE
[53488] gw1 --> io.close_write
[53488] === atexit cleanup <Group []> ===
[53488] gw0 1 channel.__del__
[53488] gw1 1 channel.__del__
Unhandled exception in thread started by
Error in sys.excepthook:

Original exception was:

It looks as though this is happening in the threading module in Python itself. I am not sure something is possible to eat up these messages.

There is a ticket open in the Python bug tracker that mentions this problem is closed:

http://bugs.python.org/issue1722344

One of the patches that one commenter added looks like what we would need to get rid of them (http://bugs.python.org/file9356/1722344_squelch_exception.patch)

--- /usr/lib/python2.5/threading.py.orig	2008-02-04 13:58:18.000000000 -0600
+++ ./threading.py	2008-02-05 11:55:33.000000000 -0600
@@ -472,34 +472,18 @@
                     _sys.stderr.write("Exception in thread %s:\n%s\n" %
                                       (self.getName(), _format_exc()))
                 else:
-                    # Do the best job possible w/o a huge amt. of code to
-                    # approximate a traceback (code ideas from
-                    # Lib/traceback.py)
-                    exc_type, exc_value, exc_tb = self.__exc_info()
-                    try:
-                        print>>self.__stderr, (
-                            "Exception in thread " + self.getName() +
-                            " (most likely raised during interpreter shutdown):")
-                        print>>self.__stderr, (
-                            "Traceback (most recent call last):")
-                        while exc_tb:
-                            print>>self.__stderr, (
-                                '  File "%s", line %s, in %s' %
-                                (exc_tb.tb_frame.f_code.co_filename,
-                                    exc_tb.tb_lineno,
-                                    exc_tb.tb_frame.f_code.co_name))
-                            exc_tb = exc_tb.tb_next
-                        print>>self.__stderr, ("%s: %s" % (exc_type, exc_value))
-                    # Make sure that exc_tb gets deleted since it is a memory
-                    # hog; deleting everything else is just for thoroughness
-                    finally:
-                        del exc_type, exc_value, exc_tb
+                    # If _sys is missing, then the interpreter is shutting
+                    # down and the thread should no longer exist.  If this
+                    # happens, ignore the error and exit gracefully.
+                    pass
             else:
                 if __debug__:
                     self._note("%s.__bootstrap(): normal return", self)
         finally:
-            self.__stop()
+            # Exceptions will also be raised during stop/delete if the
+            # interpreter is shutting down.  Ignore these as well.
             try:
+                self.__stop()
                 self.__delete()
             except:
                 pass

DeprecationWarning on Python 3.5

I've just added a DeprecationWarning to be able to catch deprecations introduced in new pytest. I'm running tests with xdist and this I get on python 3.5 with pytest-xdist.

platform linux -- Python 3.5.2, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- /home/travis/virtualenv/python3.5.2/bin/python
cachedir: .cache
rootdir: /home/travis/build/ClearcodeHQ/pytest-elasticsearch, inifile: pytest.ini
plugins: xdist-1.15.0, cov-2.4.0, pylama-7.1.0, elasticsearch-1.1.0
gw0 IINTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/_pytest/main.py", line 94, in wrap_session
INTERNALERROR>     config.hook.pytest_sessionstart(session=session)
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 745, in __call__
INTERNALERROR>     return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 339, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 334, in <lambda>
INTERNALERROR>     _MultiCall(methods, kwargs, hook.spec_opts).execute()
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 614, in execute
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/xdist/dsession.py", line 509, in pytest_sessionstart
INTERNALERROR>     nodes = self.nodemanager.setup_nodes(putevent=self.queue.put)
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/xdist/slavemanage.py", line 48, in setup_nodes
INTERNALERROR>     nodes.append(self.setup_node(spec, putevent))
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/xdist/slavemanage.py", line 53, in setup_node
INTERNALERROR>     self.config.hook.pytest_xdist_newgateway(gateway=gw)
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 745, in __call__
INTERNALERROR>     return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 339, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 334, in <lambda>
INTERNALERROR>     _MultiCall(methods, kwargs, hook.spec_opts).execute()
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py", line 614, in execute
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/xdist/dsession.py", line 763, in pytest_xdist_newgateway
INTERNALERROR>     rinfo = gateway._rinfo()
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/execnet/gateway.py", line 79, in _rinfo
INTERNALERROR>     ch = self.remote_exec(rinfo_source)
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/execnet/gateway.py", line 119, in remote_exec
INTERNALERROR>     source = _source_of_function(source)
INTERNALERROR>   File "/home/travis/virtualenv/python3.5.2/lib/python3.5/site-packages/execnet/gateway.py", line 186, in _source_of_function
INTERNALERROR>     args, varargs, keywords, defaults = inspect.getargspec(function)
INTERNALERROR>   File "/opt/python/3.5.2/lib/python3.5/inspect.py", line 1041, in getargspec
INTERNALERROR>     stacklevel=2)
INTERNALERROR> DeprecationWarning: inspect.getargspec() is deprecated, use inspect.signature() instead

Please unbundle apipkg

As far as I can see, execnet/apipkg.py in execnet 1.1 is identical to apipkg.py version 1.2. Would it be possible to unbundle it?

Background: Fedora has a policy that forbids bundling of libraries in its packages: http://fedoraproject.org/wiki/Packaging:No_Bundled_Libraries

The related Fedora bug against python-execnet is https://bugzilla.redhat.com/show_bug.cgi?id=790165

Threading issue (deadlock)

With execnet 1.1 I see a lot of _thread.error: can't start new thread failures in the testsuite, similar to https://bitbucket.org/hpk42/execnet/issue/9 I think.

After applying the patch from https://bitbucket.org/hpk42/execnet/commits/49c5934137e5 however, the testsuite doesn't terminate anymore, but hangs:

py.test-3.3 -v -v -r s
==================================================================== test session starts =====================================================================
platform linux -- Python 3.3.2 -- pytest-2.3.5 -- /usr/bin/python3
gateway test setup scope: session
execnet: /tmp/RPM_BUILDDIR/python3-python-execnet-1.1-4.fc19/execnet/__init__.py -- 1.1
collected 380 items 

[... output snipped ...]
testing/test_channel.py:15: TestChannelBasicBehaviour.test_serialize_error[popen] PASSED
testing/test_channel.py:15: TestChannelBasicBehaviour.test_serialize_error[socket] PASSED
testing/test_channel.py:15: TestChannelBasicBehaviour.test_serialize_error[ssh] SKIPPED
testing/test_channel.py:15: TestChannelBasicBehaviour.test_serialize_error[proxy] PASSED^C

Group.__init() should be parallelised

Consider the following snippet:

hosts = [...list of hosts...]
group = execnet.Group(("ssh %s" % host for host in hosts))
group.remote_exec(something)

Imagine having a grid of 200 hosts.
While Group.remote_exec() will run on all the hosts in parallel, Group.__init__() will connect via ssh to each one of them, serially. On a typical LAN, this easily accounts to minutes.

I attach a patch for multi.py (on top of the latest hg commit) that is intended to fix the problem. However, with that patch the program deadlocks in gateway_base.py, line 360, and I can't figure out the reason.

Thread Safety

gateway.py

line:

linecache.updatecache(inspect.getsourcefile(source))

is not threadsafe. if two threads access the linecache update at the same time it results in:

KeyError in linecache.updatecache in line:

del cache[filename]

A temporary fix is to comment out the line.

AttributeError: "'NoneType' object has no attribute 'CHANNEL_CLOSE'

I was getting a few of those AttributeErrors and was finally able to narrow it down to the Message object being None in the Channel.del method.

The full error is:

#!

 Exception AttributeError: "'NoneType' object has no attribute 'CHANNEL_CLOSE'" in <bound method Channel.__del__ of <Channel id=3 open>> ignored

After changing to make sure that Message was not None, I was no longer able to get the errors back:

#!python

            if Message is not None:
                if self._items is None:    # has_callback
                    msgcode = Message.CHANNEL_LAST_MESSAGE
                else:
                    msgcode = Message.CHANNEL_CLOSE
                try:
                    self.gateway._send(msgcode, self.id)
                except (IOError, ValueError): # ignore problems with sending
                    pass

I am not sure though if this is the correct approach for the problem, or why is it in the first place that Message can be None.

support sudo on local popen

To create a gateway over ssh, sudo python works great because it is used as part of a string (note that I am printing the args being passed to Popen):

gw = execnet.makegateway('ssh=node1//python=sudo python')
['ssh', '-C', 'node1', 'sudo python -c "import sys;exec(eval(sys.stdin.readline()))"']

But that is not the case with a local popen gateway:

 gw = execnet.makegateway('popen//python=sudo python')
['sudo python', '-u', '-c', 'import sys;exec(eval(sys.stdin.readline()))']

'sudo python` will make Popen raise an OSError because it can't find the executable.

When using this fix [0] I am able to start a local popen gateway with sudo python

gw = execnet.makegateway('popen//python=sudo python')
['sudo', 'python', '-u', '-c', 'import sys;exec(eval(sys.stdin.readline()))']

Is it possible to consider that change to allow local popen gateways with sudo?

[0] https://bitbucket.org/ctheune/execnet/commits/923812b8f0e43930105033464e1d09e6e923d4dd

remote_exec breaks inspect.stack() assumptions

inspect.stack() assumes that file names contain at least one character:

#!sh

(venv)peter@gremlin:~/workspace/execnet$ cat test.py
import execnet
gw = execnet.makegateway()
c = gw.remote_exec('import inspect; inspect.stack();')
c.waitclose()
(venv)peter@gremlin:~/workspace/execnet$ python test.py
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    c.waitclose()
  File "/home/peter/workspace/execnet/execnet/gateway_base.py", line 412, in waitclose
    raise error
execnet.gateway_base.RemoteError: Traceback (most recent call last):
  File "/home/peter/workspace/execnet/execnet/gateway_base.py", line 800, in executetask
    do_exec(co, loc)
  File "<string>", line 1, in do_exec
  File "", line 1, in <module>
  File "/usr/lib/python2.7/inspect.py", line 1054, in stack
    return getouterframes(sys._getframe(1), context)
  File "/usr/lib/python2.7/inspect.py", line 1032, in getouterframes
    framelist.append((frame,) + getframeinfo(frame, context))
  File "/usr/lib/python2.7/inspect.py", line 1007, in getframeinfo
    lines, lnum = findsource(frame)
  File "/usr/lib/python2.7/inspect.py", line 528, in findsource
    if not sourcefile and file[0] + file[-1] != '<>':
IndexError: string index out of range

I'll submit a pull request momentarily.

execnet submodules not found when packed in a jar for use with Jython (patch included)

Hi,

A little bit of context: I am working on an image processing software (icy.bioimageanalysis.org) written in Java. We've recently added a Jython scripting engine, and I have been trying to distribute execnet along with Jython so that users can easily write scripts that communicate with CPython and use Numpy, for example.

The problem I encounter is that I want to distribute the execnet inside a jar file. Normally it's just a matter of putting the python files in the jar, but for execnet the module cannot be used from the resulting jar. As soon as an execnet command is called, it fails with: "ImportError: No module name *" where * is the name of one of the sub-module of execnet ("multi" for example).

It turns out that the problem lies in apipkg.py. I have filed an issue and submitted a patch for apipkg.py here:
https://bitbucket.org/hpk42/apipkg/issue/3/modules-not-founds-when-packed-in-a-jar

(The problem comes from the assumption that python modules are plain files with a true path. Instead, when run by Jython from a jar, the module is located in a virtual place called "pyclasspath". I have modified the use of os.path.abspath to avoid modifying paths that begins with pyclasspath and now execnet works properly. A patch is attached to the issue).

Do you think this could be included for a new release of execnet ? Thanks !

multi.Group.allocate_id is not thread-safe

Hi,

When creating gateways is threads in Jython (where there is no GIL), I sometimes get the following exception:

ValueError "already have gateway with id ..."

Here is a test script:
https://gist.github.com/tlecomte/7784555

I think that the problem is that the increment operation "self._autoidcounter += 1" is not atomic.

Using a lock around this increment should be enough to solve this issue:

#!python

from threading import Lock

class Group(object):
    """ Gateway Groups. """
    defaultspec = "popen"
    def __init__(self, xspecs=(), execmodel="thread"):
        ....
        self.lock = Lock()

    ...

    def allocate_id(self, spec):
        """ allocate id for the given xspec object. """
        if spec.id is None:
            id = "gw" + str(self._autoidcounter)
            with self.lock:
                self._autoidcounter += 1
            if id in self:
                raise ValueError("already have gateway with id %r" %(id,))
            spec.id = id

pytest-xdist slave fail on Interrupted system call

Hi,

I get IOError Interrupted system call in pytest-xdist slave. Don't know why, can't see signal anywhere but fail

creating slavegateway on <__main__.Popen2IO instance at 0x20fa2d8>
RECEIVERTHREAD: starting to run
received <Message.CHANNEL_EXEC channelid=1 len=285>
received <Message.CHANNEL_DATA channelid=1 len=123>
execution starts[1]: "\nimport os\npath, nice, env = channel.receive()\
execution finished
sent <Message.CHANNEL_CLOSE channelid=1 >
1 sent channel close message
received <Message.CHANNEL_EXEC channelid=3 len=210>
1 channel.__del__
execution starts[3]: '\nimport sys, os\nchannel.send(dict(\n    executa
sent <Message.CHANNEL_DATA channelid=3 len=295>
execution finished
sent <Message.CHANNEL_CLOSE channelid=3 >
3 sent channel close message
received <Message.CHANNEL_EXEC channelid=5 len=5308>
3 channel.__del__
execution starts[5]: '"""\n    This module is executed in remote subpro
received <Message.CHANNEL_DATA channelid=5 len=1492>
RECEIVERTHREAD Traceback (most recent call last):
 File "<string>", line 622, in _thread_receiver
 File "<string>", line 802, in load
 File "<string>", line 86, in read
IOError: [Errno 4] Interrupted system call

RECEIVERTHREAD entering finalization
RECEIVERTHREAD leaving finalization
sent <Message.CHANNEL_DATA channelid=5 len=451>
sent <Message.CHANNEL_DATA channelid=5 ('collectionstart', {})>
sent <Message.CHANNEL_DATA channelid=5 len=115>
sent <Message.CHANNEL_DATA channelid=5 len=163>
sent <Message.CHANNEL_DATA channelid=5 len=244>
sent <Message.CHANNEL_DATA channelid=5 len=53>

gateway_base.Unserializer.load(self) can be made work by retry if get IOError with errno == 4

while True:
    opcode = self.stream.read(1)  # Retry this if IOError raised here
    if not opcode:
        raise EOFError

Threading exception on Python 3.2

I am using the following test script:

#!python
import datetime
import execnet

i = 0
while True:
	print(datetime.datetime.now(), i)
	group = execnet.Group()
	gw = group.makegateway("ssh=user@host")
	ch = gw.remote_exec("import time ; time.sleep(2.0)")
	group.terminate(timeout=1.0)
	i += 1

After about 250 runs of the loop body I get the following output:

2012-09-03 18:04:10.822562 253
2012-09-03 18:04:11.205508 254
Traceback (most recent call last):
  File "/var/home/walter/.local/lib/python3.2/site-packages/execnet-1.1-py3.2.egg/execnet/threadpool.py", line 130, in dispatch
    thread, _ = self._ready.popitem()
KeyError: 'popitem(): dictionary is empty'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "gurk.py", line 10, in <module>
    group.terminate(timeout=1.0)
  File "/var/home/walter/.local/lib/python3.2/site-packages/execnet-1.1-py3.2.egg/execnet/multi.py", line 168, in terminate
    for gw in self._gateways_to_join])
  File "/var/home/walter/.local/lib/python3.2/site-packages/execnet-1.1-py3.2.egg/execnet/multi.py", line 251, in safe_terminate
    reply = workerpool.dispatch(termkill, termfunc, killfunc)
  File "/var/home/walter/.local/lib/python3.2/site-packages/execnet-1.1-py3.2.egg/execnet/threadpool.py", line 135, in dispatch
    thread = self._newthread()
  File "/var/home/walter/.local/lib/python3.2/site-packages/execnet-1.1-py3.2.egg/execnet/threadpool.py", line 141, in _newthread
    thread.start()
  File "/var/home/walter/.local/lib/python3.2/threading.py", line 683, in start
    _start_new_thread(self._bootstrap, ())
_thread.error: can't start new thread

`struct.pack` can be None sometimes, spits Tracebacks when it is

I had to add a traceback.print.exc() to get some extra info while attempting to narrow down this.

It basically comes up while closing the connection, and it ends up being that struct.pack is None.

Again here, I am not sure if it is just safe to check if struct.pack is not None to continue, but so far that seems to work correctly for me.

Below is after adding the print_exc()

#!

Traceback (most recent call last):
  File "/home/ubuntu/ceph-deploy/ceph_deploy/lib/remoto/lib/execnet/gateway_base.py", line 342, in __del__
    self.gateway._send(msgcode, self.id)
  File "/home/ubuntu/ceph-deploy/ceph_deploy/lib/remoto/lib/execnet/gateway_base.py", line 726, in _send
    message.to_io(self._io)
  File "/home/ubuntu/ceph-deploy/ceph_deploy/lib/remoto/lib/execnet/gateway_base.py", line 129, in to_io
    header = struct.pack('!bii', self.msgcode, self.channelid, len(self.data))
TypeError: 'NoneType' object is not callable

And without it this is how it looks:

Exception in thread Thread-1 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
  File "", line 84, in run
  File "", line 65, in _run_once
  File "/usr/lib/python2.7/Queue.py", line 168, in get
  File "/usr/lib/python2.7/threading.py", line 333, in wait
<type 'exceptions.TypeError'>: 'NoneType' object is not callable
Exception TypeError: TypeError("'NoneType' object is not callable",) in <bound method Channel.__del__ of <Channel id=3 open>> ignored

release 1.3

Hi Holgar and Ronny,

There have been a number of changes that landed in execnet in Mercurial that are not available from PyPI.

Would you mind tagging 1.3 and pushing it to PyPI?

If you're busy, would you accept additional co-maintainers for the project? I'm sure @alfredodeza would make a fine co-maintainer.

Simple example fails when executed using "pythonw.exe" on Windows

Hi,

I believe I found a bug when using execnet and pythonw.exe on Windows. I implemented a solution,
but I would like some guidance on how to open a proper PR.

Suppose this file, which is a simple execnet example except it redirects things to files:

# contents of foo.py
import traceback
import execnet
try:    
    gw = execnet.makegateway()
    channel = gw.remote_exec("channel.send(channel.receive()+1)")
    channel.send(1)
    with open('foo.txt', 'w') as f:
        f.write(str(channel.receive()))
except:
    with open('foo-error.txt', 'w') as f:
        traceback.print_exc(file=f)

When running this script on Windows using python.exe, it writes file foo.txt containing "2" as expected, but when using pythonw.exe
it produces only file foo-error.txt with this traceback:

Traceback (most recent call last):
  File "foo.py", line 3, in <module>
    gw = execnet.makegateway()
  File "x:\execnet\execnet\multi.py", line 127, in makegateway
    io = gateway_io.create_io(spec, execmodel=self.execmodel)
  File "x:\execnet\execnet\gateway_io.py", line 94, in create_io
    return Popen2IOMaster(args, execmodel)
  File "x:\execnet\execnet\gateway_io.py", line 17, in __init__
    self.popen = p = execmodel.PopenPiped(args)
  File "x:\execnet\execnet\gateway_base.py", line 178, in PopenPiped
    return self.subprocess.Popen(args, stdout=PIPE, stdin=PIPE)#,
  File "D:\Programming\Python27\Lib\subprocess.py", line 701, in __init__
    errread, errwrite), to_close = self._get_handles(stdin, stdout, stderr)
  File "D:\Programming\Python27\Lib\subprocess.py", line 868, in _get_handles
    errwrite = self._make_inheritable(errwrite)
  File "D:\Programming\Python27\Lib\subprocess.py", line 883, in _make_inheritable
    _subprocess.DUPLICATE_SAME_ACCESS)
WindowsError: [Error 6] Invalid identifier

The problem is that pythonw.exe does not have valid in/out/err streams, so the Popen call fails. The following patch solves the issue
(both for python.exe and pythonw.exe):

diff -r 2a4d009856d7 execnet/gateway_base.py
--- a/execnet/gateway_base.py   Mon Feb 16 00:58:25 2015 +0100
+++ b/execnet/gateway_base.py   Wed Mar 04 20:56:13 2015 -0300
@@ -175,7 +175,8 @@

         def PopenPiped(self, args):
             PIPE = self.subprocess.PIPE
-            return self.subprocess.Popen(args, stdout=PIPE, stdin=PIPE)
+            return self.subprocess.Popen(args, stdout=PIPE, stdin=PIPE,
+                                         stderr=PIPE)

     return ExecModel(backend)

However after applying the patch and running the test suite, this single test started to fail:

================================== FAILURES ===================================
____________________ TestTracing.test_popen_stderr_tracing ____________________

self = <test_gateway.TestTracing instance at 0x0316E760>
capfd = <_pytest.capture.CaptureFixture instance at 0x0316E8C8>
monkeypatch = <_pytest.monkeypatch.monkeypatch instance at 0x0316E788>
makegateway = <bound method Group.makegateway of <Group ['gw0']>>

    def test_popen_stderr_tracing(self, capfd, monkeypatch, makegateway):
        monkeypatch.setenv('EXECNET_DEBUG', "2")
        gw = makegateway("popen")
        pid = gw.remote_exec("import os ; channel.send(os.getpid())").receive()
        out, err = capfd.readouterr()
        slave_line = "[%s] creating slavegateway" % pid
>       assert slave_line in err
E       assert '[7812] creating slavegateway' in ''

It seems it's failing because with the patch the process is no longer inheriting the same stderr stream from
the python executable used to run pytest, so capfd does not see the changes writen by the internal trace
function in gateway_base which outputs that debug information. This represents a change of behavior, but I'm not sure to how extent users rely on it.

I also tried to implement a "black box" test reproducing the steps described here in the issue, but I couldn't
make it fail either before or after the patch:

@pytest.mark.skipif(sys.platform != 'win32', reason='windows only')
def test_python_no_console_win(tmpdir):
    executable = py.path.local(sys.executable)
    executable = py.path.local(executable.dirname) / 'pythonw.exe'
    assert executable.check(file=1)

    response_file = tmpdir / 'response.txt'
    source_lines = [
        'import execnet',
        'gw = execnet.makegateway()',
        'channel = gw.remote_exec("channel.send(channel.receive()+1)")',
        'channel.send(1)',
        'response = channel.receive()',
        'with open("%s", "w") as f:' % response_file.basename,
        '    f.write(str(response))',
    ]
    source = tmpdir / 'c.py'
    source.write('\n'.join(source_lines))
    assert subprocess.call([str(executable), str(source)], cwd=str(tmpdir)) == 0
    assert response_file.read() == "2"

I believe I can't get it to fail because of the same reason, it is inheriting the streams from the python process running pytest.

Background

I found this problem after trying to use xdist from within an executable created by cx_freeze, as we want to run our
test-suite with the "frozen" code in order to detect any issues with the packaging process, as was stated in other occasions.

Any comments are welcome! ๐Ÿ˜„

Cheers,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.