The linecache module provides efficient access to individual lines from text files, with special support for Python source code. Tools such as traceback, debuggers, inspectors, and static analyzers use it to recover the source line associated with a frame without reopening and scanning the file for every lookup.
The API is small, but its behavior includes a process-global cache, invalidation, encoding rules, and support for modules loaded through import hooks. Understanding those details helps when building diagnostics, code browsers, editors, and error-reporting systems.
Read one line
The main function is linecache.getline(filename, lineno). Line numbers start at 1.
import linecache
line = linecache.getline("application.py", 12)
print(line)
A successful result normally includes the trailing newline. When the file or line cannot be read, the function commonly returns an empty string instead of raising ordinary file errors.
Line numbering starts at one
Unlike Python lists, the first source line is line 1. This matches tracebacks, editors, compiler messages, and AST positions.
first = linecache.getline("app.py", 1)
Validate user-supplied line numbers so zero, negative values, and unexpectedly large values do not create confusing reports.
Understand the empty result
An empty string can mean that the file does not exist, the line is outside the range, reading failed, or source is unavailable. The API is optimized for diagnostics, where failing to display source should not hide the original exception.
When your application must distinguish these conditions, validate the path and read the file directly with explicit error handling.
The global cache
After loading a file, linecache keeps information in a process-global cache. Later lookups avoid reopening and scanning the same file.
This is valuable when a traceback needs several lines from one source file. Long-running tools must still consider stale files and memory retained across many projects.
Refresh changed files
checkcache() compares metadata and removes entries that appear out of date.
linecache.checkcache("application.py")
line = linecache.getline("application.py", 12)
Without a filename, it checks eligible cache entries. Editors and development servers can call it before displaying source that may have changed.
Clear the cache
clearcache() removes all cached lines.
linecache.clearcache()
This is useful after a large batch, when switching workspaces, or when a long-running process must release source text. The next lookup reloads the file.
Do not clear on every request
Constant clearing removes the performance benefit. Invalidate when a known change occurs, when a workspace closes, or when measurements show meaningful memory pressure.
A file watcher can call checkcache() for modified paths instead of resetting everything.
Use module_globals when appropriate
getline() accepts an optional module_globals argument. It can help locate source for modules whose loader provides code without a conventional file.
line = linecache.getline(
filename,
number,
module_globals=module_globals,
)
This matters for import hooks, frozen modules, zip imports, and custom loaders.
Loaders and get_source
When a compatible loader is available, linecache can ask the import system for source, often through get_source(). That is why a traceback can sometimes display code even when the reported filename is not a normal filesystem path.
Custom loaders should implement import contracts correctly so debuggers and diagnostics can cooperate with them.
Source inside ZIP files
Applications distributed as ZIP archives or .pyz files may execute modules without extracting them. A loader can still expose their source.
See Python zipapp for packaging executable archives.
Generated code
Dynamically compiled code can use a symbolic filename passed to compile(). If no real file, cache entry, or loader provides the text, linecache cannot recover the line.
Frameworks that generate code should retain a controlled mapping between symbolic filenames and source if diagnostics need to display it. Avoid depending directly on undocumented cache structure.
Tracebacks
The traceback module uses linecache to show the source line for frames.
try:
run()
except Exception:
traceback.print_exc()
If a source file changes after code was loaded, the displayed line may not match the executing bytecode. This happens when deployments replace files without restarting processes.
Keep code and source aligned
Avoid modifying source beneath a live process. It continues executing old code objects while diagnostics may read new text.
Atomic deployments using versioned directories and controlled restarts preserve accurate tracebacks.
Python source encodings
Python files may declare a source encoding. Linecache works with Python’s source-reading machinery to interpret code in a compatible way.
When reading a complete source file yourself, tokenize.open() is explicit and reliable. See Python tokenize.
Trailing newlines
Returned lines normally include \n. Remove only that newline when a UI needs plain text.
text = linecache.getline(path, number).rstrip("\n")
Do not call strip() blindly because it removes meaningful indentation.
Preserve indentation
Whitespace shows block structure and affects Python syntax. Removing it makes diagnostics harder to understand and can misalign column markers.
Keep the original line and render indicators separately.
Column markers
Linecache retrieves text but does not interpret offsets. SyntaxError, tracebacks, tokens, and AST nodes may provide start and end positions.
line = linecache.getline(error.filename, error.lineno)
marker = " " * (error.offset - 1) + "^"
Tabs, Unicode, and byte-based offsets require care. Use tokenizer or AST positions for precise editor integration.
Show surrounding context
A diagnostic can display lines before and after the target.
def context(path, line_number, radius=2):
start = max(1, line_number - radius)
end = line_number + radius
return [
(number, linecache.getline(path, number))
for number in range(start, end + 1)
]
Stop at empty results beyond the file and keep the radius small to reduce noise and data exposure.
Build clearer diagnostics
Linters and validators can combine filename, line, column, message, and a short source excerpt.
config.py:18:7: invalid value
timeout = -1
^Do not copy whole files into logs. A narrow excerpt is easier to read and safer.
Path security
Never accept an arbitrary user path and pass it directly to linecache. The function can read any file available to the process.
Restrict lookups to a known workspace, resolve paths, and confirm that the target stays within the allowed root.
from pathlib import Path
root = Path("project").resolve()
target = (root / user_path).resolve()
if target != root and root not in target.parents:
raise ValueError("file is outside the project")
Also consider symlinks, permissions, and time-of-check versus time-of-use changes.
Privacy
Source lines can contain internal endpoints, customer names, queries, and secrets that were incorrectly committed. Treat excerpts as sensitive operational data.
Sanitize reports sent to external services and apply access and retention controls.
Concurrency
The cache is process-global. Threads can perform lookups, but invalidation and mutable source mean the result is not a transactional snapshot.
For a consistent analysis, read a file once and keep your own immutable copy rather than depending on the global cache.
Separate processes
Each process has its own cache. Clearing the parent cache does not affect workers.
Distributed analyzers should return compact diagnostics instead of assuming shared cached source.
Memory usage
Analyzing thousands of files can retain substantial text. Call clearcache() after finishing a repository or batch.
Measure first: for ordinary traceback use, the cache may be small and beneficial.
Very large files
Linecache is designed for convenient source access, not random-line queries over giant datasets. Loading a file can retain a list of its lines.
For large logs and data files, use indexes, seek operations, mmap, or a format designed for random access.
Temporary files
If a temporary file is deleted after entering the cache, lookups may continue returning old lines until invalidation.
This can preserve a late traceback, but it can also surprise a tool that expects the current filesystem state.
Metadata limitations
Cache validation relies on available metadata. Filesystems with coarse timestamp resolution, network synchronization, or rapid replacements can produce edge cases.
When exact identity matters, use immutable build paths or content hashes in your own layer.
Notebooks and interactive code
Interactive environments create symbolic filenames and maintain additional source caches. A name enclosed in angle brackets may not correspond to a real file.
Treat source availability as optional in notebooks, REPLs, dynamically generated functions, and embedded interpreters.
Integration with inspect
inspect.getsource() also depends on file and cache information to retrieve function and class source.
Builtins, native extensions, generated functions, and optimized distributions may have no source. Handle that as a normal result.
Integration with faulthandler
faulthandler emits minimal stacks during severe failures. Afterward, tooling can use linecache to enrich filenames and line numbers when matching source is still available.
See Python faulthandler.
Testing
Test the first and last line, missing files, out-of-range numbers, non-UTF encodings, changed files, cleared cache, custom loaders, ZIP modules, and hostile paths.
Use temporary files and reset cache state between tests to avoid order-dependent failures.
Avoid internal-cache dependencies
The internal cache dictionary exists, but its exact structure is not a stable application API. Prefer getline(), checkcache(), and clearcache().
Isolate any virtual-source integration and test it on every supported Python version.
When to read directly
Use Path.read_text() or tokenize.open() when you need the entire file, explicit errors, an immutable snapshot, or full encoding control.
Use linecache when the problem is quickly retrieving a diagnostic line.
Common mistakes
Common failures include using zero-based indexes, treating every empty result as a blank line, stripping indentation, forgetting stale cache, accepting arbitrary paths, using the module for huge data files, and assuming the current source matches running code.
Conclusion
linecache is a small but essential part of Python diagnostics. Use getline() for targeted lines, checkcache() when files may change, and clearcache() after large batches.
Preserve indentation, protect paths, and never treat the global cache as an immutable snapshot. Consult the official linecache documentation and Python tokenize.







