├── .gitignore ├── .python-version ├── LICENSE ├── README.md ├── polarsdocsfinder.py ├── pyproject.toml ├── resources ├── claud1.jpeg ├── claude2.jpeg └── mcp_inspector.png └── uv.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Python-generated files 2 | __pycache__/ 3 | *.py[oc] 4 | build/ 5 | dist/ 6 | wheels/ 7 | *.egg-info 8 | 9 | # Virtual environments 10 | .venv 11 | .idea 12 | .idea/ -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.11 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 hottechstack.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Polars Docs MCP 2 | 3 | A FastMCP tool to search and retrieve Polars API documentation with support for multiple transport methods. 4 | 5 | ## Features 6 | 7 | - Automatically discover Polars public components (classes, functions, submodules). 8 | - Search Polars API by component or query string. 9 | - Get current Polars version and package information. 10 | - Returns structured JSON with API signatures and descriptions. 11 | - Support for multiple transport methods: STDIO, Streamable HTTP, and SSE. 12 | - Integrates with `mcp` for seamless LLM-powered workflows. 13 | 14 | > By leveraging Python's built‑in introspection to reflectively discover every public class, function, and submodule in Polars at runtime, I eliminate the cost, fragility, and maintenance burden of web‑scraping or managing an external documentation database. This approach guarantees 100% up‑to‑date accuracy with every library release, requires no complex text cleaning or embedding pipelines, and avoids the heavy infrastructure overhead of semantic search—making it both simpler and far more efficient for real‑time API lookup. 15 | 16 | ## Usage 17 | 18 | ### 1. Claude Desktop Config (Recommended) 19 | 20 | ```json 21 | { 22 | "mcpServers": { 23 | "polarsapifinder": { 24 | "command": "uv", 25 | "args": [ 26 | "--directory", 27 | "/PATH/TO/polars-docs-mcp", 28 | "run", 29 | "polarsdocsfinder.py" 30 | ] 31 | } 32 | } 33 | } 34 | ``` 35 | 36 | ### 2. Manual Execution with Transport Options 37 | 38 | #### STDIO (Default - Best for Claude Desktop) 39 | ```bash 40 | python polarsdocsfinder.py 41 | # or explicitly: 42 | python polarsdocsfinder.py --transport stdio 43 | ``` 44 | 45 | #### Streamable HTTP (Best for Web Deployments) 46 | ```bash 47 | python polarsdocsfinder.py --transport streamable-http 48 | # With custom settings: 49 | python polarsdocsfinder.py --transport streamable-http --host 0.0.0.0 --port 8080 --path /api/mcp 50 | ``` 51 | 52 | #### SSE (For Legacy Client Compatibility) 53 | ```bash 54 | python polarsdocsfinder.py --transport sse 55 | # With custom settings: 56 | python polarsdocsfinder.py --transport sse --host 0.0.0.0 --port 9000 57 | ``` 58 | 59 | #### Command Line Arguments 60 | - `--transport`: Choose transport method (`stdio`, `streamable-http`, `sse`) - Default: `stdio` 61 | - `--host`: Host address for HTTP/SSE transports - Default: `127.0.0.1` 62 | - `--port`: Port number for HTTP/SSE transports - Default: `8111` 63 | - `--path`: URL path for streamable-http transport - Default: `/mcp` 64 | 65 | ### 3. Visual Testing of MCP Server 66 | 67 | ```bash 68 | npx @modelcontextprotocol/inspector uv run polarsdocsfinder.py 69 | ``` 70 | 71 | ![MCP INspector](resources/mcp_inspector.png) 72 | 73 | Requires Python 3.11+. 74 | 75 | ## Tool Endpoints 76 | 77 | - `get_polars_version()`: Get current Polars version and package information. 78 | - `list_polars_components()`: List all high-level Polars API components. 79 | - `search_polars_docs(api_refs: list[str] | None, query: str | None, max_results: int = 1000)`: Search and retrieve API signatures. 80 | - `verify_polars_api(api_ref: str)`: Verify if a Polars API reference is valid. 81 | - `list_all_modern_data_stacks()`: List modern data stacks compatible with Polars. 82 | 83 | ## Transport Methods 84 | 85 | ### STDIO (Default) 86 | - **Best for**: Claude Desktop, local tools, command-line scripts 87 | - **Usage**: Direct integration with Claude Desktop configuration 88 | - **Communication**: Standard input/output streams 89 | 90 | ### Streamable HTTP 91 | - **Best for**: Web deployments, REST API integration, browser-based clients 92 | - **Usage**: Run as HTTP service, connect via HTTP requests 93 | - **Communication**: HTTP POST requests to the specified endpoint 94 | 95 | ### SSE (Server-Sent Events) 96 | - **Best for**: Compatibility with existing SSE clients, real-time streaming 97 | - **Usage**: Legacy system integration 98 | - **Communication**: Server-sent events over HTTP 99 | 100 | ## Examples Snapshots 101 | 102 | ![Claude](resources/claud1.jpeg) 103 | 104 | ![Claud2](resources/claude2.jpeg) 105 | 106 | ## Testing HTTP Transport 107 | 108 | If running with HTTP transport, you can test the server: 109 | 110 | ```bash 111 | # Start server 112 | python polarsdocsfinder.py --transport streamable-http --port 8111 113 | 114 | # Test with curl 115 | curl -X POST http://127.0.0.1:8111/mcp \ 116 | -H "Content-Type: application/json" \ 117 | -d '{"method": "tools/list"}' 118 | ``` 119 | 120 | ## License 121 | 122 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. 123 | 124 | ## Contact 125 | 126 | Created by [ABC](mailto:abc@abhishekchoudhary.net). Report issues or request features at https://github.com/HotTechStack/polars-docs-mcp/issues. -------------------------------------------------------------------------------- /polarsdocsfinder.py: -------------------------------------------------------------------------------- 1 | from fastmcp import FastMCP 2 | import json 3 | from enum import Enum, auto 4 | from typing import Optional, List, Dict, Union, Literal 5 | import polars as pl 6 | import inspect 7 | import difflib 8 | import importlib 9 | import importlib.metadata 10 | import argparse 11 | 12 | # Initialize FastMCP 13 | mcp = FastMCP("Polars Docs Finder with FastMCP") 14 | 15 | 16 | def discover_polars_components(): 17 | """ 18 | Auto‑discover all public Polars components, including: 19 | - Classes (DataFrame, LazyFrame, Series, Expr, GroupBy, …) 20 | - Top‑level functions (read_csv, concat, etc.) 21 | - Sub‑modules (e.g. polars.io → "io") 22 | """ 23 | comps = {} 24 | 25 | # 1) Pick up all public classes in polars.* 26 | for name, obj in vars(pl).items(): 27 | if name.startswith("_"): 28 | continue 29 | if inspect.isclass(obj) and obj.__module__.startswith("polars"): 30 | comps[name] = obj 31 | 32 | # 2) Pick up all public top‑level functions in polars 33 | for name, obj in vars(pl).items(): 34 | if name.startswith("_"): 35 | continue 36 | if inspect.isfunction(obj) and obj.__module__.startswith("polars"): 37 | comps[name] = obj 38 | 39 | # 3) Explicitly include these sub‑modules 40 | for sub in ["io", "functions", "convert", "datatypes"]: 41 | try: 42 | mod = importlib.import_module(f"polars.{sub}") 43 | comps[sub] = mod 44 | except ImportError: 45 | # skip if not present in this version 46 | pass 47 | 48 | return comps 49 | 50 | 51 | @mcp.tool(description="Get the currently installed Polars version information") 52 | def get_polars_version() -> str: 53 | """ 54 | Get the currently installed Polars version information. 55 | 56 | This tool returns detailed version information about the Polars package 57 | currently installed in the environment, including the version number, 58 | installation location, and other metadata. 59 | 60 | Returns: 61 | str: A JSON-encoded object containing version information: 62 | { 63 | "version": "0.20.3", 64 | "package_name": "polars", 65 | "location": "/path/to/site-packages", 66 | "metadata": { 67 | "author": "...", 68 | "summary": "...", 69 | "home_page": "...", 70 | ... 71 | } 72 | } 73 | 74 | Example: 75 | # Get current Polars version 76 | get_polars_version() 77 | """ 78 | try: 79 | # Get version using importlib.metadata (recommended approach) 80 | version = importlib.metadata.version("polars") 81 | 82 | # Get additional metadata 83 | try: 84 | metadata = importlib.metadata.metadata("polars") 85 | metadata_dict = dict(metadata) 86 | except Exception: 87 | metadata_dict = {} 88 | 89 | # Try to get the module location 90 | try: 91 | location = pl.__file__ if hasattr(pl, '__file__') else "Unknown" 92 | if location and location.endswith("__init__.py"): 93 | location = location.replace("__init__.py", "") 94 | except Exception: 95 | location = "Unknown" 96 | 97 | version_info = { 98 | "version": version, 99 | "package_name": "polars", 100 | "location": location, 101 | "metadata": metadata_dict 102 | } 103 | 104 | return json.dumps(version_info, indent=2, default=str) 105 | 106 | except importlib.metadata.PackageNotFoundError: 107 | # Fallback: try to get version from polars module directly 108 | try: 109 | version = getattr(pl, '__version__', 'Unknown') 110 | version_info = { 111 | "version": version, 112 | "package_name": "polars", 113 | "location": getattr(pl, '__file__', 'Unknown'), 114 | "metadata": {}, 115 | "note": "Version obtained from module attribute (metadata unavailable)" 116 | } 117 | return json.dumps(version_info, indent=2, default=str) 118 | 119 | except Exception as e: 120 | error_info = { 121 | "error": "Could not determine Polars version", 122 | "details": str(e), 123 | "version": "Unknown", 124 | "package_name": "polars" 125 | } 126 | return json.dumps(error_info, indent=2) 127 | 128 | 129 | @mcp.tool(description="List all available high‑level Polars API components") 130 | def list_polars_components() -> str: 131 | """ 132 | List all available high‑level Polars API components. 133 | 134 | This tool inspects the `polars` package and returns every public class 135 | found in its top‑level namespace (e.g. DataFrame, LazyFrame, Series, 136 | Expr, GroupBy, DateChunked, etc.). It emits a JSON‑encoded list of 137 | component names. An LLM can call this first to decide which components 138 | to pass into `search_polars_docs`. 139 | 140 | Returns: 141 | str: A JSON‑encoded list of component names, e.g. 142 | [ 143 | "DataFrame", 144 | "LazyFrame", 145 | "Series", 146 | "Expr", 147 | "GroupBy", 148 | ... 149 | ] 150 | 151 | Example: 152 | # Discover which Polars components are available 153 | list_polars_components() 154 | """ 155 | comps = discover_polars_components() # returns a dict 156 | names = list(comps.keys()) # cast dict_keys to a list of str 157 | return json.dumps(names, indent=2) # JSON‑encode for the LLM 158 | 159 | 160 | @mcp.tool( 161 | description="Search Polars API methods and documentation. Finds exact matches first, then falls back to fuzzy search.") 162 | async def search_polars_api( 163 | components: str = "", 164 | methods: str = "", 165 | max_results: int = 1000, 166 | debug: bool = False, 167 | ) -> str: 168 | """ 169 | Search Polars API methods and get their signatures and documentation. 170 | 171 | This function is designed for LLMs to easily find Polars methods. It tries multiple 172 | search strategies automatically: 173 | 1. Exact component matches (case-insensitive) 174 | 2. Exact method matches (case-insensitive) 175 | 3. Fuzzy search as fallback 176 | 177 | Args: 178 | components (str): 179 | Polars component names to search (case-insensitive). 180 | Examples: "dataframe", "DataFrame", "series,lazyframe", "expr" 181 | 182 | methods (str): 183 | Specific method names to find (case-insensitive). 184 | Examples: "filter", "join,groupby", "select,with_columns" 185 | Can be used alone or combined with components. 186 | 187 | max_results (int): 188 | Maximum number of results to return (default: 50) 189 | 190 | debug (bool): 191 | Show detailed search process information 192 | 193 | Returns: 194 | str: JSON array of method information with name, signature, and description 195 | 196 | Examples: 197 | # Get all DataFrame methods 198 | search_polars_api(components="dataframe") 199 | 200 | # Get specific methods from any component 201 | search_polars_api(methods="filter,join") 202 | 203 | # Get specific methods from specific components 204 | search_polars_api(components="dataframe,series", methods="groupby") 205 | 206 | # Fuzzy search will automatically activate if exact matches fail 207 | search_polars_api(methods="filtter") # Will find "filter" 208 | """ 209 | 210 | # Parse and normalize inputs 211 | component_list = [] 212 | if components.strip(): 213 | component_list = [c.strip().lower() for c in components.split(",") if c.strip()] 214 | 215 | method_list = [] 216 | if methods.strip(): 217 | method_list = [m.strip().lower() for m in methods.split(",") if m.strip()] 218 | 219 | # Debug info 220 | debug_info = { 221 | "search_strategy": "", 222 | "inputs": { 223 | "components_raw": components, 224 | "methods_raw": methods, 225 | "components_parsed": component_list, 226 | "methods_parsed": method_list 227 | }, 228 | "search_steps": [], 229 | "results_found": 0 230 | } 231 | 232 | if debug: 233 | print(f"=== Search Input Debug ===") 234 | print(f"Components: {component_list}") 235 | print(f"Methods: {method_list}") 236 | print("=" * 30) 237 | 238 | # Build the full API index with case-insensitive mapping 239 | components_discovered = discover_polars_components() 240 | all_apis = [] 241 | component_name_mapping = {} # lowercase -> actual name 242 | 243 | for comp_name, comp in components_discovered.items(): 244 | if comp is None: 245 | continue 246 | 247 | # Store case-insensitive mapping 248 | component_name_mapping[comp_name.lower()] = comp_name 249 | 250 | for attr_name in dir(comp): 251 | if attr_name.startswith("_"): 252 | continue 253 | 254 | try: 255 | member = getattr(comp, attr_name) 256 | if not (callable(member) or isinstance(member, property)): 257 | continue 258 | 259 | try: 260 | if callable(member) and not isinstance(member, type): 261 | sig = str(inspect.signature(member)) 262 | else: 263 | sig = "" 264 | except (ValueError, TypeError, AttributeError): 265 | sig = "(...)" 266 | 267 | doc = inspect.getdoc(member) or "" 268 | short_doc = doc.strip().split("\n")[0] if doc.strip() else "" 269 | 270 | if not short_doc and not callable(member): 271 | continue 272 | 273 | all_apis.append({ 274 | "name": f"{comp_name}.{attr_name}", 275 | "component": comp_name, 276 | "method": attr_name, 277 | "signature": f"{comp_name}.{attr_name}{sig}", 278 | "description": short_doc 279 | }) 280 | 281 | except (AttributeError, TypeError): 282 | continue 283 | 284 | debug_info["total_apis"] = len(all_apis) 285 | 286 | # Search Strategy 1: Exact component matches (case-insensitive) 287 | results = [] 288 | 289 | if component_list and not method_list: 290 | debug_info["search_strategy"] = "exact_components" 291 | debug_info["search_steps"].append("Searching for exact component matches") 292 | 293 | for comp_lower in component_list: 294 | if comp_lower in component_name_mapping: 295 | actual_comp_name = component_name_mapping[comp_lower] 296 | matches = [api for api in all_apis if api["component"] == actual_comp_name] 297 | results.extend(matches) 298 | debug_info["search_steps"].append(f"Found {len(matches)} methods for {actual_comp_name}") 299 | 300 | # Search Strategy 2: Exact method matches (case-insensitive) 301 | elif method_list and not component_list: 302 | debug_info["search_strategy"] = "exact_methods" 303 | debug_info["search_steps"].append("Searching for exact method matches") 304 | 305 | for method_lower in method_list: 306 | matches = [api for api in all_apis if api["method"].lower() == method_lower] 307 | results.extend(matches) 308 | debug_info["search_steps"].append(f"Found {len(matches)} matches for method '{method_lower}'") 309 | 310 | # Search Strategy 3: Component + Method combination 311 | elif component_list and method_list: 312 | debug_info["search_strategy"] = "component_and_method" 313 | debug_info["search_steps"].append("Searching for component + method combinations") 314 | 315 | for comp_lower in component_list: 316 | if comp_lower in component_name_mapping: 317 | actual_comp_name = component_name_mapping[comp_lower] 318 | for method_lower in method_list: 319 | matches = [api for api in all_apis 320 | if api["component"] == actual_comp_name and api["method"].lower() == method_lower] 321 | results.extend(matches) 322 | debug_info["search_steps"].append( 323 | f"Found {len(matches)} matches for {actual_comp_name}.{method_lower}") 324 | 325 | # Remove duplicates while preserving order 326 | seen = set() 327 | unique_results = [] 328 | for api in results: 329 | key = api["name"] 330 | if key not in seen: 331 | seen.add(key) 332 | unique_results.append(api) 333 | results = unique_results 334 | 335 | # Search Strategy 4: Fuzzy fallback if no exact matches 336 | if not results and (component_list or method_list): 337 | debug_info["search_strategy"] += "_with_fuzzy_fallback" 338 | debug_info["search_steps"].append("No exact matches found, trying fuzzy search") 339 | 340 | fuzzy_candidates = [] 341 | 342 | # Fuzzy search on components 343 | if component_list: 344 | all_component_names = [name.lower() for name in component_name_mapping.keys()] 345 | for comp_lower in component_list: 346 | close_comps = difflib.get_close_matches(comp_lower, all_component_names, n=3, cutoff=0.6) 347 | for close_comp in close_comps: 348 | actual_comp_name = component_name_mapping[close_comp] 349 | comp_matches = [api for api in all_apis if api["component"] == actual_comp_name] 350 | fuzzy_candidates.extend(comp_matches) 351 | debug_info["search_steps"].append( 352 | f"Fuzzy: '{comp_lower}' → '{actual_comp_name}' ({len(comp_matches)} methods)") 353 | 354 | # Fuzzy search on methods 355 | if method_list: 356 | all_method_names = list(set(api["method"].lower() for api in all_apis)) 357 | for method_lower in method_list: 358 | close_methods = difflib.get_close_matches(method_lower, all_method_names, n=5, cutoff=0.6) 359 | for close_method in close_methods: 360 | method_matches = [api for api in all_apis if api["method"].lower() == close_method] 361 | fuzzy_candidates.extend(method_matches) 362 | debug_info["search_steps"].append( 363 | f"Fuzzy: '{method_lower}' → '{close_method}' ({len(method_matches)} matches)") 364 | 365 | # Remove duplicates from fuzzy results 366 | seen = set() 367 | for api in fuzzy_candidates: 368 | key = api["name"] 369 | if key not in seen: 370 | seen.add(key) 371 | results.append(api) 372 | 373 | # Limit results 374 | final_results = results[:max_results] 375 | debug_info["results_found"] = len(final_results) 376 | 377 | # Debug output 378 | if debug: 379 | print(f"=== Search Strategy Debug ===") 380 | print(f"Strategy used: {debug_info['search_strategy']}") 381 | for step in debug_info["search_steps"]: 382 | print(f" {step}") 383 | print(f"Final results: {len(final_results)} items") 384 | print("=" * 30) 385 | 386 | # Clean up results for output (remove internal fields) 387 | clean_results = [] 388 | for api in final_results: 389 | clean_results.append({ 390 | "name": api["name"], 391 | "signature": api["signature"], 392 | "description": api["description"] 393 | }) 394 | 395 | # Prepare response 396 | response = { 397 | "results": clean_results, 398 | "total_found": len(final_results), 399 | "search_strategy": debug_info["search_strategy"] 400 | } 401 | 402 | if debug: 403 | response["debug"] = debug_info 404 | 405 | return json.dumps(response, indent=2) 406 | 407 | 408 | @mcp.tool(description="Verify if a given Polars API name or signature is valid.") 409 | def verify_polars_api(api_ref: str) -> str: 410 | """ 411 | Verify that the provided Polars API reference or full signature exists. 412 | 413 | Args: 414 | api_ref (str): An API name (e.g. "DataFrame.filter") or full signature 415 | (e.g. "DataFrame.filter(self, predicate: IntoExpr) -> DataFrame"). 416 | 417 | Returns: 418 | str: JSON with { 419 | "valid": bool, 420 | "matches": [ 421 | {"name": str, "signature": str}, 422 | ... 423 | ] 424 | } 425 | """ 426 | # Rebuild index of APIs 427 | components = discover_polars_components() 428 | all_apis = [] 429 | 430 | for comp_name, comp in components.items(): 431 | if comp is None: 432 | continue 433 | 434 | for attr_name in dir(comp): 435 | if attr_name.startswith("_"): 436 | continue 437 | try: 438 | member = getattr(comp, attr_name) 439 | if callable(member): 440 | try: 441 | sig = str(inspect.signature(member)) 442 | except (ValueError, TypeError): 443 | sig = "(...)" 444 | full_sig = f"{comp_name}.{attr_name}{sig}" 445 | all_apis.append({"name": f"{comp_name}.{attr_name}", "signature": full_sig}) 446 | except (AttributeError, TypeError): 447 | continue 448 | 449 | # Find matches 450 | matches = [api for api in all_apis if api_ref == api["name"] or api_ref == api["signature"]] 451 | valid = len(matches) > 0 452 | return json.dumps({"valid": valid, "matches": matches}, indent=2) 453 | 454 | 455 | @mcp.tool(description="Debug tool to show what components are discovered and their types") 456 | def debug_polars_components() -> str: 457 | """ 458 | Debug tool to show what components are discovered and their types. 459 | This helps diagnose issues with component discovery. 460 | """ 461 | components = discover_polars_components() 462 | debug_info = [] 463 | 464 | for name, comp in components.items(): 465 | comp_info = { 466 | "name": name, 467 | "type": type(comp).__name__, 468 | "module": getattr(comp, '__module__', 'Unknown'), 469 | "is_class": inspect.isclass(comp), 470 | "is_function": inspect.isfunction(comp), 471 | "is_module": inspect.ismodule(comp), 472 | "methods_count": 0 473 | } 474 | 475 | # Count methods for classes 476 | if inspect.isclass(comp) or inspect.ismodule(comp): 477 | try: 478 | methods = [attr for attr in dir(comp) 479 | if not attr.startswith("_") and callable(getattr(comp, attr, None))] 480 | comp_info["methods_count"] = len(methods) 481 | comp_info["sample_methods"] = methods[:5] # First 5 methods as sample 482 | except Exception as e: 483 | comp_info["error"] = str(e) 484 | 485 | debug_info.append(comp_info) 486 | 487 | return json.dumps(debug_info, indent=2, default=str) 488 | 489 | 490 | @mcp.tool(description="List all modern data stacks that can be used with Polars.") 491 | def list_all_modern_data_stacks(): 492 | """ 493 | List all modern data stacks that can be used with Polars. 494 | """ 495 | # This is a placeholder function. You can implement it to return a list of 496 | # modern data stacks that are compatible with Polars. 497 | return ["DuckDB", "Polars", "Daft", "Hudi", "Iceberg", "Delta Lake", "Apache Arrow", "Apache Parquet", "Xorq"] 498 | 499 | 500 | if __name__ == "__main__": 501 | import argparse 502 | 503 | parser = argparse.ArgumentParser(description="Polars MCP Server with FastMCP") 504 | parser.add_argument( 505 | "--transport", 506 | choices=["stdio", "streamable-http", "sse"], 507 | default="stdio", 508 | help="Transport method (default: stdio)" 509 | ) 510 | parser.add_argument( 511 | "--host", 512 | default="127.0.0.1", 513 | help="Host address for HTTP/SSE transports (default: 127.0.0.1)" 514 | ) 515 | parser.add_argument( 516 | "--port", 517 | type=int, 518 | default=8111, 519 | help="Port number for HTTP/SSE transports (default: 8111)" 520 | ) 521 | parser.add_argument( 522 | "--path", 523 | default="/mcp", 524 | help="URL path for streamable-http transport (default: /mcp)" 525 | ) 526 | 527 | args = parser.parse_args() 528 | 529 | print(f"Starting Polars MCP Server with transport: {args.transport}") 530 | 531 | if args.transport == "stdio": 532 | # STDIO (Default): Best for local tools and command-line scripts 533 | print("Using STDIO transport - connect via command line or local tools") 534 | mcp.run(transport="stdio") 535 | 536 | elif args.transport == "streamable-http": 537 | # Streamable HTTP: Recommended for web deployments 538 | print(f"Using Streamable HTTP transport on {args.host}:{args.port}{args.path}") 539 | mcp.run( 540 | transport="streamable-http", 541 | host=args.host, 542 | port=args.port, 543 | path=args.path 544 | ) 545 | 546 | elif args.transport == "sse": 547 | # SSE: For compatibility with existing SSE clients 548 | print(f"Using SSE transport on {args.host}:{args.port}") 549 | mcp.run( 550 | transport="sse", 551 | host=args.host, 552 | port=args.port 553 | ) -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "polars-docs-mcp" 3 | version = "0.1.0" 4 | description = "A FastMCP tool to search and retrieve Polars API documentation." 5 | readme = "README.md" 6 | requires-python = ">=3.11" 7 | license = "MIT" 8 | license-files = ["LICENSE"] 9 | authors = [ 10 | { name = "ABC", email = "abc@abhishekchoudhary.net" } 11 | ] 12 | keywords = ["polars", "mcp", "documentation", "api"] 13 | classifiers = [ 14 | "Programming Language :: Python :: 3.11", 15 | "Topic :: Software Development :: Documentation", 16 | ] 17 | dependencies = [ 18 | "polars>=1.30.0", 19 | "fastmcp>=2.5.0", 20 | ] 21 | 22 | [tool.setuptools] 23 | py-modules = ["polarsdocsfinder"] 24 | 25 | [project.urls] 26 | Homepage = "https://github.com/HotTechStack/polars-docs-mcp" 27 | Repository = "https://github.com/HotTechStack/polars-docs-mcp.git" 28 | Documentation = "https://github.com/HotTechStack/polars-docs-mcp#readme" 29 | 30 | [build-system] 31 | requires = ["setuptools>=61.0", "wheel"] 32 | build-backend = "setuptools.build_meta" 33 | -------------------------------------------------------------------------------- /resources/claud1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotTechStack/polars-docs-mcp/d48f592c27d49dacf0fea2a7c173c7abf644f225/resources/claud1.jpeg -------------------------------------------------------------------------------- /resources/claude2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotTechStack/polars-docs-mcp/d48f592c27d49dacf0fea2a7c173c7abf644f225/resources/claude2.jpeg -------------------------------------------------------------------------------- /resources/mcp_inspector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotTechStack/polars-docs-mcp/d48f592c27d49dacf0fea2a7c173c7abf644f225/resources/mcp_inspector.png -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | revision = 1 3 | requires-python = ">=3.11" 4 | 5 | [[package]] 6 | name = "annotated-types" 7 | version = "0.7.0" 8 | source = { registry = "https://pypi.org/simple" } 9 | sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } 10 | wheels = [ 11 | { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, 12 | ] 13 | 14 | [[package]] 15 | name = "anyio" 16 | version = "4.9.0" 17 | source = { registry = "https://pypi.org/simple" } 18 | dependencies = [ 19 | { name = "idna" }, 20 | { name = "sniffio" }, 21 | { name = "typing-extensions", marker = "python_full_version < '3.13'" }, 22 | ] 23 | sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949 } 24 | wheels = [ 25 | { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916 }, 26 | ] 27 | 28 | [[package]] 29 | name = "certifi" 30 | version = "2025.4.26" 31 | source = { registry = "https://pypi.org/simple" } 32 | sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705 } 33 | wheels = [ 34 | { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618 }, 35 | ] 36 | 37 | [[package]] 38 | name = "click" 39 | version = "8.1.8" 40 | source = { registry = "https://pypi.org/simple" } 41 | dependencies = [ 42 | { name = "colorama", marker = "sys_platform == 'win32'" }, 43 | ] 44 | sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } 45 | wheels = [ 46 | { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, 47 | ] 48 | 49 | [[package]] 50 | name = "colorama" 51 | version = "0.4.6" 52 | source = { registry = "https://pypi.org/simple" } 53 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } 54 | wheels = [ 55 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, 56 | ] 57 | 58 | [[package]] 59 | name = "exceptiongroup" 60 | version = "1.3.0" 61 | source = { registry = "https://pypi.org/simple" } 62 | dependencies = [ 63 | { name = "typing-extensions", marker = "python_full_version < '3.13'" }, 64 | ] 65 | sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749 } 66 | wheels = [ 67 | { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674 }, 68 | ] 69 | 70 | [[package]] 71 | name = "fastmcp" 72 | version = "2.5.0" 73 | source = { registry = "https://pypi.org/simple" } 74 | dependencies = [ 75 | { name = "exceptiongroup" }, 76 | { name = "httpx" }, 77 | { name = "mcp" }, 78 | { name = "openapi-pydantic" }, 79 | { name = "python-dotenv" }, 80 | { name = "rich" }, 81 | { name = "typer" }, 82 | { name = "websockets" }, 83 | ] 84 | sdist = { url = "https://files.pythonhosted.org/packages/aa/88/fb6be09318d69792757545b39d88a2d918f1655fae442ada61559b3113ea/fastmcp-2.5.0.tar.gz", hash = "sha256:fcad2fd281cbcb883570116a1c68939b5e5b460f497f502336204280c8385a59", size = 1035515 } 85 | wheels = [ 86 | { url = "https://files.pythonhosted.org/packages/28/54/fc9a2b1dc6e1fd564f158e48550f9c2a5abfa0819d3aaf5e803e63fca284/fastmcp-2.5.0-py3-none-any.whl", hash = "sha256:9001227c3923b5a3a8138f5d78869e82c8f54f9184c52dde95bf719278861043", size = 105797 }, 87 | ] 88 | 89 | [[package]] 90 | name = "h11" 91 | version = "0.16.0" 92 | source = { registry = "https://pypi.org/simple" } 93 | sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 } 94 | wheels = [ 95 | { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, 96 | ] 97 | 98 | [[package]] 99 | name = "httpcore" 100 | version = "1.0.9" 101 | source = { registry = "https://pypi.org/simple" } 102 | dependencies = [ 103 | { name = "certifi" }, 104 | { name = "h11" }, 105 | ] 106 | sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 } 107 | wheels = [ 108 | { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 }, 109 | ] 110 | 111 | [[package]] 112 | name = "httpx" 113 | version = "0.28.1" 114 | source = { registry = "https://pypi.org/simple" } 115 | dependencies = [ 116 | { name = "anyio" }, 117 | { name = "certifi" }, 118 | { name = "httpcore" }, 119 | { name = "idna" }, 120 | ] 121 | sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } 122 | wheels = [ 123 | { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, 124 | ] 125 | 126 | [[package]] 127 | name = "httpx-sse" 128 | version = "0.4.0" 129 | source = { registry = "https://pypi.org/simple" } 130 | sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 } 131 | wheels = [ 132 | { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 }, 133 | ] 134 | 135 | [[package]] 136 | name = "idna" 137 | version = "3.10" 138 | source = { registry = "https://pypi.org/simple" } 139 | sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } 140 | wheels = [ 141 | { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, 142 | ] 143 | 144 | [[package]] 145 | name = "markdown-it-py" 146 | version = "3.0.0" 147 | source = { registry = "https://pypi.org/simple" } 148 | dependencies = [ 149 | { name = "mdurl" }, 150 | ] 151 | sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } 152 | wheels = [ 153 | { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, 154 | ] 155 | 156 | [[package]] 157 | name = "mcp" 158 | version = "1.9.1" 159 | source = { registry = "https://pypi.org/simple" } 160 | dependencies = [ 161 | { name = "anyio" }, 162 | { name = "httpx" }, 163 | { name = "httpx-sse" }, 164 | { name = "pydantic" }, 165 | { name = "pydantic-settings" }, 166 | { name = "python-multipart" }, 167 | { name = "sse-starlette" }, 168 | { name = "starlette" }, 169 | { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, 170 | ] 171 | sdist = { url = "https://files.pythonhosted.org/packages/e7/bc/54aec2c334698cc575ca3b3481eed627125fb66544152fa1af927b1a495c/mcp-1.9.1.tar.gz", hash = "sha256:19879cd6dde3d763297617242888c2f695a95dfa854386a6a68676a646ce75e4", size = 316247 } 172 | wheels = [ 173 | { url = "https://files.pythonhosted.org/packages/a6/c0/4ac795585a22a0a2d09cd2b1187b0252d2afcdebd01e10a68bbac4d34890/mcp-1.9.1-py3-none-any.whl", hash = "sha256:2900ded8ffafc3c8a7bfcfe8bc5204037e988e753ec398f371663e6a06ecd9a9", size = 130261 }, 174 | ] 175 | 176 | [[package]] 177 | name = "mdurl" 178 | version = "0.1.2" 179 | source = { registry = "https://pypi.org/simple" } 180 | sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } 181 | wheels = [ 182 | { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, 183 | ] 184 | 185 | [[package]] 186 | name = "openapi-pydantic" 187 | version = "0.5.1" 188 | source = { registry = "https://pypi.org/simple" } 189 | dependencies = [ 190 | { name = "pydantic" }, 191 | ] 192 | sdist = { url = "https://files.pythonhosted.org/packages/02/2e/58d83848dd1a79cb92ed8e63f6ba901ca282c5f09d04af9423ec26c56fd7/openapi_pydantic-0.5.1.tar.gz", hash = "sha256:ff6835af6bde7a459fb93eb93bb92b8749b754fc6e51b2f1590a19dc3005ee0d", size = 60892 } 193 | wheels = [ 194 | { url = "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl", hash = "sha256:a3a09ef4586f5bd760a8df7f43028b60cafb6d9f61de2acba9574766255ab146", size = 96381 }, 195 | ] 196 | 197 | [[package]] 198 | name = "polars" 199 | version = "1.30.0" 200 | source = { registry = "https://pypi.org/simple" } 201 | sdist = { url = "https://files.pythonhosted.org/packages/82/b6/8dbdf626c0705a57f052708c9fc0860ffc2aa97955930d5faaf6a66fcfd3/polars-1.30.0.tar.gz", hash = "sha256:dfe94ae84a5efd9ba74e616e3e125b24ca155494a931890a8f17480737c4db45", size = 4668318 } 202 | wheels = [ 203 | { url = "https://files.pythonhosted.org/packages/40/48/e9b2cb379abcc9f7aff2e701098fcdb9fe6d85dc4ad4cec7b35d39c70951/polars-1.30.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:4c33bc97c29b7112f0e689a2f8a33143973a3ff466c70b25c7fd1880225de6dd", size = 35704342 }, 204 | { url = "https://files.pythonhosted.org/packages/36/ca/f545f61282f75eea4dfde4db2944963dcd59abd50c20e33a1c894da44dad/polars-1.30.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:e3d05914c364b8e39a5b10dcf97e84d76e516b3b1693880bf189a93aab3ca00d", size = 32459857 }, 205 | { url = "https://files.pythonhosted.org/packages/76/20/e018cd87d7cb6f8684355f31f4e193222455a6e8f7b942f4a2934f5969c7/polars-1.30.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a52af3862082b868c1febeae650af8ae8a2105d2cb28f0449179a7b44f54ccf", size = 36267243 }, 206 | { url = "https://files.pythonhosted.org/packages/cb/e7/b88b973021be07b13d91b9301cc14392c994225ef5107a32a8ffd3fd6424/polars-1.30.0-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:ffb3ef133454275d4254442257c5f71dd6e393ce365c97997dadeb6fa9d6d4b5", size = 33416871 }, 207 | { url = "https://files.pythonhosted.org/packages/dd/7c/d46d4381adeac537b8520b653dc30cb8b7edbf59883d71fbb989e9005de1/polars-1.30.0-cp39-abi3-win_amd64.whl", hash = "sha256:c26b633a9bd530c5fc09d317fca3bb3e16c772bd7df7549a9d8ec1934773cc5d", size = 36363630 }, 208 | { url = "https://files.pythonhosted.org/packages/fb/b5/5056d0c12aadb57390d0627492bef8b1abf3549474abb9ae0fd4e2bfa885/polars-1.30.0-cp39-abi3-win_arm64.whl", hash = "sha256:476f1bde65bc7b4d9f80af370645c2981b5798d67c151055e58534e89e96f2a8", size = 32643590 }, 209 | ] 210 | 211 | [[package]] 212 | name = "polars-docs-mcp" 213 | version = "0.1.0" 214 | source = { editable = "." } 215 | dependencies = [ 216 | { name = "fastmcp" }, 217 | { name = "polars" }, 218 | ] 219 | 220 | [package.metadata] 221 | requires-dist = [ 222 | { name = "fastmcp", specifier = ">=2.5.0" }, 223 | { name = "polars", specifier = ">=1.30.0" }, 224 | ] 225 | 226 | [[package]] 227 | name = "pydantic" 228 | version = "2.11.5" 229 | source = { registry = "https://pypi.org/simple" } 230 | dependencies = [ 231 | { name = "annotated-types" }, 232 | { name = "pydantic-core" }, 233 | { name = "typing-extensions" }, 234 | { name = "typing-inspection" }, 235 | ] 236 | sdist = { url = "https://files.pythonhosted.org/packages/f0/86/8ce9040065e8f924d642c58e4a344e33163a07f6b57f836d0d734e0ad3fb/pydantic-2.11.5.tar.gz", hash = "sha256:7f853db3d0ce78ce8bbb148c401c2cdd6431b3473c0cdff2755c7690952a7b7a", size = 787102 } 237 | wheels = [ 238 | { url = "https://files.pythonhosted.org/packages/b5/69/831ed22b38ff9b4b64b66569f0e5b7b97cf3638346eb95a2147fdb49ad5f/pydantic-2.11.5-py3-none-any.whl", hash = "sha256:f9c26ba06f9747749ca1e5c94d6a85cb84254577553c8785576fd38fa64dc0f7", size = 444229 }, 239 | ] 240 | 241 | [[package]] 242 | name = "pydantic-core" 243 | version = "2.33.2" 244 | source = { registry = "https://pypi.org/simple" } 245 | dependencies = [ 246 | { name = "typing-extensions" }, 247 | ] 248 | sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195 } 249 | wheels = [ 250 | { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584 }, 251 | { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071 }, 252 | { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823 }, 253 | { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792 }, 254 | { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338 }, 255 | { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998 }, 256 | { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200 }, 257 | { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890 }, 258 | { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359 }, 259 | { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883 }, 260 | { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074 }, 261 | { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538 }, 262 | { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909 }, 263 | { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786 }, 264 | { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000 }, 265 | { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996 }, 266 | { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957 }, 267 | { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199 }, 268 | { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296 }, 269 | { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109 }, 270 | { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028 }, 271 | { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044 }, 272 | { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881 }, 273 | { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034 }, 274 | { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187 }, 275 | { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628 }, 276 | { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866 }, 277 | { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894 }, 278 | { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688 }, 279 | { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808 }, 280 | { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580 }, 281 | { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859 }, 282 | { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810 }, 283 | { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498 }, 284 | { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611 }, 285 | { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924 }, 286 | { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196 }, 287 | { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389 }, 288 | { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223 }, 289 | { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473 }, 290 | { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269 }, 291 | { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921 }, 292 | { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162 }, 293 | { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560 }, 294 | { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777 }, 295 | { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200 }, 296 | { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123 }, 297 | { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852 }, 298 | { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484 }, 299 | { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896 }, 300 | { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475 }, 301 | { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013 }, 302 | { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715 }, 303 | { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757 }, 304 | ] 305 | 306 | [[package]] 307 | name = "pydantic-settings" 308 | version = "2.9.1" 309 | source = { registry = "https://pypi.org/simple" } 310 | dependencies = [ 311 | { name = "pydantic" }, 312 | { name = "python-dotenv" }, 313 | { name = "typing-inspection" }, 314 | ] 315 | sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234 } 316 | wheels = [ 317 | { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356 }, 318 | ] 319 | 320 | [[package]] 321 | name = "pygments" 322 | version = "2.19.1" 323 | source = { registry = "https://pypi.org/simple" } 324 | sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } 325 | wheels = [ 326 | { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, 327 | ] 328 | 329 | [[package]] 330 | name = "python-dotenv" 331 | version = "1.1.0" 332 | source = { registry = "https://pypi.org/simple" } 333 | sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920 } 334 | wheels = [ 335 | { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256 }, 336 | ] 337 | 338 | [[package]] 339 | name = "python-multipart" 340 | version = "0.0.20" 341 | source = { registry = "https://pypi.org/simple" } 342 | sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158 } 343 | wheels = [ 344 | { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546 }, 345 | ] 346 | 347 | [[package]] 348 | name = "rich" 349 | version = "14.0.0" 350 | source = { registry = "https://pypi.org/simple" } 351 | dependencies = [ 352 | { name = "markdown-it-py" }, 353 | { name = "pygments" }, 354 | ] 355 | sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078 } 356 | wheels = [ 357 | { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229 }, 358 | ] 359 | 360 | [[package]] 361 | name = "shellingham" 362 | version = "1.5.4" 363 | source = { registry = "https://pypi.org/simple" } 364 | sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } 365 | wheels = [ 366 | { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, 367 | ] 368 | 369 | [[package]] 370 | name = "sniffio" 371 | version = "1.3.1" 372 | source = { registry = "https://pypi.org/simple" } 373 | sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } 374 | wheels = [ 375 | { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, 376 | ] 377 | 378 | [[package]] 379 | name = "sse-starlette" 380 | version = "2.3.5" 381 | source = { registry = "https://pypi.org/simple" } 382 | dependencies = [ 383 | { name = "anyio" }, 384 | { name = "starlette" }, 385 | ] 386 | sdist = { url = "https://files.pythonhosted.org/packages/10/5f/28f45b1ff14bee871bacafd0a97213f7ec70e389939a80c60c0fb72a9fc9/sse_starlette-2.3.5.tar.gz", hash = "sha256:228357b6e42dcc73a427990e2b4a03c023e2495ecee82e14f07ba15077e334b2", size = 17511 } 387 | wheels = [ 388 | { url = "https://files.pythonhosted.org/packages/c8/48/3e49cf0f64961656402c0023edbc51844fe17afe53ab50e958a6dbbbd499/sse_starlette-2.3.5-py3-none-any.whl", hash = "sha256:251708539a335570f10eaaa21d1848a10c42ee6dc3a9cf37ef42266cdb1c52a8", size = 10233 }, 389 | ] 390 | 391 | [[package]] 392 | name = "starlette" 393 | version = "0.46.2" 394 | source = { registry = "https://pypi.org/simple" } 395 | dependencies = [ 396 | { name = "anyio" }, 397 | ] 398 | sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846 } 399 | wheels = [ 400 | { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037 }, 401 | ] 402 | 403 | [[package]] 404 | name = "typer" 405 | version = "0.15.4" 406 | source = { registry = "https://pypi.org/simple" } 407 | dependencies = [ 408 | { name = "click" }, 409 | { name = "rich" }, 410 | { name = "shellingham" }, 411 | { name = "typing-extensions" }, 412 | ] 413 | sdist = { url = "https://files.pythonhosted.org/packages/6c/89/c527e6c848739be8ceb5c44eb8208c52ea3515c6cf6406aa61932887bf58/typer-0.15.4.tar.gz", hash = "sha256:89507b104f9b6a0730354f27c39fae5b63ccd0c95b1ce1f1a6ba0cfd329997c3", size = 101559 } 414 | wheels = [ 415 | { url = "https://files.pythonhosted.org/packages/c9/62/d4ba7afe2096d5659ec3db8b15d8665bdcb92a3c6ff0b95e99895b335a9c/typer-0.15.4-py3-none-any.whl", hash = "sha256:eb0651654dcdea706780c466cf06d8f174405a659ffff8f163cfbfee98c0e173", size = 45258 }, 416 | ] 417 | 418 | [[package]] 419 | name = "typing-extensions" 420 | version = "4.13.2" 421 | source = { registry = "https://pypi.org/simple" } 422 | sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967 } 423 | wheels = [ 424 | { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806 }, 425 | ] 426 | 427 | [[package]] 428 | name = "typing-inspection" 429 | version = "0.4.1" 430 | source = { registry = "https://pypi.org/simple" } 431 | dependencies = [ 432 | { name = "typing-extensions" }, 433 | ] 434 | sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726 } 435 | wheels = [ 436 | { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552 }, 437 | ] 438 | 439 | [[package]] 440 | name = "uvicorn" 441 | version = "0.34.2" 442 | source = { registry = "https://pypi.org/simple" } 443 | dependencies = [ 444 | { name = "click" }, 445 | { name = "h11" }, 446 | ] 447 | sdist = { url = "https://files.pythonhosted.org/packages/a6/ae/9bbb19b9e1c450cf9ecaef06463e40234d98d95bf572fab11b4f19ae5ded/uvicorn-0.34.2.tar.gz", hash = "sha256:0e929828f6186353a80b58ea719861d2629d766293b6d19baf086ba31d4f3328", size = 76815 } 448 | wheels = [ 449 | { url = "https://files.pythonhosted.org/packages/b1/4b/4cef6ce21a2aaca9d852a6e84ef4f135d99fcd74fa75105e2fc0c8308acd/uvicorn-0.34.2-py3-none-any.whl", hash = "sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403", size = 62483 }, 450 | ] 451 | 452 | [[package]] 453 | name = "websockets" 454 | version = "15.0.1" 455 | source = { registry = "https://pypi.org/simple" } 456 | sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016 } 457 | wheels = [ 458 | { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423 }, 459 | { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082 }, 460 | { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330 }, 461 | { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878 }, 462 | { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883 }, 463 | { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252 }, 464 | { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521 }, 465 | { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958 }, 466 | { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918 }, 467 | { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388 }, 468 | { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828 }, 469 | { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437 }, 470 | { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096 }, 471 | { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332 }, 472 | { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152 }, 473 | { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096 }, 474 | { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523 }, 475 | { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790 }, 476 | { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165 }, 477 | { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160 }, 478 | { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395 }, 479 | { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841 }, 480 | { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440 }, 481 | { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098 }, 482 | { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329 }, 483 | { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111 }, 484 | { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054 }, 485 | { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496 }, 486 | { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829 }, 487 | { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217 }, 488 | { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195 }, 489 | { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393 }, 490 | { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837 }, 491 | { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 }, 492 | ] 493 | --------------------------------------------------------------------------------