/Lib/linecache.py

http://unladen-swallow.googlecode.com/ · Python · 138 lines · 118 code · 11 blank · 9 comment · 4 complexity · b20256f9679d51eee0e4c169b6b13e96 MD5 · raw file

  1. """Cache lines from files.
  2. This is intended to read lines from modules imported -- hence if a filename
  3. is not found, it will look down the module search path for a file by
  4. that name.
  5. """
  6. import sys
  7. import os
  8. __all__ = ["getline", "clearcache", "checkcache"]
  9. def getline(filename, lineno, module_globals=None):
  10. lines = getlines(filename, module_globals)
  11. if 1 <= lineno <= len(lines):
  12. return lines[lineno-1]
  13. else:
  14. return ''
  15. # The cache
  16. cache = {} # The cache
  17. def clearcache():
  18. """Clear the cache entirely."""
  19. global cache
  20. cache = {}
  21. def getlines(filename, module_globals=None):
  22. """Get the lines for a file from the cache.
  23. Update the cache if it doesn't contain an entry for this file already."""
  24. if filename in cache:
  25. return cache[filename][2]
  26. else:
  27. return updatecache(filename, module_globals)
  28. def checkcache(filename=None):
  29. """Discard cache entries that are out of date.
  30. (This is not checked upon each call!)"""
  31. if filename is None:
  32. filenames = cache.keys()
  33. else:
  34. if filename in cache:
  35. filenames = [filename]
  36. else:
  37. return
  38. for filename in filenames:
  39. size, mtime, lines, fullname = cache[filename]
  40. if mtime is None:
  41. continue # no-op for files loaded via a __loader__
  42. try:
  43. stat = os.stat(fullname)
  44. except os.error:
  45. del cache[filename]
  46. continue
  47. if size != stat.st_size or mtime != stat.st_mtime:
  48. del cache[filename]
  49. def updatecache(filename, module_globals=None):
  50. """Update a cache entry and return its list of lines.
  51. If something's wrong, print a message, discard the cache entry,
  52. and return an empty list."""
  53. if filename in cache:
  54. del cache[filename]
  55. if not filename or filename[0] + filename[-1] == '<>':
  56. return []
  57. fullname = filename
  58. try:
  59. stat = os.stat(fullname)
  60. except os.error, msg:
  61. basename = filename
  62. # Try for a __loader__, if available
  63. if module_globals and '__loader__' in module_globals:
  64. name = module_globals.get('__name__')
  65. loader = module_globals['__loader__']
  66. get_source = getattr(loader, 'get_source', None)
  67. if name and get_source:
  68. try:
  69. data = get_source(name)
  70. except (ImportError, IOError):
  71. pass
  72. else:
  73. if data is None:
  74. # No luck, the PEP302 loader cannot find the source
  75. # for this module.
  76. return []
  77. cache[filename] = (
  78. len(data), None,
  79. [line+'\n' for line in data.splitlines()], fullname
  80. )
  81. return cache[filename][2]
  82. # Try looking through the module search path, which is only useful
  83. # when handling a relative filename.
  84. if os.path.isabs(filename):
  85. return []
  86. for dirname in sys.path:
  87. # When using imputil, sys.path may contain things other than
  88. # strings; ignore them when it happens.
  89. try:
  90. fullname = os.path.join(dirname, basename)
  91. except (TypeError, AttributeError):
  92. # Not sufficiently string-like to do anything useful with.
  93. pass
  94. else:
  95. try:
  96. stat = os.stat(fullname)
  97. break
  98. except os.error:
  99. pass
  100. else:
  101. # No luck
  102. ## print '*** Cannot stat', filename, ':', msg
  103. return []
  104. try:
  105. fp = open(fullname, 'rU')
  106. lines = fp.readlines()
  107. fp.close()
  108. except IOError, msg:
  109. ## print '*** Cannot open', fullname, ':', msg
  110. return []
  111. size, mtime = stat.st_size, stat.st_mtime
  112. cache[filename] = size, mtime, lines, fullname
  113. return lines