Worked Example: Reviewing a Brittle Source-Recovery Tool¶
Page Maps¶
graph LR
family["Python Programming"]
program["Python Meta-Programming"]
section["Runtime Objects Object Model"]
page["Worked Example: Reviewing a Brittle Source-Recovery Tool"]
capstone["Capstone evidence"]
family --> program --> section --> page
page -.applies in.-> capstone
flowchart LR
orient["Orient on the page map"] --> read["Read the main claim and examples"]
read --> inspect["Inspect the related code, proof, or capstone surface"]
inspect --> verify["Run or review the verification path"]
verify --> apply["Apply the idea back to the module and capstone"]
The five core lessons in Module 01 are easiest to trust when they show up in one review incident that feels tempting and flawed at the same time.
This example starts with a helper that looks clever in a small demo:
- it receives a function object
- it reads
func.__code__.co_filename - it reads
func.__code__.co_firstlineno - it scans the source file by indentation
- it claims to "recover the source" of the function
On a tiny script, that can appear to work. In a real codebase, it is brittle enough to mislead reviewers and users.
That makes it the right worked example for Module 01.
The incident¶
Assume a team built a debugging helper called print_source(func) to show "the real
implementation" of a callable during incident review.
The team reports four problems:
- decorated functions often print wrapper code instead of the original implementation
- nested functions lose their surrounding context and look harder to understand
- REPL or notebook code raises file-related errors
- formatting changes can break the indentation-based extraction logic
Every one of those failures is rooted in the Module 01 object model.
The starting helper¶
def print_source(func):
code = func.__code__
filename = code.co_filename
start_line = code.co_firstlineno - 1
if not filename or "<" in filename:
raise OSError(f"Cannot read real file for {filename!r}")
with open(filename, "r", encoding="utf-8") as handle:
lines = handle.readlines()
if start_line < 0 or start_line >= len(lines):
raise ValueError("co_firstlineno is out of bounds for file")
def_line = lines[start_line]
def_indent = len(def_line) - len(def_line.lstrip(" \t"))
result = [def_line]
index = start_line + 1
while index < len(lines):
line = lines[index]
stripped = line.lstrip(" \t")
current_indent = len(line) - len(stripped)
if stripped and current_indent <= def_indent and not stripped.startswith(")"):
break
result.append(line)
index += 1
while result and not result[-1].strip():
result.pop()
print("".join(result), end="")
The helper is not nonsense. That is exactly why it is a useful review example.
It uses real runtime facts from the function object. The mistake is treating those facts as a stable source-recovery contract.
Step 1: name the exact object surface being used¶
Before judging the helper, classify its inputs:
func.__code__is a code-object surfaceco_filenameis metadata about where the code thinks it came fromco_firstlinenois a starting-line hint
What is missing is just as important:
- no guaranteed end line
- no promise that the callable is the original undecorated function
- no promise that the filename points to a normal readable file
This is the first repair in thinking:
the helper is built on diagnostic surfaces, not on a supported source-recovery API.
That alone should lower your confidence immediately.
Step 2: explain why decorated functions fail¶
Suppose the codebase contains:
def decorated(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@decorated
def multiply(x, y):
return x * y
If you pass multiply into print_source, the function object you are inspecting is
often the wrapper returned by the decorator, not the original undecorated function.
That failure is pure Module 01:
- function objects are ordinary runtime objects
- decorators can replace one function object with another
- source recovery based on the current function object's
__code__therefore follows the replacement, not your intention
The helper is not "slightly off." It is answering a different question than the team thinks it is answering.
Step 3: explain why nested functions lose context¶
Now consider:
If you recover the source of outer(5), you may only extract the nested inner
definition without the surrounding scope that gives base meaning.
Again, this is a Module 01 object-model issue:
- the returned callable is a function object with closure state
- the closure carries captured bindings, not rich source context
- code-object line metadata is not a complete model of lexical meaning
The function still works because closures are runtime objects. The source-recovery helper still fails because it is trying to reconstruct source-level context from insufficient runtime metadata.
Step 4: explain why non-file contexts fail¶
Interactive and generated environments make the problem worse.
In a REPL, notebook, zipapp, or tool-managed runtime:
co_filenamemay point to a synthetic label like"<stdin>"- the original file may not exist anymore
- the code may have been transformed before execution
The helper reacts by raising OSError, but the runtime point is broader:
a function object is real even when its original source file is absent, synthetic, or transformed.
That is why source recovery is the wrong mental model for the core runtime object boundary.
Step 5: formatting breaks the heuristic even in files¶
Even in ordinary files, indentation scanning is a weak boundary detector.
Small changes can break it:
- multi-line signatures
- decorators above the function
- nested definitions
- comments and blank lines arranged unexpectedly
- code generators or formatters that alter layout without changing meaning
That is a useful Module 01 warning sign:
if a runtime trick depends on surface formatting to recover semantics, it is already too far from the object model to trust as a core capability.
A stronger first move: ask for supported introspection first¶
If the real goal is debugging or review, a better first move is usually:
inspect.signature(func)func.__name__func.__qualname__func.__module__inspect.getsource(func)when available, with a clear failure path
That is not perfect either, but it is a healthier contract:
- use supported introspection first
- treat source retrieval as conditional
- fail clearly instead of pretending a heuristic is ground truth
A healthier rewrite¶
import inspect
def describe_function(func):
print("name:", func.__name__)
print("qualified name:", func.__qualname__)
print("module:", func.__module__)
print("signature:", inspect.signature(func))
try:
source = inspect.getsource(func)
except OSError as exc:
print("source unavailable:", exc)
else:
print(source.rstrip())
This rewrite is more honest because it does not claim that the runtime object model can guarantee source reconstruction. It reports what the function object actually knows and then asks a supported helper for source when possible.
What this example teaches about Module 01¶
This worked example ties the module together:
- functions are runtime objects with metadata and code objects
- decorators can replace one function object with another
- closures carry runtime bindings, not recovered source context
- modules matter because filenames and globals come from runtime context, not from abstract source alone
- supported and diagnostic surfaces must be kept separate
That is the durable takeaway. The helper fails not because Python is inconsistent, but because the tool asked the runtime object model to promise more than it actually promises.
The review loop to keep¶
When you meet a clever introspection helper, run this loop:
- name the exact object surfaces it depends on
- classify those surfaces as supported or diagnostic-only
- list the runtime situations where the helper's assumptions stop holding
- rewrite the tool around supported facts first
If you can do that here, Module 01 has done its job and Module 02 can teach safe inspection with much less ambiguity.
Continue through Module 01¶
- Previous: Object Graph and Runtime Cycle
- Next: Exercises
- Reference: Exercise Answers
- Terms: Glossary