### Install Mapilli from Source using uv Source: https://github.com/alanbato/mapilli/blob/main/docs/installation.md Installs Mapilli by cloning the repository and using uv sync. This method is suitable for developers or those who need the latest development version. Requires git and uv. ```bash git clone https://github.com/alanbato/mapilli.git cd mapilli uv sync ``` -------------------------------- ### Install Mapilli using pip Source: https://github.com/alanbato/mapilli/blob/main/docs/installation.md Installs the Mapilli package using the pip package installer. Ensure Python 3.10 or higher is installed. ```bash pip install mapilli ``` -------------------------------- ### Install Mapilli using uv Source: https://github.com/alanbato/mapilli/blob/main/docs/installation.md Installs the Mapilli package using the uv package manager, known for its speed. Requires uv to be installed. ```bash uv add mapilli ``` -------------------------------- ### List All Users via Mapilli CLI Source: https://github.com/alanbato/mapilli/blob/main/docs/quickstart.md List all available users by running the `mapilli` command without a username, optionally specifying the host with `-h`. This fetches a comprehensive list. ```bash mapilli -h example.com ``` -------------------------------- ### Verify Mapilli Installation (CLI and Python) Source: https://github.com/alanbato/mapilli/blob/main/docs/installation.md Confirms that Mapilli has been successfully installed. The CLI verification checks the version via the command line, while the Python verification checks the version within a Python interpreter. ```bash mapilli --version ``` ```python import mapilli print(mapilli.__version__) ``` -------------------------------- ### Basic Mapilli Python API Usage Source: https://github.com/alanbato/mapilli/blob/main/docs/quickstart.md Demonstrates the basic usage of the Mapilli Python API to query user information. It utilizes `asyncio` and the `FingerClient` to make asynchronous requests. ```python import asyncio from mapilli import FingerClient async def main(): async with FingerClient() as client: response = await client.query("alice@example.com") print(response.body) asyncio.run(main()) ``` -------------------------------- ### Mapilli Python API Query Options Source: https://github.com/alanbato/mapilli/blob/main/docs/quickstart.md Illustrates various query options available in the Mapilli Python API, including specifying the host within the query string, using a separate host parameter, listing all users, and requesting verbose output. ```python async with FingerClient() as client: # Host in query string response = await client.query("alice@example.com") # Separate host parameter response = await client.query("alice", host="example.com") # List all users response = await client.query(host="example.com") # Verbose output response = await client.query("/W alice@example.com") ``` -------------------------------- ### Python: Basic FingerClient Usage Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/api/index.md Demonstrates how to instantiate and use the FingerClient to query a Finger server. It shows the asynchronous context manager and how to process the response body. Requires the mapilli library to be installed. ```python from mapilli import FingerClient async with FingerClient() as client: response = await client.query("alice@example.com") print(response.body) ``` -------------------------------- ### Install Mapilli with pip or uv Source: https://github.com/alanbato/mapilli/blob/main/README.md This snippet shows how to install the Mapilli library using either pip or uv, the fast Python package installer. Ensure you have Python 3.10+ installed. ```bash pip install mapilli ``` ```bash uv add mapilli ``` -------------------------------- ### Verbose Output via Mapilli CLI Source: https://github.com/alanbato/mapilli/blob/main/docs/quickstart.md Obtain verbose (whois-style) output for a user query by using the `-W` flag. This provides more detailed information than a standard query. ```bash mapilli -W alice@example.com ``` -------------------------------- ### Query User via Mapilli CLI Source: https://github.com/alanbato/mapilli/blob/main/docs/quickstart.md Use the `mapilli` command to query a specific user's information by email address. This is the basic command for fetching user data. ```bash mapilli alice@example.com ``` -------------------------------- ### Query User with Separate Host via Mapilli CLI Source: https://github.com/alanbato/mapilli/blob/main/docs/quickstart.md Query a user by providing their username and the host separately using the `-h` flag. This allows for specifying a different host than the default. ```bash mapilli alice -h example.com ``` -------------------------------- ### Mapilli Python API Error Handling Source: https://github.com/alanbato/mapilli/blob/main/docs/quickstart.md Provides an example of robust error handling for Mapilli Python API requests, catching potential `TimeoutError`, `ConnectionError`, and `ValueError` exceptions. ```python async with FingerClient(timeout=5.0) as client: try: response = await client.query("alice@example.com") print(response.body) except TimeoutError: print("Request timed out") except ConnectionError as e: print(f"Connection failed: {e}") except ValueError as e: print(f"Invalid query: {e}") ``` -------------------------------- ### Mapilli CLI - Request Verbose (WHOIS) Output Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/cli.md This example demonstrates how to request detailed, WHOIS-style output from the Finger server using the `-W` or `--whois` option. This prepends `/W` to the query. ```bash mapilli -W alice@example.com ``` ```bash mapilli "/W alice@example.com" ``` -------------------------------- ### Complete Application Example - Multi-User Query Tool Source: https://context7.com/alanbato/mapilli/llms.txt A full-featured Python application demonstrating concurrent queries to Finger servers, including error handling for timeouts and connection issues, and formatted output using Rich. It takes user@host arguments and displays success or failure for each query. ```python #!/usr/bin/env python3 """Complete Finger client application with Rich formatting.""" import asyncio import sys from typing import List, Tuple from mapilli import FingerClient, DEFAULT_TIMEOUT async def query_user( client: FingerClient, query: str ) -> Tuple[str, str, bool]: """ Query a user and return (query, result, success) tuple. Returns: Tuple of (query_string, response_body_or_error, success_flag) """ try: response = await client.query(query) return (query, response.body, True) except TimeoutError: return (query, "Request timed out", False) except ConnectionError as e: return (query, f"Connection failed: {e}", False) except ValueError as e: return (query, f"Invalid query: {e}", False) except Exception as e: return (query, f"Unexpected error: {e}", False) async def main(queries: List[str], timeout: float = DEFAULT_TIMEOUT): """Query multiple users concurrently and display results.""" if not queries: print("Usage: python app.py user@host [user@host ...]") return 1 print(f"Querying {len(queries)} user(s) with {timeout}s timeout...\n") async with FingerClient(timeout=timeout) as client: # Launch all queries concurrently tasks = [query_user(client, q) for q in queries] results = await asyncio.gather(*tasks) # Display results success_count = 0 for query, result, success in results: status = "✓" if success else "✗" print(f"{status} {query}") print("-" * 60) if success: print(result) success_count += 1 else: print(f"ERROR: {result}") print() # Summary print(f"Completed: {success_count}/{len(queries)} successful") return 0 if success_count == len(queries) else 1 if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: python app.py user@host [user@host ...]") print("Example: python app.py alice@host1.com bob@host2.com") sys.exit(1) exit_code = asyncio.run(main(sys.argv[1:])) sys.exit(exit_code) ``` -------------------------------- ### Query Finger Service via Command Line Source: https://context7.com/alanbato/mapilli/llms.txt Provides examples of using the Mapilli command-line interface to perform Finger queries. It covers various query formats, options for specifying hosts, ports, timeouts, verbose output, and accessing help and version information. ```bash # Query user@host format mapilli alice@finger.example.com # Query with separate host parameter mapilli alice -h finger.example.com # List all users on a host mapilli -h finger.example.com # Verbose/whois output mapilli -W alice@finger.example.com mapilli --whois alice -h finger.example.com # Custom port mapilli alice@finger.example.com -p 7979 mapilli alice -h finger.example.com --port 7979 # Custom timeout (in seconds) mapilli alice@finger.example.com -t 10 mapilli alice -h finger.example.com --timeout 15.0 # Version information mapilli --version mapilli -V # Help information mapilli --help # Combined options mapilli -W -t 20 -p 79 alice -h finger.example.com ``` -------------------------------- ### Mapilli Python API Custom Timeout Source: https://github.com/alanbato/mapilli/blob/main/docs/quickstart.md Shows how to configure a custom timeout for requests made using the Mapilli Python API. This is useful for controlling how long the client waits for a response. ```python client = FingerClient(timeout=10.0) async with client: response = await client.query("alice@example.com") ``` -------------------------------- ### Mapilli CLI - Example: Custom Timeout Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/cli.md An example demonstrating the use of a custom timeout value (5 seconds) for a user query. This overrides the default timeout setting. ```bash mapilli alice@example.com -t 5 ``` -------------------------------- ### Mapilli FingerClient Error Handling (Python) Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/api/client.md Provides an example of how to handle potential exceptions during a FingerClient query. It specifically catches TimeoutError, ConnectionError, and ValueError, printing informative messages. ```python async with FingerClient() as client: try: response = await client.query("alice@example.com") except TimeoutError: print("Request timed out") except ConnectionError: print("Connection failed") except ValueError: print("Invalid query") ``` -------------------------------- ### Mapilli CLI - Specify Target Port Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/cli.md This example shows how to override the default Finger port (79) by specifying a custom port using the `-p` or `--port` option. This is useful for non-standard server configurations. ```bash mapilli alice@example.com -p 1079 ``` -------------------------------- ### Custom Timeout Per Query Python Source: https://github.com/alanbato/mapilli/blob/main/docs/how-to/error-handling.md Allows setting a specific timeout duration for individual queries. This is useful when interacting with servers that have varying response time expectations. ```python from mapilli import FingerClient async def query_with_custom_timeout( query: str, timeout: float = 30.0, ) -> str | None: """Query with a custom timeout.""" async with FingerClient(timeout=timeout) as client: try: response = await client.query(query) return response.body except TimeoutError: return None ``` -------------------------------- ### Mapilli CLI - Set Request Timeout Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/cli.md This example illustrates how to configure a custom timeout for server requests using the `-t` or `--timeout` option. It allows users to control how long mapilli waits for a response before giving up. ```bash mapilli alice@example.com -t 10 ``` -------------------------------- ### Logging Errors with Structlog Python Source: https://github.com/alanbato/mapilli/blob/main/docs/how-to/error-handling.md Integrates structured logging using the `structlog` library for production environments. It logs different levels of events (info, warning, error) with relevant context such as the query and error details. ```python import structlog from mapilli import FingerClient log = structlog.get_logger() async def logged_query(query: str) -> str | None: async with FingerClient(timeout=10.0) as client: try: response = await client.query(query) log.info("finger_query_success", query=query, bytes=len(response.body)) return response.body except TimeoutError: log.warning("finger_query_timeout", query=query) return None except ConnectionError as e: log.error("finger_query_connection_error", query=query, error=str(e)) return None except ValueError as e: log.error("finger_query_invalid", query=query, error=str(e)) return None ``` -------------------------------- ### Handling Multiple Queries Concurrently Python Source: https://github.com/alanbato/mapilli/blob/main/docs/how-to/error-handling.md Utilizes `asyncio.gather` with `return_exceptions=True` to query multiple servers concurrently. This function returns a dictionary mapping each query to its result or the exception encountered during the query. ```python import asyncio from mapilli import FingerClient async def query_all(queries: list[str]) -> dict[str, str | Exception]: """Query multiple servers, collecting all results.""" async with FingerClient(timeout=10.0) as client: async def safe_query(q: str) -> tuple[str, str | Exception]: try: response = await client.query(q) return (q, response.body) except Exception as e: return (q, e) tasks = [safe_query(q) for q in queries] results = await asyncio.gather(*tasks) return dict(results) # Usage async def main(): results = await query_all([ "alice@server1.com", "bob@server2.com", ]) for query, result in results.items(): if isinstance(result, Exception): print(f"{query}: Error - {result}") else: print(f"{query}: {result[:50]}...") ``` -------------------------------- ### Basic Error Handling with Mapilli Python Source: https://github.com/alanbato/mapilli/blob/main/docs/how-to/error-handling.md Demonstrates fundamental error handling for Mapilli queries using a `try-except` block. It catches `TimeoutError`, `ConnectionError`, and `ValueError`, printing informative messages for each. This is suitable for simple applications where immediate feedback is sufficient. ```python from mapilli import FingerClient async def safe_query(query: str) -> str | None: async with FingerClient(timeout=10.0) as client: try: response = await client.query(query) return response.body except TimeoutError: print("Request timed out") return None except ConnectionError as e: print(f"Connection failed: {e}") return None except ValueError as e: print(f"Invalid query: {e}") return None ``` -------------------------------- ### Retry Logic for Transient Errors Python Source: https://github.com/alanbato/mapilli/blob/main/docs/how-to/error-handling.md Implements retry logic with exponential backoff for transient errors like `TimeoutError` and `ConnectionError`. It allows specifying maximum retries and initial delay. Invalid queries (`ValueError`) are not retried. ```python import asyncio from mapilli import FingerClient async def query_with_retry( query: str, max_retries: int = 3, delay: float = 1.0, ) -> str | None: """Query with exponential backoff retry.""" async with FingerClient(timeout=10.0) as client: for attempt in range(max_retries): try: response = await client.query(query) return response.body except (TimeoutError, ConnectionError) as e: if attempt == max_retries - 1: print(f"Failed after {max_retries} attempts: {e}") return None wait = delay * (2 ** attempt) print(f"Attempt {attempt + 1} failed, retrying in {wait}s...") await asyncio.sleep(wait) except ValueError as e: # Don't retry invalid queries print(f"Invalid query: {e}") return None return None ``` -------------------------------- ### FingerClient - Initialization and Basic Query Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/api/client.md Demonstrates how to initialize the FingerClient and perform a basic query to a Finger server. ```APIDOC ## FingerClient Initialization and Basic Query ### Description Initializes the FingerClient and performs a basic query to a Finger server. ### Method Asynchronous Context Manager (`async with`) ### Endpoint Not applicable (client-side library) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```python from mapilli import FingerClient async with FingerClient() as client: response = await client.query("alice@example.com") print(response.body) ``` ### Response #### Success Response (200) - **body** (str) - The response body from the Finger server. #### Response Example ```json { "body": "Finger user information..." } ``` ``` -------------------------------- ### Query user from command line Source: https://github.com/alanbato/mapilli/blob/main/README.md Demonstrates basic command-line usage of Mapilli to query a user's Finger information. You can specify the user and host, or use the user@host format. The `-W` flag enables verbose output. ```bash # Query a user mapilli alice@example.com # Verbose output (more details) mapilli -W alice@example.com # List all users on a host mapilli -h example.com # Custom timeout mapilli -t 10 alice@example.com ``` -------------------------------- ### Query user with Python FingerClient Source: https://github.com/alanbato/mapilli/blob/main/README.md Shows how to use the Mapilli library in Python to query Finger information. It utilizes the `FingerClient` within an `async` context and demonstrates querying a user by email address or by separating username and host. ```python import asyncio from mapilli import FingerClient async def main(): async with FingerClient() as client: # Query a user response = await client.query("alice@example.com") print(response.body) # Or specify host separately response = await client.query("alice", host="example.com") print(response.body) asyncio.run(main()) ``` -------------------------------- ### Perform concurrent queries with Python Source: https://github.com/alanbato/mapilli/blob/main/README.md Illustrates how to perform multiple Finger protocol queries concurrently using Python's `asyncio.gather`. This allows for efficient querying of several users or hosts in parallel, improving performance. ```python async with FingerClient() as client: queries = ["alice@host1.com", "bob@host2.com", "charlie@host3.com"] responses = await asyncio.gather(*[client.query(q) for q in queries]) for response in responses: print(f"{response.host}: {response.body[:50]}...") ``` -------------------------------- ### FingerClient - Low-Level Direct Query Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/api/client.md Illustrates how to perform a low-level, direct query to a specific Finger host. ```APIDOC ## FingerClient - Low-Level Direct Query ### Description Performs a direct query to a specific Finger host and user. ### Method `finger` ### Endpoint Not applicable (client-side library) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```python async with FingerClient() as client: # Direct query to specific host response = await client.finger("example.com", query="alice") ``` ### Response #### Success Response (200) - **body** (str) - The response body from the Finger server. #### Response Example ```json { "body": "Finger user information for alice..." } ``` ``` -------------------------------- ### Utilize Finger Protocol Constants Source: https://context7.com/alanbato/mapilli/llms.txt Demonstrates the usage of predefined protocol constants from the Mapilli library, including default port, timeout, maximum response size, line terminators, and verbose query prefixes. It shows how these constants simplify configuration and query construction. ```python from mapilli import ( DEFAULT_PORT, DEFAULT_TIMEOUT, FingerClient ) from mapilli.protocol.constants import ( MAX_RESPONSE_SIZE, CRLF, VERBOSE_PREFIX ) # Use default constants print(f"Default Finger port: {DEFAULT_PORT}") # 79 print(f"Default timeout: {DEFAULT_TIMEOUT}s") # 30.0 print(f"Max response size: {MAX_RESPONSE_SIZE} bytes") # 10485760 (10MB) print(f"Line terminator: {CRLF}") # b'\r\n' print(f"Verbose prefix: {VERBOSE_PREFIX}") # /W # Create client with custom timeout client = FingerClient(timeout=DEFAULT_TIMEOUT * 2) # 60 seconds # Build queries with verbose prefix query_verbose = f"{VERBOSE_PREFIX} alice@example.com" # /W alice@example.com ``` -------------------------------- ### Basic Finger Client Query with Mapilli Source: https://github.com/alanbato/mapilli/blob/main/docs/tutorials/building-a-client.md This snippet demonstrates the fundamental usage of Mapilli's FingerClient to query user information from a Finger server. It requires Python 3.10+ and the Mapilli library. The function asynchronously connects, sends a query, and prints the response body. It does not include explicit error handling. ```python import asyncio from mapilli import FingerClient async def main(): async with FingerClient() as client: response = await client.query("alice@example.com") print(response.body) if __name__ == "__main__": asyncio.run(main()) ``` -------------------------------- ### Async Finger Client Queries with Mapilli Source: https://context7.com/alanbato/mapilli/llms.txt Demonstrates using the FingerClient to query Finger servers with various options. It supports user@host format, separate host parameters, listing users on a host, verbose output, and custom timeouts with error handling. The client manages connections and parses responses. ```python import asyncio from mapilli import FingerClient async def main(): # Basic query with user@host format async with FingerClient() as client: response = await client.query("alice@finger.example.com") print(f"Response from {response.host}:{response.port}") print(response.body) # Query with separate host parameter async with FingerClient() as client: response = await client.query("bob", host="finger.example.com") print(response.body) # List all users on a host (empty username) async with FingerClient() as client: response = await client.query(host="finger.example.com") for line in response.lines: print(line) # Verbose/whois output with /W prefix async with FingerClient() as client: response = await client.query("/W alice@finger.example.com") print(response.body) # Custom timeout and error handling async with FingerClient(timeout=10.0) as client: try: response = await client.query("charlie@slow-server.com") print(response.body) except TimeoutError as e: print(f"Request timed out: {e}") except ConnectionError as e: print(f"Connection failed: {e}") except ValueError as e: print(f"Invalid query format: {e}") asyncio.run(main()) ``` -------------------------------- ### Complete Finger Client Application with Mapilli and Rich Source: https://github.com/alanbato/mapilli/blob/main/docs/tutorials/building-a-client.md This is a complete Python script for a Finger client application that takes user queries as command-line arguments. It utilizes Mapilli for Finger protocol interactions and Rich for styled console output. The script handles various errors gracefully and queries multiple users concurrently, providing a user-friendly interface and informative output. ```python #!/usr/bin/env python3 """A simple Finger client application.""" import asyncio import sys from mapilli import FingerClient from rich.console import Console from rich.panel import Panel console = Console() async def finger_user(client: FingerClient, query: str) -> tuple[str, str]: """Query a user and return (query, result) tuple.""" try: response = await client.query(query) return (query, response.body) except TimeoutError: return (query, "[red]Request timed out[/red]") except ConnectionError as e: return (query, f"[red]Connection failed: {e}[/red]") except ValueError as e: return (query, f"[yellow]Invalid query: {e}[/yellow]") async def main(queries: list[str]) -> None: """Query multiple users and display results.""" async with FingerClient(timeout=10.0) as client: tasks = [finger_user(client, query) for query in queries] results = await asyncio.gather(*tasks) for query, result in results: console.print(Panel(result, title=query)) if __name__ == "__main__": if len(sys.argv) < 2: console.print("[yellow]Usage: python client.py user@host ...[/yellow]") sys.exit(1) asyncio.run(main(sys.argv[1:])) ``` -------------------------------- ### Perform Low-Level Finger Queries Source: https://context7.com/alanbato/mapilli/llms.txt Shows how to execute raw Finger queries to specific hosts using the FingerClient. This allows for direct control over query strings, ports, and timeouts, enabling diverse query types like user lookups, listing users, and verbose outputs. ```python import asyncio from mapilli import FingerClient, DEFAULT_PORT async def main(): client = FingerClient(timeout=20.0) # Direct query to host with raw query string response = await client.finger( host="finger.example.com", query="alice", port=DEFAULT_PORT # 79 ) print(response.body) # List all users with empty query response = await client.finger( host="finger.example.com", query="" ) print(response.body) # Verbose query with /W prefix response = await client.finger( host="finger.example.com", query="/W alice" ) print(response.body) # Custom port response = await client.finger( host="finger.example.com", query="bob", port=7979 # non-standard port ) print(response.body) asyncio.run(main()) ``` -------------------------------- ### Query Finger Servers via CLI Source: https://github.com/alanbato/mapilli/blob/main/docs/index.md Command-line interface for querying Finger servers. Supports querying specific users, listing all users on a host, and requesting verbose/whois output. No external dependencies beyond the mapilli library. ```bash # Query a user mapilli alice@example.com # List all users on a host mapilli -h example.com # Verbose/whois output mapilli -W alice@example.com ``` -------------------------------- ### FingerClientProtocol Implementation in Python Source: https://github.com/alanbato/mapilli/blob/main/docs/explanation/architecture.md Demonstrates the low-level protocol handler for the Finger client. It handles connection establishment, data reception, and response processing by buffering incoming data and resolving an asyncio.Future upon connection loss. ```python class FingerClientProtocol(asyncio.Protocol): def connection_made(self, transport): # Send query immediately transport.write(f"{self.query}\r\n".encode("ascii")) def data_received(self, data): # Buffer incoming data self.buffer += data def connection_lost(self, exc): # Create response and resolve Future response = FingerResponse(body=self.buffer.decode(), ...) self.response_future.set_result(response) ``` -------------------------------- ### Mapilli CLI Synopsis Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/cli.md The basic syntax for invoking the mapilli command-line tool. It accepts optional flags and an optional query string for interacting with Finger servers. ```bash mapilli [OPTIONS] [QUERY] ``` -------------------------------- ### Mapilli CLI - Show Help Message Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/cli.md This command displays the help message for the mapilli CLI, providing a summary of available options and arguments. It's useful for quick reference. ```bash mapilli --help ``` -------------------------------- ### Mapilli FingerClient Low-Level Direct Host Query (Python) Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/api/client.md Illustrates how to use the low-level finger method of FingerClient to query a specific host directly with a given query string. This bypasses the default query mechanism. ```python async with FingerClient() as client: # Direct query to specific host response = await client.finger("example.com", query="alice") ``` -------------------------------- ### Formatted Finger Client Output with Mapilli and Rich Source: https://github.com/alanbato/mapilli/blob/main/docs/tutorials/building-a-client.md This Python snippet showcases how to enhance the Finger client's output using the Rich library for improved readability. It integrates Rich's `Console` and `Panel` to display query results within styled panels, also handling errors with Rich-compatible formatting. This version uses `asyncio.gather` for concurrent queries and provides user-friendly error messages. ```python import asyncio from mapilli import FingerClient from rich.console import Console from rich.panel import Panel console = Console() async def finger_user(client: FingerClient, query: str) -> tuple[str, str]: """Query a user and return (query, result) tuple.""" try: response = await client.query(query) return (query, response.body) except TimeoutError: return (query, "[red]Request timed out[/red]") except ConnectionError as e: return (query, f"[red]Connection failed: {e}[/red]") except ValueError as e: return (query, f"[yellow]Invalid query: {e}[/yellow]") async def main(): users = [ "alice@example.com", "bob@example.com", ] async with FingerClient(timeout=10.0) as client: tasks = [finger_user(client, user) for user in users] results = await asyncio.gather(*tasks) for query, result in results: console.print(Panel(result, title=query)) if __name__ == "__main__": asyncio.run(main()) ``` -------------------------------- ### Concurrent Finger User Queries with Mapilli and asyncio Source: https://github.com/alanbato/mapilli/blob/main/docs/tutorials/building-a-client.md This Python code demonstrates how to query multiple Finger users concurrently using `asyncio.gather`. It defines a `finger_user` helper function that queries a single user and returns a tuple of the query and its result (or an error message). The main function then gathers all tasks and prints the results, processing each query in parallel for efficiency. ```python import asyncio from mapilli import FingerClient async def finger_user(client: FingerClient, query: str) -> tuple[str, str | None]: """Query a user and return (query, result) tuple.""" try: response = await client.query(query) return (query, response.body) except Exception as e: return (query, f"Error: {e}") async def main(): users = [ "alice@example.com", "bob@example.com", "charlie@example.com", ] async with FingerClient(timeout=10.0) as client: tasks = [finger_user(client, user) for user in users] results = await asyncio.gather(*tasks) for query, result in results: print(f"=== {query} ===") print(result) print() if __name__ == "__main__": asyncio.run(main()) ``` -------------------------------- ### Concurrent Finger Queries with Mapilli and asyncio Source: https://context7.com/alanbato/mapilli/llms.txt Shows how to query multiple Finger servers in parallel using `asyncio.gather`. This function efficiently handles multiple queries and includes error handling for timeouts, connection issues, and invalid query formats. It returns results as a list of tuples, each containing the original query and its response body. ```python import asyncio from mapilli import FingerClient async def query_user(client: FingerClient, query: str) -> tuple[str, str]: """Query a user and return (query, result) tuple.""" try: response = await client.query(query) return (query, response.body) except TimeoutError: return (query, "Request timed out") except ConnectionError as e: return (query, f"Connection failed: {e}") except ValueError as e: return (query, f"Invalid query: {e}") async def main(): # Query multiple users across different hosts concurrently queries = [ "alice@host1.example.com", "bob@host2.example.com", "charlie@host3.example.com", "/W admin@host4.example.com" ] async with FingerClient(timeout=15.0) as client: # Launch all queries concurrently tasks = [query_user(client, q) for q in queries] results = await asyncio.gather(*tasks) # Process results for query, result in results: print(f"\n=== {query} ===") print(result[:100] + "..." if len(result) > 100 else result) asyncio.run(main()) ``` -------------------------------- ### Parse Finger Protocol Requests Source: https://context7.com/alanbato/mapilli/llms.txt Demonstrates parsing different types of Finger protocol requests, including empty queries and chained host queries. It shows how to extract query types and target hosts from raw string inputs. ```python req4 = FingerRequest.parse("", default_host="example.com") print(f"Query type: {req4.query_type}") # QueryType.LIST_USERS print(f"Target host: {req4.target_host}") # example.com # Parse chained host query (forwarding) req5 = FingerRequest.parse("alice@host1.com@host2.com") print(f"Target host: {req5.target_host}") # host1.com (first hop) print(f"Full hostname: {req5.hostname}") # host1.com@host2.com # Convert to wire format (bytes to send) wire_bytes = req1.to_wire() print(f"Wire bytes: {wire_bytes}") # b'alice\r\n' ``` -------------------------------- ### FingerRequest Parsing in Python Source: https://github.com/alanbato/mapilli/blob/main/docs/explanation/architecture.md Illustrates the usage of the FingerRequest class for parsing RFC 1288 finger queries. It shows how to parse different query formats and extract components like username, hostname, and query type. ```python request = FingerRequest.parse("alice@example.com") # request.username = "alice" # request.hostname = "example.com" # request.query_type = QueryType.USER_REMOTE request = FingerRequest.parse("/W alice") # request.username = "alice" # request.verbose = True ``` -------------------------------- ### Mapilli CLI - Show Version Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/cli.md This command displays the current version of the mapilli tool and exits. It's a standard option for checking software versions. ```bash mapilli --version ``` -------------------------------- ### FingerClient - Custom Timeout Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/api/client.md Shows how to initialize the FingerClient with a custom timeout value. ```APIDOC ## FingerClient with Custom Timeout ### Description Initializes the FingerClient with a specified timeout for requests. ### Method Asynchronous Context Manager (`async with`) ### Endpoint Not applicable (client-side library) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```python from mapilli import FingerClient client = FingerClient(timeout=10.0) async with client: response = await client.query("alice@example.com") ``` ### Response #### Success Response (200) - **body** (str) - The response body from the Finger server. #### Response Example ```json { "body": "Finger user information..." } ``` ``` -------------------------------- ### FingerClient - Error Handling Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/api/client.md Demonstrates how to handle potential exceptions during client operations. ```APIDOC ## FingerClient - Error Handling ### Description Provides examples of how to catch and handle common errors that may occur during Finger client operations. ### Method Asynchronous Context Manager (`async with`) and client methods. ### Endpoint Not applicable (client-side library) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```python async with FingerClient() as client: try: response = await client.query("alice@example.com") except TimeoutError: print("Request timed out") except ConnectionError: print("Connection failed") except ValueError: print("Invalid query") ``` ### Response N/A (Error handling focuses on exceptions, not standard responses.) ``` -------------------------------- ### Handle Finger Protocol Responses Source: https://context7.com/alanbato/mapilli/llms.txt Illustrates how to use the FingerResponse class to process server responses. It covers accessing response metadata like host, port, and original query, as well as retrieving the full body and iterating through response lines. ```python from mapilli import FingerClient, FingerResponse import asyncio async def inspect_response(): async with FingerClient() as client: response: FingerResponse = await client.query("alice@example.com") # Access response metadata print(f"Queried host: {response.host}") print(f"Port: {response.port}") print(f"Original query: {response.query}") # Get full response body print(f"\nFull response:\n{response.body}") # Process response line by line print(f"\nProcessing {len(response.lines)} lines:") for i, line in enumerate(response.lines, 1): print(f" Line {i}: {line}") # String representation (returns body) print(f"\nString: {str(response)}") asyncio.run(inspect_response()) ``` -------------------------------- ### Finger Client with Error Handling using Mapilli Source: https://github.com/alanbato/mapilli/blob/main/docs/tutorials/building-a-client.md This Python snippet enhances the basic Finger client by incorporating robust error handling for common network and query issues. It uses a try-except block to catch TimeoutError, ConnectionError, and ValueError, returning None and printing an error message if an exception occurs. The FingerClient is configured with a 10.0-second timeout. ```python import asyncio from mapilli import FingerClient async def finger_user(query: str) -> str | None: """Query a Finger server and return the response.""" async with FingerClient(timeout=10.0) as client: try: response = await client.query(query) return response.body except TimeoutError: print(f"Error: Request timed out for {query}") return None except ConnectionError as e: print(f"Error: Could not connect - {e}") return None except ValueError as e: print(f"Error: Invalid query - {e}") return None async def main(): result = await finger_user("alice@example.com") if result: print(result) if __name__ == "__main__": asyncio.run(main()) ``` -------------------------------- ### FingerClient Async API in Python Source: https://github.com/alanbato/mapilli/blob/main/docs/explanation/architecture.md The high-level asynchronous API for the Finger client. It manages the creation of asyncio.Future, establishes a connection using FingerClientProtocol, and awaits the response future. ```python class FingerClient: async def finger(self, host, query): loop = asyncio.get_running_loop() response_future = loop.create_future() # Create connection with protocol transport, protocol = await loop.create_connection( lambda: FingerClientProtocol(query, host, port, response_future), host=host, port=port, ) # Wait for response via Future return await response_future ``` -------------------------------- ### FingerClient - High-level async client Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/api/index.md The FingerClient class provides a high-level asynchronous interface for making queries to Finger servers. It is designed for ease of use in basic scenarios. ```APIDOC ## FingerClient ### Description High-level async client for making queries to Finger servers. ### Usage Example ```python from mapilli import FingerClient async with FingerClient() as client: response = await client.query("alice@example.com") print(response.body) ``` ### Methods - **query(user_email: str)**: Asynchronously queries the Finger server for the given user email. - **Parameters**: - `user_email` (str) - The email address of the user to query. - **Returns**: - `FingerResponse` - An object representing the server's response. ``` -------------------------------- ### Parse Finger Protocol Requests with FingerRequest Source: https://context7.com/alanbato/mapilli/llms.txt Demonstrates parsing Finger query strings into structured `FingerRequest` objects according to RFC 1288. It handles various formats including user@host, verbose queries with `/W`, and host-only queries, extracting properties like username, hostname, query type, and wire format. ```python from mapilli import FingerRequest, QueryType # Parse various query formats req1 = FingerRequest.parse("alice@example.com") print(f"Username: {req1.username}") # alice print(f"Host: {req1.hostname}") # example.com print(f"Query type: {req1.query_type}") # QueryType.USER_REMOTE print(f"Wire format: {req1.wire_query}") # alice # Parse verbose query with /W prefix req2 = FingerRequest.parse("/W bob@example.com") print(f"Verbose: {req2.verbose}") # True print(f"Wire query: {req2.wire_query}") # /W bob # Parse host-only query req3 = FingerRequest.parse("@example.com") print(f"Query type: {req3.query_type}") # QueryType.HOST_ONLY print(f"Wire query: {req3.wire_query}") # @example.com ``` -------------------------------- ### FingerRequest and FingerResponse - Protocol Representation Source: https://github.com/alanbato/mapilli/blob/main/docs/reference/api/index.md Defines the structures for representing Finger requests and responses, including details like headers, body, and status. ```APIDOC ## FingerRequest / FingerResponse ### Description Representation of a Finger protocol request and response. ### FingerRequest - **hostname** (str) - The hostname of the Finger server. - **port** (int) - The port of the Finger server. - **user_info** (str) - The user information requested. ### FingerResponse - **status_code** (int) - The HTTP status code of the response. - **headers** (dict) - A dictionary of response headers. - **body** (str) - The content of the Finger server response. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.