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 out as 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →