# How Holehe's Auto-Update Mechanism Checks for New Versions

> Discover how Holehe's auto-update checks for new versions. It polls the PyPI JSON API at startup, compares versions, and automatically upgrades if a mismatch is found.

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

---

**Holehe polls the PyPI JSON API at startup to compare the local package version against the latest release, then automatically triggers a pip upgrade if a mismatch is detected.**

The `megadose/holehe` OSINT tool includes a built-in auto-update system that ensures users always run the latest version without manual intervention. When you launch the CLI, the program immediately queries the Python Package Index to determine if a newer build exists. Understanding this mechanism helps developers troubleshoot update loops or disable checks in air-gapped environments.

## The check_update() Function in holehe/core.py

The core logic resides in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) inside the `check_update()` function (lines 65–87). This lightweight routine handles the entire lifecycle from version detection to subprocess installation.

### Fetching PyPI Metadata via HTTPX

First, the function queries the official PyPI API endpoint. It uses **httpx** to perform a synchronous GET request to retrieve the package metadata:

```python

# In holehe/core.py (simplified)

def check_update():
    """Check and update holehe if not the last version"""
    check_version = httpx.get("https://pypi.org/pypi/holehe/json")

```

The JSON response contains a nested `info` object where `info["version"]` holds the latest published release string.

### Version Comparison Logic

Next, the function compares the remote value against the local **__version__** constant defined on line 34 of [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) (and exposed via [`holehe/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/__init__.py)). 

If the strings match, the function returns silently and the CLI continues. If they differ, the execution branches into the upgrade path:

```python
    if check_version.json()["info"]["version"] != __version__:
        # Upgrade logic triggered

```

### Automated Upgrade Process

When a version mismatch is detected, Holehe spawns a subprocess to upgrade itself. The implementation uses `subprocess.check_call()` with platform-specific pip commands:

- **Windows**: Executes `pip install --upgrade holehe`
- **Linux/macOS**: Executes `pip3 install --upgrade holehe`

After the subprocess completes, the function prints a notification message and calls `exit()` to terminate the current process. This forces the user to restart the program to load the updated code:

```python
        print("Holehe has just been updated, you can restart it.")
        exit()

```

## Where the Check Runs in the CLI Lifecycle

The update check fires early in the application lifecycle to prevent stale code from running. In [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) at line 97, the CLI entry point calls `check_update()` immediately after parsing arguments but before executing any OSINT modules. This placement ensures network failures or pip hangs occur before valuable processing begins.

## Manual Update Checks

While the check runs automatically by default, you can import the function directly to force a validation outside the normal CLI flow:

```python
from holehe.core import check_update

# Force immediate version validation

check_update()

```

This is useful for CI/CD pipelines that need to verify dependency freshness before running Holehe in automated workflows.

## Summary

- **Location**: The auto-update logic is implemented in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) within the `check_update()` function (lines 65–87).
- **Source of Truth**: The script queries `https://pypi.org/pypi/holehe/json` to retrieve the canonical version from PyPI.
- **Trigger Point**: The check executes at line 97 of the core module, running before any OSINT processing begins.
- **Upgrade Method**: The mechanism spawns `pip install --upgrade holehe` (or `pip3` on Unix) and exits the current process upon completion.
- **Local Reference**: The bundled version is stored in the `__version__` constant, maintained in [`holehe/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/__init__.py) and referenced in [`core.py`](https://github.com/megadose/holehe/blob/main/core.py).

## Frequently Asked Questions

### How can I disable the auto-update check in Holehe?

Currently, the repository does not expose a configuration flag to disable the check. To bypass automatic updates, you would need to comment out the `check_update()` call on line 97 of [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) before installing the package locally.

### Why does Holehe use httpx instead of requests for version checking?

According to the source code in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), the project standardizes on **httpx** for all HTTP operations. This choice provides consistent synchronous and asynchronous API patterns across the codebase, though the version check specifically uses the synchronous client.

### What happens if the PyPI API is unreachable when Holehe starts?

If the httpx request to `pypi.org` fails due to network issues or timeout, the function will raise an exception and halt execution. There is no try-except block surrounding the request in the current implementation, meaning DNS failures or HTTP errors will crash the CLI before reaching the main logic.

### Why does the program exit after updating instead of hot-reloading?

The mechanism calls `exit()` after the pip subprocess completes because Python cannot unload and reload compiled C extensions or modified module paths within the same process. Exiting guarantees that the next invocation imports the freshly installed code from disk, avoiding version skew between the running interpreter and the updated package files.