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

Call Result.taken(extra=None, media=None) from 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 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, 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 as a static method:

@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:

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:

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:

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:

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 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, 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
  • 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 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."

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 →