22gateway code for initiating popen, socket and ssh connections.
33(c) 2004-2013, Holger Krekel and others
44"""
5+ from __future__ import annotations
6+
57import inspect
68import linecache
79import os
810import textwrap
911import types
12+ from typing import TYPE_CHECKING
13+ from typing import Any
14+ from typing import Callable
1015
1116import execnet
1217
1318from . import gateway_base
19+ from .gateway_base import IO
20+ from .gateway_base import Channel
1421from .gateway_base import Message
22+ from .multi import Group
23+ from .xspec import XSpec
1524
1625importdir = os .path .dirname (os .path .dirname (execnet .__file__ ))
1726
1827
1928class Gateway (gateway_base .BaseGateway ):
2029 """Gateway to a local or remote Python Interpreter."""
2130
22- def __init__ (self , io , spec ):
31+ _group : Group
32+
33+ def __init__ (self , io : IO , spec : XSpec ) -> None :
2334 super ().__init__ (io = io , id = spec .id , _startcount = 1 )
2435 self .spec = spec
2536 self ._initreceive ()
2637
2738 @property
28- def remoteaddress (self ):
29- return self ._io .remoteaddress
39+ def remoteaddress (self ) -> str :
40+ # Only defined for remote IO types.
41+ return self ._io .remoteaddress # type: ignore[attr-defined,no-any-return]
3042
31- def __repr__ (self ):
43+ def __repr__ (self ) -> str :
3244 """return string representing gateway type and status."""
3345 try :
34- r = self .hasreceiver () and "receive-live" or "not-receiving"
35- i = len (self ._channelfactory .channels ())
46+ r : str = self .hasreceiver () and "receive-live" or "not-receiving"
47+ i = str ( len (self ._channelfactory .channels () ))
3648 except AttributeError :
3749 r = "uninitialized"
3850 i = "no"
3951 return "<{} id={!r} {}, {} model, {} active channels>" .format (
4052 self .__class__ .__name__ , self .id , r , self .execmodel .backend , i
4153 )
4254
43- def exit (self ):
55+ def exit (self ) -> None :
4456 """trigger gateway exit. Defer waiting for finishing
4557 of receiver-thread and subprocess activity to when
4658 group.terminate() is called.
@@ -59,7 +71,9 @@ def exit(self):
5971 self ._trace ("io-error: could not send termination sequence" )
6072 self ._trace (" exception: %r" % exc )
6173
62- def reconfigure (self , py2str_as_py3str = True , py3str_as_py2str = False ):
74+ def reconfigure (
75+ self , py2str_as_py3str : bool = True , py3str_as_py2str : bool = False
76+ ) -> None :
6377 """
6478 set the string coercion for this gateway
6579 the default is to try to convert py2 str as py3 str,
@@ -69,7 +83,7 @@ def reconfigure(self, py2str_as_py3str=True, py3str_as_py2str=False):
6983 data = gateway_base .dumps_internal (self ._strconfig )
7084 self ._send (Message .RECONFIGURE , data = data )
7185
72- def _rinfo (self , update = False ):
86+ def _rinfo (self , update : bool = False ) -> RInfo :
7387 """return some sys/env information from remote."""
7488 if update or not hasattr (self , "_cache_rinfo" ):
7589 ch = self .remote_exec (rinfo_source )
@@ -79,11 +93,11 @@ def _rinfo(self, update=False):
7993 ch .waitclose ()
8094 return self ._cache_rinfo
8195
82- def hasreceiver (self ):
96+ def hasreceiver (self ) -> bool :
8397 """return True if gateway is able to receive data."""
8498 return self ._receivepool .active_count () > 0
8599
86- def remote_status (self ):
100+ def remote_status (self ) -> RemoteStatus :
87101 """return information object about remote execution status."""
88102 channel = self .newchannel ()
89103 self ._send (Message .STATUS , channel .id )
@@ -93,7 +107,11 @@ def remote_status(self):
93107 self ._channelfactory ._local_close (channel .id )
94108 return RemoteStatus (statusdict )
95109
96- def remote_exec (self , source , ** kwargs ):
110+ def remote_exec (
111+ self ,
112+ source : str | types .FunctionType | Callable [..., object ] | types .ModuleType ,
113+ ** kwargs : object ,
114+ ) -> Channel :
97115 """return channel object and connect it to a remote
98116 execution thread where the given ``source`` executes.
99117
@@ -113,7 +131,7 @@ def remote_exec(self, source, **kwargs):
113131 file_name = None
114132 if isinstance (source , types .ModuleType ):
115133 file_name = inspect .getsourcefile (source )
116- linecache .updatecache (file_name )
134+ linecache .updatecache (file_name ) # type: ignore[arg-type]
117135 source = inspect .getsource (source )
118136 elif isinstance (source , types .FunctionType ):
119137 call_name = source .__name__
@@ -133,24 +151,29 @@ def remote_exec(self, source, **kwargs):
133151 )
134152 return channel
135153
136- def remote_init_threads (self , num = None ):
154+ def remote_init_threads (self , num : int | None = None ) -> None :
137155 """DEPRECATED. Is currently a NO-OPERATION already."""
138156 print ("WARNING: remote_init_threads()" " is a no-operation in execnet-1.2" )
139157
140158
141159class RInfo :
142- def __init__ (self , kwargs ):
160+ def __init__ (self , kwargs ) -> None :
143161 self .__dict__ .update (kwargs )
144162
145- def __repr__ (self ):
163+ def __repr__ (self ) -> str :
146164 info = ", " .join (f"{ k } ={ v } " for k , v in sorted (self .__dict__ .items ()))
147165 return "<RInfo %r>" % info
148166
167+ if TYPE_CHECKING :
168+
169+ def __getattr__ (self , name : str ) -> Any :
170+ ...
171+
149172
150173RemoteStatus = RInfo
151174
152175
153- def rinfo_source (channel ):
176+ def rinfo_source (channel ) -> None :
154177 import os
155178 import sys
156179
@@ -165,7 +188,7 @@ def rinfo_source(channel):
165188 )
166189
167190
168- def _find_non_builtin_globals (source , codeobj ) :
191+ def _find_non_builtin_globals (source : str , codeobj : types . CodeType ) -> list [ str ] :
169192 import ast
170193 import builtins
171194
@@ -179,7 +202,7 @@ def _find_non_builtin_globals(source, codeobj):
179202 ]
180203
181204
182- def _source_of_function (function ) :
205+ def _source_of_function (function : types . FunctionType | Callable [..., object ]) -> str :
183206 if function .__name__ == "<lambda>" :
184207 raise ValueError ("can't evaluate lambda functions'" )
185208 # XXX: we dont check before remote instantiation
0 commit comments