Python linecache: Read Source Lines

Published on: August 27, 2026
Reading time: 7 minutes
A developer typing code on a laptop with a Python book beside in an office.

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.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python faulthandler: Diagnose Crashes

    Learn Python faulthandler to diagnose crashes, deadlocks, fatal signals, timeouts, and hangs with stack dumps from every thread.

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026
    Detailed view of programming code in a dark theme on a computer screen.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python symtable: Analyze Name Scopes

    Learn Python symtable to analyze scopes, locals, globals, parameters, imports, nonlocals, closures, and compiler namespaces.

    Ler mais

    Tempo de leitura: 9 minutos
    27/08/2026
    A close-up shot showcasing the intricate scales of a snake, highlighting texture and color.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python dis: Understand Bytecode

    Learn Python dis to inspect bytecode instructions, jumps, stack effects, adaptive caches, and optimizations without relying on unstable internals.

    Ler mais

    Tempo de leitura: 6 minutos
    27/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python tokenize: Read Source Code Tokens

    Learn Python tokenize to read tokens, comments, encodings, indentation, and positions, then transform and rebuild source safely.

    Ler mais

    Tempo de leitura: 6 minutos
    27/08/2026
    High-angle view of woman coding on a laptop, with a Python book nearby. Ideal for programming and tech content.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python zipapp: Build Executable .pyz Files

    Learn Python zipapp to build .pyz files, define entry points, bundle pure dependencies, handle resources, and distribute secure CLI tools.

    Ler mais

    Tempo de leitura: 6 minutos
    27/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python sysconfig: Paths and Build Info

    Learn Python sysconfig to inspect paths, schemes, headers, compiler flags, ABI details, native extensions, and virtual environments.

    Ler mais

    Tempo de leitura: 6 minutos
    27/08/2026