# How `get_functions()` Filters Modules in Holehe Based on CLI Arguments

> Discover how holehe's get_functions() filters modules using CLI arguments. Learn how the -NP flag excludes specific password recovery modules for targeted scans.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: internals
- Published: 2026-08-18

---

**When you pass the `-NP` flag, `get_functions()` in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) selectively excludes four password‑recovery modules—`adobe`, `mail_ru`, `odnoklassniki`, and `samsung`—from the execution list by inspecting string representations of the module objects.**

The `holehe` tool dynamically discovers every site‑checking module under `holehe/modules` using `import_submodules`. The `get_functions()` helper then transforms those imported objects into a list of callables that execute email verification checks. This article explains exactly how that filtering mechanism works based on command‑line arguments parsed in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py).

## Where `get_functions()` Lives and What It Does

In [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) at lines 50‑63, the `get_functions()` function takes two parameters:

- `modules`: A dictionary of imported module objects from `holehe.modules`
- `args`: The parsed `argparse.Namespace` containing CLI flags (optional)

```python
def get_functions(modules, args=None):
    """Transform the modules objects to functions"""
    websites = []

    for module in modules:
        # Only consider real site modules (depth > 3)

        if len(module.split(".")) > 3:
            modu = modules[module]                # the imported module object

            site = module.split(".")[-1]          # e.g. "github", "adobe", …

            
            # ── Filtering based on the "-NP / --no-password-recovery" flag ──

            if args is not None and args.nopasswordrecovery == True:
                # Exclude sites that expose password-recovery helpers

                if ("adobe"      not in str(modu.__dict__[site]) and
                    "mail_ru"    not in str(modu.__dict__[site]) and
                    "odnoklassniki" not in str(modu.__dict__[site]) and
                    "samsung"    not in str(modu.__dict__[site])):
                    websites.append(modu.__dict__[site])
            else:
                # No filtering – keep every discovered site function

                websites.append(modu.__dict__[site])
    return websites

```

## How Module Depth Filtering Works First

Before any CLI‑based filtering occurs, `get_functions()` applies a structural filter. It splits the module name by dots and checks if the depth exceeds 3 levels. Modules like `holehe.modules.social.github` pass this check (4 components), while shallower package markers get skipped. This ensures only actual site‑checking modules—not package infrastructure—are processed.

## The Password‑Recovery Exclusion Logic

When `args.nopasswordrecovery` is `True`—set by the `-NP` or `--no-password-recovery` flag defined at lines 90‑92 of [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py)—the function enters exclusion mode.

### Why These Four Modules?

The code explicitly checks string representations of each module's callable attribute against four hardcoded names:

| Excluded Module | Reason for Exclusion |
|-----------------|----------------------|
| `adobe` | Implements password‑recovery flow for Adobe accounts |
| `mail_ru` | Triggers Mail.ru password‑reset mechanisms |
| `odnoklassniki` | Involves Odnoklassniki (OK.ru) recovery workflows |
| `samsung` | Executes Samsung account password‑recovery steps |

The filtering uses substring matching: `str(modu.__dict__[site])` converts the function object to its string representation, and the code verifies none of the four target names appear. If clean, the module is appended to `websites`.

## Execution Flow: From Discovery to Filtered Execution

Understanding how `get_functions()` fits into the broader architecture clarifies its role:

1. **Discovery phase**: `import_submodules("holehe.modules")` recursively imports all submodules and returns a dictionary mapping module paths to module objects.

2. **Filtering phase**: `get_functions(modules, args)` applies depth and CLI‑argument filtering to produce the final `websites` list.

3. **Execution phase**: The filtered list feeds into the async nursery via `launch_module`, where each callable runs concurrently with progress instrumentation from [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py).

## Running Holehe With and Without Filtering

```bash

# Normal run – password-recovery attempts are performed

holehe user@example.com

```

```bash

# Skip password-recovery (the -NP flag)

holehe user@example.com -NP

# Equivalent long form

holehe user@example.com --no-password-recovery

```

In the first command, all discovered modules—including `adobe`, `mail_ru`, `odnoklassniki`, and `samsung`—execute their full check logic. In the second, `get_functions()` excludes those four, reducing HTTP requests and avoiding rate‑limit triggers from recovery‑endpoint probing.

## Key Design Decisions in the Implementation

The `holehe` codebase makes several interesting tradeoffs in `get_functions()`:

- **String‑based inspection**: Rather than using formal module metadata or decorators, the code inspects `str(modu.__dict__[site])`. This is lightweight but fragile—renaming the excluded modules requires updating the substring checks.

- **Hardcoded exclusions**: The four module names are embedded directly in the conditional logic. There's no external configuration file for exclusion lists.

- **Opt‑out security**: Password‑recovery checks run by default; users must explicitly request exclusion. This prioritizes thoroughness over speed unless overridden.

## Summary

- `get_functions()` in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) (lines 50‑63) filters modules by depth first, then by CLI arguments.

- When `args.nopasswordrecovery` is `True`, the function string‑inspects each module's callable and excludes `adobe`, `mail_ru`, `odnoklassniki`, and `samsung`.

- The `-NP` / `--no-password-recovery` flag enables this filtering, defined at lines 90‑92 of the same file.

- Filtered results flow to `launch_module` for concurrent async execution with progress tracking.

## Frequently Asked Questions

### How does `get_functions()` know which modules to exclude?

`get_functions()` checks if the string representation of `modu.__dict__[site]` contains any of four hardcoded substrings: "adobe", "mail_ru", "odnoklassniki", or "samsung". This inspection only activates when the `-NP` flag sets `args.nopasswordrecovery` to `True`.

### Why are only four modules excluded from password recovery?

These four modules implement explicit password‑recovery workflows that can trigger account‑recovery emails or rate‑limits. The `holehe` maintainers identified them as the most time‑consuming and side‑effect‑prone checks. Other modules either lack recovery flows or implement lighter verification methods.

### Can I exclude additional modules using the same flag?

No. The exclusion list is hardcoded in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) lines 56‑59. To exclude other modules, you would need to modify the source code or implement custom filtering outside the standard `holehe` workflow.

### Where does the actual site checking happen after filtering?

After `get_functions()` returns the filtered `websites` list, [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) passes each callable to `launch_module` within an async nursery. This orchestrates concurrent HTTP requests with progress instrumentation from [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py).