/lib/appengine-ndb-experiment/ndb/utils.py

https://code.google.com/p/webapp-improved/ · Python · 100 lines · 75 code · 10 blank · 15 comment · 22 complexity · 11ec5362bb226c25432236fef22f2faf MD5 · raw file

  1. import logging
  2. import os
  3. import sys
  4. DEBUG = True # Set to False for some speedups
  5. def wrapping(wrapped):
  6. # A decorator to decorate a decorator's wrapper. Following the lead
  7. # of Twisted and Monocle, this is supposed to make debugging heavily
  8. # decorated code easier. We'll see...
  9. # TODO: Evaluate; so far it hasn't helped (nor hurt).
  10. def wrapping_wrapper(wrapper):
  11. wrapper.__name__ = wrapped.__name__
  12. wrapper.__doc__ = wrapped.__doc__
  13. wrapper.__dict__.update(wrapped.__dict__)
  14. return wrapper
  15. return wrapping_wrapper
  16. def get_stack(limit=10):
  17. # Return a list of strings showing where the current frame was called.
  18. if not DEBUG:
  19. return ()
  20. frame = sys._getframe(1) # Always skip get_stack() itself.
  21. lines = []
  22. while len(lines) < limit and frame is not None:
  23. locals = frame.f_locals
  24. ndb_debug = locals.get('__ndb_debug__')
  25. if ndb_debug != 'SKIP':
  26. line = frame_info(frame)
  27. if ndb_debug is not None:
  28. line += ' # ' + str(ndb_debug)
  29. lines.append(line)
  30. frame = frame.f_back
  31. return lines
  32. def func_info(func, lineno=None):
  33. code = func.func_code
  34. return code_info(code, lineno)
  35. def gen_info(gen):
  36. frame = gen.gi_frame
  37. if gen.gi_running:
  38. prefix = 'running generator '
  39. elif frame:
  40. if frame.f_lasti < 0:
  41. prefix = 'initial generator '
  42. else:
  43. prefix = 'suspended generator '
  44. else:
  45. prefix = 'terminated generator '
  46. if frame:
  47. return prefix + frame_info(frame)
  48. code = getattr(gen, 'gi_code', None)
  49. if code:
  50. return prefix + code_info(code)
  51. return prefix + hex(id(gen))
  52. def frame_info(frame):
  53. return code_info(frame.f_code, frame.f_lineno)
  54. def code_info(code, lineno=None):
  55. funcname = code.co_name
  56. # TODO: Be cleverer about stripping filename,
  57. # e.g. strip based on sys.path.
  58. filename = os.path.basename(code.co_filename)
  59. if lineno is None:
  60. lineno = code.co_firstlineno
  61. return '%s(%s:%s)' % (funcname, filename, lineno)
  62. def logging_debug(*args):
  63. # NOTE: If you want to see debug messages, set the logging level
  64. # manually to logging.DEBUG - 1; or for tests use -v -v -v (see below).
  65. if DEBUG and logging.getLogger().level < logging.DEBUG:
  66. logging.debug(*args)
  67. def tweak_logging():
  68. # Hack for running tests with verbose logging. If there are two or
  69. # more -v flags, turn on INFO logging; if there are 3 or more, DEBUG.
  70. # (A single -v just tells unittest.main() to print the name of each
  71. # test; we don't want to interfere with that.)
  72. # Also, if there is a -q flag, set DEBUG to False, suppressing more
  73. # debug info even from warnings.
  74. q = 0
  75. v = 0
  76. for arg in sys.argv[1:]:
  77. if arg.startswith('-v'):
  78. v += arg.count('v')
  79. if arg.startswith('-q'):
  80. q += arg.count('q')
  81. if v >= 2:
  82. level = logging.INFO
  83. if v >= 3:
  84. level = logging.DEBUG - 1
  85. logging.basicConfig(level=level)
  86. if q > 0:
  87. global DEBUG
  88. DEBUG = False
  89. if sys.argv[0].endswith('_test.py'):
  90. tweak_logging()