Discussion of the ways a value in Locals/Watch can have children


I am posting this as a single place to put information about all the various ways that a value in Locals or Watch can have children, and the rules or issues involved with each.
This is my understanding of the rules. Anyone please feel free to edit this text directly to make corrections.


An attribute of val is any name that appears in dir(val). It includes properties. The value for name is val.name.
PTVS excludes certain attributes:
  • Anything of the form __xxx__.
  • Anything where val.name.__call__ exists. This includes all user-defined methods defined at the class level for an instance, but it also excludes any other callable objects. Proposal, please come up with some criterion to show more of these objects without cluttering up the space. If names that are found only in the class tree are grouped separately, then I would suppose that all callable children could be shown without too much clutter.


Generally speaking, val is iterable if it behaves like some sort of sequence or mapping. It yields a sequence of values, and in the case of a mapping, (key, value) pairs.
Children are listed in iteration order. For a sequence, the names are [0], etc. and the values are the iterated values. For a mapping, the names are [key] (using repr() of the key) and value from the iterated pairs.
Sequence and mapping types are supposed to provide len(val), iter(val) and val[key]. But not all of these are required to successfully enumerate the children.
Issues for discussion are:
  1. Distinguishing mapping types and what are the keys and values.
    A mapping type is an object that can generate (key, value) pairs in one of various ways. A val.items/iteritems/viewitems() method should be used if it exists. Otherwise, a val.keys/iterkeys/viewkeys() method should be used if it exists. Otherwise, iter(val) should be used to get the keys.
    In the latter two cases, val[key] is evaluated for each key generated and should succeed.
    len(val) is used, if it exists, to limit the iterations, except for val.items() or val.keys(), which produce lists. If len(val) does not exist, then the number of iterations can be limited, as it is currently to 10,000.
    I like the idea of having a special child node for "items", which will show (key, value) tuples in the same order. This will allow the user to examine the keys by their children or adding to a Watch window.
    PTVS currently only treates types derived from dict as mapping types. Proposal: to do this for all mapping types as defined here.
  2. Distinguishing sequence types and what are the values.
    A sequence type is an object that can generate a sequence of values. It could have an iter(val). The length of the iteration can be limited to 10,000 if len(val) is not available, just as for mapping types. If there is no iter(val) then there must be a len(val) and val[n] must succeed for all 0 <= n < len(val).
    An object with iter(val) might be either a mapping type or a sequence type. The difference is in how the values coincide with val[] evaluations.
  3. Values that should not iterate the children.
    val should not iterate children if it has an iter() and iter(val) is val. Enumerating values from this object is destructive to the object and makes it an iterator. At present the only types of iterator that do not iterate children are generators. Proposal: to do this for all iterators.
  4. Being able to correctly expand descendants of the children.
    I believe all these problems will be solved by a possible change in PTVS in which the actual Python object being shown in the window is remembered, and later reused if expanded or added to a Watch window. See Issue #2074, comment by pminaev Jan 17 1:17 a.m. Even though the objects won't later be reevaluated, it's still nice to have an equivalent Python expression which will show up in the Watch window. The user can copy/paste or edit the expression text at her own risk, if it has side effects or an expansion (direct or indirect) has side effects.

Special child nodes and top level Locals nodes

As a way of making the screen less cluttered, certain categories of children or top level items might be grouped under special nodes. An example mentioned above would be <items> for mapping types. I don't know if you all would prefer <...> or some other spelling; however I suggest that a consistent convention be adopted and that it not be [...]. In C++, you see [Raw view] nodes for some objects, but that's OK because the brackets for sequences only contain numbers. Not the case with Python mapping types.
Some possibilities for categories are: (1) global variables at the top level, (2) imported modules (if not included with globals), (3) the class of an instance, (4) the base classes of a class, or perhaps each base class separately, (5) all attributes for an instance, wherever they are found, (6) all attributes for an instance that are found somewhere in the class tree, (7) special names (that is, __xxx__), and so on. I invite specific proposals of this nature.