Exemple #1
0
 def test_long_typename_with_no_module(self):
     x = type('MyClass', (), {'__module__': None})()
     self.assertEqual('MyClass', objgraph._long_typename(x))
Exemple #2
0
 def test_long_typename_with_no_module(self):
     x = type('MyClass', (), {'__module__': None})()
     self.assertEqual('MyClass', objgraph._long_typename(x))
Exemple #3
0
def get_new_ids(skip_update=False, limit=10, sortby='deltas',  # pylint: disable=dangerous-default-value
                shortnames=None, ignore_thresholds=IGNORE_THRESHOLDS,
                output=None, _state={}):
    """Find and display new objects allocated since last call.

    Shows the increase in object counts since last call to this
    function and returns the memory address ids for new objects.

    Returns a dictionary mapping object type names to sets of object IDs
    that have been created since the last time this function was called.

    ``skip_update`` (bool): If True, returns the same dictionary that
    was returned during the previous call without updating the internal
    state or examining the objects currently in memory.

    ``limit`` (int): The maximum number of rows that you want to print
    data for.  Use 0 to suppress the printing.  Use None to print everything.

    ``sortby`` (str): This is the column that you want to sort by in
    descending order.  Possible values are: 'old', 'current', 'new',
    'deltas'

    ``shortnames`` (bool): If True, classes with the same name but
    defined in different modules will be lumped together.  If False,
    all type names will be qualified with the module name.  If None (default),
    ``get_new_ids`` will remember the value from previous calls, so it's
    enough to prime this once.  By default the primed value is True.

    ``_state`` (dict): Stores old, current, and new_ids in memory.
    It is used by the function to store the internal state between calls.
    Never pass in this argument unless you know what you're doing.

    The caveats documented in :func:`growth` apply.

    When one gets new_ids from :func:`get_new_ids`, one can use
    :func:`at_addrs` to get a list of those objects. Then one can iterate over
    the new objects, print out what they are, and call :func:`show_backrefs` or
    :func:`show_chain` to see where they are referenced.

    Example:

        >>> _ = get_new_ids() # store current objects in _state
        >>> _ = get_new_ids() # current_ids become old_ids in _state
        >>> a = [0, 1, 2] # list we don't know about
        >>> b = [3, 4, 5] # list we don't know about
        >>> new_ids = get_new_ids(limit=3) # we see new lists
        ======================================================================
        Type                    Old_ids  Current_ids      New_ids Count_Deltas
        ======================================================================
        list                        324          326           +3           +2
        dict                       1125         1125           +0           +0
        wrapper_descriptor         1001         1001           +0           +0
        ======================================================================
        >>> new_lists = at_addrs(new_ids['list'])
        >>> a in new_lists
        True
        >>> b in new_lists
        True
    """
    if ignore_thresholds is None:
        ignore_thresholds = IGNORE_THRESHOLDS
    _initialize_state(_state)
    new_ids = _state['new']
    if skip_update:
        return new_ids
    old_ids = _state['old']
    current_ids = _state['current']
    if shortnames is None:
        shortnames = _state['shortnames']
    else:
        _state['shortnames'] = shortnames
    gc.collect()
    objects = gc.get_objects()
    for class_name in old_ids:
        old_ids[class_name].clear()
    for class_name, ids_set in current_ids.items():
        old_ids[class_name].update(ids_set)
    for class_name in current_ids:
        current_ids[class_name].clear()
    for o in objects:
        if shortnames:
            class_name = _short_typename(o)
        else:
            class_name = _long_typename(o)
        id_number = id(o)
        current_ids[class_name].add(id_number)
    for class_name in new_ids:
        new_ids[class_name].clear()
    rows = []
    keys_to_remove = []
    for class_name in current_ids:
        num_old = len(old_ids[class_name])
        num_current = len(current_ids[class_name])
        if num_old == 0 and num_current == 0:
            # remove the key from our dicts if we don't have any old or
            # current class_name objects
            keys_to_remove.append(class_name)
            continue
        new_ids_set = current_ids[class_name] - old_ids[class_name]
        new_ids[class_name].update(new_ids_set)
        num_new = len(new_ids_set)
        num_delta = num_current - num_old
        if num_delta < 1 or (class_name in ignore_thresholds and num_current < ignore_thresholds[class_name]):
            # ignore types with no net increase or whose overall count isn't large enough to worry us
            if class_name in new_ids:
                del new_ids[class_name]
            continue
        row = (class_name, num_old, num_current, num_new, num_delta)
        rows.append(row)
    for key in keys_to_remove:
        del old_ids[key]
        del current_ids[key]
        if key in new_ids:
            del new_ids[key]
    index_by_sortby = {'old': 1, 'current': 2, 'new': 3, 'deltas': 4}
    rows.sort(key=operator.itemgetter(index_by_sortby[sortby], 0),
              reverse=True)
    _show_results(rows, limit, output)
    return new_ids