# How `get_functions` Filters Holehe Modules Based on Command-Line Arguments

> Learn how holehe's get_functions filters modules using command-line arguments and the nopasswordrecovery flag to exclude specific sites. Optimize your checks with this guide.

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

---

**The `get_functions` helper in holehe filters modules by checking the `args.nopasswordrecovery` flag and excluding four specific sites—adobe, mail_ru, odnoklassniki, and samsung—when the `--no-password-recovery` option is enabled.**

Holehe is an open-source OSINT tool developed by megadose that checks email addresses against hundreds of websites to uncover registered accounts. The tool dynamically discovers site-checking modules and selectively filters them based on runtime flags. Understanding how `get_functions` performs this filtering reveals important details about holehe's modular architecture and execution pipeline.

## Where `get_functions` Lives in the Codebase

The filtering logic resides in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), which serves as the main entry point for the entire application. This file handles argument parsing, module discovery, and the async orchestration of site checks.

The relevant function spans lines 50-63:

```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

                # (adobe, mail_ru, odnoklassniki, samsung)

                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

```

The function receives two parameters:

- `modules` — a dictionary of imported submodule objects from `holehe/modules`
- `args` — the parsed `ArgumentParser` namespace (optional, defaults to `None`)

## The Module Discovery Pipeline

Before `get_functions` can filter anything, holehe must first discover available modules. This happens through a separate helper called `import_submodules`.

The execution flow proceeds as follows:

1. **`import_submodules("holehe.modules")`** recursively imports every Python file under `holehe/modules/` and returns a dictionary mapping module names to module objects
2. **`get_functions(modules, args)`** transforms these module objects into executable site-checking functions, applying filters based on command-line arguments
3. The resulting `websites` list is passed to the async nursery (`launch_module`) for parallel execution against the target email address

## How the `--no-password-recovery` Filter Works

The critical filtering logic activates when users pass `-NP` or `--no-password-recovery`. This flag gets parsed in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) at lines 90-92:

```python
parser.add_argument("-NP", "--no-password-recovery", action='store_true', default=False,
                    help="Don't try password recovery on each website")

```

When present, `args.nopasswordrecovery` becomes `True`. Inside `get_functions`, this triggers a substring-based exclusion check against four hardcoded site names:

| Excluded Site | Rationale |
|-------------|-----------|
| **adobe** | Password recovery involves additional API calls |
| **mail_ru** | Russian mail service with recovery-specific endpoints |
| **odnoklassniki** | Social network requiring recovery flow interactions |
| **samsung** | Account recovery triggers extended verification steps |

The check works by converting the site function object to its string representation and verifying none of these substrings appear:

```python
"adobe" not in str(modu.__dict__[site])

```

This approach relies on the fact that Python function objects include their module path in `__repr__`, making the site name detectable without explicit metadata.

## Practical Usage Examples

Run holehe with full password recovery attempts (default behavior):

```bash
holehe user@example.com

```

Skip password-recovery modules for faster, lighter scanning:

```bash

# Short form

holehe user@example.com -NP

# Long form

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

```

In the first case, all discovered modules execute including the four password-recovery sites. In the second case, `get_functions` reduces the workload by excluding those specific modules, resulting in fewer HTTP requests and reduced execution time.

## Key Design Decisions

The filtering implementation reflects several practical engineering choices:

- **Namespace depth check** — The `len(module.split(".")) > 3` guard ensures only actual site modules are processed, skipping package-level [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py) files
- **String-based matching** — Rather than maintaining a registry of module classes or decorators, holehe uses simple substring detection against function representations
- **Explicit opt-out** — Password recovery is included by default since it can yield valuable account existence confirmations, but users can disable it when speed or stealth matters

These choices keep the codebase lightweight while providing meaningful control over execution scope.

## Related Source Files

| File | Purpose |
|------|---------|
| [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) | Main entry point; argument parsing, `get_functions` definition, async orchestration |
| [`holehe/modules/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/__init__.py) | Package marker for site-specific checking modules |
| [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py) | Progress bar instrumentation for async task monitoring |

## Summary

- `get_functions` in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) transforms imported module objects into executable site-checking functions
- When `args.nopasswordrecovery` is `True`, the function excludes **adobe**, **mail_ru**, **odnoklassniki**, and **samsung** by checking their string representations
- The `--no-password-recovery` flag (or `-NP`) triggers this filtering to reduce API calls and execution time
- Module discovery relies on `import_submodules`, while execution uses async nursery pattern via `launch_module`

## Frequently Asked Questions

### How does holehe know which modules support password recovery?

Holehe uses hardcoded site names in `get_functions` rather than detecting capabilities dynamically. The four excluded sites—adobe, mail_ru, odnoklassniki, and samsung—are explicitly listed in the filtering logic based on known recovery-flow implementations in their respective modules.

### Can I exclude other sites besides the password-recovery ones?

Not through built-in flags. The current implementation only supports filtering those four specific sites via `--no-password-recovery`. To exclude additional sites, you would need to modify the `get_functions` implementation in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) or fork the repository.

### Why check `str(modu.__dict__[site])` instead of using a module attribute?

The string-based approach avoids requiring every module to implement a specific interface or metadata attribute. Since Python function objects naturally include their defining module in the string representation, this lightweight detection works without additional boilerplate across all 120+ site modules.

### What happens if `args` is None when calling `get_functions`?

The function handles `None` gracefully by skipping the password-recovery filter and appending all discovered site modules. This ensures backward compatibility for any internal callers that don't pass an argument namespace.