summaryrefslogtreecommitdiff
path: root/.emacs.d.back/.python-environments/default/lib/python3.7/site-packages/epc/client.py
blob: f24a7cd9c9095d23febb339786f695495fb26f4e (plain)
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
# Copyright (C) 2012-  Takafumi Arakaki

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


from .py3compat import Queue
from .utils import ThreadedIterator, newthread
from .core import EPCCore
from .handler import ThreadingEPCHandler


class EPCClientHandler(ThreadingEPCHandler):

    # In BaseRequestHandler, everything happen in `.__init__()`.
    # Let's defer it to `.start()`.

    def __init__(self, *args):
        self._args = args
        self._ready = Queue.Queue()

    def start(self):
        ThreadingEPCHandler.__init__(self, *self._args)

    def setup(self):
        ThreadingEPCHandler.setup(self)
        self._ready.put(True)

    def wait_until_ready(self):
        self._ready.get()

    def _recv(self):
        self._recv_iter = ThreadedIterator(ThreadingEPCHandler._recv(self))
        return self._recv_iter


class EPCClient(EPCCore):

    """
    EPC client class to call remote functions and serve Python functions.

    >>> client = EPCClient()
    >>> client.connect(('localhost', 9999))                 #doctest: +SKIP
    >>> client.call_sync('echo', [111, 222, 333])           #doctest: +SKIP
    [111, 222, 333]

    To serve Python functions, you can use :meth:`register_function`.

    >>> client.register_function(str.upper)
    <method 'upper' of 'str' objects>

    :meth:`register_function` can be used as a decorator.

    >>> @client.register_function
    ... def add(x, y):
    ...     return x + y

    Also, you can initialize client and connect to the server by one line.

    >>> client = EPCClient(('localhost', 9999))             #doctest: +SKIP

    .. method:: call

       Alias of :meth:`epc.server.EPCHandler.call`.

    .. method:: call_sync

       Alias of :meth:`epc.server.EPCHandler.call_sync`.

    .. method:: methods

       Alias of :meth:`epc.server.EPCHandler.methods`.

    .. method:: methods_sync

       Alias of :meth:`epc.server.EPCHandler.methods_sync`.

    """

    thread_daemon = True

    def __init__(self, socket_or_address=None,
                 debugger=None, log_traceback=False):
        if socket_or_address is not None:
            self.connect(socket_or_address)
        EPCCore.__init__(self, debugger, log_traceback)

    def connect(self, socket_or_address):
        """
        Connect to server and start serving registered functions.

        :type socket_or_address: tuple or socket object
        :arg  socket_or_address: A ``(host, port)`` pair to be passed
                                 to `socket.create_connection`, or
                                 a socket object.

        """
        if isinstance(socket_or_address, tuple):
            import socket
            self.socket = socket.create_connection(socket_or_address)
        else:
            self.socket = socket_or_address

        # This is what BaseServer.finish_request does:
        address = None  # it is not used, so leave it empty
        self.handler = EPCClientHandler(self.socket, address, self)

        self.call = self.handler.call
        self.call_sync = self.handler.call_sync
        self.methods = self.handler.methods
        self.methods_sync = self.handler.methods_sync

        self.handler_thread = newthread(self, target=self.handler.start)
        self.handler_thread.daemon = self.thread_daemon
        self.handler_thread.start()
        self.handler.wait_until_ready()

    def close(self):
        """Close connection."""
        try:
            self.handler._recv_iter.stop()
        except AttributeError:
            # Do not fail to close even if the client is never used.
            pass

    def _ignore(*_):
        """"Do nothing method for `EPCHandler`."""
    add_client = _ignore
    remove_client = _ignore