diff --git a/python/helpers/jupyter_debug/pydev_jupyter_vars.py b/python/helpers/jupyter_debug/pydev_jupyter_vars.py index e3589be5218c..1f4c914c567d 100644 --- a/python/helpers/jupyter_debug/pydev_jupyter_vars.py +++ b/python/helpers/jupyter_debug/pydev_jupyter_vars.py @@ -97,7 +97,15 @@ def table_command(command_text): print(res) -def image_table_command(command_text): +def image_start_load_table_command(command_text): + ipython_shell = get_ipython() + namespace = ipython_shell.user_ns + command, command_type, _ = command_text.split(NEXT_VALUE_SEPARATOR) + status, res = exec_image_table_command(command, command_type, None, None, namespace, namespace) + print(res) + + +def image_load_chunk_table_command(command_text): ipython_shell = get_ipython() namespace = ipython_shell.user_ns command, command_type, offset, image_id = command_text.split(NEXT_VALUE_SEPARATOR) diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_tables.py b/python/helpers/pydev/_pydevd_bundle/pydevd_tables.py index 1dc17b9f4592..626a277abec4 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_tables.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_tables.py @@ -5,6 +5,7 @@ from _pydevd_bundle import pydevd_vars from _pydevd_bundle.pydevd_constants import NEXT_VALUE_SEPARATOR from _pydevd_bundle.pydevd_xml import ExceptionOnEvaluate from _pydevd_bundle.tables.images.pydevd_image_loader import load_image_chunk +from typing import Optional class TableCommandType: @@ -27,7 +28,7 @@ def is_error_on_eval(val): return is_exception_on_eval def exec_image_table_command(init_command, command_type, offset, image_id, f_globals, f_locals): - # type: (str, str, [int, None], [str, None], dict, dict) -> (bool, str) + # type: (str, str, Optional[int], Optional[str], dict, dict) -> (bool, str) table = pydevd_vars.eval_in_context(init_command, f_globals, f_locals) is_exception_on_eval = is_error_on_eval(table) if is_exception_on_eval: diff --git a/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_image_loader.py b/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_image_loader.py index 7d995d0f9365..8f21139da55f 100644 --- a/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_image_loader.py +++ b/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_image_loader.py @@ -1,5 +1,7 @@ # Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. import base64 +import io +import uuid IMAGE_DATA_STORAGE = {} DEFAULT_IMAGE_FORMAT = 'PNG' @@ -27,4 +29,24 @@ def load_image_chunk(offset, image_id): except ValueError: return "Error: Invalid offset format." except Exception as e: - return "Error: {}".format(e) \ No newline at end of file + return "Error: {}".format(e) + + +def save_image_to_storage(image_data, format=DEFAULT_IMAGE_FORMAT, save_func=None): + # type: (any, str, callable) -> str + try: + bytes_buffer = io.BytesIO() + try: + if save_func: + save_func(bytes_buffer, format) + else: + image_data.save(bytes_buffer, format=format) + bytes_buffer.seek(0) + bytes_data = bytes_buffer.getvalue() + image_id = str(uuid.uuid4()) + IMAGE_DATA_STORAGE[image_id] = bytes_data + return "{};{}".format(image_id, len(bytes_data)) + finally: + bytes_buffer.close() + except Exception as e: + return "Error: {}".format(e) diff --git a/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_matplotlib_image.py b/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_matplotlib_image.py index f210bc34b3de..b4be7af557e9 100644 --- a/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_matplotlib_image.py +++ b/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_matplotlib_image.py @@ -1,22 +1,7 @@ # Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -import io import matplotlib -import uuid -from _pydevd_bundle.tables.images.pydevd_image_loader import IMAGE_DATA_STORAGE -from _pydevd_bundle.tables.images.pydevd_image_loader import DEFAULT_IMAGE_FORMAT +from _pydevd_bundle.tables.images.pydevd_image_loader import save_image_to_storage, DEFAULT_IMAGE_FORMAT def create_image(matplotlib_figure): # type: (matplotlib.figure.Figure) -> str - try: - bytes_buffer = io.BytesIO() - try: - matplotlib_figure.savefig(bytes_buffer, format=DEFAULT_IMAGE_FORMAT) - bytes_buffer.seek(0) - bytes_data = bytes_buffer.getvalue() - image_id = str(uuid.uuid4()) - IMAGE_DATA_STORAGE[image_id] = bytes_data - return "{};{}".format(image_id, len(bytes_data)) - finally: - bytes_buffer.close() - except Exception as e: - return "Error: {}".format(e) + return save_image_to_storage(matplotlib_figure, format=DEFAULT_IMAGE_FORMAT, save_func=lambda buffer, fmt: matplotlib_figure.savefig(buffer, format=fmt)) diff --git a/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_numpy_based_image.py b/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_numpy_based_image.py index a53adeceb738..9f3458cbbe7a 100644 --- a/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_numpy_based_image.py +++ b/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_numpy_based_image.py @@ -1,12 +1,7 @@ # Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. import numpy as np -import io -import uuid -from _pydevd_bundle.tables.images.pydevd_image_loader import IMAGE_DATA_STORAGE -from _pydevd_bundle.tables.images.pydevd_image_loader import DEFAULT_IMAGE_FORMAT -from _pydevd_bundle.tables.images.pydevd_image_loader import RGB_MODE -from _pydevd_bundle.tables.images.pydevd_image_loader import RGBA_MODE -from _pydevd_bundle.tables.images.pydevd_image_loader import GRAYSCALE_MODE + +from _pydevd_bundle.tables.images.pydevd_image_loader import (save_image_to_storage, GRAYSCALE_MODE, RGB_MODE, RGBA_MODE) try: import tensorflow as tf @@ -57,16 +52,7 @@ def create_image(arr): mode = RGBA_MODE else: mode = RGB_MODE - bytes_buffer = io.BytesIO() - try: - image = Image.fromarray(arr_to_convert, mode=mode) - image.save(bytes_buffer, format=DEFAULT_IMAGE_FORMAT) - bytes_data = bytes_buffer.getvalue() - image_id = str(uuid.uuid4()) - IMAGE_DATA_STORAGE[image_id] = bytes_data - return "{};{}".format(image_id, len(bytes_data)) - finally: - bytes_buffer.close() + return save_image_to_storage(Image.fromarray(arr_to_convert, mode=mode)) except ImportError: return "Error: Pillow library is not installed." diff --git a/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_numpy_image.py b/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_numpy_image.py index 2913967eb323..48d059c78272 100644 --- a/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_numpy_image.py +++ b/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_numpy_image.py @@ -1,12 +1,6 @@ # Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. import numpy as np -import io -import uuid -from _pydevd_bundle.tables.images.pydevd_image_loader import IMAGE_DATA_STORAGE -from _pydevd_bundle.tables.images.pydevd_image_loader import DEFAULT_IMAGE_FORMAT -from _pydevd_bundle.tables.images.pydevd_image_loader import RGB_MODE -from _pydevd_bundle.tables.images.pydevd_image_loader import RGBA_MODE -from _pydevd_bundle.tables.images.pydevd_image_loader import GRAYSCALE_MODE +from _pydevd_bundle.tables.images.pydevd_image_loader import (save_image_to_storage, GRAYSCALE_MODE, RGB_MODE, RGBA_MODE) def create_image(arr): # type: (np.ndarray) -> str @@ -39,16 +33,7 @@ def create_image(arr): else: mode = RGB_MODE - bytes_buffer = io.BytesIO() - try: - image = Image.fromarray(arr_to_convert, mode=mode) - image.save(bytes_buffer, format=DEFAULT_IMAGE_FORMAT) - bytes_data = bytes_buffer.getvalue() - image_id = str(uuid.uuid4()) - IMAGE_DATA_STORAGE[image_id] = bytes_data - return "{};{}".format(image_id, len(bytes_data)) - finally: - bytes_buffer.close() + return save_image_to_storage(Image.fromarray(arr_to_convert, mode=mode)) except ImportError: return "Error: Pillow library is not installed." diff --git a/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_pillow_image.py b/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_pillow_image.py index dedbab77d4b8..467eff21494a 100644 --- a/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_pillow_image.py +++ b/python/helpers/pydev/_pydevd_bundle/tables/images/pydevd_pillow_image.py @@ -1,22 +1,8 @@ # Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -import io import PIL -import uuid -from _pydevd_bundle.tables.images.pydevd_image_loader import IMAGE_DATA_STORAGE -from _pydevd_bundle.tables.images.pydevd_image_loader import DEFAULT_IMAGE_FORMAT +from _pydevd_bundle.tables.images.pydevd_image_loader import save_image_to_storage, DEFAULT_IMAGE_FORMAT def create_image(pillow_image): # type: (PIL.Image.Image) -> str - try: - bytes_buffer = io.BytesIO() - try: - image_format = pillow_image.format if pillow_image.format else DEFAULT_IMAGE_FORMAT - pillow_image.save(bytes_buffer, format=image_format) - bytes_data = bytes_buffer.getvalue() - image_id = str(uuid.uuid4()) - IMAGE_DATA_STORAGE[image_id] = bytes_data - return "{};{}".format(image_id, len(bytes_data)) - finally: - bytes_buffer.close() - except Exception as e: - return "Error: {}".format(e) + image_format = pillow_image.format if pillow_image.format else DEFAULT_IMAGE_FORMAT + return save_image_to_storage(pillow_image, format=image_format)