3434
3535from . import format_helpers
3636
37- _HANDLE_CANCELLED = object ()
37+ class _HandleCancelled :
38+ @staticmethod
39+ def callback (* args ):
40+ pass
41+
42+ args = ()
43+
44+ _HANDLE_CANCELLED = _HandleCancelled ()
45+
46+
47+ class _HandlePartial :
48+ __slots__ = ("callback" , "args" )
49+
50+ def __init__ (self , callback , args ):
51+ self .callback = callback
52+ self .args = args
53+
54+ def __eq__ (self , other ):
55+ if isinstance (other , _HandlePartial ):
56+ return (self .callback == other .callback and
57+ self .args == other .args )
58+ return NotImplemented
3859
3960
4061class Handle :
4162 """Object returned by callback registration methods."""
4263
43- __slots__ = ('_callback_args ' , '_loop' ,
64+ __slots__ = ('_callback_partial ' , '_loop' ,
4465 '_source_traceback' , '_repr' , '__weakref__' ,
4566 '_context' )
4667
4768 def __init__ (self , callback , args , loop , context = None ):
4869 if context is None :
4970 context = contextvars .copy_context ()
50- self ._context = context
5171 self ._loop = loop
52- self ._callback_args = (callback , args )
72+ self ._context = context
73+ self ._callback_partial = _HandlePartial (callback , args )
5374 self ._repr = None
5475 if self ._loop .get_debug ():
5576 self ._source_traceback = format_helpers .extract_stack (
5677 sys ._getframe (1 ))
5778 else :
5879 self ._source_traceback = None
5980
60- def _repr_info (self , cancelling , callback_args ):
81+ def _repr_info (self , cancelling , callback_partial ):
6182 info = [self .__class__ .__name__ ]
6283 if cancelling :
6384 info .append ('cancelled' )
64- if callback_args is _HANDLE_CANCELLED :
85+ if callback_partial is _HANDLE_CANCELLED :
6586 info .append ('cancelled' )
6687 callback = None
6788 args = None
6889 else :
69- callback , args = callback_args
90+ callback = callback_partial .callback
91+ args = callback_partial .args
7092
7193 if callback is not None :
7294 info .append (format_helpers ._format_callback_source (
@@ -77,61 +99,58 @@ def _repr_info(self, cancelling, callback_args):
7799 info .append (f'created at { frame [0 ]} :{ frame [1 ]} ' )
78100 return info
79101
80- def _repr_atomic (self , cancelling , callback_args ):
81- info = self ._repr_info (cancelling , callback_args )
102+ def _repr_atomic (self , cancelling , callback_partial ):
103+ info = self ._repr_info (cancelling , callback_partial )
82104 return '<{}>' .format (' ' .join (info ))
83105
84106 def __repr__ (self ):
85107 if self ._repr is not None :
86108 return self ._repr
87- return self ._repr_atomic (cancelling = False , callback_args = self ._callback_args )
109+ return self ._repr_atomic (cancelling = False , callback_partial = self ._callback_partial )
88110
89111 def get_context (self ):
90112 return self ._context
91113
92114 def cancel (self ):
93- callback_args = self ._callback_args
94- self ._callback_args = _HANDLE_CANCELLED
95- if callback_args is not _HANDLE_CANCELLED :
115+ callback_partial = self ._callback_partial
116+ self ._callback_partial = _HANDLE_CANCELLED
117+ if callback_partial is not _HANDLE_CANCELLED :
96118 if self ._loop .get_debug ():
97119 # Keep a representation in debug mode to keep callback and
98120 # parameters. For example, to log the warning
99121 # "Executing <Handle...> took 2.5 second"
100- self ._repr = self ._repr_atomic (cancelling = True , callback_args = callback_args )
122+ self ._repr = self ._repr_atomic (cancelling = True , callback_partial = callback_partial )
101123
102124 def cancelled (self ):
103- return self ._callback_args is _HANDLE_CANCELLED
125+ return self ._callback_partial is _HANDLE_CANCELLED
104126
105127 @property
106128 def _cancelled (self ):
107129 return self .cancelled ()
108130
109131 @property
110132 def _callback (self ):
111- callback_args = self ._callback_args
112- if callback_args is _HANDLE_CANCELLED :
133+ callback_partial = self ._callback_partial
134+ if callback_partial is _HANDLE_CANCELLED :
113135 return None
114- return callback_args [ 0 ]
136+ return callback_partial . callback
115137
116138 @property
117139 def _args (self ):
118- callback_args = self ._callback_args
119- if callback_args is _HANDLE_CANCELLED :
140+ callback_partial = self ._callback_partial
141+ if callback_partial is _HANDLE_CANCELLED :
120142 return None
121- return callback_args [ 1 ]
143+ return callback_partial . args
122144
123145 def _run (self ):
124- callback_args = self ._callback_args
125- if callback_args is _HANDLE_CANCELLED :
126- return
127- callback , args = callback_args
146+ callback_partial = self ._callback_partial
128147 try :
129- self ._context .run (callback , * args )
148+ self ._context .run (callback_partial . callback , * callback_partial . args )
130149 except (SystemExit , KeyboardInterrupt ):
131150 raise
132151 except BaseException as exc :
133152 cb = format_helpers ._format_callback_source (
134- callback , args ,
153+ callback_partial . callback , callback_partial . args ,
135154 debug = self ._loop .get_debug ())
136155 msg = f'Exception in callback { cb } '
137156 context = {
@@ -142,9 +161,7 @@ def _run(self):
142161 if self ._source_traceback :
143162 context ['source_traceback' ] = self ._source_traceback
144163 self ._loop .call_exception_handler (context )
145- callback = None
146- args = None
147- callback_args = None
164+ callback_partial = None
148165 self = None # Needed to break cycles when an exception occurs.
149166
150167
@@ -192,7 +209,7 @@ def __ge__(self, other):
192209 def __eq__ (self , other ):
193210 if isinstance (other , TimerHandle ):
194211 return (self ._when == other ._when and
195- self ._callback_args == other ._callback_args )
212+ self ._callback_partial == other ._callback_partial )
196213 return NotImplemented
197214
198215 def cancel (self ):
0 commit comments