# How to Create a "Taken" Result Using the Result Factory Methods in user-scanner

> Easily create a taken result in user-scanner using the Result.taken factory method. Learn how to indicate username or email existence with this Python function.

- Repository: [Kaif/user-scanner](https://github.com/kaifcodec/user-scanner)
- Tags: how-to-guide
- Published: 2026-09-02

---

**Call `Result.taken(extra=None, media=None)` from [`user_scanner/core/result.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/result.py) to return a fully-populated result indicating a username or email exists.**

The `Result` class is the central data structure in the [kaifcodec/user-scanner](https://github.com/kaifcodec/user-scanner) repository. Validators use its factory methods to communicate findings to the scan engine. This guide explains how to correctly create a "taken" result—the most common output when a username or email address is found to exist on a platform.

---

## Understanding the Result Factory Methods

In [`user_scanner/core/result.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/result.py), the `Result` class provides three static factory methods:

| Method | Status | Purpose |
|--------|--------|---------|
| `Result.available()` | `Result.Status.AVAILABLE` | Username/email does not exist on the platform |
| `Result.taken(extra=None, media=None)` | `Result.Status.TAKEN` | Username/email exists (is taken) |
| `Result.error(message)` | `Result.Status.ERROR` | Scan failed due to network, captcha, or unexpected issue |

Each factory method constructs a `Result` instance with the correct `status` field pre-populated. The engine, formatters, and exporters depend on this consistent schema.

---

## The `Result.taken()` Method Signature

The method is defined in [`user_scanner/core/result.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/result.py) as a static method:

```python
@staticmethod
def taken(extra: dict | None = None, media: list[str] | None = None) -> "Result":

```

### Parameters

- **`extra`** – Optional dictionary of metadata about the discovered account. Common fields include `profile_url`, `full_name`, `bio`, `location`, and `followers_count`.
- **`media`** – Optional list of image URLs (profile pictures, banners) discovered during the scan.

Both parameters default to `None`. When omitted, the method initializes empty containers (`{}` for `extra`, `[]` for `media`).

---

## Code Examples: Creating Taken Results

### Minimal Taken Result

Return a basic taken result with no additional data:

```python
from user_scanner.core.result import Result

result = Result.taken()

# Result(status=Result.Status.TAKEN, extra={}, media=[])

```

### Taken Result with Metadata

Populate the `extra` dictionary with account details:

```python
result = Result.taken(
    extra={
        "profile_url": "https://github.com/octocat",
        "full_name": "The Octocat",
        "bio": "GitHub's mascot",
        "location": "San Francisco, CA",
    }
)

```

### Taken Result with Media URLs

Include discovered image assets:

```python
result = Result.taken(
    extra={"profile_url": "https://twitter.com/example"},
    media=[
        "https://pbs.twimg.com/profile_images/1234567890/profile.jpg",
        "https://pbs.twimg.com/profile_banners/1234567890/1234567890/1500x500",
    ]
)

```

### Complete Validator Implementation

A real-world validator combining all patterns, as implemented in scanners consuming this API:

```python
from user_scanner.core.result import Result

def validate_github(username: str) -> Result:
    """Check if a GitHub username exists."""
    url = f"https://github.com/{username}"
    response = generic_validate(url)  # Platform-specific HTTP logic

    
    if response.status_code == 200 and '"login":' in response.text:
        # User exists—return taken result with extracted data

        return Result.taken(
            extra={
                "profile_url": url,
                "api_url": f"https://api.github.com/users/{username}",
            },
            media=[f"https://github.com/{username}.png"],
        )
    
    # User does not exist

    return Result.available()

```

---

## How the Engine Processes Taken Results

The scan engine in [`user_scanner/core/engine.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/engine.py) consumes `Result` objects returned by validators:

1. **Validation loop** – Each platform validator returns a `Result` via `Result.taken()`, `Result.available()`, or `Result.error()`.
2. **Aggregation** – The engine collects results across all platforms for a given query.
3. **Formatting** – Results pass to [`user_scanner/core/formatter.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/formatter.py), which serializes them for CLI, JSON, CSV, or PDF output.
4. **Export** – Formatters access `result.status`, `result.extra`, and `result.media` to build the final report.

Using the factory method guarantees these components receive properly structured data.

---

## Best Practices for Taken Results

- **Always use the factory method** rather than constructing `Result` objects directly. This ensures the `status` field is correctly set and future-proofs your code against schema changes.
- **Keep `extra` JSON-serializable** – The JSON and CSV formatters attempt to serialize this dictionary; avoid non-primitive objects.
- **Validate `media` URLs** – Provide only well-formed HTTP/HTTPS strings. The PDF generator renders these as embedded images.
- **Return early on errors** – Use `Result.error()` for timeouts, rate limits, or ambiguous responses; don't conflate these with `taken`.

---

## Summary

- **Factory method:** `Result.taken(extra=None, media=None)` in [`user_scanner/core/result.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/result.py)
- **Purpose:** Signal that a username or email exists on a platform
- **Parameters:** Optional `extra` dict for metadata, `media` list for image URLs
- **Benefits:** Guaranteed schema compliance, centralized validation, seamless integration with engine and formatters

---

## Frequently Asked Questions

### What happens if I omit both parameters to `Result.taken()`?

The method returns a valid `Result` with `status=Result.Status.TAKEN`, empty `extra={}`, and empty `media=[]`. This is useful when you only need to signal existence without additional details.

### Can I modify a taken result after creation?

The `Result` class is typically implemented as a **frozen dataclass** or similar immutable structure. Modify data before passing it to `Result.taken()` rather than mutating the returned object.

### How does the PDF formatter use the `media` field?

The PDF generator in [`user_scanner/core/formatter.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/formatter.py) retrieves image URLs from `Result.media` and embeds them as thumbnails in the scan report. Invalid or unreachable URLs are skipped with a warning.

### What's the difference between `Result.taken()` and raising an exception?

`Result.taken()` indicates **successful discovery** of an account. Exceptions or `Result.error()` indicate **scan failure**—the platform couldn't be checked. These are semantically distinct: a taken result answers "yes, it exists," while an error answers "we couldn't determine."