[debugger] PY-85094 enable "view as" in children attributes of container variables

Merge-request: IJ-MR-180781
Merged-by: Maxim Popov <maxim.popov@jetbrains.com>

(cherry picked from commit d402a21be94b40c89aa2317da891eba59d41d25c)

IJ-MR-180781

GitOrigin-RevId: 597aa0a5fdd28e13d291c3b9f717e6aa3d4b4fe3
This commit is contained in:
Maxim Popov
2025-11-02 23:34:50 +00:00
committed by intellij-monorepo-bot
parent 45632d5873
commit de9e369cd7
3 changed files with 77 additions and 15 deletions
@@ -24,3 +24,31 @@ def find_class_name(val):
class_name = class_name[:-2]
return class_name
def get_contents_debug_adapter_protocol_container(resolver, value, fmt):
dct = resolver.get_dictionary(value)
lst = sorted(dct.items(), key=lambda tup: sorted_attributes_key(tup[0]))
def evaluate_name(key):
if not key.startswith("[") and not key.endswith("]"):
return f".{key}"
else:
return key
lst = [(key, value, evaluate_name(key)) for (key, value) in lst]
return lst
def sorted_attributes_key(attr_name):
if attr_name.startswith("__"):
if attr_name.endswith("__"):
# __ double under before and after __
return 3, attr_name
else:
# __ double under before
return 2, attr_name
elif attr_name.startswith("_"):
# _ single under
return 1, attr_name
else:
# Regular (Before anything)
return 0, attr_name
@@ -1,10 +1,3 @@
from _pydevd_bundle.custom.pydevd_utils import get_var_and_offset
from _pydevd_bundle.pydevd_extension_api import TypeResolveProvider, \
StrPresentationProvider
from _pydevd_bundle.pydevd_resolver import defaultResolver
from .pydevd_helpers import find_mod_attr
from _pydevd_bundle.custom.pydevd_repr_utils import get_value_repr
import inspect
try:
@@ -12,13 +5,20 @@ try:
except:
OrderedDict = dict
from _pydevd_bundle.custom.pydevd_repr_utils import get_value_repr
from _pydevd_bundle.custom.pydevd_utils import get_var_and_offset
from _pydevd_bundle.pydevd_extension_api import TypeResolveProvider, \
StrPresentationProvider
from _pydevd_bundle.pydevd_resolver import defaultResolver
from .pydevd_helpers import find_mod_attr, sorted_attributes_key
TOO_LARGE_MSG = "Maximum number of items (%s) reached. To show more items customize the value of the PYDEVD_CONTAINER_NUMPY_MAX_ITEMS environment variable."
TOO_LARGE_ATTR = "Unable to handle:"
IS_PYCHARM = True
MAX_ITEMS_TO_HANDLE = 300 if not IS_PYCHARM else 100
DEFAULT_PRECISION = 5
ARRAY_CONTAINER_ATTR_NAME = "array"
class NdArrayItemsContainer(object):
pass
@@ -79,7 +79,7 @@ class NDArrayTypeResolveProvider(object):
setattr(container, TOO_LARGE_ATTR, TOO_LARGE_MSG)
break
return container
if IS_PYCHARM and attribute == 'array':
if IS_PYCHARM and attribute == ARRAY_CONTAINER_ATTR_NAME:
container = NdArrayItemsContainer()
container.items = obj
return container
@@ -105,11 +105,25 @@ class NDArrayTypeResolveProvider(object):
if IS_PYCHARM:
container = NdArrayItemsContainer()
container.items = obj
ret['array'] = container
ret[ARRAY_CONTAINER_ATTR_NAME] = container
else:
ret['[0:%s] ' % (len(obj))] = list(obj[0:MAX_ITEMS_TO_HANDLE])
return ret
def get_contents_debug_adapter_protocol(self, value, fmt):
dct = self.get_dictionary(value)
lst = sorted(dct.items(), key=lambda tup: sorted_attributes_key(tup[0]))
def evaluate_name(key):
if key == ARRAY_CONTAINER_ATTR_NAME:
# container is just a variable for display, it cannot be accessed
return ""
else:
return key
lst = [(key, value, evaluate_name(key)) for (key, value) in lst]
return lst
class NDArrayStrProvider(StrPresentationProvider):
def can_provide(self, type_object, type_name):
nd_array = find_mod_attr('numpy', 'ndarray')
@@ -155,6 +169,19 @@ class NdArrayItemsContainerProvider(object):
d['__len__'] = l
return d
def get_contents_debug_adapter_protocol(self, value, fmt):
dct = self.get_dictionary(value)
lst = sorted(dct.items(), key=lambda tup: sorted_attributes_key(tup[0]))
def evaluate_name(key: str):
if key.isdigit():
# container indices have trailing zeros, we turn the representation
# into an int first
return f"[{int(key)}]"
return f".{key}"
lst = [(key, value, evaluate_name(key)) for (key, value) in lst]
return lst
import sys
if not sys.platform.startswith("java"):
@@ -1,14 +1,15 @@
import sys
from _pydevd_bundle.custom.pydevd_repr_utils import get_value_repr
from _pydevd_bundle.pydevd_constants import PANDAS_MAX_ROWS, PANDAS_MAX_COLS, PANDAS_MAX_COLWIDTH
from _pydevd_bundle.pydevd_extension_api import TypeResolveProvider, StrPresentationProvider
from _pydevd_bundle.pydevd_constants import PANDAS_MAX_ROWS, PANDAS_MAX_COLS, \
PANDAS_MAX_COLWIDTH
from _pydevd_bundle.pydevd_extension_api import TypeResolveProvider, \
StrPresentationProvider
from _pydevd_bundle.pydevd_resolver import inspect, MethodWrapperType
from _pydevd_bundle.pydevd_utils import Timer
from .pydevd_helpers import find_mod_attr
from contextlib import contextmanager
from .pydevd_helpers import find_mod_attr, get_contents_debug_adapter_protocol_container
def _get_dictionary(obj, replacements):
ret = dict()
@@ -97,6 +98,9 @@ class PandasDataFrameTypeResolveProvider(object):
}
return _get_dictionary(obj, replacements)
def get_contents_debug_adapter_protocol(self, value, fmt):
return get_contents_debug_adapter_protocol_container(self, value, fmt)
def get_str_in_context(self, df, context: str):
"""
:param context:
@@ -144,6 +148,9 @@ class PandasSeriesTypeResolveProvider(object):
}
return _get_dictionary(obj, replacements)
def get_contents_debug_adapter_protocol(self, value, fmt):
return get_contents_debug_adapter_protocol_container(self, value, fmt)
def get_str_in_context(self, df, context: str):
"""
:param context: