├── .gitignore ├── .pre-commit-config.yaml ├── .python-version ├── .vscode ├── settings.json └── tasks.json ├── Dockerfile ├── README.md ├── linkedin_mcp_server ├── __init__.py ├── cli.py ├── config │ ├── __init__.py │ ├── loaders.py │ ├── providers.py │ ├── schema.py │ └── secrets.py ├── drivers │ ├── __init__.py │ └── chrome.py ├── server.py └── tools │ ├── __init__.py │ ├── company.py │ ├── job.py │ └── person.py ├── main.py ├── pyproject.toml ├── smithery.yaml └── uv.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # UV 98 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | #uv.lock 102 | 103 | # poetry 104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 105 | # This is especially recommended for binary packages to ensure reproducibility, and is more 106 | # commonly ignored for libraries. 107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 108 | #poetry.lock 109 | 110 | # pdm 111 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 112 | #pdm.lock 113 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 114 | # in version control. 115 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 116 | .pdm.toml 117 | .pdm-python 118 | .pdm-build/ 119 | 120 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 121 | __pypackages__/ 122 | 123 | # Celery stuff 124 | celerybeat-schedule 125 | celerybeat.pid 126 | 127 | # SageMath parsed files 128 | *.sage.py 129 | 130 | # Environments 131 | .env 132 | .venv 133 | env/ 134 | venv/ 135 | ENV/ 136 | env.bak/ 137 | venv.bak/ 138 | 139 | # Spyder project settings 140 | .spyderproject 141 | .spyproject 142 | 143 | # Rope project settings 144 | .ropeproject 145 | 146 | # mkdocs documentation 147 | /site 148 | 149 | # mypy 150 | .mypy_cache/ 151 | .dmypy.json 152 | dmypy.json 153 | 154 | # Pyre type checker 155 | .pyre/ 156 | 157 | # pytype static type analyzer 158 | .pytype/ 159 | 160 | # Cython debug symbols 161 | cython_debug/ 162 | 163 | # PyCharm 164 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 165 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 166 | # and can be added to the global gitignore or merged into this file. For a more nuclear 167 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 168 | #.idea/ 169 | 170 | # Visual Studio Code 171 | # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore 172 | # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore 173 | # and can be added to the global gitignore or merged into this file. However, if you prefer, 174 | # you could uncomment the following to ignore the enitre vscode folder 175 | # .vscode/ 176 | 177 | # Ruff stuff: 178 | .ruff_cache/ 179 | 180 | # PyPI configuration file 181 | .pypirc 182 | 183 | # Cursor 184 | # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to 185 | # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data 186 | # refer to https://docs.cursor.com/context/ignore-files 187 | .cursorignore 188 | .cursorindexingignore 189 | .cursor 190 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # .pre-commit-config.yaml 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v4.1.0 5 | hooks: 6 | - id: trailing-whitespace 7 | - id: end-of-file-fixer 8 | 9 | - repo: https://github.com/astral-sh/ruff-pre-commit 10 | # Ruff version. 11 | rev: v0.9.10 12 | hooks: 13 | - id: ruff 14 | args: [--fix] 15 | - id: ruff-format 16 | 17 | - repo: https://github.com/pre-commit/mirrors-mypy 18 | rev: v1.15.0 19 | hooks: 20 | - id: mypy 21 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.12 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.codeActionsOnSave": { 4 | "source.fixAll": "explicit", 5 | "source.organizeImports": "explicit" 6 | }, 7 | "editor.defaultFormatter": "charliermarsh.ruff", 8 | "[python]": { 9 | "editor.defaultFormatter": "charliermarsh.ruff", 10 | "editor.formatOnSave": true, 11 | "editor.codeActionsOnSave": { 12 | "source.fixAll": "explicit", 13 | "source.organizeImports.ruff": "explicit" 14 | } 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Run pre-commit", 6 | "type": "shell", 7 | "command": "uv", 8 | "args": ["run", "pre-commit", "run", "--all-files"], 9 | "group": { 10 | "kind": "test", 11 | "isDefault": true 12 | }, 13 | "presentation": { 14 | "reveal": "never", 15 | "panel": "new", 16 | "focus": true 17 | }, 18 | "problemMatcher": [] 19 | }, 20 | { 21 | "label": "Run main.py (debug)", 22 | "type": "shell", 23 | "command": "uv", 24 | "args": ["run", "main.py", "--no-headless", "--no-lazy-init", "--debug"], 25 | "group": { 26 | "kind": "build", 27 | "isDefault": false 28 | }, 29 | "presentation": { 30 | "reveal": "always", 31 | "panel": "new", 32 | "focus": true 33 | }, 34 | "problemMatcher": [] 35 | }, { 36 | "label": "Run main.py", 37 | "type": "shell", 38 | "command": "uv", 39 | "args": ["run", "main.py", "--no-headless", "--no-lazy-init"], 40 | "group": { 41 | "kind": "build", 42 | "isDefault": true 43 | }, 44 | "presentation": { 45 | "reveal": "always", 46 | "panel": "new", 47 | "focus": true 48 | }, 49 | "problemMatcher": [] 50 | }, 51 | { 52 | "label": "Follow Logs", 53 | "type": "shell", 54 | "command": "tail", 55 | "args": ["-n", "20", "-F", "~/Library/Logs/Claude/mcp*.log"], 56 | "isBackground": true, 57 | "presentation": { 58 | "reveal": "always", 59 | "panel": "new", 60 | "focus": false 61 | }, 62 | "problemMatcher": [] 63 | } 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile 2 | FROM python:3.12-slim 3 | 4 | # Install Chrome dependencies 5 | RUN apt-get update && apt-get install -y \ 6 | wget \ 7 | unzip \ 8 | libnss3 \ 9 | libgconf-2-4 \ 10 | libxi6 \ 11 | libgdk-pixbuf2.0-0 \ 12 | libxrandr2 \ 13 | ca-certificates \ 14 | fonts-liberation \ 15 | libappindicator3-1 \ 16 | libasound2 \ 17 | libatk-bridge2.0-0 \ 18 | libatk1.0-0 \ 19 | libgtk-3-0 \ 20 | && rm -rf /var/lib/apt/lists/* 21 | 22 | # Set work directory 23 | WORKDIR /app 24 | 25 | # Copy the project files 26 | COPY . /app 27 | 28 | # Upgrade pip and install build dependencies 29 | RUN pip install --upgrade pip \ 30 | && pip install --no-cache-dir . 31 | 32 | # Expose any ports if necessary (MCP likely communicates via stdio so no port exposure) 33 | 34 | # Set default command to run the MCP server 35 | CMD ["python", "main.py", "--no-setup"] 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LinkedIn MCP Server 2 | 3 | [![smithery badge](https://smithery.ai/badge/@stickerdaniel/linkedin-mcp-server)](https://smithery.ai/server/@stickerdaniel/linkedin-mcp-server) 4 | 5 | A Model Context Protocol (MCP) server that enables interaction with LinkedIn through Claude and other AI assistants. This server allows you to scrape LinkedIn profiles, companies, jobs, and perform job searches. 6 | 7 | 8 | https://github.com/user-attachments/assets/eb84419a-6eaf-47bd-ac52-37bc59c83680 9 | 10 | 11 | ## Features & Tool Status 12 | 13 | ### Working Tools 14 | - **Profile Scraping** (`get_person_profile`): Get detailed information from LinkedIn profiles including work history, education, skills, and connections 15 | - **Company Analysis** (`get_company_profile`): Extract company information with comprehensive details 16 | - **Job Details** (`get_job_details`): Retrieve specific job posting details using direct LinkedIn job URLs 17 | - **Session Management** (`close_session`): Properly close browser sessions and clean up resources 18 | 19 | ### Tools with Known Issues 20 | - **Job Search** (`search_jobs`): Currently experiencing ChromeDriver compatibility issues with LinkedIn's search interface 21 | - **Recommended Jobs** (`get_recommended_jobs`): Has Selenium method compatibility issues due to outdated scraping methods 22 | - **Company Profiles**: Some companies may have restricted access or may return empty results (need further investigation) 23 | 24 | ## Installation 25 | 26 | ### Prerequisites 27 | 28 | - Python 3.12 or higher 29 | - Chrome browser installed 30 | - ChromeDriver matching your Chrome version (we'll help you set this up) 31 | - A LinkedIn account 32 | 33 | ### Quick Start (Recommended) 34 | 35 | ```bash 36 | # 1. Clone the repository 37 | git clone https://github.com/stickerdaniel/linkedin-mcp-server 38 | cd linkedin-mcp-server 39 | 40 | # 2. Install UV if you don't have it 41 | curl -LsSf https://astral.sh/uv/install.sh | sh 42 | 43 | # 3. Install the project and all dependencies 44 | uv sync 45 | ``` 46 | 47 | #### For Development 48 | 49 | If you want to contribute or modify the code: 50 | 51 | ```bash 52 | # Install with development dependencies 53 | uv sync --group dev 54 | 55 | # Install pre-commit hooks 56 | uv run pre-commit install 57 | ``` 58 | 59 | ### ChromeDriver Setup 60 | 61 | ChromeDriver is required for Selenium to interact with Chrome. You need to install the version that matches your Chrome browser. 62 | 63 | 1. **Check your Chrome version**: 64 | - Open Chrome and go to the menu (three dots) > Help > About Google Chrome 65 | - Note the version number (e.g., 123.0.6312.87) 66 | 67 | 2. **Download matching ChromeDriver**: 68 | - Go to [ChromeDriver Downloads](https://chromedriver.chromium.org/downloads) / [Chrome for Testing](https://googlechromelabs.github.io/chrome-for-testing/) (Chrome-Version 115+) 69 | - Download the version that matches your Chrome version 70 | - Extract the downloaded file 71 | 72 | 3. **Make ChromeDriver accessible**: 73 | - **Option 1**: Place it in a directory that's in your PATH (e.g., `/usr/local/bin` on macOS/Linux) 74 | - **Option 2**: Set the CHROMEDRIVER environment variable to the path where you placed it: 75 | ```bash 76 | export CHROMEDRIVER=/path/to/chromedriver # macOS/Linux 77 | # OR 78 | set CHROMEDRIVER=C:\path\to\chromedriver.exe # Windows 79 | ``` 80 | - **Option 3**: The server will attempt to auto-detect or prompt you for the path when run 81 | 82 | ## Running the Server 83 | 84 | ### Quick Start 85 | 86 | After installation, run: 87 | 88 | ```bash 89 | # Start the server (first time setup) 90 | uv run main.py --no-lazy-init --no-headless 91 | ``` 92 | 93 | ### Running Options 94 | 95 | ```bash 96 | # Normal operation (lazy initialization) 97 | uv run main.py 98 | 99 | # Debug mode with visible browser and direct startup 100 | uv run main.py --no-headless --debug --no-lazy-init 101 | 102 | # Skip setup prompts (for automation) 103 | uv run main.py --no-setup 104 | ``` 105 | 106 | ### Configuration for Claude Desktop 107 | 108 | 1. **The server will automatically**: 109 | - Display the configuration needed for Claude Desktop 110 | - Copy it to your clipboard for easy pasting 111 | 112 | 2. **Add to Claude Desktop**: 113 | - Open Claude Desktop and go to Settings > Developer > Edit Config 114 | - Paste the configuration provided by the server 115 | 116 | Example Claude Desktop configuration: 117 | ```json 118 | { 119 | "mcpServers": { 120 | "linkedin-scraper": { 121 | "command": "uv", 122 | "args": ["--directory", "/path/to/linkedin-mcp-server", "run", "main.py", "--no-setup"], 123 | "env": { 124 | "LINKEDIN_EMAIL": "your.email@example.com", 125 | "LINKEDIN_PASSWORD": "your_password" 126 | } 127 | } 128 | } 129 | } 130 | ``` 131 | 132 | ### Credential Management 133 | 134 | - **Lazy initialization (default behavior)**: 135 | - The server uses lazy initialization, meaning it will only create the Chrome driver and log in when a tool is actually used 136 | - You can set environment variables for non-interactive use: 137 | ```bash 138 | export LINKEDIN_EMAIL=your.email@example.com 139 | export LINKEDIN_PASSWORD=your_password 140 | ``` 141 | - Alternatively, you can run the server once manually. You'll be prompted for credentials, which will then be stored securely in your system's keychain (macOS Keychain, Windows Credential Locker, etc.). 142 | 143 | ## Configuration System 144 | 145 | ### Configuration Hierarchy 146 | 147 | Configuration values are loaded with the following precedence (highest to lowest): 148 | 149 | 1. **Command-line arguments**: 150 | ```bash 151 | uv run main.py --no-headless --debug 152 | ``` 153 | 154 | 2. **Environment variables**: 155 | ```bash 156 | export LINKEDIN_EMAIL=your.email@example.com 157 | export LINKEDIN_PASSWORD=your_password 158 | export CHROMEDRIVER=/path/to/chromedriver 159 | ``` 160 | *Note: Environment variables always override credentials stored in the system keychain* 161 | 162 | 3. **System keychain**: Securely stored credentials from previous sessions 163 | 164 | 4. **Default values**: Built-in fallback values 165 | 166 | ### Command-line Options 167 | 168 | | Option | Description | 169 | |--------|-------------| 170 | | `--no-headless` | Run Chrome with a visible browser window | 171 | | `--debug` | Enable debug mode with additional logging | 172 | | `--no-setup` | Skip configuration setup prompts | 173 | | `--no-lazy-init` | Initialize Chrome driver immediately (instead of on first use) | 174 | 175 | ### Credential Storage 176 | 177 | Your LinkedIn credentials are stored securely using your system's native keychain/credential manager: 178 | 179 | - **macOS**: macOS Keychain 180 | - **Windows**: Windows Credential Locker 181 | - **Linux**: Native keyring (varies by distribution) 182 | 183 | Credentials are managed as follows: 184 | 185 | 1. First, the application checks for credentials in environment variables 186 | 2. Next, it checks the system keychain for stored credentials 187 | 3. If no credentials are found, you'll be prompted to enter them (in interactive mode) 188 | 4. Entered credentials are securely stored in your system keychain for future use 189 | 190 | ### Clearing Stored Credentials 191 | 192 | If you need to change your stored credentials, run the application with the `--no-lazy-init` flag and when prompted about login failure, select "Yes" to try with different credentials. 193 | 194 | ### ChromeDriver Configuration 195 | 196 | The ChromeDriver path is found in this order: 197 | 1. From the `CHROMEDRIVER` environment variable 198 | 2. Auto-detected from common locations 199 | 3. Manually specified when prompted (if auto-detection fails) 200 | 201 | Once specified, the ChromeDriver path is used for the current session but not stored persistently. 202 | 203 | ## Using with Claude Desktop 204 | 205 | 1. **After adding the configuration** to Claude Desktop, restart Claude Desktop. The tools should be listed in the settings icon menu. 206 | 2. **Start a conversation** with Claude 207 | 3. **You'll see tools available** in the tools menu (settings icon) 208 | 4. **You can now ask Claude** to retrieve LinkedIn profiles, companies, and job details 209 | 210 | ### Recommended Usage Examples 211 | - "Can you tell me about Daniel's work experience? His LinkedIn profile is https://www.linkedin.com/in/stickerdaniel/" 212 | - "Get details about this job posting: https://www.linkedin.com/jobs/view/1234567890" 213 | - "Tell me about the company Google based on their LinkedIn page." 214 | 215 | ## Security and Privacy 216 | 217 | - Your LinkedIn credentials are securely stored in your system's native keychain/credential manager with user-only permissions 218 | - Credentials are never exposed to Claude or any other AI and are only used for the LinkedIn login to scrape data 219 | - The server runs on your local machine, not in the cloud 220 | - All LinkedIn scraping happens through your account - be aware that profile visits are visible to other users 221 | 222 | ## Troubleshooting 223 | 224 | ### Tool-Specific Issues 225 | 226 | **Job Search (`search_jobs`) Not Working:** 227 | - This tool currently has ChromeDriver compatibility issues 228 | - Use direct job URLs with `get_job_details` instead 229 | - LinkedIn's search interface has anti-automation measures 230 | 231 | **Recommended Jobs (`get_recommended_jobs`) Errors:** 232 | - Contains outdated Selenium methods (`find_elements_by_class_name`) 233 | - LinkedIn has updated their DOM structure 234 | 235 | ### ChromeDriver Issues 236 | 237 | If you encounter ChromeDriver errors: 238 | 1. Ensure your Chrome browser is updated 239 | 2. Download the matching ChromeDriver version 240 | 3. Set the CHROMEDRIVER path correctly 241 | 4. Try running with administrator/sudo privileges if permission issues occur 242 | 243 | ### Authentication Issues 244 | 245 | If login fails: 246 | 1. Verify your LinkedIn credentials 247 | 2. Check if your account has two-factor authentication enabled 248 | 3. Try logging in manually to LinkedIn first, then run the server 249 | 4. Check your LinkedIn mobile app for a login request after running the server 250 | 5. Try to run the server with `--no-headless` to see where the login fails 251 | 6. Try to run the server with `--debug` to see more detailed logs 252 | 253 | ### Connection Issues 254 | 255 | If Claude cannot connect to the server: 256 | 1. Ensure the server is running when you start it manually 257 | 2. Verify the configuration in Claude Desktop is correct 258 | 3. Restart Claude Desktop 259 | 260 | ## License 261 | 262 | This project is licensed under the MIT License 263 | 264 | ## Acknowledgements 265 | 266 | - Based on the [LinkedIn Scraper](https://github.com/joeyism/linkedin_scraper) by joeyism 267 | - Uses the Model Context Protocol (MCP) for integration with AI assistants 268 | 269 | --- 270 | 271 | **Note**: This tool is for personal use only. Use responsibly and in accordance with LinkedIn's terms of service. Web scraping may violate LinkedIn's terms of service. 272 | -------------------------------------------------------------------------------- /linkedin_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/__init__.py 2 | """LinkedIn MCP Server package.""" 3 | 4 | __version__ = "0.1.0" 5 | -------------------------------------------------------------------------------- /linkedin_mcp_server/cli.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/cli.py 2 | """ 3 | CLI utilities for LinkedIn MCP server. 4 | 5 | This module handles the command-line interface and configuration management. 6 | """ 7 | 8 | from typing import Dict, Any, List 9 | import os 10 | import json 11 | import subprocess 12 | import logging 13 | import pyperclip # type: ignore 14 | 15 | from linkedin_mcp_server.config import get_config 16 | 17 | logger = logging.getLogger(__name__) 18 | 19 | 20 | def print_claude_config() -> None: 21 | """ 22 | Print Claude configuration and copy to clipboard. 23 | 24 | This function generates the configuration needed for Claude Desktop 25 | and copies it to the clipboard for easy pasting. 26 | """ 27 | config = get_config() 28 | current_dir = os.path.abspath( 29 | os.path.dirname(os.path.dirname(os.path.dirname(__file__))) 30 | ) 31 | 32 | # Find the full path to uv executable 33 | try: 34 | uv_path = subprocess.check_output(["which", "uv"], text=True).strip() 35 | print(f"🔍 Found uv at: {uv_path}") 36 | except subprocess.CalledProcessError: 37 | # Fallback if which uv fails 38 | uv_path = "uv" 39 | print( 40 | "⚠️ Could not find full path to uv, using 'uv' directly. " 41 | "This may not work in Claude Desktop." 42 | ) 43 | 44 | # Include useful command-line arguments in the default args 45 | args: List[str] = [ 46 | "--directory", 47 | current_dir, 48 | "run", 49 | "main.py", 50 | "--no-setup", 51 | ] 52 | 53 | # Add environment variables to the configuration 54 | env_vars: Dict[str, str] = {} 55 | if config.linkedin.email: 56 | env_vars["LINKEDIN_EMAIL"] = config.linkedin.email 57 | if config.linkedin.password: 58 | env_vars["LINKEDIN_PASSWORD"] = config.linkedin.password 59 | if config.chrome.chromedriver_path: 60 | env_vars["CHROMEDRIVER"] = config.chrome.chromedriver_path 61 | 62 | config_json: Dict[str, Any] = { 63 | "mcpServers": { 64 | "linkedin-scraper": { 65 | "command": uv_path, 66 | "args": args, 67 | "disabled": False, 68 | "requiredTools": [ 69 | "get_person_profile", 70 | "get_company_profile", 71 | "get_job_details", 72 | "search_jobs", 73 | ], 74 | } 75 | } 76 | } 77 | 78 | # Add environment variables if available 79 | if env_vars: 80 | config_json["mcpServers"]["linkedin-scraper"]["env"] = env_vars 81 | 82 | # Convert to string for clipboard 83 | config_str = json.dumps(config_json, indent=2) 84 | 85 | # Print the final configuration 86 | print("\n📋 Your Claude configuration should look like:") 87 | print(config_str) 88 | print( 89 | "\n🔧 Add this to your Claude Desktop configuration in Settings > Developer > Edit Config" 90 | ) 91 | 92 | # Copy to clipboard 93 | try: 94 | pyperclip.copy(config_str) 95 | print("✅ Claude configuration copied to clipboard!") 96 | except ImportError: 97 | print( 98 | "⚠️ pyperclip not installed. To copy configuration automatically, run: uv add pyperclip" 99 | ) 100 | except Exception as e: 101 | print(f"❌ Could not copy to clipboard: {e}") 102 | -------------------------------------------------------------------------------- /linkedin_mcp_server/config/__init__.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/config/__init__.py 2 | from typing import Optional 3 | import logging 4 | from .schema import AppConfig, ChromeConfig, LinkedInConfig, ServerConfig 5 | from .loaders import load_config 6 | from .providers import ( 7 | get_credentials_from_keyring, 8 | save_credentials_to_keyring, 9 | clear_credentials_from_keyring, 10 | get_keyring_name, 11 | ) 12 | 13 | logger = logging.getLogger(__name__) 14 | 15 | # Singleton pattern for configuration 16 | _config: Optional[AppConfig] = None 17 | 18 | 19 | def get_config() -> AppConfig: 20 | """Get the application configuration, initializing it if needed.""" 21 | global _config 22 | if _config is None: 23 | _config = load_config() 24 | logger.debug("Configuration loaded") 25 | return _config 26 | 27 | 28 | def reset_config() -> None: 29 | """Reset the configuration to force reloading.""" 30 | global _config 31 | _config = None 32 | logger.debug("Configuration reset") 33 | 34 | 35 | # Export schema classes for type annotations 36 | __all__ = [ 37 | "AppConfig", 38 | "ChromeConfig", 39 | "LinkedInConfig", 40 | "ServerConfig", 41 | "get_config", 42 | "reset_config", 43 | "get_credentials_from_keyring", 44 | "save_credentials_to_keyring", 45 | "clear_credentials_from_keyring", 46 | "get_keyring_name", 47 | ] 48 | -------------------------------------------------------------------------------- /linkedin_mcp_server/config/loaders.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/config/loaders.py 2 | import os 3 | import argparse 4 | import logging 5 | from typing import Optional 6 | from .schema import AppConfig 7 | from .providers import get_chromedriver_paths 8 | 9 | logger = logging.getLogger(__name__) 10 | 11 | 12 | def find_chromedriver() -> Optional[str]: 13 | """Find the ChromeDriver executable in common locations.""" 14 | # First check environment variable 15 | if path := os.getenv("CHROMEDRIVER"): 16 | if os.path.exists(path): 17 | return path 18 | 19 | # Check common locations 20 | for path in get_chromedriver_paths(): 21 | if os.path.exists(path) and (os.access(path, os.X_OK) or path.endswith(".exe")): 22 | return path 23 | 24 | return None 25 | 26 | 27 | def load_from_env(config: AppConfig) -> AppConfig: 28 | """Load configuration from environment variables.""" 29 | # LinkedIn credentials 30 | if email := os.environ.get("LINKEDIN_EMAIL"): 31 | config.linkedin.email = email 32 | 33 | if password := os.environ.get("LINKEDIN_PASSWORD"): 34 | config.linkedin.password = password 35 | 36 | # ChromeDriver configuration 37 | if chromedriver := os.environ.get("CHROMEDRIVER"): 38 | config.chrome.chromedriver_path = chromedriver 39 | 40 | # Debug mode 41 | if os.environ.get("DEBUG") in ("1", "true", "True", "yes", "Yes"): 42 | config.server.debug = True 43 | 44 | # Headless mode 45 | if os.environ.get("HEADLESS") in ("0", "false", "False", "no", "No"): 46 | config.chrome.headless = False 47 | 48 | return config 49 | 50 | 51 | def load_from_args(config: AppConfig) -> AppConfig: 52 | """Load configuration from command line arguments.""" 53 | parser = argparse.ArgumentParser( 54 | description="LinkedIn MCP Server - A Model Context Protocol server for LinkedIn integration" 55 | ) 56 | 57 | parser.add_argument( 58 | "--no-headless", 59 | action="store_true", 60 | help="Run Chrome with a visible browser window (useful for debugging)", 61 | ) 62 | 63 | parser.add_argument( 64 | "--debug", 65 | action="store_true", 66 | help="Enable debug mode with additional logging", 67 | ) 68 | 69 | parser.add_argument( 70 | "--no-setup", 71 | action="store_true", 72 | help="Skip printing configuration information and interactive setup", 73 | ) 74 | 75 | parser.add_argument( 76 | "--no-lazy-init", 77 | action="store_true", 78 | help="Initialize Chrome driver and login immediately", 79 | ) 80 | 81 | parser.add_argument( 82 | "--transport", 83 | choices=["stdio", "sse"], 84 | default=None, 85 | help="Specify the transport mode (stdio or sse)", 86 | ) 87 | 88 | parser.add_argument( 89 | "--chromedriver", 90 | type=str, 91 | help="Specify the path to the ChromeDriver executable", 92 | ) 93 | 94 | args = parser.parse_args() 95 | 96 | # Update configuration with parsed arguments 97 | if args.no_headless: 98 | config.chrome.headless = False 99 | 100 | if args.debug: 101 | config.server.debug = True 102 | 103 | if args.no_setup: 104 | config.server.setup = False 105 | 106 | if args.no_lazy_init: 107 | config.server.lazy_init = False 108 | 109 | if args.transport: 110 | config.server.transport = args.transport 111 | 112 | if args.chromedriver: 113 | config.chrome.chromedriver_path = args.chromedriver 114 | 115 | return config 116 | 117 | 118 | def load_config() -> AppConfig: 119 | """ 120 | Load configuration from all sources with defined precedence: 121 | 1. Command line arguments (highest priority) 122 | 2. Environment variables 123 | 3. Default values and auto-detection (lowest priority) 124 | """ 125 | # Start with default configuration 126 | config = AppConfig() 127 | 128 | # Auto-detect ChromeDriver path 129 | if chromedriver_path := find_chromedriver(): 130 | config.chrome.chromedriver_path = chromedriver_path 131 | logger.debug(f"Auto-detected ChromeDriver at: {chromedriver_path}") 132 | 133 | # Override with environment variables 134 | config = load_from_env(config) 135 | 136 | # Override with command line arguments (highest priority) 137 | config = load_from_args(config) 138 | 139 | return config 140 | -------------------------------------------------------------------------------- /linkedin_mcp_server/config/providers.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/config/providers.py 2 | from typing import Dict, Optional, List 3 | import os 4 | import platform 5 | import logging 6 | import keyring 7 | from keyring.errors import KeyringError 8 | 9 | # Constants 10 | SERVICE_NAME = "linkedin_mcp_server" 11 | EMAIL_KEY = "linkedin_email" 12 | PASSWORD_KEY = "linkedin_password" 13 | 14 | logger = logging.getLogger(__name__) 15 | 16 | 17 | def get_keyring_name() -> str: 18 | """Get the name of the current keyring backend.""" 19 | system = platform.system() 20 | if system == "Darwin": 21 | return "macOS Keychain" 22 | elif system == "Windows": 23 | return "Windows Credential Locker" 24 | else: 25 | return keyring.get_keyring().__class__.__name__ 26 | 27 | 28 | def get_secret_from_keyring(key: str) -> Optional[str]: 29 | """Retrieve a secret from system keyring.""" 30 | try: 31 | secret = keyring.get_password(SERVICE_NAME, key) 32 | return secret 33 | except KeyringError as e: 34 | logger.error(f"Error accessing keyring for {key}: {e}") 35 | return None 36 | 37 | 38 | def set_secret_in_keyring(key: str, value: str) -> bool: 39 | """Store a secret in system keyring.""" 40 | try: 41 | keyring.set_password(SERVICE_NAME, key, value) 42 | logger.debug(f"Secret '{key}' stored successfully in {get_keyring_name()}") 43 | return True 44 | except KeyringError as e: 45 | logger.error(f"Error storing secret '{key}': {e}") 46 | return False 47 | 48 | 49 | def get_credentials_from_keyring() -> Dict[str, Optional[str]]: 50 | """Retrieve LinkedIn credentials from system keyring.""" 51 | email = get_secret_from_keyring(EMAIL_KEY) 52 | password = get_secret_from_keyring(PASSWORD_KEY) 53 | 54 | return {"email": email, "password": password} 55 | 56 | 57 | def save_credentials_to_keyring(email: str, password: str) -> bool: 58 | """Save LinkedIn credentials to system keyring.""" 59 | email_saved = set_secret_in_keyring(EMAIL_KEY, email) 60 | password_saved = set_secret_in_keyring(PASSWORD_KEY, password) 61 | 62 | return email_saved and password_saved 63 | 64 | 65 | def clear_credentials_from_keyring() -> bool: 66 | """Clear stored credentials from the keyring.""" 67 | try: 68 | keyring.delete_password(SERVICE_NAME, EMAIL_KEY) 69 | keyring.delete_password(SERVICE_NAME, PASSWORD_KEY) 70 | logger.info(f"Credentials removed from {get_keyring_name()}") 71 | return True 72 | except KeyringError as e: 73 | logger.error(f"Error clearing credentials: {e}") 74 | return False 75 | 76 | 77 | def get_chromedriver_paths() -> List[str]: 78 | """Get possible ChromeDriver paths based on the platform.""" 79 | paths = [ 80 | os.path.join(os.path.dirname(__file__), "../../../../drivers/chromedriver"), 81 | os.path.join(os.path.expanduser("~"), "chromedriver"), 82 | "/usr/local/bin/chromedriver", 83 | "/usr/bin/chromedriver", 84 | "/opt/homebrew/bin/chromedriver", 85 | "/Applications/chromedriver", 86 | ] 87 | 88 | if platform.system() == "Windows": 89 | paths.extend( 90 | [ 91 | "C:\\Program Files\\chromedriver.exe", 92 | "C:\\Program Files (x86)\\chromedriver.exe", 93 | ] 94 | ) 95 | 96 | return paths 97 | -------------------------------------------------------------------------------- /linkedin_mcp_server/config/schema.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/config/schema.py 2 | from dataclasses import dataclass, field 3 | from typing import Optional, List, Literal 4 | 5 | 6 | @dataclass 7 | class ChromeConfig: 8 | """Configuration for Chrome driver.""" 9 | 10 | headless: bool = True 11 | chromedriver_path: Optional[str] = None 12 | browser_args: List[str] = field(default_factory=list) 13 | non_interactive: bool = False 14 | 15 | 16 | @dataclass 17 | class LinkedInConfig: 18 | """LinkedIn connection configuration.""" 19 | 20 | email: Optional[str] = None 21 | password: Optional[str] = None 22 | use_keyring: bool = True 23 | 24 | 25 | @dataclass 26 | class ServerConfig: 27 | """MCP server configuration.""" 28 | 29 | transport: Literal["stdio", "sse"] = "stdio" 30 | lazy_init: bool = True 31 | debug: bool = False 32 | setup: bool = True 33 | 34 | 35 | @dataclass 36 | class AppConfig: 37 | """Main application configuration.""" 38 | 39 | chrome: ChromeConfig = field(default_factory=ChromeConfig) 40 | linkedin: LinkedInConfig = field(default_factory=LinkedInConfig) 41 | server: ServerConfig = field(default_factory=ServerConfig) 42 | -------------------------------------------------------------------------------- /linkedin_mcp_server/config/secrets.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/config/secrets.py 2 | from typing import Dict, Optional 3 | import logging 4 | import inquirer # type: ignore 5 | from linkedin_mcp_server.config import get_config 6 | from .providers import ( 7 | get_credentials_from_keyring, 8 | save_credentials_to_keyring, 9 | get_keyring_name, 10 | ) 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | 15 | def get_credentials() -> Optional[Dict[str, str]]: 16 | """Get LinkedIn credentials from config, keyring, or prompt.""" 17 | config = get_config() 18 | 19 | # First, try configuration (includes environment variables) 20 | if config.linkedin.email and config.linkedin.password: 21 | print("Using LinkedIn credentials from configuration") 22 | return {"email": config.linkedin.email, "password": config.linkedin.password} 23 | 24 | # Second, try keyring if enabled 25 | if config.linkedin.use_keyring: 26 | credentials = get_credentials_from_keyring() 27 | if credentials["email"] and credentials["password"]: 28 | print(f"Using LinkedIn credentials from {get_keyring_name()}") 29 | return {"email": credentials["email"], "password": credentials["password"]} 30 | 31 | # If in non-interactive mode and no credentials found, return None 32 | if config.chrome.non_interactive: 33 | print("No credentials found in non-interactive mode") 34 | return None 35 | 36 | # Otherwise, prompt for credentials 37 | return prompt_for_credentials() 38 | 39 | 40 | def prompt_for_credentials() -> Dict[str, str]: 41 | """Prompt user for LinkedIn credentials and store them securely.""" 42 | print(f"🔑 LinkedIn credentials required (will be stored in {get_keyring_name()})") 43 | questions = [ 44 | inquirer.Text("email", message="LinkedIn Email"), 45 | inquirer.Password("password", message="LinkedIn Password"), 46 | ] 47 | credentials = inquirer.prompt(questions) 48 | 49 | if not credentials: 50 | raise KeyboardInterrupt("Credential input was cancelled") 51 | 52 | # Store credentials securely in keyring 53 | if save_credentials_to_keyring(credentials["email"], credentials["password"]): 54 | print(f"✅ Credentials stored securely in {get_keyring_name()}") 55 | else: 56 | print("⚠️ Warning: Could not store credentials in system keyring.") 57 | print(" Your credentials will only be used for this session.") 58 | 59 | return credentials 60 | -------------------------------------------------------------------------------- /linkedin_mcp_server/drivers/__init__.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/drivers/__init__.py 2 | """Driver management for LinkedIn scraping.""" 3 | -------------------------------------------------------------------------------- /linkedin_mcp_server/drivers/chrome.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/drivers/chrome.py 2 | """ 3 | Chrome driver management for LinkedIn scraping. 4 | 5 | This module handles the creation and management of Chrome WebDriver instances. 6 | """ 7 | 8 | import sys 9 | from typing import Dict, Optional 10 | import os 11 | from selenium import webdriver 12 | from selenium.webdriver.chrome.options import Options 13 | from selenium.webdriver.chrome.service import Service 14 | from selenium.common.exceptions import WebDriverException 15 | import inquirer # type: ignore 16 | from linkedin_mcp_server.config import get_config 17 | from linkedin_mcp_server.config.secrets import get_credentials 18 | from linkedin_mcp_server.config.providers import clear_credentials_from_keyring 19 | 20 | # Global driver storage to reuse sessions 21 | active_drivers: Dict[str, webdriver.Chrome] = {} 22 | 23 | 24 | def get_or_create_driver() -> Optional[webdriver.Chrome]: 25 | """ 26 | Get existing driver or create a new one using the configured settings. 27 | 28 | Returns: 29 | Optional[webdriver.Chrome]: Chrome WebDriver instance or None if initialization fails 30 | in non-interactive mode 31 | 32 | Raises: 33 | WebDriverException: If the driver cannot be created and not in non-interactive mode 34 | """ 35 | config = get_config() 36 | session_id = "default" # We use a single session for simplicity 37 | 38 | # Return existing driver if available 39 | if session_id in active_drivers: 40 | return active_drivers[session_id] 41 | 42 | # Set up Chrome options 43 | chrome_options = Options() 44 | print( 45 | f"🌐 Running browser in {'headless' if config.chrome.headless else 'visible'} mode" 46 | ) 47 | if config.chrome.headless: 48 | chrome_options.add_argument("--headless=new") 49 | 50 | # Add additional options for stability 51 | chrome_options.add_argument("--no-sandbox") 52 | chrome_options.add_argument("--disable-dev-shm-usage") 53 | chrome_options.add_argument("--disable-gpu") 54 | chrome_options.add_argument("--window-size=1920,1080") 55 | chrome_options.add_argument( 56 | "--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" 57 | ) 58 | 59 | # Add any custom browser arguments from config 60 | for arg in config.chrome.browser_args: 61 | chrome_options.add_argument(arg) 62 | 63 | # Initialize Chrome driver 64 | try: 65 | if config.chrome.chromedriver_path: 66 | print(f"🌐 Using ChromeDriver at path: {config.chrome.chromedriver_path}") 67 | service = Service(executable_path=config.chrome.chromedriver_path) 68 | driver = webdriver.Chrome(service=service, options=chrome_options) 69 | else: 70 | print("🌐 Using auto-detected ChromeDriver") 71 | driver = webdriver.Chrome(options=chrome_options) 72 | 73 | # Add a page load timeout for safety 74 | driver.set_page_load_timeout(60) 75 | 76 | # Try to log in 77 | if login_to_linkedin(driver): 78 | print("Successfully logged in to LinkedIn") 79 | elif config.chrome.non_interactive: 80 | # In non-interactive mode, if login fails, return None 81 | driver.quit() 82 | return None 83 | 84 | active_drivers[session_id] = driver 85 | return driver 86 | except Exception as e: 87 | error_msg = f"🛑 Error creating web driver: {e}" 88 | print(error_msg) 89 | 90 | if config.chrome.non_interactive: 91 | print("🛑 Failed to initialize driver in non-interactive mode") 92 | return None 93 | 94 | raise WebDriverException(error_msg) 95 | 96 | 97 | def login_to_linkedin(driver: webdriver.Chrome) -> bool: 98 | """ 99 | Log in to LinkedIn using stored or provided credentials. 100 | 101 | Args: 102 | driver: Chrome WebDriver instance 103 | 104 | Returns: 105 | bool: True if login was successful, False otherwise 106 | """ 107 | config = get_config() 108 | 109 | # Get LinkedIn credentials from config 110 | credentials = get_credentials() 111 | 112 | if not credentials: 113 | print("❌ No credentials available") 114 | return False 115 | 116 | try: 117 | # Login to LinkedIn 118 | print("🔑 Logging in to LinkedIn...") 119 | 120 | from linkedin_scraper import actions # type: ignore 121 | 122 | actions.login(driver, credentials["email"], credentials["password"]) 123 | 124 | print("✅ Successfully logged in to LinkedIn") 125 | return True 126 | except Exception as e: 127 | error_msg = f"Failed to login: {str(e)}" 128 | print(f"❌ {error_msg}") 129 | 130 | if not config.chrome.non_interactive: 131 | print( 132 | "⚠️ You might need to confirm the login in your LinkedIn mobile app. " 133 | "Please try again and confirm the login." 134 | ) 135 | 136 | if config.chrome.headless: 137 | print( 138 | "🔍 Try running with visible browser window to see what's happening: " 139 | "uv run main.py --no-headless" 140 | ) 141 | 142 | retry = inquirer.prompt( 143 | [ 144 | inquirer.Confirm( 145 | "retry", 146 | message="Would you like to try with different credentials?", 147 | default=True, 148 | ), 149 | ] 150 | ) 151 | 152 | if retry and retry.get("retry", False): 153 | # Clear credentials from keyring and try again 154 | clear_credentials_from_keyring() 155 | # Try again with new credentials 156 | return login_to_linkedin(driver) 157 | 158 | return False 159 | 160 | 161 | def initialize_driver() -> None: 162 | """ 163 | Initialize the driver based on global configuration. 164 | """ 165 | config = get_config() 166 | 167 | if config.server.lazy_init: 168 | print("Using lazy initialization - driver will be created on first tool call") 169 | if config.linkedin.email and config.linkedin.password: 170 | print("LinkedIn credentials found in configuration") 171 | else: 172 | print( 173 | "No LinkedIn credentials found - will look for stored credentials on first use" 174 | ) 175 | return 176 | 177 | # Validate chromedriver can be found 178 | if config.chrome.chromedriver_path: 179 | print(f"✅ ChromeDriver found at: {config.chrome.chromedriver_path}") 180 | os.environ["CHROMEDRIVER"] = config.chrome.chromedriver_path 181 | else: 182 | print("⚠️ ChromeDriver not found in common locations.") 183 | print("⚡ Continuing with automatic detection...") 184 | print( 185 | "💡 Tip: install ChromeDriver and set the CHROMEDRIVER environment variable" 186 | ) 187 | 188 | # Create driver and log in 189 | try: 190 | driver = get_or_create_driver() 191 | if driver: 192 | print("✅ Web driver initialized successfully") 193 | else: 194 | print("❌ Failed to initialize web driver.") 195 | except WebDriverException as e: 196 | print(f"❌ Failed to initialize web driver: {str(e)}") 197 | handle_driver_error() 198 | 199 | 200 | def handle_driver_error() -> None: 201 | """ 202 | Handle ChromeDriver initialization errors by providing helpful options. 203 | """ 204 | config = get_config() 205 | 206 | questions = [ 207 | inquirer.List( 208 | "chromedriver_action", 209 | message="What would you like to do?", 210 | choices=[ 211 | ("Specify ChromeDriver path manually", "specify"), 212 | ("Get help installing ChromeDriver", "help"), 213 | ("Exit", "exit"), 214 | ], 215 | ), 216 | ] 217 | answers = inquirer.prompt(questions) 218 | 219 | if answers["chromedriver_action"] == "specify": 220 | path = inquirer.prompt( 221 | [inquirer.Text("custom_path", message="Enter ChromeDriver path")] 222 | )["custom_path"] 223 | 224 | if os.path.exists(path): 225 | # Update config with the new path 226 | config.chrome.chromedriver_path = path 227 | os.environ["CHROMEDRIVER"] = path 228 | print(f"✅ ChromeDriver path set to: {path}") 229 | # Try again with the new path 230 | initialize_driver() 231 | else: 232 | print(f"⚠️ Warning: The specified path does not exist: {path}") 233 | initialize_driver() 234 | 235 | elif answers["chromedriver_action"] == "help": 236 | print("\n📋 ChromeDriver Installation Guide:") 237 | print("1. Find your Chrome version: Chrome menu > Help > About Google Chrome") 238 | print( 239 | "2. Download matching ChromeDriver: https://chromedriver.chromium.org/downloads" 240 | ) 241 | print("3. Place ChromeDriver in a location on your PATH") 242 | print(" - macOS/Linux: /usr/local/bin/ is recommended") 243 | print( 244 | " - Windows: Add to a directory in your PATH or specify the full path\n" 245 | ) 246 | 247 | if inquirer.prompt( 248 | [inquirer.Confirm("try_again", message="Try again?", default=True)] 249 | )["try_again"]: 250 | initialize_driver() 251 | 252 | print("❌ ChromeDriver is required for this application to work properly.") 253 | sys.exit(1) 254 | -------------------------------------------------------------------------------- /linkedin_mcp_server/server.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/server.py 2 | """ 3 | MCP server setup for LinkedIn integration. 4 | 5 | This module creates the MCP server and registers all the LinkedIn tools. 6 | """ 7 | 8 | from typing import Dict, Any 9 | from mcp.server.fastmcp import FastMCP 10 | 11 | from linkedin_mcp_server.drivers.chrome import active_drivers 12 | from linkedin_mcp_server.tools.person import register_person_tools 13 | from linkedin_mcp_server.tools.company import register_company_tools 14 | from linkedin_mcp_server.tools.job import register_job_tools 15 | 16 | 17 | def create_mcp_server() -> FastMCP: 18 | """Create and configure the MCP server with all LinkedIn tools.""" 19 | mcp = FastMCP("linkedin_scraper") 20 | 21 | # Register all tools 22 | register_person_tools(mcp) 23 | register_company_tools(mcp) 24 | register_job_tools(mcp) 25 | 26 | # Register session management tool 27 | @mcp.tool() 28 | async def close_session() -> Dict[str, Any]: 29 | """Close the current browser session and clean up resources.""" 30 | session_id = "default" # Using the same default session 31 | 32 | if session_id in active_drivers: 33 | try: 34 | active_drivers[session_id].quit() 35 | del active_drivers[session_id] 36 | return { 37 | "status": "success", 38 | "message": "Successfully closed the browser session", 39 | } 40 | except Exception as e: 41 | return { 42 | "status": "error", 43 | "message": f"Error closing browser session: {str(e)}", 44 | } 45 | else: 46 | return { 47 | "status": "warning", 48 | "message": "No active browser session to close", 49 | } 50 | 51 | return mcp 52 | 53 | 54 | def shutdown_handler() -> None: 55 | """Clean up resources on shutdown.""" 56 | for session_id, driver in list(active_drivers.items()): 57 | try: 58 | driver.quit() 59 | del active_drivers[session_id] 60 | except Exception as e: 61 | print(f"❌ Error closing driver during shutdown: {e}") 62 | -------------------------------------------------------------------------------- /linkedin_mcp_server/tools/__init__.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/tools/__init__.py 2 | """Tools for LinkedIn scraping.""" 3 | -------------------------------------------------------------------------------- /linkedin_mcp_server/tools/company.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/tools/company.py 2 | """ 3 | Company profile tools for LinkedIn MCP server. 4 | 5 | This module provides tools for scraping LinkedIn company profiles. 6 | """ 7 | 8 | from typing import Dict, Any, List 9 | from mcp.server.fastmcp import FastMCP 10 | from linkedin_scraper import Company 11 | 12 | from linkedin_mcp_server.drivers.chrome import get_or_create_driver 13 | 14 | 15 | def register_company_tools(mcp: FastMCP) -> None: 16 | """ 17 | Register all company-related tools with the MCP server. 18 | 19 | Args: 20 | mcp (FastMCP): The MCP server instance 21 | """ 22 | 23 | @mcp.tool() 24 | async def get_company_profile( 25 | linkedin_url: str, get_employees: bool = False 26 | ) -> Dict[str, Any]: 27 | """ 28 | Scrape a company's LinkedIn profile. 29 | 30 | Args: 31 | linkedin_url (str): The LinkedIn URL of the company's profile 32 | get_employees (bool): Whether to scrape the company's employees (slower) 33 | 34 | Returns: 35 | Dict[str, Any]: Structured data from the company's profile 36 | """ 37 | driver = get_or_create_driver() 38 | 39 | try: 40 | print(f"🏢 Scraping company: {linkedin_url}") 41 | if get_employees: 42 | print("⚠️ Fetching employees may take a while...") 43 | 44 | company = Company( 45 | linkedin_url, 46 | driver=driver, 47 | get_employees=get_employees, 48 | close_on_complete=False, 49 | ) 50 | 51 | # Convert showcase pages to structured dictionaries 52 | showcase_pages: List[Dict[str, Any]] = [ 53 | { 54 | "name": page.name, 55 | "linkedin_url": page.linkedin_url, 56 | "followers": page.followers, 57 | } 58 | for page in company.showcase_pages 59 | ] 60 | 61 | # Convert affiliated companies to structured dictionaries 62 | affiliated_companies: List[Dict[str, Any]] = [ 63 | { 64 | "name": affiliated.name, 65 | "linkedin_url": affiliated.linkedin_url, 66 | "followers": affiliated.followers, 67 | } 68 | for affiliated in company.affiliated_companies 69 | ] 70 | 71 | # Build the result dictionary 72 | result: Dict[str, Any] = { 73 | "name": company.name, 74 | "about_us": company.about_us, 75 | "website": company.website, 76 | "phone": company.phone, 77 | "headquarters": company.headquarters, 78 | "founded": company.founded, 79 | "industry": company.industry, 80 | "company_type": company.company_type, 81 | "company_size": company.company_size, 82 | "specialties": company.specialties, 83 | "showcase_pages": showcase_pages, 84 | "affiliated_companies": affiliated_companies, 85 | "headcount": company.headcount, 86 | } 87 | 88 | # Add employees if requested and available 89 | if get_employees and company.employees: 90 | result["employees"] = company.employees 91 | 92 | return result 93 | except Exception as e: 94 | print(f"❌ Error scraping company: {e}") 95 | return {"error": f"Failed to scrape company profile: {str(e)}"} 96 | -------------------------------------------------------------------------------- /linkedin_mcp_server/tools/job.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/tools/job.py 2 | """ 3 | Job-related tools for LinkedIn MCP server. 4 | 5 | This module provides tools for scraping LinkedIn job postings and searches. 6 | """ 7 | 8 | from typing import Any, Dict, List 9 | 10 | from linkedin_scraper import Job, JobSearch 11 | from mcp.server.fastmcp import FastMCP 12 | 13 | from linkedin_mcp_server.drivers.chrome import get_or_create_driver 14 | 15 | 16 | def register_job_tools(mcp: FastMCP) -> None: 17 | """ 18 | Register all job-related tools with the MCP server. 19 | 20 | Args: 21 | mcp (FastMCP): The MCP server instance 22 | """ 23 | 24 | @mcp.tool() 25 | async def get_job_details(job_url: str) -> Dict[str, Any]: 26 | """ 27 | Scrape job details from a LinkedIn job posting. 28 | 29 | IMPORTANT: Only use direct LinkedIn job URLs in the format: 30 | https://www.linkedin.com/jobs/view/[JOB_ID] 31 | 32 | DO NOT use collection URLs like: 33 | - /collections/recommended/?currentJobId= 34 | - /jobs/search/?keywords= 35 | 36 | If you have a collection URL, extract the job ID and convert it to the direct format. 37 | Example: If you see currentJobId=1234567890, use https://www.linkedin.com/jobs/view/1234567890 38 | 39 | Args: 40 | job_url (str): The direct LinkedIn job URL (must be /jobs/view/[ID] format) 41 | 42 | Returns: 43 | Dict[str, Any]: Structured job data including title, company, location, posting date, 44 | application count, and job description (may be empty if content is protected) 45 | """ 46 | driver = get_or_create_driver() 47 | 48 | try: 49 | print(f"💼 Scraping job: {job_url}") 50 | job = Job(job_url, driver=driver, close_on_complete=False) 51 | 52 | # Convert job object to a dictionary 53 | return job.to_dict() 54 | except Exception as e: 55 | print(f"❌ Error scraping job: {e}") 56 | return {"error": f"Failed to scrape job posting: {str(e)}"} 57 | 58 | @mcp.tool() 59 | async def search_jobs(search_term: str) -> List[Dict[str, Any]]: 60 | """ 61 | Search for jobs on LinkedIn with the given search term. 62 | 63 | Args: 64 | search_term (str): The job search query 65 | 66 | Returns: 67 | List[Dict[str, Any]]: List of job search results 68 | """ 69 | driver = get_or_create_driver() 70 | 71 | try: 72 | print(f"🔍 Searching jobs: {search_term}") 73 | job_search = JobSearch(driver=driver, close_on_complete=False, scrape=False) 74 | jobs = job_search.search(search_term) 75 | 76 | # Convert job objects to dictionaries 77 | return [job.to_dict() for job in jobs] 78 | except Exception as e: 79 | print(f"❌ Error searching jobs: {e}") 80 | return [{"error": f"Failed to search jobs: {str(e)}"}] 81 | 82 | @mcp.tool() 83 | async def get_recommended_jobs() -> List[Dict[str, Any]]: 84 | """ 85 | Get recommended jobs from your LinkedIn homepage. 86 | 87 | Returns: 88 | List[Dict[str, Any]]: List of recommended jobs 89 | """ 90 | driver = get_or_create_driver() 91 | 92 | try: 93 | print("📋 Getting recommended jobs") 94 | job_search = JobSearch( 95 | driver=driver, 96 | close_on_complete=False, 97 | scrape=True, 98 | scrape_recommended_jobs=True, 99 | ) 100 | 101 | # Get recommended jobs and convert to dictionaries 102 | if hasattr(job_search, "recommended_jobs"): 103 | return [job.to_dict() for job in job_search.recommended_jobs] 104 | else: 105 | return [] 106 | except Exception as e: 107 | print(f"❌ Error getting recommended jobs: {e}") 108 | return [{"error": f"Failed to get recommended jobs: {str(e)}"}] 109 | -------------------------------------------------------------------------------- /linkedin_mcp_server/tools/person.py: -------------------------------------------------------------------------------- 1 | # src/linkedin_mcp_server/tools/person.py 2 | """ 3 | Person profile tools for LinkedIn MCP server. 4 | 5 | This module provides tools for scraping LinkedIn person profiles. 6 | """ 7 | 8 | from typing import Dict, Any, List 9 | from mcp.server.fastmcp import FastMCP 10 | from linkedin_scraper import Person 11 | 12 | from linkedin_mcp_server.drivers.chrome import get_or_create_driver 13 | 14 | 15 | def register_person_tools(mcp: FastMCP) -> None: 16 | """ 17 | Register all person-related tools with the MCP server. 18 | 19 | Args: 20 | mcp (FastMCP): The MCP server instance 21 | """ 22 | 23 | @mcp.tool() 24 | async def get_person_profile(linkedin_url: str) -> Dict[str, Any]: 25 | """ 26 | Scrape a person's LinkedIn profile. 27 | 28 | Args: 29 | linkedin_url (str): The LinkedIn URL of the person's profile 30 | 31 | Returns: 32 | Dict[str, Any]: Structured data from the person's profile 33 | """ 34 | driver = get_or_create_driver() 35 | 36 | try: 37 | print(f"🔍 Scraping profile: {linkedin_url}") 38 | person = Person(linkedin_url, driver=driver, close_on_complete=False) 39 | 40 | # Convert experiences to structured dictionaries 41 | experiences: List[Dict[str, Any]] = [ 42 | { 43 | "position_title": exp.position_title, 44 | "company": exp.institution_name, 45 | "from_date": exp.from_date, 46 | "to_date": exp.to_date, 47 | "duration": exp.duration, 48 | "location": exp.location, 49 | "description": exp.description, 50 | } 51 | for exp in person.experiences 52 | ] 53 | 54 | # Convert educations to structured dictionaries 55 | educations: List[Dict[str, Any]] = [ 56 | { 57 | "institution": edu.institution_name, 58 | "degree": edu.degree, 59 | "from_date": edu.from_date, 60 | "to_date": edu.to_date, 61 | "description": edu.description, 62 | } 63 | for edu in person.educations 64 | ] 65 | 66 | # Convert interests to list of titles 67 | interests: List[str] = [interest.title for interest in person.interests] 68 | 69 | # Convert accomplishments to structured dictionaries 70 | accomplishments: List[Dict[str, str]] = [ 71 | {"category": acc.category, "title": acc.title} 72 | for acc in person.accomplishments 73 | ] 74 | 75 | # Convert contacts to structured dictionaries 76 | contacts: List[Dict[str, str]] = [ 77 | { 78 | "name": contact.name, 79 | "occupation": contact.occupation, 80 | "url": contact.url, 81 | } 82 | for contact in person.contacts 83 | ] 84 | 85 | # Return the complete profile data 86 | return { 87 | "name": person.name, 88 | "about": person.about, 89 | "experiences": experiences, 90 | "educations": educations, 91 | "interests": interests, 92 | "accomplishments": accomplishments, 93 | "contacts": contacts, 94 | "company": person.company, 95 | "job_title": person.job_title, 96 | "open_to_work": getattr(person, "open_to_work", False), 97 | } 98 | except Exception as e: 99 | print(f"❌ Error scraping profile: {e}") 100 | return {"error": f"Failed to scrape profile: {str(e)}"} 101 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # main.py 2 | """ 3 | LinkedIn MCP Server - A Model Context Protocol server for LinkedIn integration. 4 | """ 5 | 6 | import sys 7 | import logging 8 | import inquirer # type: ignore 9 | from typing import Literal, NoReturn 10 | 11 | # Import the new centralized configuration 12 | from linkedin_mcp_server.config import get_config 13 | from linkedin_mcp_server.cli import print_claude_config 14 | from linkedin_mcp_server.drivers.chrome import initialize_driver 15 | from linkedin_mcp_server.server import create_mcp_server, shutdown_handler 16 | 17 | 18 | def choose_transport_interactive() -> Literal["stdio", "sse"]: 19 | """Prompt user for transport mode using inquirer.""" 20 | questions = [ 21 | inquirer.List( 22 | "transport", 23 | message="Choose mcp transport mode", 24 | choices=[ 25 | ("stdio (Default CLI mode)", "stdio"), 26 | ("sse (Server-Sent Events HTTP mode)", "sse"), 27 | ], 28 | default="stdio", 29 | ) 30 | ] 31 | answers = inquirer.prompt(questions) 32 | return answers["transport"] 33 | 34 | 35 | def main() -> None: 36 | """Initialize and run the LinkedIn MCP server.""" 37 | print("🔗 LinkedIn MCP Server 🔗") 38 | print("=" * 40) 39 | 40 | # Get configuration using the new centralized system 41 | config = get_config() 42 | 43 | # Configure logging 44 | log_level = logging.DEBUG if config.server.debug else logging.ERROR 45 | logging.basicConfig( 46 | level=log_level, 47 | format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", 48 | ) 49 | 50 | logger = logging.getLogger("linkedin_mcp_server") 51 | logger.debug(f"Server configuration: {config}") 52 | 53 | # Initialize the driver with configuration 54 | initialize_driver() 55 | 56 | # Decide transport 57 | transport = config.server.transport 58 | if config.server.setup: 59 | transport = choose_transport_interactive() 60 | 61 | # Print configuration for Claude if in setup mode 62 | if config.server.setup: 63 | print_claude_config() 64 | 65 | # Create and run the MCP server 66 | mcp = create_mcp_server() 67 | 68 | # Start server 69 | print(f"\n🚀 Running LinkedIn MCP server ({transport.upper()} mode)...") 70 | mcp.run(transport=transport) 71 | 72 | 73 | def exit_gracefully(exit_code: int = 0) -> NoReturn: 74 | """Exit the application gracefully, cleaning up resources.""" 75 | print("\n👋 Shutting down LinkedIn MCP server...") 76 | shutdown_handler() 77 | sys.exit(exit_code) 78 | 79 | 80 | if __name__ == "__main__": 81 | try: 82 | main() 83 | except KeyboardInterrupt: 84 | exit_gracefully(0) 85 | except Exception as e: 86 | print(f"❌ Error running MCP server: {e}") 87 | exit_gracefully(1) 88 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "linkedin-mcp-server" 3 | version = "0.1.0" 4 | description = "MCP server for LinkedIn profile, company, and job scraping with Claude AI integration. Supports direct profile/company/job URL scraping with secure credential storage." 5 | readme = "README.md" 6 | requires-python = ">=3.12" 7 | dependencies = [ 8 | "httpx>=0.28.1", 9 | "inquirer>=3.4.0", 10 | "keyring>=25.6.0", 11 | "linkedin-scraper", 12 | "mcp[cli]>=1.6.0", 13 | "pyperclip>=1.9.0", 14 | ] 15 | 16 | [tool.setuptools.package-data] 17 | linkedin_mcp_server = ["py.typed"] 18 | 19 | [tool.uv.sources] 20 | linkedin-scraper = { git = "https://github.com/joeyism/linkedin_scraper.git" } 21 | 22 | [dependency-groups] 23 | dev = [ 24 | "mypy>=1.15.0", 25 | "pre-commit>=4.2.0", 26 | "pytest>=8.3.5", 27 | "pytest-cov>=6.1.1", 28 | "ruff>=0.11.11", 29 | ] 30 | -------------------------------------------------------------------------------- /smithery.yaml: -------------------------------------------------------------------------------- 1 | # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml 2 | 3 | startCommand: 4 | type: stdio 5 | configSchema: 6 | # JSON Schema defining the configuration options for the MCP. 7 | type: object 8 | properties: 9 | LINKEDIN_EMAIL: 10 | type: string 11 | description: Email for LinkedIn login 12 | LINKEDIN_PASSWORD: 13 | type: string 14 | description: Password for LinkedIn login 15 | CHROMEDRIVER: 16 | type: string 17 | description: Path to the ChromeDriver binary. Optional if ChromeDriver is in PATH. 18 | commandFunction: 19 | # A JS function that produces the CLI command based on the given config to start the MCP on stdio. 20 | |- 21 | (config) => ({ 22 | command: 'python', 23 | args: ['main.py', '--no-setup'], 24 | env: { 25 | LINKEDIN_EMAIL: config.LINKEDIN_EMAIL || '', 26 | LINKEDIN_PASSWORD: config.LINKEDIN_PASSWORD || '', 27 | CHROMEDRIVER: config.CHROMEDRIVER || '' 28 | } 29 | }) 30 | exampleConfig: 31 | LINKEDIN_EMAIL: example.user@example.com 32 | LINKEDIN_PASSWORD: yourLinkedInPassword 33 | CHROMEDRIVER: /usr/local/bin/chromedriver 34 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | revision = 2 3 | requires-python = ">=3.12" 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, upload-time = "2024-05-20T21:33:25.928Z" } 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, upload-time = "2024-05-20T21:33:24.1Z" }, 12 | ] 13 | 14 | [[package]] 15 | name = "ansicon" 16 | version = "1.89.0" 17 | source = { registry = "https://pypi.org/simple" } 18 | sdist = { url = "https://files.pythonhosted.org/packages/b6/e2/1c866404ddbd280efedff4a9f15abfe943cb83cde6e895022370f3a61f85/ansicon-1.89.0.tar.gz", hash = "sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1", size = 67312, upload-time = "2019-04-29T20:23:57.314Z" } 19 | wheels = [ 20 | { url = "https://files.pythonhosted.org/packages/75/f9/f1c10e223c7b56a38109a3f2eb4e7fe9a757ea3ed3a166754fb30f65e466/ansicon-1.89.0-py2.py3-none-any.whl", hash = "sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec", size = 63675, upload-time = "2019-04-29T20:23:53.83Z" }, 21 | ] 22 | 23 | [[package]] 24 | name = "anyio" 25 | version = "4.9.0" 26 | source = { registry = "https://pypi.org/simple" } 27 | dependencies = [ 28 | { name = "idna" }, 29 | { name = "sniffio" }, 30 | { name = "typing-extensions", marker = "python_full_version < '3.13'" }, 31 | ] 32 | sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } 33 | wheels = [ 34 | { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, 35 | ] 36 | 37 | [[package]] 38 | name = "attrs" 39 | version = "25.3.0" 40 | source = { registry = "https://pypi.org/simple" } 41 | sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } 42 | wheels = [ 43 | { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, 44 | ] 45 | 46 | [[package]] 47 | name = "blessed" 48 | version = "1.20.0" 49 | source = { registry = "https://pypi.org/simple" } 50 | dependencies = [ 51 | { name = "jinxed", marker = "sys_platform == 'win32'" }, 52 | { name = "six" }, 53 | { name = "wcwidth" }, 54 | ] 55 | sdist = { url = "https://files.pythonhosted.org/packages/25/ae/92e9968ad23205389ec6bd82e2d4fca3817f1cdef34e10aa8d529ef8b1d7/blessed-1.20.0.tar.gz", hash = "sha256:2cdd67f8746e048f00df47a2880f4d6acbcdb399031b604e34ba8f71d5787680", size = 6655612, upload-time = "2023-02-04T02:25:45.886Z" } 56 | wheels = [ 57 | { url = "https://files.pythonhosted.org/packages/76/98/584f211c3a4bb38f2871fa937ee0cc83c130de50c955d6c7e2334dbf4acb/blessed-1.20.0-py2.py3-none-any.whl", hash = "sha256:0c542922586a265e699188e52d5f5ac5ec0dd517e5a1041d90d2bbf23f906058", size = 58372, upload-time = "2023-02-04T02:25:43.093Z" }, 58 | ] 59 | 60 | [[package]] 61 | name = "certifi" 62 | version = "2025.4.26" 63 | source = { registry = "https://pypi.org/simple" } 64 | sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } 65 | wheels = [ 66 | { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, 67 | ] 68 | 69 | [[package]] 70 | name = "cffi" 71 | version = "1.17.1" 72 | source = { registry = "https://pypi.org/simple" } 73 | dependencies = [ 74 | { name = "pycparser" }, 75 | ] 76 | sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } 77 | wheels = [ 78 | { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, 79 | { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, 80 | { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, 81 | { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, 82 | { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, 83 | { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, 84 | { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, 85 | { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, 86 | { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, 87 | { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, 88 | { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, 89 | { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, 90 | { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, 91 | { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, 92 | { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, 93 | { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, 94 | { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, 95 | { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, 96 | ] 97 | 98 | [[package]] 99 | name = "cfgv" 100 | version = "3.4.0" 101 | source = { registry = "https://pypi.org/simple" } 102 | sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } 103 | wheels = [ 104 | { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, 105 | ] 106 | 107 | [[package]] 108 | name = "charset-normalizer" 109 | version = "3.4.2" 110 | source = { registry = "https://pypi.org/simple" } 111 | sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } 112 | wheels = [ 113 | { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, 114 | { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, 115 | { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, 116 | { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, 117 | { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, 118 | { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, 119 | { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, 120 | { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, 121 | { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, 122 | { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, 123 | { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, 124 | { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, 125 | { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, 126 | { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, 127 | { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, 128 | { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, 129 | { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, 130 | { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, 131 | { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, 132 | { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, 133 | { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, 134 | { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, 135 | { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, 136 | { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, 137 | { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, 138 | { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, 139 | { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, 140 | ] 141 | 142 | [[package]] 143 | name = "click" 144 | version = "8.1.8" 145 | source = { registry = "https://pypi.org/simple" } 146 | dependencies = [ 147 | { name = "colorama", marker = "sys_platform == 'win32'" }, 148 | ] 149 | sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } 150 | wheels = [ 151 | { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" }, 152 | ] 153 | 154 | [[package]] 155 | name = "colorama" 156 | version = "0.4.6" 157 | source = { registry = "https://pypi.org/simple" } 158 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } 159 | wheels = [ 160 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, 161 | ] 162 | 163 | [[package]] 164 | name = "coverage" 165 | version = "7.8.2" 166 | source = { registry = "https://pypi.org/simple" } 167 | sdist = { url = "https://files.pythonhosted.org/packages/ba/07/998afa4a0ecdf9b1981ae05415dad2d4e7716e1b1f00abbd91691ac09ac9/coverage-7.8.2.tar.gz", hash = "sha256:a886d531373a1f6ff9fad2a2ba4a045b68467b779ae729ee0b3b10ac20033b27", size = 812759, upload-time = "2025-05-23T11:39:57.856Z" } 168 | wheels = [ 169 | { url = "https://files.pythonhosted.org/packages/8d/2a/1da1ada2e3044fcd4a3254fb3576e160b8fe5b36d705c8a31f793423f763/coverage-7.8.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e2f6fe3654468d061942591aef56686131335b7a8325684eda85dacdf311356c", size = 211876, upload-time = "2025-05-23T11:38:29.01Z" }, 170 | { url = "https://files.pythonhosted.org/packages/70/e9/3d715ffd5b6b17a8be80cd14a8917a002530a99943cc1939ad5bb2aa74b9/coverage-7.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76090fab50610798cc05241bf83b603477c40ee87acd358b66196ab0ca44ffa1", size = 212130, upload-time = "2025-05-23T11:38:30.675Z" }, 171 | { url = "https://files.pythonhosted.org/packages/a0/02/fdce62bb3c21649abfd91fbdcf041fb99be0d728ff00f3f9d54d97ed683e/coverage-7.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bd0a0a5054be160777a7920b731a0570284db5142abaaf81bcbb282b8d99279", size = 246176, upload-time = "2025-05-23T11:38:32.395Z" }, 172 | { url = "https://files.pythonhosted.org/packages/a7/52/decbbed61e03b6ffe85cd0fea360a5e04a5a98a7423f292aae62423b8557/coverage-7.8.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da23ce9a3d356d0affe9c7036030b5c8f14556bd970c9b224f9c8205505e3b99", size = 243068, upload-time = "2025-05-23T11:38:33.989Z" }, 173 | { url = "https://files.pythonhosted.org/packages/38/6c/d0e9c0cce18faef79a52778219a3c6ee8e336437da8eddd4ab3dbd8fadff/coverage-7.8.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9392773cffeb8d7e042a7b15b82a414011e9d2b5fdbbd3f7e6a6b17d5e21b20", size = 245328, upload-time = "2025-05-23T11:38:35.568Z" }, 174 | { url = "https://files.pythonhosted.org/packages/f0/70/f703b553a2f6b6c70568c7e398ed0789d47f953d67fbba36a327714a7bca/coverage-7.8.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:876cbfd0b09ce09d81585d266c07a32657beb3eaec896f39484b631555be0fe2", size = 245099, upload-time = "2025-05-23T11:38:37.627Z" }, 175 | { url = "https://files.pythonhosted.org/packages/ec/fb/4cbb370dedae78460c3aacbdad9d249e853f3bc4ce5ff0e02b1983d03044/coverage-7.8.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3da9b771c98977a13fbc3830f6caa85cae6c9c83911d24cb2d218e9394259c57", size = 243314, upload-time = "2025-05-23T11:38:39.238Z" }, 176 | { url = "https://files.pythonhosted.org/packages/39/9f/1afbb2cb9c8699b8bc38afdce00a3b4644904e6a38c7bf9005386c9305ec/coverage-7.8.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a990f6510b3292686713bfef26d0049cd63b9c7bb17e0864f133cbfd2e6167f", size = 244489, upload-time = "2025-05-23T11:38:40.845Z" }, 177 | { url = "https://files.pythonhosted.org/packages/79/fa/f3e7ec7d220bff14aba7a4786ae47043770cbdceeea1803083059c878837/coverage-7.8.2-cp312-cp312-win32.whl", hash = "sha256:bf8111cddd0f2b54d34e96613e7fbdd59a673f0cf5574b61134ae75b6f5a33b8", size = 214366, upload-time = "2025-05-23T11:38:43.551Z" }, 178 | { url = "https://files.pythonhosted.org/packages/54/aa/9cbeade19b7e8e853e7ffc261df885d66bf3a782c71cba06c17df271f9e6/coverage-7.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:86a323a275e9e44cdf228af9b71c5030861d4d2610886ab920d9945672a81223", size = 215165, upload-time = "2025-05-23T11:38:45.148Z" }, 179 | { url = "https://files.pythonhosted.org/packages/c4/73/e2528bf1237d2448f882bbebaec5c3500ef07301816c5c63464b9da4d88a/coverage-7.8.2-cp312-cp312-win_arm64.whl", hash = "sha256:820157de3a589e992689ffcda8639fbabb313b323d26388d02e154164c57b07f", size = 213548, upload-time = "2025-05-23T11:38:46.74Z" }, 180 | { url = "https://files.pythonhosted.org/packages/1a/93/eb6400a745ad3b265bac36e8077fdffcf0268bdbbb6c02b7220b624c9b31/coverage-7.8.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ea561010914ec1c26ab4188aef8b1567272ef6de096312716f90e5baa79ef8ca", size = 211898, upload-time = "2025-05-23T11:38:49.066Z" }, 181 | { url = "https://files.pythonhosted.org/packages/1b/7c/bdbf113f92683024406a1cd226a199e4200a2001fc85d6a6e7e299e60253/coverage-7.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cb86337a4fcdd0e598ff2caeb513ac604d2f3da6d53df2c8e368e07ee38e277d", size = 212171, upload-time = "2025-05-23T11:38:51.207Z" }, 182 | { url = "https://files.pythonhosted.org/packages/91/22/594513f9541a6b88eb0dba4d5da7d71596dadef6b17a12dc2c0e859818a9/coverage-7.8.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26a4636ddb666971345541b59899e969f3b301143dd86b0ddbb570bd591f1e85", size = 245564, upload-time = "2025-05-23T11:38:52.857Z" }, 183 | { url = "https://files.pythonhosted.org/packages/1f/f4/2860fd6abeebd9f2efcfe0fd376226938f22afc80c1943f363cd3c28421f/coverage-7.8.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5040536cf9b13fb033f76bcb5e1e5cb3b57c4807fef37db9e0ed129c6a094257", size = 242719, upload-time = "2025-05-23T11:38:54.529Z" }, 184 | { url = "https://files.pythonhosted.org/packages/89/60/f5f50f61b6332451520e6cdc2401700c48310c64bc2dd34027a47d6ab4ca/coverage-7.8.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc67994df9bcd7e0150a47ef41278b9e0a0ea187caba72414b71dc590b99a108", size = 244634, upload-time = "2025-05-23T11:38:57.326Z" }, 185 | { url = "https://files.pythonhosted.org/packages/3b/70/7f4e919039ab7d944276c446b603eea84da29ebcf20984fb1fdf6e602028/coverage-7.8.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e6c86888fd076d9e0fe848af0a2142bf606044dc5ceee0aa9eddb56e26895a0", size = 244824, upload-time = "2025-05-23T11:38:59.421Z" }, 186 | { url = "https://files.pythonhosted.org/packages/26/45/36297a4c0cea4de2b2c442fe32f60c3991056c59cdc3cdd5346fbb995c97/coverage-7.8.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:684ca9f58119b8e26bef860db33524ae0365601492e86ba0b71d513f525e7050", size = 242872, upload-time = "2025-05-23T11:39:01.049Z" }, 187 | { url = "https://files.pythonhosted.org/packages/a4/71/e041f1b9420f7b786b1367fa2a375703889ef376e0d48de9f5723fb35f11/coverage-7.8.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8165584ddedb49204c4e18da083913bdf6a982bfb558632a79bdaadcdafd0d48", size = 244179, upload-time = "2025-05-23T11:39:02.709Z" }, 188 | { url = "https://files.pythonhosted.org/packages/bd/db/3c2bf49bdc9de76acf2491fc03130c4ffc51469ce2f6889d2640eb563d77/coverage-7.8.2-cp313-cp313-win32.whl", hash = "sha256:34759ee2c65362163699cc917bdb2a54114dd06d19bab860725f94ef45a3d9b7", size = 214393, upload-time = "2025-05-23T11:39:05.457Z" }, 189 | { url = "https://files.pythonhosted.org/packages/c6/dc/947e75d47ebbb4b02d8babb1fad4ad381410d5bc9da7cfca80b7565ef401/coverage-7.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:2f9bc608fbafaee40eb60a9a53dbfb90f53cc66d3d32c2849dc27cf5638a21e3", size = 215194, upload-time = "2025-05-23T11:39:07.171Z" }, 190 | { url = "https://files.pythonhosted.org/packages/90/31/a980f7df8a37eaf0dc60f932507fda9656b3a03f0abf188474a0ea188d6d/coverage-7.8.2-cp313-cp313-win_arm64.whl", hash = "sha256:9fe449ee461a3b0c7105690419d0b0aba1232f4ff6d120a9e241e58a556733f7", size = 213580, upload-time = "2025-05-23T11:39:08.862Z" }, 191 | { url = "https://files.pythonhosted.org/packages/8a/6a/25a37dd90f6c95f59355629417ebcb74e1c34e38bb1eddf6ca9b38b0fc53/coverage-7.8.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8369a7c8ef66bded2b6484053749ff220dbf83cba84f3398c84c51a6f748a008", size = 212734, upload-time = "2025-05-23T11:39:11.109Z" }, 192 | { url = "https://files.pythonhosted.org/packages/36/8b/3a728b3118988725f40950931abb09cd7f43b3c740f4640a59f1db60e372/coverage-7.8.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:159b81df53a5fcbc7d45dae3adad554fdbde9829a994e15227b3f9d816d00b36", size = 212959, upload-time = "2025-05-23T11:39:12.751Z" }, 193 | { url = "https://files.pythonhosted.org/packages/53/3c/212d94e6add3a3c3f412d664aee452045ca17a066def8b9421673e9482c4/coverage-7.8.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6fcbbd35a96192d042c691c9e0c49ef54bd7ed865846a3c9d624c30bb67ce46", size = 257024, upload-time = "2025-05-23T11:39:15.569Z" }, 194 | { url = "https://files.pythonhosted.org/packages/a4/40/afc03f0883b1e51bbe804707aae62e29c4e8c8bbc365c75e3e4ddeee9ead/coverage-7.8.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05364b9cc82f138cc86128dc4e2e1251c2981a2218bfcd556fe6b0fbaa3501be", size = 252867, upload-time = "2025-05-23T11:39:17.64Z" }, 195 | { url = "https://files.pythonhosted.org/packages/18/a2/3699190e927b9439c6ded4998941a3c1d6fa99e14cb28d8536729537e307/coverage-7.8.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46d532db4e5ff3979ce47d18e2fe8ecad283eeb7367726da0e5ef88e4fe64740", size = 255096, upload-time = "2025-05-23T11:39:19.328Z" }, 196 | { url = "https://files.pythonhosted.org/packages/b4/06/16e3598b9466456b718eb3e789457d1a5b8bfb22e23b6e8bbc307df5daf0/coverage-7.8.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4000a31c34932e7e4fa0381a3d6deb43dc0c8f458e3e7ea6502e6238e10be625", size = 256276, upload-time = "2025-05-23T11:39:21.077Z" }, 197 | { url = "https://files.pythonhosted.org/packages/a7/d5/4b5a120d5d0223050a53d2783c049c311eea1709fa9de12d1c358e18b707/coverage-7.8.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:43ff5033d657cd51f83015c3b7a443287250dc14e69910577c3e03bd2e06f27b", size = 254478, upload-time = "2025-05-23T11:39:22.838Z" }, 198 | { url = "https://files.pythonhosted.org/packages/ba/85/f9ecdb910ecdb282b121bfcaa32fa8ee8cbd7699f83330ee13ff9bbf1a85/coverage-7.8.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94316e13f0981cbbba132c1f9f365cac1d26716aaac130866ca812006f662199", size = 255255, upload-time = "2025-05-23T11:39:24.644Z" }, 199 | { url = "https://files.pythonhosted.org/packages/50/63/2d624ac7d7ccd4ebbd3c6a9eba9d7fc4491a1226071360d59dd84928ccb2/coverage-7.8.2-cp313-cp313t-win32.whl", hash = "sha256:3f5673888d3676d0a745c3d0e16da338c5eea300cb1f4ada9c872981265e76d8", size = 215109, upload-time = "2025-05-23T11:39:26.722Z" }, 200 | { url = "https://files.pythonhosted.org/packages/22/5e/7053b71462e970e869111c1853afd642212568a350eba796deefdfbd0770/coverage-7.8.2-cp313-cp313t-win_amd64.whl", hash = "sha256:2c08b05ee8d7861e45dc5a2cc4195c8c66dca5ac613144eb6ebeaff2d502e73d", size = 216268, upload-time = "2025-05-23T11:39:28.429Z" }, 201 | { url = "https://files.pythonhosted.org/packages/07/69/afa41aa34147655543dbe96994f8a246daf94b361ccf5edfd5df62ce066a/coverage-7.8.2-cp313-cp313t-win_arm64.whl", hash = "sha256:1e1448bb72b387755e1ff3ef1268a06617afd94188164960dba8d0245a46004b", size = 214071, upload-time = "2025-05-23T11:39:30.55Z" }, 202 | { url = "https://files.pythonhosted.org/packages/a0/1a/0b9c32220ad694d66062f571cc5cedfa9997b64a591e8a500bb63de1bd40/coverage-7.8.2-py3-none-any.whl", hash = "sha256:726f32ee3713f7359696331a18daf0c3b3a70bb0ae71141b9d3c52be7c595e32", size = 203623, upload-time = "2025-05-23T11:39:53.846Z" }, 203 | ] 204 | 205 | [[package]] 206 | name = "cryptography" 207 | version = "44.0.3" 208 | source = { registry = "https://pypi.org/simple" } 209 | dependencies = [ 210 | { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, 211 | ] 212 | sdist = { url = "https://files.pythonhosted.org/packages/53/d6/1411ab4d6108ab167d06254c5be517681f1e331f90edf1379895bcb87020/cryptography-44.0.3.tar.gz", hash = "sha256:fe19d8bc5536a91a24a8133328880a41831b6c5df54599a8417b62fe015d3053", size = 711096, upload-time = "2025-05-02T19:36:04.667Z" } 213 | wheels = [ 214 | { url = "https://files.pythonhosted.org/packages/6a/06/af2cf8d56ef87c77319e9086601bef621bedf40f6f59069e1b6d1ec498c5/cryptography-44.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc61e8f3bf5b60346d89cd3d37231019c17a081208dfbbd6e1605ba03fa137", size = 3959305, upload-time = "2025-05-02T19:34:53.042Z" }, 215 | { url = "https://files.pythonhosted.org/packages/ae/01/80de3bec64627207d030f47bf3536889efee8913cd363e78ca9a09b13c8e/cryptography-44.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58968d331425a6f9eedcee087f77fd3c927c88f55368f43ff7e0a19891f2642c", size = 4171040, upload-time = "2025-05-02T19:34:54.675Z" }, 216 | { url = "https://files.pythonhosted.org/packages/bd/48/bb16b7541d207a19d9ae8b541c70037a05e473ddc72ccb1386524d4f023c/cryptography-44.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e28d62e59a4dbd1d22e747f57d4f00c459af22181f0b2f787ea83f5a876d7c76", size = 3963411, upload-time = "2025-05-02T19:34:56.61Z" }, 217 | { url = "https://files.pythonhosted.org/packages/42/b2/7d31f2af5591d217d71d37d044ef5412945a8a8e98d5a2a8ae4fd9cd4489/cryptography-44.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af653022a0c25ef2e3ffb2c673a50e5a0d02fecc41608f4954176f1933b12359", size = 3689263, upload-time = "2025-05-02T19:34:58.591Z" }, 218 | { url = "https://files.pythonhosted.org/packages/25/50/c0dfb9d87ae88ccc01aad8eb93e23cfbcea6a6a106a9b63a7b14c1f93c75/cryptography-44.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:157f1f3b8d941c2bd8f3ffee0af9b049c9665c39d3da9db2dc338feca5e98a43", size = 4196198, upload-time = "2025-05-02T19:35:00.988Z" }, 219 | { url = "https://files.pythonhosted.org/packages/66/c9/55c6b8794a74da652690c898cb43906310a3e4e4f6ee0b5f8b3b3e70c441/cryptography-44.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:c6cd67722619e4d55fdb42ead64ed8843d64638e9c07f4011163e46bc512cf01", size = 3966502, upload-time = "2025-05-02T19:35:03.091Z" }, 220 | { url = "https://files.pythonhosted.org/packages/b6/f7/7cb5488c682ca59a02a32ec5f975074084db4c983f849d47b7b67cc8697a/cryptography-44.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b424563394c369a804ecbee9b06dfb34997f19d00b3518e39f83a5642618397d", size = 4196173, upload-time = "2025-05-02T19:35:05.018Z" }, 221 | { url = "https://files.pythonhosted.org/packages/d2/0b/2f789a8403ae089b0b121f8f54f4a3e5228df756e2146efdf4a09a3d5083/cryptography-44.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c91fc8e8fd78af553f98bc7f2a1d8db977334e4eea302a4bfd75b9461c2d8904", size = 4087713, upload-time = "2025-05-02T19:35:07.187Z" }, 222 | { url = "https://files.pythonhosted.org/packages/1d/aa/330c13655f1af398fc154089295cf259252f0ba5df93b4bc9d9c7d7f843e/cryptography-44.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:25cd194c39fa5a0aa4169125ee27d1172097857b27109a45fadc59653ec06f44", size = 4299064, upload-time = "2025-05-02T19:35:08.879Z" }, 223 | { url = "https://files.pythonhosted.org/packages/b1/f0/7491d44bba8d28b464a5bc8cc709f25a51e3eac54c0a4444cf2473a57c37/cryptography-44.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ffef566ac88f75967d7abd852ed5f182da252d23fac11b4766da3957766759", size = 3960307, upload-time = "2025-05-02T19:35:15.917Z" }, 224 | { url = "https://files.pythonhosted.org/packages/f7/c8/e5c5d0e1364d3346a5747cdcd7ecbb23ca87e6dea4f942a44e88be349f06/cryptography-44.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:192ed30fac1728f7587c6f4613c29c584abdc565d7417c13904708db10206645", size = 4170876, upload-time = "2025-05-02T19:35:18.138Z" }, 225 | { url = "https://files.pythonhosted.org/packages/73/96/025cb26fc351d8c7d3a1c44e20cf9a01e9f7cf740353c9c7a17072e4b264/cryptography-44.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7d5fe7195c27c32a64955740b949070f21cba664604291c298518d2e255931d2", size = 3964127, upload-time = "2025-05-02T19:35:19.864Z" }, 226 | { url = "https://files.pythonhosted.org/packages/01/44/eb6522db7d9f84e8833ba3bf63313f8e257729cf3a8917379473fcfd6601/cryptography-44.0.3-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3f07943aa4d7dad689e3bb1638ddc4944cc5e0921e3c227486daae0e31a05e54", size = 3689164, upload-time = "2025-05-02T19:35:21.449Z" }, 227 | { url = "https://files.pythonhosted.org/packages/68/fb/d61a4defd0d6cee20b1b8a1ea8f5e25007e26aeb413ca53835f0cae2bcd1/cryptography-44.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb90f60e03d563ca2445099edf605c16ed1d5b15182d21831f58460c48bffb93", size = 4198081, upload-time = "2025-05-02T19:35:23.187Z" }, 228 | { url = "https://files.pythonhosted.org/packages/1b/50/457f6911d36432a8811c3ab8bd5a6090e8d18ce655c22820994913dd06ea/cryptography-44.0.3-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ab0b005721cc0039e885ac3503825661bd9810b15d4f374e473f8c89b7d5460c", size = 3967716, upload-time = "2025-05-02T19:35:25.426Z" }, 229 | { url = "https://files.pythonhosted.org/packages/35/6e/dca39d553075980ccb631955c47b93d87d27f3596da8d48b1ae81463d915/cryptography-44.0.3-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3bb0847e6363c037df8f6ede57d88eaf3410ca2267fb12275370a76f85786a6f", size = 4197398, upload-time = "2025-05-02T19:35:27.678Z" }, 230 | { url = "https://files.pythonhosted.org/packages/9b/9d/d1f2fe681eabc682067c66a74addd46c887ebacf39038ba01f8860338d3d/cryptography-44.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0cc66c74c797e1db750aaa842ad5b8b78e14805a9b5d1348dc603612d3e3ff5", size = 4087900, upload-time = "2025-05-02T19:35:29.312Z" }, 231 | { url = "https://files.pythonhosted.org/packages/c4/f5/3599e48c5464580b73b236aafb20973b953cd2e7b44c7c2533de1d888446/cryptography-44.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6866df152b581f9429020320e5eb9794c8780e90f7ccb021940d7f50ee00ae0b", size = 4301067, upload-time = "2025-05-02T19:35:31.547Z" }, 232 | ] 233 | 234 | [[package]] 235 | name = "distlib" 236 | version = "0.3.9" 237 | source = { registry = "https://pypi.org/simple" } 238 | sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923, upload-time = "2024-10-09T18:35:47.551Z" } 239 | wheels = [ 240 | { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973, upload-time = "2024-10-09T18:35:44.272Z" }, 241 | ] 242 | 243 | [[package]] 244 | name = "editor" 245 | version = "1.6.6" 246 | source = { registry = "https://pypi.org/simple" } 247 | dependencies = [ 248 | { name = "runs" }, 249 | { name = "xmod" }, 250 | ] 251 | sdist = { url = "https://files.pythonhosted.org/packages/2a/92/734a4ab345914259cb6146fd36512608ea42be16195375c379046f33283d/editor-1.6.6.tar.gz", hash = "sha256:bb6989e872638cd119db9a4fce284cd8e13c553886a1c044c6b8d8a160c871f8", size = 3197, upload-time = "2024-01-25T10:44:59.909Z" } 252 | wheels = [ 253 | { url = "https://files.pythonhosted.org/packages/1b/c2/4bc8cd09b14e28ce3f406a8b05761bed0d785d1ca8c2a5c6684d884c66a2/editor-1.6.6-py3-none-any.whl", hash = "sha256:e818e6913f26c2a81eadef503a2741d7cca7f235d20e217274a009ecd5a74abf", size = 4017, upload-time = "2024-01-25T10:44:58.66Z" }, 254 | ] 255 | 256 | [[package]] 257 | name = "filelock" 258 | version = "3.18.0" 259 | source = { registry = "https://pypi.org/simple" } 260 | sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } 261 | wheels = [ 262 | { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, 263 | ] 264 | 265 | [[package]] 266 | name = "h11" 267 | version = "0.14.0" 268 | source = { registry = "https://pypi.org/simple" } 269 | sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418, upload-time = "2022-09-25T15:40:01.519Z" } 270 | wheels = [ 271 | { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259, upload-time = "2022-09-25T15:39:59.68Z" }, 272 | ] 273 | 274 | [[package]] 275 | name = "httpcore" 276 | version = "1.0.8" 277 | source = { registry = "https://pypi.org/simple" } 278 | dependencies = [ 279 | { name = "certifi" }, 280 | { name = "h11" }, 281 | ] 282 | sdist = { url = "https://files.pythonhosted.org/packages/9f/45/ad3e1b4d448f22c0cff4f5692f5ed0666658578e358b8d58a19846048059/httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad", size = 85385, upload-time = "2025-04-11T14:42:46.661Z" } 283 | wheels = [ 284 | { url = "https://files.pythonhosted.org/packages/18/8d/f052b1e336bb2c1fc7ed1aaed898aa570c0b61a09707b108979d9fc6e308/httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be", size = 78732, upload-time = "2025-04-11T14:42:44.896Z" }, 285 | ] 286 | 287 | [[package]] 288 | name = "httpx" 289 | version = "0.28.1" 290 | source = { registry = "https://pypi.org/simple" } 291 | dependencies = [ 292 | { name = "anyio" }, 293 | { name = "certifi" }, 294 | { name = "httpcore" }, 295 | { name = "idna" }, 296 | ] 297 | sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } 298 | wheels = [ 299 | { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, 300 | ] 301 | 302 | [[package]] 303 | name = "httpx-sse" 304 | version = "0.4.0" 305 | source = { registry = "https://pypi.org/simple" } 306 | sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624, upload-time = "2023-12-22T08:01:21.083Z" } 307 | wheels = [ 308 | { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819, upload-time = "2023-12-22T08:01:19.89Z" }, 309 | ] 310 | 311 | [[package]] 312 | name = "identify" 313 | version = "2.6.12" 314 | source = { registry = "https://pypi.org/simple" } 315 | sdist = { url = "https://files.pythonhosted.org/packages/a2/88/d193a27416618628a5eea64e3223acd800b40749a96ffb322a9b55a49ed1/identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6", size = 99254, upload-time = "2025-05-23T20:37:53.3Z" } 316 | wheels = [ 317 | { url = "https://files.pythonhosted.org/packages/7a/cd/18f8da995b658420625f7ef13f037be53ae04ec5ad33f9b718240dcfd48c/identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2", size = 99145, upload-time = "2025-05-23T20:37:51.495Z" }, 318 | ] 319 | 320 | [[package]] 321 | name = "idna" 322 | version = "3.10" 323 | source = { registry = "https://pypi.org/simple" } 324 | sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } 325 | wheels = [ 326 | { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, 327 | ] 328 | 329 | [[package]] 330 | name = "iniconfig" 331 | version = "2.1.0" 332 | source = { registry = "https://pypi.org/simple" } 333 | sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } 334 | wheels = [ 335 | { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, 336 | ] 337 | 338 | [[package]] 339 | name = "inquirer" 340 | version = "3.4.0" 341 | source = { registry = "https://pypi.org/simple" } 342 | dependencies = [ 343 | { name = "blessed" }, 344 | { name = "editor" }, 345 | { name = "readchar" }, 346 | ] 347 | sdist = { url = "https://files.pythonhosted.org/packages/f3/06/ef91eb8f3feafb736aa33dcb278fc9555d17861aa571b684715d095db24d/inquirer-3.4.0.tar.gz", hash = "sha256:8edc99c076386ee2d2204e5e3653c2488244e82cb197b2d498b3c1b5ffb25d0b", size = 14472, upload-time = "2024-08-12T12:03:43.83Z" } 348 | wheels = [ 349 | { url = "https://files.pythonhosted.org/packages/a4/b2/be907c8c0f8303bc4b10089f5470014c3bf3521e9b8d3decf3037fd94725/inquirer-3.4.0-py3-none-any.whl", hash = "sha256:bb0ec93c833e4ce7b51b98b1644b0a4d2bb39755c39787f6a504e4fee7a11b60", size = 18077, upload-time = "2024-08-12T12:03:41.589Z" }, 350 | ] 351 | 352 | [[package]] 353 | name = "jaraco-classes" 354 | version = "3.4.0" 355 | source = { registry = "https://pypi.org/simple" } 356 | dependencies = [ 357 | { name = "more-itertools" }, 358 | ] 359 | sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" } 360 | wheels = [ 361 | { url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777, upload-time = "2024-03-31T07:27:34.792Z" }, 362 | ] 363 | 364 | [[package]] 365 | name = "jaraco-context" 366 | version = "6.0.1" 367 | source = { registry = "https://pypi.org/simple" } 368 | sdist = { url = "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", size = 13912, upload-time = "2024-08-20T03:39:27.358Z" } 369 | wheels = [ 370 | { url = "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4", size = 6825, upload-time = "2024-08-20T03:39:25.966Z" }, 371 | ] 372 | 373 | [[package]] 374 | name = "jaraco-functools" 375 | version = "4.1.0" 376 | source = { registry = "https://pypi.org/simple" } 377 | dependencies = [ 378 | { name = "more-itertools" }, 379 | ] 380 | sdist = { url = "https://files.pythonhosted.org/packages/ab/23/9894b3df5d0a6eb44611c36aec777823fc2e07740dabbd0b810e19594013/jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", size = 19159, upload-time = "2024-09-27T19:47:09.122Z" } 381 | wheels = [ 382 | { url = "https://files.pythonhosted.org/packages/9f/4f/24b319316142c44283d7540e76c7b5a6dbd5db623abd86bb7b3491c21018/jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649", size = 10187, upload-time = "2024-09-27T19:47:07.14Z" }, 383 | ] 384 | 385 | [[package]] 386 | name = "jeepney" 387 | version = "0.9.0" 388 | source = { registry = "https://pypi.org/simple" } 389 | sdist = { url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" } 390 | wheels = [ 391 | { url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" }, 392 | ] 393 | 394 | [[package]] 395 | name = "jinxed" 396 | version = "1.3.0" 397 | source = { registry = "https://pypi.org/simple" } 398 | dependencies = [ 399 | { name = "ansicon", marker = "sys_platform == 'win32'" }, 400 | ] 401 | sdist = { url = "https://files.pythonhosted.org/packages/20/d0/59b2b80e7a52d255f9e0ad040d2e826342d05580c4b1d7d7747cfb8db731/jinxed-1.3.0.tar.gz", hash = "sha256:1593124b18a41b7a3da3b078471442e51dbad3d77b4d4f2b0c26ab6f7d660dbf", size = 80981, upload-time = "2024-07-31T22:39:18.854Z" } 402 | wheels = [ 403 | { url = "https://files.pythonhosted.org/packages/27/e3/0e0014d6ab159d48189e92044ace13b1e1fe9aa3024ba9f4e8cf172aa7c2/jinxed-1.3.0-py2.py3-none-any.whl", hash = "sha256:b993189f39dc2d7504d802152671535b06d380b26d78070559551cbf92df4fc5", size = 33085, upload-time = "2024-07-31T22:39:17.426Z" }, 404 | ] 405 | 406 | [[package]] 407 | name = "keyring" 408 | version = "25.6.0" 409 | source = { registry = "https://pypi.org/simple" } 410 | dependencies = [ 411 | { name = "jaraco-classes" }, 412 | { name = "jaraco-context" }, 413 | { name = "jaraco-functools" }, 414 | { name = "jeepney", marker = "sys_platform == 'linux'" }, 415 | { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" }, 416 | { name = "secretstorage", marker = "sys_platform == 'linux'" }, 417 | ] 418 | sdist = { url = "https://files.pythonhosted.org/packages/70/09/d904a6e96f76ff214be59e7aa6ef7190008f52a0ab6689760a98de0bf37d/keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66", size = 62750, upload-time = "2024-12-25T15:26:45.782Z" } 419 | wheels = [ 420 | { url = "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd", size = 39085, upload-time = "2024-12-25T15:26:44.377Z" }, 421 | ] 422 | 423 | [[package]] 424 | name = "linkedin-mcp-server" 425 | version = "0.1.0" 426 | source = { virtual = "." } 427 | dependencies = [ 428 | { name = "httpx" }, 429 | { name = "inquirer" }, 430 | { name = "keyring" }, 431 | { name = "linkedin-scraper" }, 432 | { name = "mcp", extra = ["cli"] }, 433 | { name = "pyperclip" }, 434 | ] 435 | 436 | [package.dev-dependencies] 437 | dev = [ 438 | { name = "mypy" }, 439 | { name = "pre-commit" }, 440 | { name = "pytest" }, 441 | { name = "pytest-cov" }, 442 | { name = "ruff" }, 443 | ] 444 | 445 | [package.metadata] 446 | requires-dist = [ 447 | { name = "httpx", specifier = ">=0.28.1" }, 448 | { name = "inquirer", specifier = ">=3.4.0" }, 449 | { name = "keyring", specifier = ">=25.6.0" }, 450 | { name = "linkedin-scraper", git = "https://github.com/joeyism/linkedin_scraper.git" }, 451 | { name = "mcp", extras = ["cli"], specifier = ">=1.6.0" }, 452 | { name = "pyperclip", specifier = ">=1.9.0" }, 453 | ] 454 | 455 | [package.metadata.requires-dev] 456 | dev = [ 457 | { name = "mypy", specifier = ">=1.15.0" }, 458 | { name = "pre-commit", specifier = ">=4.2.0" }, 459 | { name = "pytest", specifier = ">=8.3.5" }, 460 | { name = "pytest-cov", specifier = ">=6.1.1" }, 461 | { name = "ruff", specifier = ">=0.11.11" }, 462 | ] 463 | 464 | [[package]] 465 | name = "linkedin-scraper" 466 | version = "2.11.5" 467 | source = { git = "https://github.com/joeyism/linkedin_scraper.git#44eafb893e691732474e37a20123c5cc9007e0ad" } 468 | dependencies = [ 469 | { name = "lxml" }, 470 | { name = "requests" }, 471 | { name = "selenium" }, 472 | ] 473 | 474 | [[package]] 475 | name = "lxml" 476 | version = "5.4.0" 477 | source = { registry = "https://pypi.org/simple" } 478 | sdist = { url = "https://files.pythonhosted.org/packages/76/3d/14e82fc7c8fb1b7761f7e748fd47e2ec8276d137b6acfe5a4bb73853e08f/lxml-5.4.0.tar.gz", hash = "sha256:d12832e1dbea4be280b22fd0ea7c9b87f0d8fc51ba06e92dc62d52f804f78ebd", size = 3679479, upload-time = "2025-04-23T01:50:29.322Z" } 479 | wheels = [ 480 | { url = "https://files.pythonhosted.org/packages/f8/4c/d101ace719ca6a4ec043eb516fcfcb1b396a9fccc4fcd9ef593df34ba0d5/lxml-5.4.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b5aff6f3e818e6bdbbb38e5967520f174b18f539c2b9de867b1e7fde6f8d95a4", size = 8127392, upload-time = "2025-04-23T01:46:04.09Z" }, 481 | { url = "https://files.pythonhosted.org/packages/11/84/beddae0cec4dd9ddf46abf156f0af451c13019a0fa25d7445b655ba5ccb7/lxml-5.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942a5d73f739ad7c452bf739a62a0f83e2578afd6b8e5406308731f4ce78b16d", size = 4415103, upload-time = "2025-04-23T01:46:07.227Z" }, 482 | { url = "https://files.pythonhosted.org/packages/d0/25/d0d93a4e763f0462cccd2b8a665bf1e4343dd788c76dcfefa289d46a38a9/lxml-5.4.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:460508a4b07364d6abf53acaa0a90b6d370fafde5693ef37602566613a9b0779", size = 5024224, upload-time = "2025-04-23T01:46:10.237Z" }, 483 | { url = "https://files.pythonhosted.org/packages/31/ce/1df18fb8f7946e7f3388af378b1f34fcf253b94b9feedb2cec5969da8012/lxml-5.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529024ab3a505fed78fe3cc5ddc079464e709f6c892733e3f5842007cec8ac6e", size = 4769913, upload-time = "2025-04-23T01:46:12.757Z" }, 484 | { url = "https://files.pythonhosted.org/packages/4e/62/f4a6c60ae7c40d43657f552f3045df05118636be1165b906d3423790447f/lxml-5.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ca56ebc2c474e8f3d5761debfd9283b8b18c76c4fc0967b74aeafba1f5647f9", size = 5290441, upload-time = "2025-04-23T01:46:16.037Z" }, 485 | { url = "https://files.pythonhosted.org/packages/9e/aa/04f00009e1e3a77838c7fc948f161b5d2d5de1136b2b81c712a263829ea4/lxml-5.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a81e1196f0a5b4167a8dafe3a66aa67c4addac1b22dc47947abd5d5c7a3f24b5", size = 4820165, upload-time = "2025-04-23T01:46:19.137Z" }, 486 | { url = "https://files.pythonhosted.org/packages/c9/1f/e0b2f61fa2404bf0f1fdf1898377e5bd1b74cc9b2cf2c6ba8509b8f27990/lxml-5.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00b8686694423ddae324cf614e1b9659c2edb754de617703c3d29ff568448df5", size = 4932580, upload-time = "2025-04-23T01:46:21.963Z" }, 487 | { url = "https://files.pythonhosted.org/packages/24/a2/8263f351b4ffe0ed3e32ea7b7830f845c795349034f912f490180d88a877/lxml-5.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:c5681160758d3f6ac5b4fea370495c48aac0989d6a0f01bb9a72ad8ef5ab75c4", size = 4759493, upload-time = "2025-04-23T01:46:24.316Z" }, 488 | { url = "https://files.pythonhosted.org/packages/05/00/41db052f279995c0e35c79d0f0fc9f8122d5b5e9630139c592a0b58c71b4/lxml-5.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:2dc191e60425ad70e75a68c9fd90ab284df64d9cd410ba8d2b641c0c45bc006e", size = 5324679, upload-time = "2025-04-23T01:46:27.097Z" }, 489 | { url = "https://files.pythonhosted.org/packages/1d/be/ee99e6314cdef4587617d3b3b745f9356d9b7dd12a9663c5f3b5734b64ba/lxml-5.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:67f779374c6b9753ae0a0195a892a1c234ce8416e4448fe1e9f34746482070a7", size = 4890691, upload-time = "2025-04-23T01:46:30.009Z" }, 490 | { url = "https://files.pythonhosted.org/packages/ad/36/239820114bf1d71f38f12208b9c58dec033cbcf80101cde006b9bde5cffd/lxml-5.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:79d5bfa9c1b455336f52343130b2067164040604e41f6dc4d8313867ed540079", size = 4955075, upload-time = "2025-04-23T01:46:32.33Z" }, 491 | { url = "https://files.pythonhosted.org/packages/d4/e1/1b795cc0b174efc9e13dbd078a9ff79a58728a033142bc6d70a1ee8fc34d/lxml-5.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3d3c30ba1c9b48c68489dc1829a6eede9873f52edca1dda900066542528d6b20", size = 4838680, upload-time = "2025-04-23T01:46:34.852Z" }, 492 | { url = "https://files.pythonhosted.org/packages/72/48/3c198455ca108cec5ae3662ae8acd7fd99476812fd712bb17f1b39a0b589/lxml-5.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1af80c6316ae68aded77e91cd9d80648f7dd40406cef73df841aa3c36f6907c8", size = 5391253, upload-time = "2025-04-23T01:46:37.608Z" }, 493 | { url = "https://files.pythonhosted.org/packages/d6/10/5bf51858971c51ec96cfc13e800a9951f3fd501686f4c18d7d84fe2d6352/lxml-5.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4d885698f5019abe0de3d352caf9466d5de2baded00a06ef3f1216c1a58ae78f", size = 5261651, upload-time = "2025-04-23T01:46:40.183Z" }, 494 | { url = "https://files.pythonhosted.org/packages/2b/11/06710dd809205377da380546f91d2ac94bad9ff735a72b64ec029f706c85/lxml-5.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea53d51859b6c64e7c51d522c03cc2c48b9b5d6172126854cc7f01aa11f52bc", size = 5024315, upload-time = "2025-04-23T01:46:43.333Z" }, 495 | { url = "https://files.pythonhosted.org/packages/f5/b0/15b6217834b5e3a59ebf7f53125e08e318030e8cc0d7310355e6edac98ef/lxml-5.4.0-cp312-cp312-win32.whl", hash = "sha256:d90b729fd2732df28130c064aac9bb8aff14ba20baa4aee7bd0795ff1187545f", size = 3486149, upload-time = "2025-04-23T01:46:45.684Z" }, 496 | { url = "https://files.pythonhosted.org/packages/91/1e/05ddcb57ad2f3069101611bd5f5084157d90861a2ef460bf42f45cced944/lxml-5.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1dc4ca99e89c335a7ed47d38964abcb36c5910790f9bd106f2a8fa2ee0b909d2", size = 3817095, upload-time = "2025-04-23T01:46:48.521Z" }, 497 | { url = "https://files.pythonhosted.org/packages/87/cb/2ba1e9dd953415f58548506fa5549a7f373ae55e80c61c9041b7fd09a38a/lxml-5.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:773e27b62920199c6197130632c18fb7ead3257fce1ffb7d286912e56ddb79e0", size = 8110086, upload-time = "2025-04-23T01:46:52.218Z" }, 498 | { url = "https://files.pythonhosted.org/packages/b5/3e/6602a4dca3ae344e8609914d6ab22e52ce42e3e1638c10967568c5c1450d/lxml-5.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ce9c671845de9699904b1e9df95acfe8dfc183f2310f163cdaa91a3535af95de", size = 4404613, upload-time = "2025-04-23T01:46:55.281Z" }, 499 | { url = "https://files.pythonhosted.org/packages/4c/72/bf00988477d3bb452bef9436e45aeea82bb40cdfb4684b83c967c53909c7/lxml-5.4.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9454b8d8200ec99a224df8854786262b1bd6461f4280064c807303c642c05e76", size = 5012008, upload-time = "2025-04-23T01:46:57.817Z" }, 500 | { url = "https://files.pythonhosted.org/packages/92/1f/93e42d93e9e7a44b2d3354c462cd784dbaaf350f7976b5d7c3f85d68d1b1/lxml-5.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cccd007d5c95279e529c146d095f1d39ac05139de26c098166c4beb9374b0f4d", size = 4760915, upload-time = "2025-04-23T01:47:00.745Z" }, 501 | { url = "https://files.pythonhosted.org/packages/45/0b/363009390d0b461cf9976a499e83b68f792e4c32ecef092f3f9ef9c4ba54/lxml-5.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fce1294a0497edb034cb416ad3e77ecc89b313cff7adbee5334e4dc0d11f422", size = 5283890, upload-time = "2025-04-23T01:47:04.702Z" }, 502 | { url = "https://files.pythonhosted.org/packages/19/dc/6056c332f9378ab476c88e301e6549a0454dbee8f0ae16847414f0eccb74/lxml-5.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24974f774f3a78ac12b95e3a20ef0931795ff04dbb16db81a90c37f589819551", size = 4812644, upload-time = "2025-04-23T01:47:07.833Z" }, 503 | { url = "https://files.pythonhosted.org/packages/ee/8a/f8c66bbb23ecb9048a46a5ef9b495fd23f7543df642dabeebcb2eeb66592/lxml-5.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:497cab4d8254c2a90bf988f162ace2ddbfdd806fce3bda3f581b9d24c852e03c", size = 4921817, upload-time = "2025-04-23T01:47:10.317Z" }, 504 | { url = "https://files.pythonhosted.org/packages/04/57/2e537083c3f381f83d05d9b176f0d838a9e8961f7ed8ddce3f0217179ce3/lxml-5.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:e794f698ae4c5084414efea0f5cc9f4ac562ec02d66e1484ff822ef97c2cadff", size = 4753916, upload-time = "2025-04-23T01:47:12.823Z" }, 505 | { url = "https://files.pythonhosted.org/packages/d8/80/ea8c4072109a350848f1157ce83ccd9439601274035cd045ac31f47f3417/lxml-5.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:2c62891b1ea3094bb12097822b3d44b93fc6c325f2043c4d2736a8ff09e65f60", size = 5289274, upload-time = "2025-04-23T01:47:15.916Z" }, 506 | { url = "https://files.pythonhosted.org/packages/b3/47/c4be287c48cdc304483457878a3f22999098b9a95f455e3c4bda7ec7fc72/lxml-5.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:142accb3e4d1edae4b392bd165a9abdee8a3c432a2cca193df995bc3886249c8", size = 4874757, upload-time = "2025-04-23T01:47:19.793Z" }, 507 | { url = "https://files.pythonhosted.org/packages/2f/04/6ef935dc74e729932e39478e44d8cfe6a83550552eaa072b7c05f6f22488/lxml-5.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1a42b3a19346e5601d1b8296ff6ef3d76038058f311902edd574461e9c036982", size = 4947028, upload-time = "2025-04-23T01:47:22.401Z" }, 508 | { url = "https://files.pythonhosted.org/packages/cb/f9/c33fc8daa373ef8a7daddb53175289024512b6619bc9de36d77dca3df44b/lxml-5.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4291d3c409a17febf817259cb37bc62cb7eb398bcc95c1356947e2871911ae61", size = 4834487, upload-time = "2025-04-23T01:47:25.513Z" }, 509 | { url = "https://files.pythonhosted.org/packages/8d/30/fc92bb595bcb878311e01b418b57d13900f84c2b94f6eca9e5073ea756e6/lxml-5.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4f5322cf38fe0e21c2d73901abf68e6329dc02a4994e483adbcf92b568a09a54", size = 5381688, upload-time = "2025-04-23T01:47:28.454Z" }, 510 | { url = "https://files.pythonhosted.org/packages/43/d1/3ba7bd978ce28bba8e3da2c2e9d5ae3f8f521ad3f0ca6ea4788d086ba00d/lxml-5.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0be91891bdb06ebe65122aa6bf3fc94489960cf7e03033c6f83a90863b23c58b", size = 5242043, upload-time = "2025-04-23T01:47:31.208Z" }, 511 | { url = "https://files.pythonhosted.org/packages/ee/cd/95fa2201041a610c4d08ddaf31d43b98ecc4b1d74b1e7245b1abdab443cb/lxml-5.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:15a665ad90054a3d4f397bc40f73948d48e36e4c09f9bcffc7d90c87410e478a", size = 5021569, upload-time = "2025-04-23T01:47:33.805Z" }, 512 | { url = "https://files.pythonhosted.org/packages/2d/a6/31da006fead660b9512d08d23d31e93ad3477dd47cc42e3285f143443176/lxml-5.4.0-cp313-cp313-win32.whl", hash = "sha256:d5663bc1b471c79f5c833cffbc9b87d7bf13f87e055a5c86c363ccd2348d7e82", size = 3485270, upload-time = "2025-04-23T01:47:36.133Z" }, 513 | { url = "https://files.pythonhosted.org/packages/fc/14/c115516c62a7d2499781d2d3d7215218c0731b2c940753bf9f9b7b73924d/lxml-5.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:bcb7a1096b4b6b24ce1ac24d4942ad98f983cd3810f9711bcd0293f43a9d8b9f", size = 3814606, upload-time = "2025-04-23T01:47:39.028Z" }, 514 | ] 515 | 516 | [[package]] 517 | name = "markdown-it-py" 518 | version = "3.0.0" 519 | source = { registry = "https://pypi.org/simple" } 520 | dependencies = [ 521 | { name = "mdurl" }, 522 | ] 523 | sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } 524 | wheels = [ 525 | { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, 526 | ] 527 | 528 | [[package]] 529 | name = "mcp" 530 | version = "1.6.0" 531 | source = { registry = "https://pypi.org/simple" } 532 | dependencies = [ 533 | { name = "anyio" }, 534 | { name = "httpx" }, 535 | { name = "httpx-sse" }, 536 | { name = "pydantic" }, 537 | { name = "pydantic-settings" }, 538 | { name = "sse-starlette" }, 539 | { name = "starlette" }, 540 | { name = "uvicorn" }, 541 | ] 542 | sdist = { url = "https://files.pythonhosted.org/packages/95/d2/f587cb965a56e992634bebc8611c5b579af912b74e04eb9164bd49527d21/mcp-1.6.0.tar.gz", hash = "sha256:d9324876de2c5637369f43161cd71eebfd803df5a95e46225cab8d280e366723", size = 200031, upload-time = "2025-03-27T16:46:32.336Z" } 543 | wheels = [ 544 | { url = "https://files.pythonhosted.org/packages/10/30/20a7f33b0b884a9d14dd3aa94ff1ac9da1479fe2ad66dd9e2736075d2506/mcp-1.6.0-py3-none-any.whl", hash = "sha256:7bd24c6ea042dbec44c754f100984d186620d8b841ec30f1b19eda9b93a634d0", size = 76077, upload-time = "2025-03-27T16:46:29.919Z" }, 545 | ] 546 | 547 | [package.optional-dependencies] 548 | cli = [ 549 | { name = "python-dotenv" }, 550 | { name = "typer" }, 551 | ] 552 | 553 | [[package]] 554 | name = "mdurl" 555 | version = "0.1.2" 556 | source = { registry = "https://pypi.org/simple" } 557 | sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } 558 | wheels = [ 559 | { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, 560 | ] 561 | 562 | [[package]] 563 | name = "more-itertools" 564 | version = "10.7.0" 565 | source = { registry = "https://pypi.org/simple" } 566 | sdist = { url = "https://files.pythonhosted.org/packages/ce/a0/834b0cebabbfc7e311f30b46c8188790a37f89fc8d756660346fe5abfd09/more_itertools-10.7.0.tar.gz", hash = "sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3", size = 127671, upload-time = "2025-04-22T14:17:41.838Z" } 567 | wheels = [ 568 | { url = "https://files.pythonhosted.org/packages/2b/9f/7ba6f94fc1e9ac3d2b853fdff3035fb2fa5afbed898c4a72b8a020610594/more_itertools-10.7.0-py3-none-any.whl", hash = "sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e", size = 65278, upload-time = "2025-04-22T14:17:40.49Z" }, 569 | ] 570 | 571 | [[package]] 572 | name = "mypy" 573 | version = "1.15.0" 574 | source = { registry = "https://pypi.org/simple" } 575 | dependencies = [ 576 | { name = "mypy-extensions" }, 577 | { name = "typing-extensions" }, 578 | ] 579 | sdist = { url = "https://files.pythonhosted.org/packages/ce/43/d5e49a86afa64bd3839ea0d5b9c7103487007d728e1293f52525d6d5486a/mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43", size = 3239717, upload-time = "2025-02-05T03:50:34.655Z" } 580 | wheels = [ 581 | { url = "https://files.pythonhosted.org/packages/98/3a/03c74331c5eb8bd025734e04c9840532226775c47a2c39b56a0c8d4f128d/mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd", size = 10793981, upload-time = "2025-02-05T03:50:28.25Z" }, 582 | { url = "https://files.pythonhosted.org/packages/f0/1a/41759b18f2cfd568848a37c89030aeb03534411eef981df621d8fad08a1d/mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f", size = 9749175, upload-time = "2025-02-05T03:50:13.411Z" }, 583 | { url = "https://files.pythonhosted.org/packages/12/7e/873481abf1ef112c582db832740f4c11b2bfa510e829d6da29b0ab8c3f9c/mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464", size = 11455675, upload-time = "2025-02-05T03:50:31.421Z" }, 584 | { url = "https://files.pythonhosted.org/packages/b3/d0/92ae4cde706923a2d3f2d6c39629134063ff64b9dedca9c1388363da072d/mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee", size = 12410020, upload-time = "2025-02-05T03:48:48.705Z" }, 585 | { url = "https://files.pythonhosted.org/packages/46/8b/df49974b337cce35f828ba6fda228152d6db45fed4c86ba56ffe442434fd/mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e", size = 12498582, upload-time = "2025-02-05T03:49:03.628Z" }, 586 | { url = "https://files.pythonhosted.org/packages/13/50/da5203fcf6c53044a0b699939f31075c45ae8a4cadf538a9069b165c1050/mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22", size = 9366614, upload-time = "2025-02-05T03:50:00.313Z" }, 587 | { url = "https://files.pythonhosted.org/packages/6a/9b/fd2e05d6ffff24d912f150b87db9e364fa8282045c875654ce7e32fffa66/mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445", size = 10788592, upload-time = "2025-02-05T03:48:55.789Z" }, 588 | { url = "https://files.pythonhosted.org/packages/74/37/b246d711c28a03ead1fd906bbc7106659aed7c089d55fe40dd58db812628/mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d", size = 9753611, upload-time = "2025-02-05T03:48:44.581Z" }, 589 | { url = "https://files.pythonhosted.org/packages/a6/ac/395808a92e10cfdac8003c3de9a2ab6dc7cde6c0d2a4df3df1b815ffd067/mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5", size = 11438443, upload-time = "2025-02-05T03:49:25.514Z" }, 590 | { url = "https://files.pythonhosted.org/packages/d2/8b/801aa06445d2de3895f59e476f38f3f8d610ef5d6908245f07d002676cbf/mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", size = 12402541, upload-time = "2025-02-05T03:49:57.623Z" }, 591 | { url = "https://files.pythonhosted.org/packages/c7/67/5a4268782eb77344cc613a4cf23540928e41f018a9a1ec4c6882baf20ab8/mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", size = 12494348, upload-time = "2025-02-05T03:48:52.361Z" }, 592 | { url = "https://files.pythonhosted.org/packages/83/3e/57bb447f7bbbfaabf1712d96f9df142624a386d98fb026a761532526057e/mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", size = 9373648, upload-time = "2025-02-05T03:49:11.395Z" }, 593 | { url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777, upload-time = "2025-02-05T03:50:08.348Z" }, 594 | ] 595 | 596 | [[package]] 597 | name = "mypy-extensions" 598 | version = "1.1.0" 599 | source = { registry = "https://pypi.org/simple" } 600 | sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } 601 | wheels = [ 602 | { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, 603 | ] 604 | 605 | [[package]] 606 | name = "nodeenv" 607 | version = "1.9.1" 608 | source = { registry = "https://pypi.org/simple" } 609 | sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } 610 | wheels = [ 611 | { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, 612 | ] 613 | 614 | [[package]] 615 | name = "outcome" 616 | version = "1.3.0.post0" 617 | source = { registry = "https://pypi.org/simple" } 618 | dependencies = [ 619 | { name = "attrs" }, 620 | ] 621 | sdist = { url = "https://files.pythonhosted.org/packages/98/df/77698abfac98571e65ffeb0c1fba8ffd692ab8458d617a0eed7d9a8d38f2/outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8", size = 21060, upload-time = "2023-10-26T04:26:04.361Z" } 622 | wheels = [ 623 | { url = "https://files.pythonhosted.org/packages/55/8b/5ab7257531a5d830fc8000c476e63c935488d74609b50f9384a643ec0a62/outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b", size = 10692, upload-time = "2023-10-26T04:26:02.532Z" }, 624 | ] 625 | 626 | [[package]] 627 | name = "packaging" 628 | version = "25.0" 629 | source = { registry = "https://pypi.org/simple" } 630 | sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } 631 | wheels = [ 632 | { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, 633 | ] 634 | 635 | [[package]] 636 | name = "platformdirs" 637 | version = "4.3.8" 638 | source = { registry = "https://pypi.org/simple" } 639 | sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } 640 | wheels = [ 641 | { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, 642 | ] 643 | 644 | [[package]] 645 | name = "pluggy" 646 | version = "1.6.0" 647 | source = { registry = "https://pypi.org/simple" } 648 | sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } 649 | wheels = [ 650 | { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, 651 | ] 652 | 653 | [[package]] 654 | name = "pre-commit" 655 | version = "4.2.0" 656 | source = { registry = "https://pypi.org/simple" } 657 | dependencies = [ 658 | { name = "cfgv" }, 659 | { name = "identify" }, 660 | { name = "nodeenv" }, 661 | { name = "pyyaml" }, 662 | { name = "virtualenv" }, 663 | ] 664 | sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" } 665 | wheels = [ 666 | { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" }, 667 | ] 668 | 669 | [[package]] 670 | name = "pycparser" 671 | version = "2.22" 672 | source = { registry = "https://pypi.org/simple" } 673 | sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } 674 | wheels = [ 675 | { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, 676 | ] 677 | 678 | [[package]] 679 | name = "pydantic" 680 | version = "2.11.3" 681 | source = { registry = "https://pypi.org/simple" } 682 | dependencies = [ 683 | { name = "annotated-types" }, 684 | { name = "pydantic-core" }, 685 | { name = "typing-extensions" }, 686 | { name = "typing-inspection" }, 687 | ] 688 | sdist = { url = "https://files.pythonhosted.org/packages/10/2e/ca897f093ee6c5f3b0bee123ee4465c50e75431c3d5b6a3b44a47134e891/pydantic-2.11.3.tar.gz", hash = "sha256:7471657138c16adad9322fe3070c0116dd6c3ad8d649300e3cbdfe91f4db4ec3", size = 785513, upload-time = "2025-04-08T13:27:06.399Z" } 689 | wheels = [ 690 | { url = "https://files.pythonhosted.org/packages/b0/1d/407b29780a289868ed696d1616f4aad49d6388e5a77f567dcd2629dcd7b8/pydantic-2.11.3-py3-none-any.whl", hash = "sha256:a082753436a07f9ba1289c6ffa01cd93db3548776088aa917cc43b63f68fa60f", size = 443591, upload-time = "2025-04-08T13:27:03.789Z" }, 691 | ] 692 | 693 | [[package]] 694 | name = "pydantic-core" 695 | version = "2.33.1" 696 | source = { registry = "https://pypi.org/simple" } 697 | dependencies = [ 698 | { name = "typing-extensions" }, 699 | ] 700 | sdist = { url = "https://files.pythonhosted.org/packages/17/19/ed6a078a5287aea7922de6841ef4c06157931622c89c2a47940837b5eecd/pydantic_core-2.33.1.tar.gz", hash = "sha256:bcc9c6fdb0ced789245b02b7d6603e17d1563064ddcfc36f046b61c0c05dd9df", size = 434395, upload-time = "2025-04-02T09:49:41.8Z" } 701 | wheels = [ 702 | { url = "https://files.pythonhosted.org/packages/c8/ce/3cb22b07c29938f97ff5f5bb27521f95e2ebec399b882392deb68d6c440e/pydantic_core-2.33.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1293d7febb995e9d3ec3ea09caf1a26214eec45b0f29f6074abb004723fc1de8", size = 2026640, upload-time = "2025-04-02T09:47:25.394Z" }, 703 | { url = "https://files.pythonhosted.org/packages/19/78/f381d643b12378fee782a72126ec5d793081ef03791c28a0fd542a5bee64/pydantic_core-2.33.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99b56acd433386c8f20be5c4000786d1e7ca0523c8eefc995d14d79c7a081498", size = 1852649, upload-time = "2025-04-02T09:47:27.417Z" }, 704 | { url = "https://files.pythonhosted.org/packages/9d/2b/98a37b80b15aac9eb2c6cfc6dbd35e5058a352891c5cce3a8472d77665a6/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35a5ec3fa8c2fe6c53e1b2ccc2454398f95d5393ab398478f53e1afbbeb4d939", size = 1892472, upload-time = "2025-04-02T09:47:29.006Z" }, 705 | { url = "https://files.pythonhosted.org/packages/4e/d4/3c59514e0f55a161004792b9ff3039da52448f43f5834f905abef9db6e4a/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b172f7b9d2f3abc0efd12e3386f7e48b576ef309544ac3a63e5e9cdd2e24585d", size = 1977509, upload-time = "2025-04-02T09:47:33.464Z" }, 706 | { url = "https://files.pythonhosted.org/packages/a9/b6/c2c7946ef70576f79a25db59a576bce088bdc5952d1b93c9789b091df716/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9097b9f17f91eea659b9ec58148c0747ec354a42f7389b9d50701610d86f812e", size = 2128702, upload-time = "2025-04-02T09:47:34.812Z" }, 707 | { url = "https://files.pythonhosted.org/packages/88/fe/65a880f81e3f2a974312b61f82a03d85528f89a010ce21ad92f109d94deb/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc77ec5b7e2118b152b0d886c7514a4653bcb58c6b1d760134a9fab915f777b3", size = 2679428, upload-time = "2025-04-02T09:47:37.315Z" }, 708 | { url = "https://files.pythonhosted.org/packages/6f/ff/4459e4146afd0462fb483bb98aa2436d69c484737feaceba1341615fb0ac/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3d15245b08fa4a84cefc6c9222e6f37c98111c8679fbd94aa145f9a0ae23d", size = 2008753, upload-time = "2025-04-02T09:47:39.013Z" }, 709 | { url = "https://files.pythonhosted.org/packages/7c/76/1c42e384e8d78452ededac8b583fe2550c84abfef83a0552e0e7478ccbc3/pydantic_core-2.33.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef99779001d7ac2e2461d8ab55d3373fe7315caefdbecd8ced75304ae5a6fc6b", size = 2114849, upload-time = "2025-04-02T09:47:40.427Z" }, 710 | { url = "https://files.pythonhosted.org/packages/00/72/7d0cf05095c15f7ffe0eb78914b166d591c0eed72f294da68378da205101/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fc6bf8869e193855e8d91d91f6bf59699a5cdfaa47a404e278e776dd7f168b39", size = 2069541, upload-time = "2025-04-02T09:47:42.01Z" }, 711 | { url = "https://files.pythonhosted.org/packages/b3/69/94a514066bb7d8be499aa764926937409d2389c09be0b5107a970286ef81/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:b1caa0bc2741b043db7823843e1bde8aaa58a55a58fda06083b0569f8b45693a", size = 2239225, upload-time = "2025-04-02T09:47:43.425Z" }, 712 | { url = "https://files.pythonhosted.org/packages/84/b0/e390071eadb44b41f4f54c3cef64d8bf5f9612c92686c9299eaa09e267e2/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ec259f62538e8bf364903a7d0d0239447059f9434b284f5536e8402b7dd198db", size = 2248373, upload-time = "2025-04-02T09:47:44.979Z" }, 713 | { url = "https://files.pythonhosted.org/packages/d6/b2/288b3579ffc07e92af66e2f1a11be3b056fe1214aab314748461f21a31c3/pydantic_core-2.33.1-cp312-cp312-win32.whl", hash = "sha256:e14f369c98a7c15772b9da98987f58e2b509a93235582838bd0d1d8c08b68fda", size = 1907034, upload-time = "2025-04-02T09:47:46.843Z" }, 714 | { url = "https://files.pythonhosted.org/packages/02/28/58442ad1c22b5b6742b992ba9518420235adced665513868f99a1c2638a5/pydantic_core-2.33.1-cp312-cp312-win_amd64.whl", hash = "sha256:1c607801d85e2e123357b3893f82c97a42856192997b95b4d8325deb1cd0c5f4", size = 1956848, upload-time = "2025-04-02T09:47:48.404Z" }, 715 | { url = "https://files.pythonhosted.org/packages/a1/eb/f54809b51c7e2a1d9f439f158b8dd94359321abcc98767e16fc48ae5a77e/pydantic_core-2.33.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d13f0276806ee722e70a1c93da19748594f19ac4299c7e41237fc791d1861ea", size = 1903986, upload-time = "2025-04-02T09:47:49.839Z" }, 716 | { url = "https://files.pythonhosted.org/packages/7a/24/eed3466a4308d79155f1cdd5c7432c80ddcc4530ba8623b79d5ced021641/pydantic_core-2.33.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:70af6a21237b53d1fe7b9325b20e65cbf2f0a848cf77bed492b029139701e66a", size = 2033551, upload-time = "2025-04-02T09:47:51.648Z" }, 717 | { url = "https://files.pythonhosted.org/packages/ab/14/df54b1a0bc9b6ded9b758b73139d2c11b4e8eb43e8ab9c5847c0a2913ada/pydantic_core-2.33.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:282b3fe1bbbe5ae35224a0dbd05aed9ccabccd241e8e6b60370484234b456266", size = 1852785, upload-time = "2025-04-02T09:47:53.149Z" }, 718 | { url = "https://files.pythonhosted.org/packages/fa/96/e275f15ff3d34bb04b0125d9bc8848bf69f25d784d92a63676112451bfb9/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b315e596282bbb5822d0c7ee9d255595bd7506d1cb20c2911a4da0b970187d3", size = 1897758, upload-time = "2025-04-02T09:47:55.006Z" }, 719 | { url = "https://files.pythonhosted.org/packages/b7/d8/96bc536e975b69e3a924b507d2a19aedbf50b24e08c80fb00e35f9baaed8/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1dfae24cf9921875ca0ca6a8ecb4bb2f13c855794ed0d468d6abbec6e6dcd44a", size = 1986109, upload-time = "2025-04-02T09:47:56.532Z" }, 720 | { url = "https://files.pythonhosted.org/packages/90/72/ab58e43ce7e900b88cb571ed057b2fcd0e95b708a2e0bed475b10130393e/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6dd8ecfde08d8bfadaea669e83c63939af76f4cf5538a72597016edfa3fad516", size = 2129159, upload-time = "2025-04-02T09:47:58.088Z" }, 721 | { url = "https://files.pythonhosted.org/packages/dc/3f/52d85781406886c6870ac995ec0ba7ccc028b530b0798c9080531b409fdb/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f593494876eae852dc98c43c6f260f45abdbfeec9e4324e31a481d948214764", size = 2680222, upload-time = "2025-04-02T09:47:59.591Z" }, 722 | { url = "https://files.pythonhosted.org/packages/f4/56/6e2ef42f363a0eec0fd92f74a91e0ac48cd2e49b695aac1509ad81eee86a/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:948b73114f47fd7016088e5186d13faf5e1b2fe83f5e320e371f035557fd264d", size = 2006980, upload-time = "2025-04-02T09:48:01.397Z" }, 723 | { url = "https://files.pythonhosted.org/packages/4c/c0/604536c4379cc78359f9ee0aa319f4aedf6b652ec2854953f5a14fc38c5a/pydantic_core-2.33.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e11f3864eb516af21b01e25fac915a82e9ddad3bb0fb9e95a246067398b435a4", size = 2120840, upload-time = "2025-04-02T09:48:03.056Z" }, 724 | { url = "https://files.pythonhosted.org/packages/1f/46/9eb764814f508f0edfb291a0f75d10854d78113fa13900ce13729aaec3ae/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:549150be302428b56fdad0c23c2741dcdb5572413776826c965619a25d9c6bde", size = 2072518, upload-time = "2025-04-02T09:48:04.662Z" }, 725 | { url = "https://files.pythonhosted.org/packages/42/e3/fb6b2a732b82d1666fa6bf53e3627867ea3131c5f39f98ce92141e3e3dc1/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:495bc156026efafd9ef2d82372bd38afce78ddd82bf28ef5276c469e57c0c83e", size = 2248025, upload-time = "2025-04-02T09:48:06.226Z" }, 726 | { url = "https://files.pythonhosted.org/packages/5c/9d/fbe8fe9d1aa4dac88723f10a921bc7418bd3378a567cb5e21193a3c48b43/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ec79de2a8680b1a67a07490bddf9636d5c2fab609ba8c57597e855fa5fa4dacd", size = 2254991, upload-time = "2025-04-02T09:48:08.114Z" }, 727 | { url = "https://files.pythonhosted.org/packages/aa/99/07e2237b8a66438d9b26482332cda99a9acccb58d284af7bc7c946a42fd3/pydantic_core-2.33.1-cp313-cp313-win32.whl", hash = "sha256:ee12a7be1742f81b8a65b36c6921022301d466b82d80315d215c4c691724986f", size = 1915262, upload-time = "2025-04-02T09:48:09.708Z" }, 728 | { url = "https://files.pythonhosted.org/packages/8a/f4/e457a7849beeed1e5defbcf5051c6f7b3c91a0624dd31543a64fc9adcf52/pydantic_core-2.33.1-cp313-cp313-win_amd64.whl", hash = "sha256:ede9b407e39949d2afc46385ce6bd6e11588660c26f80576c11c958e6647bc40", size = 1956626, upload-time = "2025-04-02T09:48:11.288Z" }, 729 | { url = "https://files.pythonhosted.org/packages/20/d0/e8d567a7cff7b04e017ae164d98011f1e1894269fe8e90ea187a3cbfb562/pydantic_core-2.33.1-cp313-cp313-win_arm64.whl", hash = "sha256:aa687a23d4b7871a00e03ca96a09cad0f28f443690d300500603bd0adba4b523", size = 1909590, upload-time = "2025-04-02T09:48:12.861Z" }, 730 | { url = "https://files.pythonhosted.org/packages/ef/fd/24ea4302d7a527d672c5be06e17df16aabfb4e9fdc6e0b345c21580f3d2a/pydantic_core-2.33.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:401d7b76e1000d0dd5538e6381d28febdcacb097c8d340dde7d7fc6e13e9f95d", size = 1812963, upload-time = "2025-04-02T09:48:14.553Z" }, 731 | { url = "https://files.pythonhosted.org/packages/5f/95/4fbc2ecdeb5c1c53f1175a32d870250194eb2fdf6291b795ab08c8646d5d/pydantic_core-2.33.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aeb055a42d734c0255c9e489ac67e75397d59c6fbe60d155851e9782f276a9c", size = 1986896, upload-time = "2025-04-02T09:48:16.222Z" }, 732 | { url = "https://files.pythonhosted.org/packages/71/ae/fe31e7f4a62431222d8f65a3bd02e3fa7e6026d154a00818e6d30520ea77/pydantic_core-2.33.1-cp313-cp313t-win_amd64.whl", hash = "sha256:338ea9b73e6e109f15ab439e62cb3b78aa752c7fd9536794112e14bee02c8d18", size = 1931810, upload-time = "2025-04-02T09:48:17.97Z" }, 733 | ] 734 | 735 | [[package]] 736 | name = "pydantic-settings" 737 | version = "2.8.1" 738 | source = { registry = "https://pypi.org/simple" } 739 | dependencies = [ 740 | { name = "pydantic" }, 741 | { name = "python-dotenv" }, 742 | ] 743 | sdist = { url = "https://files.pythonhosted.org/packages/88/82/c79424d7d8c29b994fb01d277da57b0a9b09cc03c3ff875f9bd8a86b2145/pydantic_settings-2.8.1.tar.gz", hash = "sha256:d5c663dfbe9db9d5e1c646b2e161da12f0d734d422ee56f567d0ea2cee4e8585", size = 83550, upload-time = "2025-02-27T10:10:32.338Z" } 744 | wheels = [ 745 | { url = "https://files.pythonhosted.org/packages/0b/53/a64f03044927dc47aafe029c42a5b7aabc38dfb813475e0e1bf71c4a59d0/pydantic_settings-2.8.1-py3-none-any.whl", hash = "sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c", size = 30839, upload-time = "2025-02-27T10:10:30.711Z" }, 746 | ] 747 | 748 | [[package]] 749 | name = "pygments" 750 | version = "2.19.1" 751 | source = { registry = "https://pypi.org/simple" } 752 | sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } 753 | wheels = [ 754 | { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, 755 | ] 756 | 757 | [[package]] 758 | name = "pyperclip" 759 | version = "1.9.0" 760 | source = { registry = "https://pypi.org/simple" } 761 | sdist = { url = "https://files.pythonhosted.org/packages/30/23/2f0a3efc4d6a32f3b63cdff36cd398d9701d26cda58e3ab97ac79fb5e60d/pyperclip-1.9.0.tar.gz", hash = "sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310", size = 20961, upload-time = "2024-06-18T20:38:48.401Z" } 762 | 763 | [[package]] 764 | name = "pysocks" 765 | version = "1.7.1" 766 | source = { registry = "https://pypi.org/simple" } 767 | sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429, upload-time = "2019-09-20T02:07:35.714Z" } 768 | wheels = [ 769 | { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725, upload-time = "2019-09-20T02:06:22.938Z" }, 770 | ] 771 | 772 | [[package]] 773 | name = "pytest" 774 | version = "8.3.5" 775 | source = { registry = "https://pypi.org/simple" } 776 | dependencies = [ 777 | { name = "colorama", marker = "sys_platform == 'win32'" }, 778 | { name = "iniconfig" }, 779 | { name = "packaging" }, 780 | { name = "pluggy" }, 781 | ] 782 | sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } 783 | wheels = [ 784 | { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, 785 | ] 786 | 787 | [[package]] 788 | name = "pytest-cov" 789 | version = "6.1.1" 790 | source = { registry = "https://pypi.org/simple" } 791 | dependencies = [ 792 | { name = "coverage" }, 793 | { name = "pytest" }, 794 | ] 795 | sdist = { url = "https://files.pythonhosted.org/packages/25/69/5f1e57f6c5a39f81411b550027bf72842c4567ff5fd572bed1edc9e4b5d9/pytest_cov-6.1.1.tar.gz", hash = "sha256:46935f7aaefba760e716c2ebfbe1c216240b9592966e7da99ea8292d4d3e2a0a", size = 66857, upload-time = "2025-04-05T14:07:51.592Z" } 796 | wheels = [ 797 | { url = "https://files.pythonhosted.org/packages/28/d0/def53b4a790cfb21483016430ed828f64830dd981ebe1089971cd10cab25/pytest_cov-6.1.1-py3-none-any.whl", hash = "sha256:bddf29ed2d0ab6f4df17b4c55b0a657287db8684af9c42ea546b21b1041b3dde", size = 23841, upload-time = "2025-04-05T14:07:49.641Z" }, 798 | ] 799 | 800 | [[package]] 801 | name = "python-dotenv" 802 | version = "1.1.0" 803 | source = { registry = "https://pypi.org/simple" } 804 | sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920, upload-time = "2025-03-25T10:14:56.835Z" } 805 | wheels = [ 806 | { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256, upload-time = "2025-03-25T10:14:55.034Z" }, 807 | ] 808 | 809 | [[package]] 810 | name = "pywin32-ctypes" 811 | version = "0.2.3" 812 | source = { registry = "https://pypi.org/simple" } 813 | sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" } 814 | wheels = [ 815 | { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" }, 816 | ] 817 | 818 | [[package]] 819 | name = "pyyaml" 820 | version = "6.0.2" 821 | source = { registry = "https://pypi.org/simple" } 822 | sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } 823 | wheels = [ 824 | { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, 825 | { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, 826 | { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, 827 | { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, 828 | { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, 829 | { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, 830 | { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, 831 | { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, 832 | { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, 833 | { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, 834 | { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, 835 | { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, 836 | { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, 837 | { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, 838 | { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, 839 | { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, 840 | { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, 841 | { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, 842 | ] 843 | 844 | [[package]] 845 | name = "readchar" 846 | version = "4.2.1" 847 | source = { registry = "https://pypi.org/simple" } 848 | sdist = { url = "https://files.pythonhosted.org/packages/dd/f8/8657b8cbb4ebeabfbdf991ac40eca8a1d1bd012011bd44ad1ed10f5cb494/readchar-4.2.1.tar.gz", hash = "sha256:91ce3faf07688de14d800592951e5575e9c7a3213738ed01d394dcc949b79adb", size = 9685, upload-time = "2024-11-04T18:28:07.757Z" } 849 | wheels = [ 850 | { url = "https://files.pythonhosted.org/packages/a9/10/e4b1e0e5b6b6745c8098c275b69bc9d73e9542d5c7da4f137542b499ed44/readchar-4.2.1-py3-none-any.whl", hash = "sha256:a769305cd3994bb5fa2764aa4073452dc105a4ec39068ffe6efd3c20c60acc77", size = 9350, upload-time = "2024-11-04T18:28:02.859Z" }, 851 | ] 852 | 853 | [[package]] 854 | name = "requests" 855 | version = "2.32.3" 856 | source = { registry = "https://pypi.org/simple" } 857 | dependencies = [ 858 | { name = "certifi" }, 859 | { name = "charset-normalizer" }, 860 | { name = "idna" }, 861 | { name = "urllib3" }, 862 | ] 863 | sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } 864 | wheels = [ 865 | { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, 866 | ] 867 | 868 | [[package]] 869 | name = "rich" 870 | version = "14.0.0" 871 | source = { registry = "https://pypi.org/simple" } 872 | dependencies = [ 873 | { name = "markdown-it-py" }, 874 | { name = "pygments" }, 875 | ] 876 | sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } 877 | wheels = [ 878 | { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, 879 | ] 880 | 881 | [[package]] 882 | name = "ruff" 883 | version = "0.11.11" 884 | source = { registry = "https://pypi.org/simple" } 885 | sdist = { url = "https://files.pythonhosted.org/packages/b2/53/ae4857030d59286924a8bdb30d213d6ff22d8f0957e738d0289990091dd8/ruff-0.11.11.tar.gz", hash = "sha256:7774173cc7c1980e6bf67569ebb7085989a78a103922fb83ef3dfe230cd0687d", size = 4186707, upload-time = "2025-05-22T19:19:34.363Z" } 886 | wheels = [ 887 | { url = "https://files.pythonhosted.org/packages/b1/14/f2326676197bab099e2a24473158c21656fbf6a207c65f596ae15acb32b9/ruff-0.11.11-py3-none-linux_armv6l.whl", hash = "sha256:9924e5ae54125ed8958a4f7de320dab7380f6e9fa3195e3dc3b137c6842a0092", size = 10229049, upload-time = "2025-05-22T19:18:45.516Z" }, 888 | { url = "https://files.pythonhosted.org/packages/9a/f3/bff7c92dd66c959e711688b2e0768e486bbca46b2f35ac319bb6cce04447/ruff-0.11.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c8a93276393d91e952f790148eb226658dd275cddfde96c6ca304873f11d2ae4", size = 11053601, upload-time = "2025-05-22T19:18:49.269Z" }, 889 | { url = "https://files.pythonhosted.org/packages/e2/38/8e1a3efd0ef9d8259346f986b77de0f62c7a5ff4a76563b6b39b68f793b9/ruff-0.11.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d6e333dbe2e6ae84cdedefa943dfd6434753ad321764fd937eef9d6b62022bcd", size = 10367421, upload-time = "2025-05-22T19:18:51.754Z" }, 890 | { url = "https://files.pythonhosted.org/packages/b4/50/557ad9dd4fb9d0bf524ec83a090a3932d284d1a8b48b5906b13b72800e5f/ruff-0.11.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7885d9a5e4c77b24e8c88aba8c80be9255fa22ab326019dac2356cff42089fc6", size = 10581980, upload-time = "2025-05-22T19:18:54.011Z" }, 891 | { url = "https://files.pythonhosted.org/packages/c4/b2/e2ed82d6e2739ece94f1bdbbd1d81b712d3cdaf69f0a1d1f1a116b33f9ad/ruff-0.11.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1b5ab797fcc09121ed82e9b12b6f27e34859e4227080a42d090881be888755d4", size = 10089241, upload-time = "2025-05-22T19:18:56.041Z" }, 892 | { url = "https://files.pythonhosted.org/packages/3d/9f/b4539f037a5302c450d7c695c82f80e98e48d0d667ecc250e6bdeb49b5c3/ruff-0.11.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e231ff3132c1119ece836487a02785f099a43992b95c2f62847d29bace3c75ac", size = 11699398, upload-time = "2025-05-22T19:18:58.248Z" }, 893 | { url = "https://files.pythonhosted.org/packages/61/fb/32e029d2c0b17df65e6eaa5ce7aea5fbeaed22dddd9fcfbbf5fe37c6e44e/ruff-0.11.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:a97c9babe1d4081037a90289986925726b802d180cca784ac8da2bbbc335f709", size = 12427955, upload-time = "2025-05-22T19:19:00.981Z" }, 894 | { url = "https://files.pythonhosted.org/packages/6e/e3/160488dbb11f18c8121cfd588e38095ba779ae208292765972f7732bfd95/ruff-0.11.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8c4ddcbe8a19f59f57fd814b8b117d4fcea9bee7c0492e6cf5fdc22cfa563c8", size = 12069803, upload-time = "2025-05-22T19:19:03.258Z" }, 895 | { url = "https://files.pythonhosted.org/packages/ff/16/3b006a875f84b3d0bff24bef26b8b3591454903f6f754b3f0a318589dcc3/ruff-0.11.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6224076c344a7694c6fbbb70d4f2a7b730f6d47d2a9dc1e7f9d9bb583faf390b", size = 11242630, upload-time = "2025-05-22T19:19:05.871Z" }, 896 | { url = "https://files.pythonhosted.org/packages/65/0d/0338bb8ac0b97175c2d533e9c8cdc127166de7eb16d028a43c5ab9e75abd/ruff-0.11.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:882821fcdf7ae8db7a951df1903d9cb032bbe838852e5fc3c2b6c3ab54e39875", size = 11507310, upload-time = "2025-05-22T19:19:08.584Z" }, 897 | { url = "https://files.pythonhosted.org/packages/6f/bf/d7130eb26174ce9b02348b9f86d5874eafbf9f68e5152e15e8e0a392e4a3/ruff-0.11.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:dcec2d50756463d9df075a26a85a6affbc1b0148873da3997286caf1ce03cae1", size = 10441144, upload-time = "2025-05-22T19:19:13.621Z" }, 898 | { url = "https://files.pythonhosted.org/packages/b3/f3/4be2453b258c092ff7b1761987cf0749e70ca1340cd1bfb4def08a70e8d8/ruff-0.11.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:99c28505ecbaeb6594701a74e395b187ee083ee26478c1a795d35084d53ebd81", size = 10081987, upload-time = "2025-05-22T19:19:15.821Z" }, 899 | { url = "https://files.pythonhosted.org/packages/6c/6e/dfa4d2030c5b5c13db158219f2ec67bf333e8a7748dccf34cfa2a6ab9ebc/ruff-0.11.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9263f9e5aa4ff1dec765e99810f1cc53f0c868c5329b69f13845f699fe74f639", size = 11073922, upload-time = "2025-05-22T19:19:18.104Z" }, 900 | { url = "https://files.pythonhosted.org/packages/ff/f4/f7b0b0c3d32b593a20ed8010fa2c1a01f2ce91e79dda6119fcc51d26c67b/ruff-0.11.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:64ac6f885e3ecb2fdbb71de2701d4e34526651f1e8503af8fb30d4915a3fe345", size = 11568537, upload-time = "2025-05-22T19:19:20.889Z" }, 901 | { url = "https://files.pythonhosted.org/packages/d2/46/0e892064d0adc18bcc81deed9aaa9942a27fd2cd9b1b7791111ce468c25f/ruff-0.11.11-py3-none-win32.whl", hash = "sha256:1adcb9a18802268aaa891ffb67b1c94cd70578f126637118e8099b8e4adcf112", size = 10536492, upload-time = "2025-05-22T19:19:23.642Z" }, 902 | { url = "https://files.pythonhosted.org/packages/1b/d9/232e79459850b9f327e9f1dc9c047a2a38a6f9689e1ec30024841fc4416c/ruff-0.11.11-py3-none-win_amd64.whl", hash = "sha256:748b4bb245f11e91a04a4ff0f96e386711df0a30412b9fe0c74d5bdc0e4a531f", size = 11612562, upload-time = "2025-05-22T19:19:27.013Z" }, 903 | { url = "https://files.pythonhosted.org/packages/ce/eb/09c132cff3cc30b2e7244191dcce69437352d6d6709c0adf374f3e6f476e/ruff-0.11.11-py3-none-win_arm64.whl", hash = "sha256:6c51f136c0364ab1b774767aa8b86331bd8e9d414e2d107db7a2189f35ea1f7b", size = 10735951, upload-time = "2025-05-22T19:19:30.043Z" }, 904 | ] 905 | 906 | [[package]] 907 | name = "runs" 908 | version = "1.2.2" 909 | source = { registry = "https://pypi.org/simple" } 910 | dependencies = [ 911 | { name = "xmod" }, 912 | ] 913 | sdist = { url = "https://files.pythonhosted.org/packages/26/6d/b9aace390f62db5d7d2c77eafce3d42774f27f1829d24fa9b6f598b3ef71/runs-1.2.2.tar.gz", hash = "sha256:9dc1815e2895cfb3a48317b173b9f1eac9ba5549b36a847b5cc60c3bf82ecef1", size = 5474, upload-time = "2024-01-25T14:44:01.563Z" } 914 | wheels = [ 915 | { url = "https://files.pythonhosted.org/packages/86/d6/17caf2e4af1dec288477a0cbbe4a96fbc9b8a28457dce3f1f452630ce216/runs-1.2.2-py3-none-any.whl", hash = "sha256:0980dcbc25aba1505f307ac4f0e9e92cbd0be2a15a1e983ee86c24c87b839dfd", size = 7033, upload-time = "2024-01-25T14:43:59.959Z" }, 916 | ] 917 | 918 | [[package]] 919 | name = "secretstorage" 920 | version = "3.3.3" 921 | source = { registry = "https://pypi.org/simple" } 922 | dependencies = [ 923 | { name = "cryptography" }, 924 | { name = "jeepney" }, 925 | ] 926 | sdist = { url = "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", size = 19739, upload-time = "2022-08-13T16:22:46.976Z" } 927 | wheels = [ 928 | { url = "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99", size = 15221, upload-time = "2022-08-13T16:22:44.457Z" }, 929 | ] 930 | 931 | [[package]] 932 | name = "selenium" 933 | version = "4.33.0" 934 | source = { registry = "https://pypi.org/simple" } 935 | dependencies = [ 936 | { name = "certifi" }, 937 | { name = "trio" }, 938 | { name = "trio-websocket" }, 939 | { name = "typing-extensions" }, 940 | { name = "urllib3", extra = ["socks"] }, 941 | { name = "websocket-client" }, 942 | ] 943 | sdist = { url = "https://files.pythonhosted.org/packages/5f/7e/4145666dd275760b56d0123a9439915af167932dd6caa19b5f8b281ae297/selenium-4.33.0.tar.gz", hash = "sha256:d90974db95d2cdeb34d2fb1b13f03dc904f53e6c5d228745b0635ada10cd625d", size = 882387, upload-time = "2025-05-23T17:45:22.046Z" } 944 | wheels = [ 945 | { url = "https://files.pythonhosted.org/packages/7e/c0/092fde36918574e144613de73ba43c36ab8d31e7d36bb44c35261909452d/selenium-4.33.0-py3-none-any.whl", hash = "sha256:af9ea757813918bddfe05cc677bf63c8a0cd277ebf8474b3dd79caa5727fca85", size = 9370835, upload-time = "2025-05-23T17:45:19.448Z" }, 946 | ] 947 | 948 | [[package]] 949 | name = "shellingham" 950 | version = "1.5.4" 951 | source = { registry = "https://pypi.org/simple" } 952 | sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } 953 | wheels = [ 954 | { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, 955 | ] 956 | 957 | [[package]] 958 | name = "six" 959 | version = "1.17.0" 960 | source = { registry = "https://pypi.org/simple" } 961 | sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } 962 | wheels = [ 963 | { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, 964 | ] 965 | 966 | [[package]] 967 | name = "sniffio" 968 | version = "1.3.1" 969 | source = { registry = "https://pypi.org/simple" } 970 | sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } 971 | wheels = [ 972 | { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, 973 | ] 974 | 975 | [[package]] 976 | name = "sortedcontainers" 977 | version = "2.4.0" 978 | source = { registry = "https://pypi.org/simple" } 979 | sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } 980 | wheels = [ 981 | { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, 982 | ] 983 | 984 | [[package]] 985 | name = "sse-starlette" 986 | version = "2.2.1" 987 | source = { registry = "https://pypi.org/simple" } 988 | dependencies = [ 989 | { name = "anyio" }, 990 | { name = "starlette" }, 991 | ] 992 | sdist = { url = "https://files.pythonhosted.org/packages/71/a4/80d2a11af59fe75b48230846989e93979c892d3a20016b42bb44edb9e398/sse_starlette-2.2.1.tar.gz", hash = "sha256:54470d5f19274aeed6b2d473430b08b4b379ea851d953b11d7f1c4a2c118b419", size = 17376, upload-time = "2024-12-25T09:09:30.616Z" } 993 | wheels = [ 994 | { url = "https://files.pythonhosted.org/packages/d9/e0/5b8bd393f27f4a62461c5cf2479c75a2cc2ffa330976f9f00f5f6e4f50eb/sse_starlette-2.2.1-py3-none-any.whl", hash = "sha256:6410a3d3ba0c89e7675d4c273a301d64649c03a5ef1ca101f10b47f895fd0e99", size = 10120, upload-time = "2024-12-25T09:09:26.761Z" }, 995 | ] 996 | 997 | [[package]] 998 | name = "starlette" 999 | version = "0.46.1" 1000 | source = { registry = "https://pypi.org/simple" } 1001 | dependencies = [ 1002 | { name = "anyio" }, 1003 | ] 1004 | sdist = { url = "https://files.pythonhosted.org/packages/04/1b/52b27f2e13ceedc79a908e29eac426a63465a1a01248e5f24aa36a62aeb3/starlette-0.46.1.tar.gz", hash = "sha256:3c88d58ee4bd1bb807c0d1acb381838afc7752f9ddaec81bbe4383611d833230", size = 2580102, upload-time = "2025-03-08T10:55:34.504Z" } 1005 | wheels = [ 1006 | { url = "https://files.pythonhosted.org/packages/a0/4b/528ccf7a982216885a1ff4908e886b8fb5f19862d1962f56a3fce2435a70/starlette-0.46.1-py3-none-any.whl", hash = "sha256:77c74ed9d2720138b25875133f3a2dae6d854af2ec37dceb56aef370c1d8a227", size = 71995, upload-time = "2025-03-08T10:55:32.662Z" }, 1007 | ] 1008 | 1009 | [[package]] 1010 | name = "trio" 1011 | version = "0.30.0" 1012 | source = { registry = "https://pypi.org/simple" } 1013 | dependencies = [ 1014 | { name = "attrs" }, 1015 | { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, 1016 | { name = "idna" }, 1017 | { name = "outcome" }, 1018 | { name = "sniffio" }, 1019 | { name = "sortedcontainers" }, 1020 | ] 1021 | sdist = { url = "https://files.pythonhosted.org/packages/01/c1/68d582b4d3a1c1f8118e18042464bb12a7c1b75d64d75111b297687041e3/trio-0.30.0.tar.gz", hash = "sha256:0781c857c0c81f8f51e0089929a26b5bb63d57f927728a5586f7e36171f064df", size = 593776, upload-time = "2025-04-21T00:48:19.507Z" } 1022 | wheels = [ 1023 | { url = "https://files.pythonhosted.org/packages/69/8e/3f6dfda475ecd940e786defe6df6c500734e686c9cd0a0f8ef6821e9b2f2/trio-0.30.0-py3-none-any.whl", hash = "sha256:3bf4f06b8decf8d3cf00af85f40a89824669e2d033bb32469d34840edcfc22a5", size = 499194, upload-time = "2025-04-21T00:48:17.167Z" }, 1024 | ] 1025 | 1026 | [[package]] 1027 | name = "trio-websocket" 1028 | version = "0.12.2" 1029 | source = { registry = "https://pypi.org/simple" } 1030 | dependencies = [ 1031 | { name = "outcome" }, 1032 | { name = "trio" }, 1033 | { name = "wsproto" }, 1034 | ] 1035 | sdist = { url = "https://files.pythonhosted.org/packages/d1/3c/8b4358e81f2f2cfe71b66a267f023a91db20a817b9425dd964873796980a/trio_websocket-0.12.2.tar.gz", hash = "sha256:22c72c436f3d1e264d0910a3951934798dcc5b00ae56fc4ee079d46c7cf20fae", size = 33549, upload-time = "2025-02-25T05:16:58.947Z" } 1036 | wheels = [ 1037 | { url = "https://files.pythonhosted.org/packages/c7/19/eb640a397bba49ba49ef9dbe2e7e5c04202ba045b6ce2ec36e9cadc51e04/trio_websocket-0.12.2-py3-none-any.whl", hash = "sha256:df605665f1db533f4a386c94525870851096a223adcb97f72a07e8b4beba45b6", size = 21221, upload-time = "2025-02-25T05:16:57.545Z" }, 1038 | ] 1039 | 1040 | [[package]] 1041 | name = "typer" 1042 | version = "0.15.2" 1043 | source = { registry = "https://pypi.org/simple" } 1044 | dependencies = [ 1045 | { name = "click" }, 1046 | { name = "rich" }, 1047 | { name = "shellingham" }, 1048 | { name = "typing-extensions" }, 1049 | ] 1050 | sdist = { url = "https://files.pythonhosted.org/packages/8b/6f/3991f0f1c7fcb2df31aef28e0594d8d54b05393a0e4e34c65e475c2a5d41/typer-0.15.2.tar.gz", hash = "sha256:ab2fab47533a813c49fe1f16b1a370fd5819099c00b119e0633df65f22144ba5", size = 100711, upload-time = "2025-02-27T19:17:34.807Z" } 1051 | wheels = [ 1052 | { url = "https://files.pythonhosted.org/packages/7f/fc/5b29fea8cee020515ca82cc68e3b8e1e34bb19a3535ad854cac9257b414c/typer-0.15.2-py3-none-any.whl", hash = "sha256:46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc", size = 45061, upload-time = "2025-02-27T19:17:32.111Z" }, 1053 | ] 1054 | 1055 | [[package]] 1056 | name = "typing-extensions" 1057 | version = "4.13.2" 1058 | source = { registry = "https://pypi.org/simple" } 1059 | sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967, upload-time = "2025-04-10T14:19:05.416Z" } 1060 | wheels = [ 1061 | { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806, upload-time = "2025-04-10T14:19:03.967Z" }, 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "typing-inspection" 1066 | version = "0.4.0" 1067 | source = { registry = "https://pypi.org/simple" } 1068 | dependencies = [ 1069 | { name = "typing-extensions" }, 1070 | ] 1071 | sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222, upload-time = "2025-02-25T17:27:59.638Z" } 1072 | wheels = [ 1073 | { url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125, upload-time = "2025-02-25T17:27:57.754Z" }, 1074 | ] 1075 | 1076 | [[package]] 1077 | name = "urllib3" 1078 | version = "2.4.0" 1079 | source = { registry = "https://pypi.org/simple" } 1080 | sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } 1081 | wheels = [ 1082 | { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, 1083 | ] 1084 | 1085 | [package.optional-dependencies] 1086 | socks = [ 1087 | { name = "pysocks" }, 1088 | ] 1089 | 1090 | [[package]] 1091 | name = "uvicorn" 1092 | version = "0.34.0" 1093 | source = { registry = "https://pypi.org/simple" } 1094 | dependencies = [ 1095 | { name = "click" }, 1096 | { name = "h11" }, 1097 | ] 1098 | sdist = { url = "https://files.pythonhosted.org/packages/4b/4d/938bd85e5bf2edeec766267a5015ad969730bb91e31b44021dfe8b22df6c/uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9", size = 76568, upload-time = "2024-12-15T13:33:30.42Z" } 1099 | wheels = [ 1100 | { url = "https://files.pythonhosted.org/packages/61/14/33a3a1352cfa71812a3a21e8c9bfb83f60b0011f5e36f2b1399d51928209/uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4", size = 62315, upload-time = "2024-12-15T13:33:27.467Z" }, 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "virtualenv" 1105 | version = "20.31.2" 1106 | source = { registry = "https://pypi.org/simple" } 1107 | dependencies = [ 1108 | { name = "distlib" }, 1109 | { name = "filelock" }, 1110 | { name = "platformdirs" }, 1111 | ] 1112 | sdist = { url = "https://files.pythonhosted.org/packages/56/2c/444f465fb2c65f40c3a104fd0c495184c4f2336d65baf398e3c75d72ea94/virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af", size = 6076316, upload-time = "2025-05-08T17:58:23.811Z" } 1113 | wheels = [ 1114 | { url = "https://files.pythonhosted.org/packages/f3/40/b1c265d4b2b62b58576588510fc4d1fe60a86319c8de99fd8e9fec617d2c/virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11", size = 6057982, upload-time = "2025-05-08T17:58:21.15Z" }, 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "wcwidth" 1119 | version = "0.2.13" 1120 | source = { registry = "https://pypi.org/simple" } 1121 | sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" } 1122 | wheels = [ 1123 | { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" }, 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "websocket-client" 1128 | version = "1.8.0" 1129 | source = { registry = "https://pypi.org/simple" } 1130 | sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648, upload-time = "2024-04-23T22:16:16.976Z" } 1131 | wheels = [ 1132 | { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826, upload-time = "2024-04-23T22:16:14.422Z" }, 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "wsproto" 1137 | version = "1.2.0" 1138 | source = { registry = "https://pypi.org/simple" } 1139 | dependencies = [ 1140 | { name = "h11" }, 1141 | ] 1142 | sdist = { url = "https://files.pythonhosted.org/packages/c9/4a/44d3c295350d776427904d73c189e10aeae66d7f555bb2feee16d1e4ba5a/wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065", size = 53425, upload-time = "2022-08-23T19:58:21.447Z" } 1143 | wheels = [ 1144 | { url = "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736", size = 24226, upload-time = "2022-08-23T19:58:19.96Z" }, 1145 | ] 1146 | 1147 | [[package]] 1148 | name = "xmod" 1149 | version = "1.8.1" 1150 | source = { registry = "https://pypi.org/simple" } 1151 | sdist = { url = "https://files.pythonhosted.org/packages/72/b2/e3edc608823348e628a919e1d7129e641997afadd946febdd704aecc5881/xmod-1.8.1.tar.gz", hash = "sha256:38c76486b9d672c546d57d8035df0beb7f4a9b088bc3fb2de5431ae821444377", size = 3988, upload-time = "2024-01-04T18:03:17.663Z" } 1152 | wheels = [ 1153 | { url = "https://files.pythonhosted.org/packages/33/6b/0dc75b64a764ea1cb8e4c32d1fb273c147304d4e5483cd58be482dc62e45/xmod-1.8.1-py3-none-any.whl", hash = "sha256:a24e9458a4853489042522bdca9e50ee2eac5ab75c809a91150a8a7f40670d48", size = 4610, upload-time = "2024-01-04T18:03:16.078Z" }, 1154 | ] 1155 | --------------------------------------------------------------------------------