File: test_info.rst

package info (click to toggle)
execnet 2.1.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 684 kB
  • sloc: python: 5,244; makefile: 78; sh: 2
file content (194 lines) | stat: -rw-r--r-- 6,271 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
Basic local and remote communication
====================================

Execute source code in subprocess, communicate through a channel
-------------------------------------------------------------------

You can instantiate a subprocess gateway, execute code
in it and bidirectionally send messages::

    >>> import execnet
    >>> gw = execnet.makegateway()
    >>> channel = gw.remote_exec("channel.send(channel.receive()+1)")
    >>> channel.send(1)
    >>> channel.receive()
    2

The initiating and the remote execution happen concurrently.
``channel.receive()`` operations return when input is available.
``channel.send(data)`` operations return when the message could
be delivered to the IO system.

The initiating and the "other" process work use a `share-nothing
model`_ and ``channel.send|receive`` are means to pass basic data
messages between two processes.

.. _`share-nothing model`: http://en.wikipedia.org/wiki/Shared_nothing_architecture

Remote-exec a function (avoiding inlined source part I)
-------------------------------------------------------

You can send and remote execute parametrized pure functions like this:

.. include:: funcmultiplier.py
    :literal:

The ``multiplier`` function executes remotely and establishes
a loop multipliying incoming data with a constant factor passed
in via keyword arguments to ``remote_exec``.

Notes:

* unfortunately, you can not type this example interactively because
  ``inspect.getsource(func)`` fails for interactively defined
  functions.

* You will get an explicit error if you try to execute non-pure
  functions, i.e. functions that access any global state (which
  will not be available remotely as we have a share-nothing model
  between the nodes).


Remote-exec a module (avoiding inlined source part II)
------------------------------------------------------

You can pass a module object to ``remote_exec`` in which case
its source code will be sent.  No dependencies will be transferred
so the module must be self-contained or only use modules that are
installed on the "other" side.   Module code can detect if it is
running in a remote_exec situation by checking for the special
``__name__`` attribute.

.. include:: remote1.py
    :literal:

You can now remote-execute the module like this::

    >>> import execnet, remote1
    >>> gw = execnet.makegateway()
    >>> ch = gw.remote_exec(remote1)
    >>> print (ch.receive())
    initialization complete

which will print the 'initialization complete' string.


Compare current working directories
----------------------------------------

A local subprocess gateway has the same working directory as the instantiatior::

    >>> import execnet, os
    >>> gw = execnet.makegateway()
    >>> ch = gw.remote_exec("import os; channel.send(os.getcwd())")
    >>> res = ch.receive()
    >>> assert res == os.getcwd()

"ssh" gateways default to the login home directory.

Get information from remote SSH account
---------------------------------------

Use simple execution to obtain information from remote environments::

  >>> import execnet, os
  >>> gw = execnet.makegateway("ssh=codespeak.net")
  >>> channel = gw.remote_exec("""
  ...     import sys, os
  ...     channel.send((sys.platform, tuple(sys.version_info), os.getpid()))
  ... """)
  >>> platform, version_info, remote_pid = channel.receive()
  >>> platform
  'linux2'
  >>> version_info
  (2, 6, 6, 'final', 0)

Use a callback instead of receive() and wait for completion
-------------------------------------------------------------

Set a channel callback to immediately react on incoming data::

    >>> import execnet
    >>> gw = execnet.makegateway()
    >>> channel = gw.remote_exec("for i in range(10): channel.send(i)")
    >>> l = []
    >>> channel.setcallback(l.append, endmarker=None)
    >>> channel.waitclose() # waits for closing, i.e. remote exec finish
    >>> l
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, None]

Note that the callback function will execute in the receiver thread
so it should not block on IO or long to execute.

Sending channels over channels
------------------------------------------------------

You can create and transfer a channel over an existing channel
and use it to transfer information::

    >>> import execnet
    >>> gw = execnet.makegateway()
    >>> channel = gw.remote_exec("""
    ...        ch1, ch2 = channel.receive()
    ...        ch2.send("world")
    ...        ch1.send("hello")
    ... """)
    >>> c1 = gw.newchannel()    # create new channel
    >>> c2 = gw.newchannel()    # create another channel
    >>> channel.send((c1, c2))  # send them over
    >>> c1.receive()
    'hello'
    >>> c2.receive()
    'world'



A simple command loop pattern
--------------------------------------------------------------

If you want the remote side to serve a number
of synchronous function calls into your module
you can setup a serving loop and write a local protocol.

.. include:: remotecmd.py
    :literal:

Then on the local side you can do::

    >>> import execnet, remotecmd
    >>> gw = execnet.makegateway()
    >>> ch = gw.remote_exec(remotecmd)
    >>> ch.send('simple(10)') # execute func-call remotely
    >>> ch.receive()
    11

Our remotecmd module starts up remote serving
through the ``for item in channel`` loop which
will terminate when the channel closes. It evaluates
all incoming requests in the global name space and
sends back the results.


Instantiate gateways through sockets
-----------------------------------------------------

.. _`socketserver.py`: https://raw.githubusercontent.com/pytest-dev/execnet/master/execnet/script/socketserver.py

In cases where you do not have SSH-access to a machine
you need to download a small version-independent standalone
`socketserver.py`_ script to provide a remote bootstrapping-point.
You do not need to install the execnet package remotely.
Simply run the script like this::

    python socketserver.py :8888   # bind to all IPs, port 8888

You can then instruct execnet on your local machine to bootstrap
itself into the remote socket endpoint::

    import execnet
    gw = execnet.makegateway("socket=TARGET-IP:8888")

That's it, you can now use the gateway object just like
a popen- or SSH-based one.

.. include:: test_ssh_fileserver.rst