From a8509f79634eba21b45ea9a97eab066799c73ec3 Mon Sep 17 00:00:00 2001 From: Maarten Breddels Date: Wed, 20 Mar 2019 15:08:56 +0100 Subject: [PATCH 1/3] FIX: respect wait for clear_output --- nbconvert/preprocessors/execute.py | 23 ++- .../tests/files/Clear Output.ipynb | 152 ++++++++++++++++++ 2 files changed, 170 insertions(+), 5 deletions(-) diff --git a/nbconvert/preprocessors/execute.py b/nbconvert/preprocessors/execute.py index ff051603c..2505a2cdc 100644 --- a/nbconvert/preprocessors/execute.py +++ b/nbconvert/preprocessors/execute.py @@ -440,6 +440,7 @@ def run_cell(self, cell, cell_index=0): exec_reply = self._wait_for_reply(msg_id, cell) outs = cell.outputs = [] + clear_before_next_output = False while True: try: @@ -475,11 +476,13 @@ def run_cell(self, cell, cell_index=0): elif msg_type == 'execute_input': continue elif msg_type == 'clear_output': - outs[:] = [] - # clear display_id mapping for this cell - for display_id, cell_map in self._display_id_map.items(): - if cell_index in cell_map: - cell_map[cell_index] = [] + if content.get('wait'): + self.log.debug('Wait to clear output') + clear_before_next_output = True + else: + self.log.debug('Immediate clear output') + outs[:] = [] + self.clear_display_id_mapping(cell_index) continue elif msg_type.startswith('comm'): continue @@ -493,6 +496,12 @@ def run_cell(self, cell, cell_index=0): # update_display_data doesn't get recorded continue + if clear_before_next_output: + self.log.debug('Executing delayed clear_output') + outs[:] = [] + self.clear_display_id_mapping(cell_index) + clear_before_next_output = False + try: out = output_from_msg(msg) except ValueError: @@ -509,6 +518,10 @@ def run_cell(self, cell, cell_index=0): return exec_reply, outs + def clear_display_id_mapping(self, cell_index): + for display_id, cell_map in self._display_id_map.items(): + if cell_index in cell_map: + cell_map[cell_index] = [] def executenb(nb, cwd=None, km=None, **kwargs): """Execute a notebook's code, updating outputs within the notebook object. diff --git a/nbconvert/preprocessors/tests/files/Clear Output.ipynb b/nbconvert/preprocessors/tests/files/Clear Output.ipynb index dfada3992..91c16a593 100644 --- a/nbconvert/preprocessors/tests/files/Clear Output.ipynb +++ b/nbconvert/preprocessors/tests/files/Clear Output.ipynb @@ -31,6 +31,158 @@ " clear_output()\n", " print(i)" ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Hello world\")\n", + "clear_output()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello world\n" + ] + } + ], + "source": [ + "print(\"Hello world\")\n", + "clear_output(wait=True) # no output after this" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "world\n" + ] + } + ], + "source": [ + "print(\"Hello\")\n", + "clear_output(wait=True) # here we have new output after wait=True\n", + "print(\"world\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Hello world'" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "handle0 = display(\"Hello world\", display_id=\"id0\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'world'" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "handle1 = display(\"Hello\", display_id=\"id1\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "handle1.update('world')" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "handle2 = display(\"Hello world\", display_id=\"id2\")\n", + "clear_output() # clears all output, also with display_ids" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Hello world'" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "handle3 = display(\"Hello world\", display_id=\"id3\")\n", + "clear_output(wait=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "world\n" + ] + } + ], + "source": [ + "handle4 = display(\"Hello\", display_id=\"id4\")\n", + "clear_output(wait=True)\n", + "print('world')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "handle4.update('Hello world') # it is cleared, so it should not show up in the above cell" + ] } ], "metadata": {}, From d71b95fba7641b97a42bc80c3b9ee76591f43a3f Mon Sep 17 00:00:00 2001 From: Maarten Breddels Date: Thu, 21 Mar 2019 15:20:28 +0100 Subject: [PATCH 2/3] refactor run_cell to make it easier to reuse --- nbconvert/preprocessors/execute.py | 63 ++++++++++++++++++------------ 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/nbconvert/preprocessors/execute.py b/nbconvert/preprocessors/execute.py index 2505a2cdc..22ee28f20 100644 --- a/nbconvert/preprocessors/execute.py +++ b/nbconvert/preprocessors/execute.py @@ -440,7 +440,7 @@ def run_cell(self, cell, cell_index=0): exec_reply = self._wait_for_reply(msg_id, cell) outs = cell.outputs = [] - clear_before_next_output = False + self.clear_before_next_output = False while True: try: @@ -476,15 +476,10 @@ def run_cell(self, cell, cell_index=0): elif msg_type == 'execute_input': continue elif msg_type == 'clear_output': - if content.get('wait'): - self.log.debug('Wait to clear output') - clear_before_next_output = True - else: - self.log.debug('Immediate clear output') - outs[:] = [] - self.clear_display_id_mapping(cell_index) + self.clear_output(outs, msg, cell_index) continue elif msg_type.startswith('comm'): + self.handle_comm_msg(msg) continue display_id = None @@ -496,33 +491,49 @@ def run_cell(self, cell, cell_index=0): # update_display_data doesn't get recorded continue - if clear_before_next_output: - self.log.debug('Executing delayed clear_output') - outs[:] = [] - self.clear_display_id_mapping(cell_index) - clear_before_next_output = False + self.output(outs, msg, display_id, cell_index) - try: - out = output_from_msg(msg) - except ValueError: - self.log.error("unhandled iopub msg: " + msg_type) - continue - if display_id: - # record output index in: - # _display_id_map[display_id][cell_idx] - cell_map = self._display_id_map.setdefault(display_id, {}) - output_idx_list = cell_map.setdefault(cell_index, []) - output_idx_list.append(len(outs)) + return exec_reply, outs - outs.append(out) + def output(self, outs, msg, display_id, cell_index): + msg_type = msg['msg_type'] + if self.clear_before_next_output: + self.log.debug('Executing delayed clear_output') + outs[:] = [] + self.clear_display_id_mapping(cell_index) + self.clear_before_next_output = False - return exec_reply, outs + try: + out = output_from_msg(msg) + except ValueError: + self.log.error("unhandled iopub msg: " + msg_type) + return + if display_id: + # record output index in: + # _display_id_map[display_id][cell_idx] + cell_map = self._display_id_map.setdefault(display_id, {}) + output_idx_list = cell_map.setdefault(cell_index, []) + output_idx_list.append(len(outs)) + outs.append(out) + + def clear_output(self, outs, msg, cell_index): + content = msg['content'] + if content.get('wait'): + self.log.debug('Wait to clear output') + self.clear_before_next_output = True + else: + self.log.debug('Immediate clear output') + outs[:] = [] + self.clear_display_id_mapping(cell_index) def clear_display_id_mapping(self, cell_index): for display_id, cell_map in self._display_id_map.items(): if cell_index in cell_map: cell_map[cell_index] = [] + def handle_comm_msg(self, msg): + pass + def executenb(nb, cwd=None, km=None, **kwargs): """Execute a notebook's code, updating outputs within the notebook object. From 741332a857913f3be72d759a032e239a91141df6 Mon Sep 17 00:00:00 2001 From: Maarten Breddels Date: Thu, 21 Mar 2019 15:29:09 +0100 Subject: [PATCH 3/3] pass same arguments to handle_comm_msg --- nbconvert/preprocessors/execute.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nbconvert/preprocessors/execute.py b/nbconvert/preprocessors/execute.py index 22ee28f20..205f9efc9 100644 --- a/nbconvert/preprocessors/execute.py +++ b/nbconvert/preprocessors/execute.py @@ -479,7 +479,7 @@ def run_cell(self, cell, cell_index=0): self.clear_output(outs, msg, cell_index) continue elif msg_type.startswith('comm'): - self.handle_comm_msg(msg) + self.handle_comm_msg(outs, msg, cell_index) continue display_id = None @@ -531,7 +531,7 @@ def clear_display_id_mapping(self, cell_index): if cell_index in cell_map: cell_map[cell_index] = [] - def handle_comm_msg(self, msg): + def handle_comm_msg(self, outs, msg, cell_index): pass def executenb(nb, cwd=None, km=None, **kwargs):