Source code for peep
# Copyright 2013 litl, LLC. All Rights Reserved
# coding: utf-8
import collections
import cProfile
import gc
import os
import pstats
import sys
import tempfile
import time
import traceback
__version__ = "0.9.0"
def _visit_referents(root):
"""Yield the objects reachable from obj
This yields each object once, in no particular order.
"""
seen = set()
left = collections.deque([root])
while left:
obj = left.popleft()
if id(obj) in seen:
continue
yield obj
seen.add(id(obj))
for child in gc.get_referents(obj):
left.append(child)
def print_stats(stats):
stats.strip_dirs().sort_stats("cumulative").print_stats(10)
class cpu_profile(object):
def __init__(self, callback):
self.callback = callback
def __call__(self, func):
def wrapped(*args, **kwargs):
prof = cProfile.Profile()
ret = prof.runcall(func, *args, **kwargs)
with tempfile.NamedTemporaryFile() as dumpfile:
prof.dump_stats(dumpfile.name)
stats = pstats.Stats(dumpfile.name)
self.callback(stats)
return ret
return wrapped
[docs]def mem_usage(obj):
"""Sum the bytes used by obj and any object reachable from obj
>>> peep.mem_usage([1, 2, 3, 4])
200
"""
return sum(sys.getsizeof(o) for o in _visit_referents(obj))
[docs]def mem_usage_by_type(obj):
"""Aggregate the memory usage of objects reachable from obj (by type)
>>> peep.mem_usage_by_type([1, 2, 3, 4, (1, 2)])
{<type 'list'>: 112, <type 'tuple'>: 72, <type 'int'>: 24}
"""
# This would use a collections.Counter(), but that doesn't exist
# in 2.6. You can always collections.Counter(result) on 2.7 if
# you want its methods.
counts = dict()
for o in _visit_referents(obj):
counts.setdefault(type(o), 0)
counts[type(o)] += sys.getsizeof(o)
return counts
[docs]def call_on_change(callable):
"""Call callable() once, then whenever Python source files are changed
Print the result after each execution. Catch exceptions and print
those, too.
This doesn't yet manage dependencies between loaded modules, so if
"bar" requires "foo" it will not be reloaded when "foo" is
changed.
"""
while 1:
lastrun = time.time()
print "========", lastrun
try:
print callable()
except:
traceback.print_exc()
# poll until some .pyc file has changed
while 1:
restart = False
for module in filter(_is_py_module, sys.modules.values()):
if _module_changed_since(lastrun, module):
print "=== reloading", module
try:
reload(module)
restart = True
except:
restart = False
lastrun = time.time()
traceback.print_exc()
continue
if restart:
break
time.sleep(0.5)
def _module_changed_since(since, module):
filename = getattr(module, "__file__", None)
if filename and os.path.exists(filename)\
and _py_changed_since(since, filename):
return True
def _py_changed_since(since, filename):
"""True if the filename (or associated .py) has been modified"""
if filename.endswith(".pyc") or filename.endswith(".pyo"):
filename = filename[:-1]
return filename.endswith(".py") and os.path.getmtime(filename) > since
def _is_py_module(module):
"""True if the module has been loaded from a .py file"""
exts = frozenset([".pyc", ".pyo", ".py"])
filename = getattr(module, "__file__", None)
return filename and any(filename.endswith(ext) for ext in exts)