Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/IPython/core/events.py: 44%

48 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

1"""Infrastructure for registering and firing callbacks on application events. 

2 

3Unlike :mod:`IPython.core.hooks`, which lets end users set single functions to 

4be called at specific times, or a collection of alternative methods to try, 

5callbacks are designed to be used by extension authors. A number of callbacks 

6can be registered for the same event without needing to be aware of one another. 

7 

8The functions defined in this module are no-ops indicating the names of available 

9events and the arguments which will be passed to them. 

10 

11.. note:: 

12 

13 This API is experimental in IPython 2.0, and may be revised in future versions. 

14""" 

15 

16from backcall import callback_prototype 

17 

18 

19class EventManager(object): 

20 """Manage a collection of events and a sequence of callbacks for each. 

21  

22 This is attached to :class:`~IPython.core.interactiveshell.InteractiveShell` 

23 instances as an ``events`` attribute. 

24  

25 .. note:: 

26 

27 This API is experimental in IPython 2.0, and may be revised in future versions. 

28 """ 

29 def __init__(self, shell, available_events): 

30 """Initialise the :class:`CallbackManager`. 

31 

32 Parameters 

33 ---------- 

34 shell 

35 The :class:`~IPython.core.interactiveshell.InteractiveShell` instance 

36 available_events 

37 An iterable of names for callback events. 

38 """ 

39 self.shell = shell 

40 self.callbacks = {n:[] for n in available_events} 

41 

42 def register(self, event, function): 

43 """Register a new event callback. 

44 

45 Parameters 

46 ---------- 

47 event : str 

48 The event for which to register this callback. 

49 function : callable 

50 A function to be called on the given event. It should take the same 

51 parameters as the appropriate callback prototype. 

52 

53 Raises 

54 ------ 

55 TypeError 

56 If ``function`` is not callable. 

57 KeyError 

58 If ``event`` is not one of the known events. 

59 """ 

60 if not callable(function): 

61 raise TypeError('Need a callable, got %r' % function) 

62 callback_proto = available_events.get(event) 

63 if function not in self.callbacks[event]: 

64 self.callbacks[event].append(callback_proto.adapt(function)) 

65 

66 def unregister(self, event, function): 

67 """Remove a callback from the given event.""" 

68 if function in self.callbacks[event]: 

69 return self.callbacks[event].remove(function) 

70 

71 # Remove callback in case ``function`` was adapted by `backcall`. 

72 for callback in self.callbacks[event]: 

73 try: 

74 if callback.__wrapped__ is function: 

75 return self.callbacks[event].remove(callback) 

76 except AttributeError: 

77 pass 

78 

79 raise ValueError('Function {!r} is not registered as a {} callback'.format(function, event)) 

80 

81 def trigger(self, event, *args, **kwargs): 

82 """Call callbacks for ``event``. 

83 

84 Any additional arguments are passed to all callbacks registered for this 

85 event. Exceptions raised by callbacks are caught, and a message printed. 

86 """ 

87 for func in self.callbacks[event][:]: 

88 try: 

89 func(*args, **kwargs) 

90 except (Exception, KeyboardInterrupt): 

91 print("Error in callback {} (for {}):".format(func, event)) 

92 self.shell.showtraceback() 

93 

94# event_name -> prototype mapping 

95available_events = {} 

96 

97def _define_event(callback_function): 

98 callback_proto = callback_prototype(callback_function) 

99 available_events[callback_function.__name__] = callback_proto 

100 return callback_proto 

101 

102# ------------------------------------------------------------------------------ 

103# Callback prototypes 

104# 

105# No-op functions which describe the names of available events and the 

106# signatures of callbacks for those events. 

107# ------------------------------------------------------------------------------ 

108 

109@_define_event 

110def pre_execute(): 

111 """Fires before code is executed in response to user/frontend action. 

112 

113 This includes comm and widget messages and silent execution, as well as user 

114 code cells. 

115 """ 

116 pass 

117 

118@_define_event 

119def pre_run_cell(info): 

120 """Fires before user-entered code runs. 

121 

122 Parameters 

123 ---------- 

124 info : :class:`~IPython.core.interactiveshell.ExecutionInfo` 

125 An object containing information used for the code execution. 

126 """ 

127 pass 

128 

129@_define_event 

130def post_execute(): 

131 """Fires after code is executed in response to user/frontend action. 

132 

133 This includes comm and widget messages and silent execution, as well as user 

134 code cells. 

135 """ 

136 pass 

137 

138@_define_event 

139def post_run_cell(result): 

140 """Fires after user-entered code runs. 

141 

142 Parameters 

143 ---------- 

144 result : :class:`~IPython.core.interactiveshell.ExecutionResult` 

145 The object which will be returned as the execution result. 

146 """ 

147 pass 

148 

149@_define_event 

150def shell_initialized(ip): 

151 """Fires after initialisation of :class:`~IPython.core.interactiveshell.InteractiveShell`. 

152 

153 This is before extensions and startup scripts are loaded, so it can only be 

154 set by subclassing. 

155 

156 Parameters 

157 ---------- 

158 ip : :class:`~IPython.core.interactiveshell.InteractiveShell` 

159 The newly initialised shell. 

160 """ 

161 pass