How Holehe Sorts Results by Module Name in the `maincore` Function
Holehe sorts results alphabetically by module name using a standard Python sorted() call on the results list, extracting the function name from each module's string representation.
The maincore function in holehe/core.py orchestrates concurrent execution of multiple site-specific modules and ensures consistent output ordering. This article explains exactly how the sorting mechanism works, where the module names originate, and why this design ensures predictable results regardless of async completion order.
Where Module Names Originate
Each module in Holehe is an asynchronous function defined in holehe/modules/. When a module executes—whether successfully or with an exception—its name is captured for the final output dictionary.
In the launch_module function, the module name is extracted from the function object's string representation:
# holehe/core.py → lines 71-73
name = str(module).split('<function ')[1].split(' ')[0]
out.append({"name": name, ... })
This parsing extracts the function identifier (e.g., "github", "twitter", "instagram") from a string like <function github at 0x7f8b2c>. The name value becomes the sorting key used later in maincore.
The extraction occurs in both success and exception paths, ensuring every result has a consistent name field for alphabetical ordering.
The Sorting Implementation in maincore
After all modules complete their asynchronous execution, maincore performs the final ordering before displaying results. The sorting happens after the trio.open_nursery() context manager exits and all concurrent tasks have finished:
# holehe/core.py → lines 22-24
# Sort by modules names
out = sorted(out, key=lambda i: i['name'])
This single line guarantees that:
- Results appear in alphabetical order by module name
- Output is deterministic regardless of network latency or execution timing
- Downstream consumers (CLI output, JSON export, etc.) receive consistently ordered data
The sorted() function returns a new list, replacing the original out list with its ordered version before passing to print_result().
Complete Workflow in Context
The full maincore function demonstrates how sorting fits into the broader execution flow:
# holehe/core.py (excerpt)
async def maincore():
...
async with trio.open_nursery() as nursery:
for website in websites:
nursery.start_soon(launch_module, website, email, client, out)
# Sort by modules names
out = sorted(out, key=lambda i: i['name'])
await client.aclose()
print_result(out, args, email, start_time, websites)
...
Key observations about this pattern:
- Concurrent execution first: All modules run simultaneously via
trio.start_soon(), maximizing throughput - Aggregation unordered: Results accumulate in
outas modules complete, potentially in random order - Deterministic presentation: The final
sorted()call establishes user-friendly alphabetical ordering
Exception Handling and Name Extraction
When a module raises an exception, the same name extraction logic applies. The error case still produces a valid result entry with the module name intact:
# inside launch_module
except Exception:
# Extract the function name from the callable
name = str(module).split('<function ')[1].split(' ')[0]
out.append({
"name": name,
"domain": data[name],
"rateLimit": False,
"error": True,
"exists": False,
# … other fields …
})
This ensures that even failed modules participate correctly in the alphabetical sorting, maintaining consistent output structure.
Key Source Files
Understanding the sorting behavior requires familiarity with these components:
| File | Purpose |
|---|---|
holehe/core.py |
Main entry point, implements maincore(), launch_module(), and the sorting logic |
holehe/modules/* |
Individual site-specific async functions whose names become sort keys |
holehe/instruments.py |
Progress bar instrumentation during concurrent execution |
Summary
- Name extraction:
str(module).split('<function ')[1].split(' ')[0]parses function identifiers from callable objects - Concurrent execution:
trio.open_nursery()runs all modules simultaneously without blocking - Alphabetical ordering:
sorted(out, key=lambda i: i['name'])produces deterministic, user-friendly output - Consistent application: Sorting occurs after all tasks complete, affecting both success and error results equally
Frequently Asked Questions
Why does Holehe sort results alphabetically instead of by execution order?
Alphabetical sorting provides predictable, scannable output for users reviewing multiple site checks. Execution order varies due to network latency and rate limiting, making it unsuitable for consistent presentation. The name field sorting ensures identical inputs always produce identically ordered outputs.
What happens if two modules have the same function name?
This scenario is unlikely given Holehe's module structure—each site typically has a unique function name. If collision occurred, Python's sorted() would preserve the original relative order of equal elements (stable sorting), though the codebase design avoids this situation entirely.
Can I modify the sorting behavior in Holehe?
The sorting is hardcoded in holehe/core.py at line 22-24. To change the sort order, you would modify or remove the sorted() call before print_result(). However, this requires editing the source directly as no configuration option exists for alternative ordering.
Does sorting affect performance with many modules?
No. The sorted() operation is O(n log n) and executes on an in-memory list after all network operations complete. With typical usage (dozens to low hundreds of modules), this overhead is negligible compared to HTTP request latency.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →