linecache.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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. try:
  27. return updatecache(filename, module_globals)
  28. except MemoryError:
  29. clearcache()
  30. return []
  31. def checkcache(filename=None):
  32. """Discard cache entries that are out of date.
  33. (This is not checked upon each call!)"""
  34. if filename is None:
  35. filenames = cache.keys()
  36. else:
  37. if filename in cache:
  38. filenames = [filename]
  39. else:
  40. return
  41. for filename in filenames:
  42. size, mtime, lines, fullname = cache[filename]
  43. if mtime is None:
  44. continue # no-op for files loaded via a __loader__
  45. try:
  46. stat = os.stat(fullname)
  47. except os.error:
  48. del cache[filename]
  49. continue
  50. if size != stat.st_size or mtime != stat.st_mtime:
  51. del cache[filename]
  52. def updatecache(filename, module_globals=None):
  53. """Update a cache entry and return its list of lines.
  54. If something's wrong, print a message, discard the cache entry,
  55. and return an empty list."""
  56. if filename in cache:
  57. del cache[filename]
  58. if not filename or (filename.startswith('<') and filename.endswith('>')):
  59. return []
  60. fullname = filename
  61. try:
  62. stat = os.stat(fullname)
  63. except OSError:
  64. basename = filename
  65. # Try for a __loader__, if available
  66. if module_globals and '__loader__' in module_globals:
  67. name = module_globals.get('__name__')
  68. loader = module_globals['__loader__']
  69. get_source = getattr(loader, 'get_source', None)
  70. if name and get_source:
  71. try:
  72. data = get_source(name)
  73. except (ImportError, IOError):
  74. pass
  75. else:
  76. if data is None:
  77. # No luck, the PEP302 loader cannot find the source
  78. # for this module.
  79. return []
  80. cache[filename] = (
  81. len(data), None,
  82. [line+'\n' for line in data.splitlines()], fullname
  83. )
  84. return cache[filename][2]
  85. # Try looking through the module search path, which is only useful
  86. # when handling a relative filename.
  87. if os.path.isabs(filename):
  88. return []
  89. for dirname in sys.path:
  90. # When using imputil, sys.path may contain things other than
  91. # strings; ignore them when it happens.
  92. try:
  93. fullname = os.path.join(dirname, basename)
  94. except (TypeError, AttributeError):
  95. # Not sufficiently string-like to do anything useful with.
  96. continue
  97. try:
  98. stat = os.stat(fullname)
  99. break
  100. except os.error:
  101. pass
  102. else:
  103. return []
  104. try:
  105. with open(fullname, 'rU') as fp:
  106. lines = fp.readlines()
  107. except IOError:
  108. return []
  109. if lines and not lines[-1].endswith('\n'):
  110. lines[-1] += '\n'
  111. size, mtime = stat.st_size, stat.st_mtime
  112. cache[filename] = size, mtime, lines, fullname
  113. return lines