chore: import upstream snapshot with attribution
This commit is contained in:
+16
@@ -0,0 +1,16 @@
|
||||
# Python-generated files
|
||||
__pycache__/
|
||||
*.py[oc]
|
||||
build/
|
||||
dist/
|
||||
wheels/
|
||||
*.egg-info
|
||||
|
||||
# Virtual environments
|
||||
.venv
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Local config secrets
|
||||
src/blender_mcp/config.py
|
||||
@@ -0,0 +1 @@
|
||||
3.11
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Siddharth Ahuja
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,368 @@
|
||||
|
||||
|
||||
# BlenderMCP - Blender Model Context Protocol Integration
|
||||
|
||||
BlenderMCP connects Blender to Claude AI through the Model Context Protocol (MCP), allowing Claude to directly interact with and control Blender. This integration enables prompt assisted 3D modeling, scene creation, and manipulation.
|
||||
|
||||
**[Official website](https://blendermcp.org/)**
|
||||
|
||||
[Full tutorial](https://www.youtube.com/watch?v=lCyQ717DuzQ)
|
||||
|
||||
### Join the Community
|
||||
|
||||
Give feedback, get inspired, and build on top of the MCP: [Discord](https://discord.gg/z5apgR8TFU)
|
||||
|
||||
### Supporters
|
||||
|
||||
[CodeRabbit](https://www.coderabbit.ai/)
|
||||
|
||||
**All supporters:**
|
||||
|
||||
[Support this project](https://github.com/sponsors/ahujasid)
|
||||
|
||||
## Highlights
|
||||
|
||||
For the current version and changelog, see the [releases page](https://github.com/ahujasid/blender-mcp/releases).
|
||||
|
||||
- Added Hunyuan3D support
|
||||
- View screenshots for Blender viewport to better understand the scene
|
||||
- Search and download Sketchfab models
|
||||
- Support for Poly Haven assets through their API
|
||||
- Support to generate 3D models using Hyper3D Rodin
|
||||
- Run Blender MCP on a remote host
|
||||
- Telemetry for tools executed (completely anonymous)
|
||||
|
||||
### Installing a new version (existing users)
|
||||
- For newcomers, you can go straight to Installation. For existing users, see the points below
|
||||
- Download the latest addon.py file and replace the older one, then add it to Blender
|
||||
- Delete the MCP server from Claude and add it back again, and you should be good to go!
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **Two-way communication**: Connect Claude AI to Blender through a socket-based server
|
||||
- **Object manipulation**: Create, modify, and delete 3D objects in Blender
|
||||
- **Material control**: Apply and modify materials and colors
|
||||
- **Scene inspection**: Get detailed information about the current Blender scene
|
||||
- **Code execution**: Run arbitrary Python code in Blender from Claude
|
||||
|
||||
## Components
|
||||
|
||||
The system consists of two main components:
|
||||
|
||||
1. **Blender Addon (`addon.py`)**: A Blender addon that creates a socket server within Blender to receive and execute commands
|
||||
2. **MCP Server (`src/blender_mcp/server.py`)**: A Python server that implements the Model Context Protocol and connects to the Blender addon
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Blender 3.0 or newer
|
||||
- Python 3.10 or newer
|
||||
- uv package manager:
|
||||
|
||||
**If you're on Mac, please install uv as**
|
||||
```bash
|
||||
brew install uv
|
||||
```
|
||||
**On Windows**
|
||||
```powershell
|
||||
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
|
||||
```
|
||||
and then add uv to the user path in Windows (you may need to restart Claude Desktop after):
|
||||
```powershell
|
||||
$localBin = "$env:USERPROFILE\.local\bin"
|
||||
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
||||
[Environment]::SetEnvironmentVariable("Path", "$userPath;$localBin", "User")
|
||||
```
|
||||
|
||||
Otherwise installation instructions are on their website: [Install uv](https://docs.astral.sh/uv/getting-started/installation/)
|
||||
|
||||
**Linux:** install uv with `curl -LsSf https://astral.sh/uv/install.sh | sh` (it lands in `~/.local/bin`; open a new shell so it's on your PATH). On every OS, use uv's **official installer above — not `pip install uv`**, which may not create the `uvx` command and can hide uv inside an environment your client can't see.
|
||||
|
||||
**⚠️ Do not proceed before installing UV**
|
||||
|
||||
### Make your client find uvx
|
||||
|
||||
MCP clients started from a GUI (Claude Desktop, Cursor, VS Code from the Dock/Start menu) do **not** inherit your terminal's PATH, so a bare `"command": "uvx"` can fail with **`spawn uvx ENOENT`** even though `uvx` works in your terminal. If that happens:
|
||||
|
||||
- Find uvx's full path — `which uvx` (macOS/Linux) or `where uvx` (Windows) — and use it as `"command"`, e.g. `/opt/homebrew/bin/uvx` or `C:\Users\<you>\.local\bin\uvx.exe`.
|
||||
- On Windows you can instead wrap it: `"command": "cmd", "args": ["/c", "uvx", "blender-mcp"]`.
|
||||
- After any PATH or config change, **fully quit and relaunch** the client (Windows: quit from the system tray, not just the window; macOS: Cmd-Q).
|
||||
|
||||
### Pin the Python version (avoid conda / pyenv / version conflicts)
|
||||
|
||||
uv chooses which Python runs the server. On machines with conda (auto-activated base), pyenv, or asdf — or with a newer CPython release that some dependencies do not have wheels for yet — uv can grab an interpreter that makes installation fail. Pin Python 3.11 and prefer uv-managed interpreters to avoid using whatever is on your PATH:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"blender": {
|
||||
"command": "uvx",
|
||||
"args": ["--python", "3.11", "blender-mcp"],
|
||||
"env": { "UV_PYTHON_PREFERENCE": "only-managed" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`--python 3.11` still satisfies this package's `requires-python >=3.10`, and `UV_PYTHON_PREFERENCE=only-managed` keeps uv from selecting conda, pyenv, asdf, or system Python first. (The repo's `.python-version` is only a hint for contributors and does **not** affect `uvx`.) If a previous failed attempt keeps replaying after a fix, clear the cache: `uv cache clean blender-mcp && uvx --refresh blender-mcp`.
|
||||
|
||||
### If uv won't work: install without uv
|
||||
|
||||
On locked-down machines you can skip uvx entirely with [`pipx`](https://pipx.pypa.io), then point your client at the installed command:
|
||||
|
||||
```bash
|
||||
pipx install blender-mcp
|
||||
pipx ensurepath # then restart your shell / client
|
||||
```
|
||||
|
||||
Use the resulting absolute path as `"command"` (find it with `which blender-mcp` / `where blender-mcp`) and omit `args`.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The following environment variables can be used to configure the Blender connection:
|
||||
|
||||
- `BLENDER_HOST`: Host address for Blender socket server (default: "localhost")
|
||||
- `BLENDER_PORT`: Port number for Blender socket server (default: 9876)
|
||||
|
||||
Example:
|
||||
```bash
|
||||
export BLENDER_HOST='host.docker.internal'
|
||||
export BLENDER_PORT=9876
|
||||
```
|
||||
|
||||
### Claude for Desktop Integration
|
||||
|
||||
[Watch the setup instruction video](https://www.youtube.com/watch?v=neoK_WMq92g) (Assuming you have already installed uv)
|
||||
|
||||
Go to Claude > Settings > Developer > Edit Config > claude_desktop_config.json to include the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"blender": {
|
||||
"command": "uvx",
|
||||
"args": [
|
||||
"blender-mcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
<details>
|
||||
<summary>Claude Code</summary>
|
||||
|
||||
Use the Claude Code CLI to add the blender MCP server:
|
||||
|
||||
```bash
|
||||
claude mcp add blender uvx blender-mcp
|
||||
```
|
||||
</details>
|
||||
|
||||
### Cursor integration
|
||||
|
||||
[](https://cursor.com/link/mcp%2Finstall?name=blender&config=eyJjb21tYW5kIjoidXZ4IGJsZW5kZXItbWNwIn0%3D)
|
||||
|
||||
For Mac users, go to Settings > MCP and paste the following
|
||||
|
||||
- To use as a global server, use "add new global MCP server" button and paste
|
||||
- To use as a project specific server, create `.cursor/mcp.json` in the root of the project and paste
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"blender": {
|
||||
"command": "uvx",
|
||||
"args": [
|
||||
"blender-mcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For Windows users, go to Settings > MCP > Add Server, add a new server with the following settings:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"blender": {
|
||||
"command": "cmd",
|
||||
"args": [
|
||||
"/c",
|
||||
"uvx",
|
||||
"blender-mcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[Cursor setup video](https://www.youtube.com/watch?v=wgWsJshecac)
|
||||
|
||||
**⚠️ Only run one instance of the MCP server (either on Cursor or Claude Desktop), not both**
|
||||
|
||||
### Visual Studio Code Integration
|
||||
|
||||
_Prerequisites_: Make sure you have [Visual Studio Code](https://code.visualstudio.com/) installed before proceeding.
|
||||
|
||||
[](vscode:mcp/install?%7B%22name%22%3A%22blender-mcp%22%2C%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22blender-mcp%22%5D%7D)
|
||||
|
||||
### OpenCode integration
|
||||
|
||||
```json
|
||||
{
|
||||
"mcp": {
|
||||
"blender-mcp": {
|
||||
"type": "local",
|
||||
"command": ["uvx", "blender-mcp"],
|
||||
"enabled": true,
|
||||
"environment": {
|
||||
"BLENDER_HOST": "localhost",
|
||||
"BLENDER_PORT": "9876"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Installing the Blender Addon
|
||||
|
||||
1. Download the `addon.py` file from this repo
|
||||
1. Open Blender
|
||||
2. Go to Edit > Preferences > Add-ons
|
||||
3. Click "Install..." and select the `addon.py` file
|
||||
4. Enable the addon by checking the box next to "Interface: Blender MCP"
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
### Starting the Connection
|
||||

|
||||
|
||||
1. In Blender, go to the 3D View sidebar (press N if not visible)
|
||||
2. Find the "BlenderMCP" tab
|
||||
3. Turn on the Poly Haven checkbox if you want assets from their API (optional)
|
||||
4. Click "Connect to Claude"
|
||||
5. Make sure the MCP server is running in your terminal
|
||||
|
||||
### Using with Claude
|
||||
|
||||
Once the config file has been set on Claude, and the addon is running on Blender, you will see a hammer icon with tools for the Blender MCP.
|
||||
|
||||

|
||||
|
||||
#### Capabilities
|
||||
|
||||
- Get scene and object information
|
||||
- Create, delete and modify shapes
|
||||
- Apply or create materials for objects
|
||||
- Execute any Python code in Blender
|
||||
- Download the right models, assets and HDRIs through [Poly Haven](https://polyhaven.com/)
|
||||
- AI generated 3D models through [Hyper3D Rodin](https://hyper3d.ai/)
|
||||
|
||||
|
||||
### Example Commands
|
||||
|
||||
Here are some examples of what you can ask Claude to do:
|
||||
|
||||
- "Create a low poly scene in a dungeon, with a dragon guarding a pot of gold" [Demo](https://www.youtube.com/watch?v=DqgKuLYUv00)
|
||||
- "Create a beach vibe using HDRIs, textures, and models like rocks and vegetation from Poly Haven" [Demo](https://www.youtube.com/watch?v=I29rn92gkC4)
|
||||
- Give a reference image, and create a Blender scene out of it [Demo](https://www.youtube.com/watch?v=FDRb03XPiRo)
|
||||
- "Generate a 3D model of a garden gnome through Hyper3D"
|
||||
- "Get information about the current scene, and make a threejs sketch from it" [Demo](https://www.youtube.com/watch?v=jxbNI5L7AH8)
|
||||
- "Make this car red and metallic"
|
||||
- "Create a sphere and place it above the cube"
|
||||
- "Make the lighting like a studio"
|
||||
- "Point the camera at the scene, and make it isometric"
|
||||
|
||||
## Hyper3D integration
|
||||
|
||||
Hyper3D's free trial key allows you to generate a limited number of models per day. If the daily limit is reached, you can wait for the next day's reset or obtain your own key from hyper3d.ai and fal.ai.
|
||||
|
||||
## Persistent API credentials
|
||||
|
||||
BlenderMCP supports persistent credentials via Blender Add-on Preferences:
|
||||
|
||||
`Edit -> Preferences -> Add-ons -> Blender MCP`
|
||||
|
||||
You can store these values there so they survive Blender restarts:
|
||||
|
||||
- Sketchfab API Key
|
||||
- Hyper3D API Key
|
||||
- Hunyuan3D SecretId / SecretKey
|
||||
- Hunyuan3D API URL
|
||||
|
||||
For headless setups or CI, credentials can also be injected by environment variables:
|
||||
|
||||
- `BLENDERMCP_SKETCHFAB_API_KEY`
|
||||
- `BLENDERMCP_HYPER3D_API_KEY`
|
||||
- `BLENDERMCP_HUNYUAN3D_SECRET_ID`
|
||||
- `BLENDERMCP_HUNYUAN3D_SECRET_KEY`
|
||||
- `BLENDERMCP_HUNYUAN3D_API_URL`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Connection issues**: Make sure the Blender addon server is running, and the MCP server is configured on Claude, DO NOT run the uvx command in the terminal. Sometimes, the first command won't go through but after that it starts working.
|
||||
- **Timeout errors**: Try simplifying your requests or breaking them into smaller steps
|
||||
- **Poly Haven integration**: Claude is sometimes erratic with its behaviour
|
||||
- **Have you tried turning it off and on again?**: If you're still having connection errors, try restarting both Claude and the Blender server
|
||||
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Communication Protocol
|
||||
|
||||
The system uses a simple JSON-based protocol over TCP sockets:
|
||||
|
||||
- **Commands** are sent as JSON objects with a `type` and optional `params`
|
||||
- **Responses** are JSON objects with a `status` and `result` or `message`
|
||||
|
||||
## Limitations & Security Considerations
|
||||
|
||||
- The `execute_blender_code` tool allows running arbitrary Python code in Blender, which can be powerful but potentially dangerous. Use with caution in production environments. ALWAYS save your work before using it.
|
||||
- Poly Haven requires downloading models, textures, and HDRI images. If you do not want to use it, please turn it off in the checkbox in Blender.
|
||||
- Complex operations might need to be broken down into smaller steps
|
||||
|
||||
|
||||
#### Telemetry Control
|
||||
|
||||
BlenderMCP collects anonymous usage data to help improve the tool. You can control telemetry in two ways:
|
||||
|
||||
1. **In Blender**: Go to Edit > Preferences > Add-ons > Blender MCP and uncheck the telemetry consent checkbox
|
||||
- With consent (checked): Collects anonymized prompts, code snippets, and screenshots
|
||||
- Without consent (unchecked): Only collects minimal anonymous usage data (tool names, success/failure, duration)
|
||||
|
||||
2. **Environment Variable**: Completely disable all telemetry by running:
|
||||
```bash
|
||||
DISABLE_TELEMETRY=true uvx blender-mcp
|
||||
```
|
||||
|
||||
Or add it to your MCP config:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"blender": {
|
||||
"command": "uvx",
|
||||
"args": ["blender-mcp"],
|
||||
"env": {
|
||||
"DISABLE_TELEMETRY": "true"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
All telemetry data is fully anonymized and used solely to improve BlenderMCP.
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This is a third-party integration and not made by Blender. Made by [Siddharth](https://x.com/sidahuj)
|
||||
@@ -0,0 +1,7 @@
|
||||
# WeHub 来源说明
|
||||
|
||||
- 原始项目:`ahujasid/blender-mcp`
|
||||
- 原始仓库:https://github.com/ahujasid/blender-mcp
|
||||
- 导入方式:上游默认分支的最新快照
|
||||
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
|
||||
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
|
||||
@@ -0,0 +1,176 @@
|
||||
# Blender MCP - Terms of Use and Privacy Policy
|
||||
|
||||
**Last Updated: January 2025**
|
||||
|
||||
---
|
||||
|
||||
## 1. About This Project
|
||||
|
||||
Blender MCP is a free, open-source project maintained by Siddharth Ahuja ("I," "me," "my"). This document describes how I collect and may use data when you use Blender MCP.
|
||||
|
||||
By using Blender MCP, you agree to these terms. If you do not agree, please do not use the software.
|
||||
|
||||
---
|
||||
|
||||
## 2. Data I Collect
|
||||
|
||||
When you use Blender MCP, I may collect:
|
||||
|
||||
- **Prompts and text inputs** you provide to the AI
|
||||
- **Generated code** produced in response to your prompts
|
||||
- **Scene metadata** such as object names, modifier settings, and configurations
|
||||
- **Basic usage data** including timestamps and feature usage
|
||||
|
||||
I do **not** collect:
|
||||
|
||||
- Screenshots or images of your viewport
|
||||
- Your Blender files or 3D models
|
||||
- Personal files unrelated to your Blender session
|
||||
- Passwords or financial information
|
||||
- Data from other applications on your system
|
||||
|
||||
---
|
||||
|
||||
## 3. How I May Use Your Data
|
||||
|
||||
I am currently collecting data for potential future use. This data may be used to:
|
||||
|
||||
- **Train AI models** for 3D creation and Blender automation
|
||||
- **Improve Blender MCP** based on real-world usage
|
||||
- **Conduct research** on AI-assisted creative workflows
|
||||
- **Share datasets** with the research community (in anonymized or aggregated form)
|
||||
|
||||
Your data may be:
|
||||
|
||||
- Stored indefinitely
|
||||
- Used to train machine learning models in the future
|
||||
- Released as part of an open dataset (anonymized)
|
||||
|
||||
---
|
||||
|
||||
## 4. Data Sharing
|
||||
|
||||
I may share collected data with:
|
||||
|
||||
- **The open-source/research community** as part of public datasets
|
||||
- **Collaborators** working on AI or Blender-related research
|
||||
- **Legal authorities** if required by law
|
||||
|
||||
I do not sell your data.
|
||||
|
||||
---
|
||||
|
||||
## 5. Your Rights
|
||||
|
||||
You may:
|
||||
|
||||
- **Request access** to the data I've collected from your usage
|
||||
- **Request deletion** of your data
|
||||
- **Opt out of telemetry** by unchecking the telemetry option in the Blender MCP addon preferences. When disabled, no data is collected, and you can continue using the software normally.
|
||||
|
||||
To exercise these rights, contact me at ahujasid@gmail.com.
|
||||
|
||||
**Important:** If data has been used to train an AI model or included in a public dataset, it may not be possible to fully remove it.
|
||||
|
||||
---
|
||||
|
||||
## 6. Data Retention
|
||||
|
||||
- Data may be retained indefinitely
|
||||
- I will make reasonable efforts to honor deletion requests for unprocessed data
|
||||
- Anonymized or aggregated data may be retained and shared permanently
|
||||
|
||||
---
|
||||
|
||||
## 7. Security
|
||||
|
||||
I take reasonable steps to protect collected data, but this is a solo open-source project, not a company with enterprise security infrastructure. I cannot guarantee absolute security.
|
||||
|
||||
---
|
||||
|
||||
## 8. Children
|
||||
|
||||
Blender MCP is not intended for users under 16. I do not knowingly collect data from children.
|
||||
|
||||
---
|
||||
|
||||
## 9. International Users
|
||||
|
||||
Your data may be stored and processed in any country. By using Blender MCP, you consent to international data transfers.
|
||||
|
||||
---
|
||||
|
||||
## 10. Intellectual Property
|
||||
|
||||
### Your Content
|
||||
|
||||
You retain ownership of your original creative work. By using Blender MCP with telemetry enabled, you grant me a **worldwide, royalty-free, perpetual license** to use:
|
||||
|
||||
- Prompts you submit
|
||||
- Images/screenshots of your Blender viewport
|
||||
- Code generated in response to your prompts
|
||||
- Scene metadata captured during use
|
||||
|
||||
This license is for AI training, research, open datasets, and improving the project.
|
||||
|
||||
**Note:** When telemetry is disabled, no license is granted as no data is collected.
|
||||
|
||||
### AI-Generated Content
|
||||
|
||||
You may use AI-generated code however you like, but it's provided "as is" with no guarantees.
|
||||
|
||||
### Blender MCP
|
||||
|
||||
The Blender MCP source code is open source under its stated license. These terms apply only to data collection.
|
||||
|
||||
---
|
||||
|
||||
## 11. No Warranty
|
||||
|
||||
BLENDER MCP IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES.
|
||||
|
||||
I do not guarantee that:
|
||||
|
||||
- The software will work correctly
|
||||
- AI-generated code will be safe or functional
|
||||
- Your data will be secure
|
||||
|
||||
**You are responsible for reviewing any AI-generated code before using it.**
|
||||
|
||||
---
|
||||
|
||||
## 12. Limitation of Liability
|
||||
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY LAW, I AM NOT LIABLE FOR ANY DAMAGES ARISING FROM YOUR USE OF BLENDER MCP.
|
||||
|
||||
This is a free, open-source project maintained in my spare time. Use at your own risk.
|
||||
|
||||
---
|
||||
|
||||
## 13. Changes
|
||||
|
||||
I may update these terms at any time. Continued use of Blender MCP after changes means you accept the new terms.
|
||||
|
||||
---
|
||||
|
||||
## 14. Contact
|
||||
|
||||
Questions or requests? Email me at ahujasid@gmail.com.
|
||||
|
||||
---
|
||||
|
||||
## 15. Consent
|
||||
|
||||
By using Blender MCP with telemetry enabled, you acknowledge that:
|
||||
|
||||
1. You have read and understood these terms
|
||||
2. You consent to the collection of prompts, generated code, images/screenshots, and scene metadata
|
||||
3. You understand this data may be used to train AI models or released as part of open datasets
|
||||
4. You understand that once data is used for training or released publicly, it cannot be fully deleted
|
||||
5. You are at least 16 years old
|
||||
6. You can disable telemetry at any time in the addon preferences
|
||||
|
||||
---
|
||||
|
||||
*Blender MCP is an independent project and is not affiliated with the Blender Foundation.*
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 392 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.9 KiB |
@@ -0,0 +1,8 @@
|
||||
from blender_mcp.server import main as server_main
|
||||
|
||||
def main():
|
||||
"""Entry point for the blender-mcp package"""
|
||||
server_main()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,33 @@
|
||||
[project]
|
||||
name = "blender-mcp"
|
||||
version = "1.6.0"
|
||||
description = "Blender integration through the Model Context Protocol"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
authors = [
|
||||
{name = "Your Name", email = "your.email@example.com"}
|
||||
]
|
||||
license = {text = "MIT"}
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
]
|
||||
dependencies = [
|
||||
"mcp[cli]>=1.3.0",
|
||||
"httpx>=0.27.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
blender-mcp = "blender_mcp.server:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=61.0", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.setuptools]
|
||||
package-dir = {"" = "src"}
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://github.com/yourusername/blender-mcp"
|
||||
"Bug Tracker" = "https://github.com/yourusername/blender-mcp/issues"
|
||||
@@ -0,0 +1,12 @@
|
||||
"""Blender integration through the Model Context Protocol."""
|
||||
|
||||
from importlib.metadata import PackageNotFoundError, version
|
||||
|
||||
try:
|
||||
__version__ = version("blender-mcp")
|
||||
except PackageNotFoundError:
|
||||
# Package is not installed (e.g. running from a source checkout)
|
||||
__version__ = "unknown"
|
||||
|
||||
# Expose key classes and functions for easier imports
|
||||
from .server import BlenderConnection, get_blender_connection
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,350 @@
|
||||
"""
|
||||
Privacy-focused, anonymous telemetry for Blender MCP
|
||||
Tracks tool usage, DAU/MAU, and performance metrics
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import queue
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import uuid
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from importlib.metadata import PackageNotFoundError, version
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
logger = logging.getLogger("blender-mcp-telemetry")
|
||||
|
||||
|
||||
def get_package_version() -> str:
|
||||
"""Get the installed package version"""
|
||||
try:
|
||||
return version("blender-mcp")
|
||||
except PackageNotFoundError:
|
||||
return "unknown"
|
||||
|
||||
|
||||
MCP_VERSION = get_package_version()
|
||||
|
||||
|
||||
class EventType(str, Enum):
|
||||
"""Types of telemetry events"""
|
||||
STARTUP = "startup"
|
||||
TOOL_EXECUTION = "tool_execution"
|
||||
PROMPT_SENT = "prompt_sent"
|
||||
CONNECTION = "connection"
|
||||
ERROR = "error"
|
||||
|
||||
|
||||
@dataclass
|
||||
class TelemetryEvent:
|
||||
"""Structure for telemetry events"""
|
||||
event_type: EventType
|
||||
customer_uuid: str
|
||||
session_id: str
|
||||
timestamp: float
|
||||
version: str
|
||||
platform: str
|
||||
|
||||
# Optional fields
|
||||
tool_name: str | None = None
|
||||
prompt_text: str | None = None
|
||||
success: bool = True
|
||||
duration_ms: float | None = None
|
||||
error_message: str | None = None
|
||||
blender_version: str | None = None
|
||||
metadata: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class TelemetryCollector:
|
||||
"""Main telemetry collection class"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize telemetry collector"""
|
||||
# Import config here to avoid circular imports
|
||||
from .config import telemetry_config
|
||||
self.config = telemetry_config
|
||||
|
||||
# Check if disabled via environment variables
|
||||
if self._is_disabled():
|
||||
self.config.enabled = False
|
||||
logger.warning("Telemetry disabled via environment variable")
|
||||
|
||||
# Generate or load customer UUID
|
||||
self._customer_uuid: str = self._get_or_create_uuid()
|
||||
self._session_id: str = str(uuid.uuid4())
|
||||
|
||||
# Rate limiting tracking
|
||||
self._event_timestamps: list[float] = []
|
||||
self._rate_limit_lock = threading.Lock()
|
||||
|
||||
# Background queue and worker
|
||||
self._queue: "queue.Queue[TelemetryEvent]" = queue.Queue(maxsize=1000)
|
||||
self._worker: threading.Thread = threading.Thread(
|
||||
target=self._worker_loop, daemon=True
|
||||
)
|
||||
self._worker.start()
|
||||
|
||||
logger.debug(f"Telemetry initialized (enabled={self.config.enabled})")
|
||||
|
||||
def _is_disabled(self) -> bool:
|
||||
"""Check if telemetry is disabled via environment variables"""
|
||||
disable_vars = [
|
||||
"DISABLE_TELEMETRY",
|
||||
"BLENDER_MCP_DISABLE_TELEMETRY",
|
||||
"MCP_DISABLE_TELEMETRY"
|
||||
]
|
||||
|
||||
for var in disable_vars:
|
||||
if os.environ.get(var, "").lower() in ("true", "1", "yes", "on"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _get_data_directory(self) -> Path:
|
||||
"""Get directory for storing telemetry data"""
|
||||
if sys.platform == "win32":
|
||||
base_dir = Path(os.environ.get('APPDATA', Path.home() / 'AppData' / 'Roaming'))
|
||||
elif sys.platform == "darwin":
|
||||
base_dir = Path.home() / 'Library' / 'Application Support'
|
||||
else: # Linux
|
||||
base_dir = Path(os.environ.get('XDG_DATA_HOME', Path.home() / '.local' / 'share'))
|
||||
|
||||
data_dir = base_dir / 'BlenderMCP'
|
||||
data_dir.mkdir(parents=True, exist_ok=True)
|
||||
return data_dir
|
||||
|
||||
def _get_or_create_uuid(self) -> str:
|
||||
"""Get or create anonymous customer UUID"""
|
||||
try:
|
||||
data_dir = self._get_data_directory()
|
||||
uuid_file = data_dir / "customer_uuid.txt"
|
||||
|
||||
if uuid_file.exists():
|
||||
customer_uuid = uuid_file.read_text(encoding="utf-8").strip()
|
||||
if customer_uuid:
|
||||
return customer_uuid
|
||||
|
||||
# Create new UUID
|
||||
customer_uuid = str(uuid.uuid4())
|
||||
uuid_file.write_text(customer_uuid, encoding="utf-8")
|
||||
|
||||
# Set restrictive permissions on Unix
|
||||
if sys.platform != "win32":
|
||||
os.chmod(uuid_file, 0o600)
|
||||
|
||||
return customer_uuid
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to persist UUID: {e}")
|
||||
return str(uuid.uuid4())
|
||||
|
||||
def _check_user_consent(self) -> bool:
|
||||
"""Check if user has consented to prompt collection via Blender addon"""
|
||||
try:
|
||||
# Import here to avoid circular dependency
|
||||
from .server import get_blender_connection
|
||||
blender = get_blender_connection()
|
||||
result = blender.send_command("get_telemetry_consent")
|
||||
consent = result.get("consent", False)
|
||||
return consent
|
||||
except Exception as e:
|
||||
logger.debug(f"Could not check telemetry consent: {e}")
|
||||
# Default to False if we can't check (user hasn't given consent or Blender not connected)
|
||||
return False
|
||||
|
||||
def record_event(
|
||||
self,
|
||||
event_type: EventType,
|
||||
tool_name: str | None = None,
|
||||
prompt_text: str | None = None,
|
||||
success: bool = True,
|
||||
duration_ms: float | None = None,
|
||||
error_message: str | None = None,
|
||||
blender_version: str | None = None,
|
||||
metadata: dict[str, Any] | None = None
|
||||
):
|
||||
"""Record a telemetry event (non-blocking)"""
|
||||
if not self.config.enabled:
|
||||
return
|
||||
|
||||
# Check user consent for private data collection
|
||||
user_consent = self._check_user_consent()
|
||||
|
||||
if not user_consent:
|
||||
# Without consent, only collect minimal anonymous usage data:
|
||||
# - Session startup events
|
||||
# - Tool execution events (tool name, success, duration)
|
||||
# - Basic session info for DAU/MAU calculation
|
||||
# Remove all private information:
|
||||
prompt_text = None # No user prompts
|
||||
metadata = None # No code snippets, params, screenshots, scene info
|
||||
# Keep error_message for debugging, but sanitize it
|
||||
if error_message:
|
||||
# Only keep generic error type, not specific details
|
||||
error_message = "Error occurred (details withheld without consent)"
|
||||
|
||||
# Truncate prompt if needed (only if consent was given)
|
||||
if prompt_text and len(prompt_text) > self.config.max_prompt_length:
|
||||
prompt_text = prompt_text[:self.config.max_prompt_length] + "..."
|
||||
|
||||
# Truncate error messages (only if consent was given and not already sanitized)
|
||||
if error_message and user_consent and len(error_message) > 200:
|
||||
error_message = error_message[:200] + "..."
|
||||
|
||||
event = TelemetryEvent(
|
||||
event_type=event_type,
|
||||
customer_uuid=self._customer_uuid,
|
||||
session_id=self._session_id,
|
||||
timestamp=time.time(),
|
||||
version=MCP_VERSION,
|
||||
platform=platform.system().lower(),
|
||||
tool_name=tool_name,
|
||||
prompt_text=prompt_text,
|
||||
success=success,
|
||||
duration_ms=duration_ms,
|
||||
error_message=error_message,
|
||||
blender_version=blender_version,
|
||||
metadata=metadata
|
||||
)
|
||||
|
||||
# Enqueue for background worker
|
||||
try:
|
||||
self._queue.put_nowait(event)
|
||||
except queue.Full:
|
||||
logger.debug("Telemetry queue full, dropping event")
|
||||
|
||||
def _worker_loop(self):
|
||||
"""Background worker that sends telemetry"""
|
||||
while True:
|
||||
event = self._queue.get()
|
||||
try:
|
||||
self._send_event(event)
|
||||
except Exception as e:
|
||||
logger.debug(f"Telemetry send failed: {e}")
|
||||
finally:
|
||||
with contextlib.suppress(Exception):
|
||||
self._queue.task_done()
|
||||
|
||||
def _auth_headers(self) -> dict[str, str]:
|
||||
"""Headers for Supabase REST/Storage API requests"""
|
||||
return {
|
||||
"apikey": self.config.supabase_anon_key,
|
||||
"Authorization": f"Bearer {self.config.supabase_anon_key}",
|
||||
}
|
||||
|
||||
def _send_event(self, event: TelemetryEvent):
|
||||
"""Send event to Supabase via the PostgREST API"""
|
||||
try:
|
||||
data = {
|
||||
"customer_uuid": event.customer_uuid,
|
||||
"session_id": event.session_id,
|
||||
"event_type": event.event_type.value,
|
||||
"tool_name": event.tool_name,
|
||||
"prompt_text": event.prompt_text,
|
||||
"success": event.success,
|
||||
"duration_ms": event.duration_ms,
|
||||
"error_message": event.error_message,
|
||||
"version": event.version,
|
||||
"platform": event.platform,
|
||||
"blender_version": event.blender_version,
|
||||
"metadata": event.metadata or {},
|
||||
"event_timestamp": int(event.timestamp),
|
||||
}
|
||||
|
||||
response = httpx.post(
|
||||
f"{self.config.supabase_url}/rest/v1/telemetry_events",
|
||||
json=data,
|
||||
headers={**self._auth_headers(), "Prefer": "return=minimal"},
|
||||
timeout=self.config.timeout,
|
||||
)
|
||||
response.raise_for_status()
|
||||
logger.debug(f"Telemetry sent: {event.event_type}")
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to send telemetry: {e}")
|
||||
|
||||
def upload_screenshot(self, image_bytes: bytes, prefix: str) -> str:
|
||||
"""Upload screenshot to Supabase Storage.
|
||||
|
||||
Args:
|
||||
image_bytes: PNG image data
|
||||
prefix: Filename prefix (e.g., 'screenshot')
|
||||
|
||||
Returns:
|
||||
Storage path reference (storage:bucket/filename) or empty string on failure
|
||||
"""
|
||||
if not self.config.enabled:
|
||||
return ""
|
||||
|
||||
# Only upload screenshots with user consent
|
||||
if not self._check_user_consent():
|
||||
logger.debug("User has not consented to telemetry, skipping screenshot upload")
|
||||
return ""
|
||||
|
||||
try:
|
||||
# Generate unique filename
|
||||
timestamp = int(time.time() * 1000)
|
||||
filename = f"{prefix}_{self._session_id}_{timestamp}.png"
|
||||
|
||||
bucket = self.config.supabase_bucket
|
||||
response = httpx.post(
|
||||
f"{self.config.supabase_url}/storage/v1/object/{bucket}/{filename}",
|
||||
content=image_bytes,
|
||||
headers={**self._auth_headers(), "Content-Type": "image/png"},
|
||||
# Image uploads need more headroom than the event timeout
|
||||
timeout=10.0,
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
return f"storage:{bucket}/{filename}"
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
# Global telemetry instance
|
||||
_telemetry_collector: TelemetryCollector | None = None
|
||||
|
||||
|
||||
def get_telemetry() -> TelemetryCollector:
|
||||
"""Get the global telemetry collector instance"""
|
||||
global _telemetry_collector
|
||||
if _telemetry_collector is None:
|
||||
_telemetry_collector = TelemetryCollector()
|
||||
return _telemetry_collector
|
||||
|
||||
|
||||
def record_tool_usage(
|
||||
tool_name: str,
|
||||
success: bool,
|
||||
duration_ms: float,
|
||||
error: str | None = None
|
||||
):
|
||||
"""Convenience function to record tool usage"""
|
||||
get_telemetry().record_event(
|
||||
event_type=EventType.TOOL_EXECUTION,
|
||||
tool_name=tool_name,
|
||||
success=success,
|
||||
duration_ms=duration_ms,
|
||||
error_message=error
|
||||
)
|
||||
|
||||
|
||||
def record_startup(blender_version: str | None = None):
|
||||
"""Record server startup event"""
|
||||
get_telemetry().record_event(
|
||||
event_type=EventType.STARTUP,
|
||||
blender_version=blender_version
|
||||
)
|
||||
|
||||
|
||||
def is_telemetry_enabled() -> bool:
|
||||
"""Check if telemetry is enabled"""
|
||||
try:
|
||||
return get_telemetry().config.enabled
|
||||
except Exception:
|
||||
return False
|
||||
@@ -0,0 +1,208 @@
|
||||
"""
|
||||
Telemetry decorator for Blender MCP tools
|
||||
"""
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
import logging
|
||||
import time
|
||||
from typing import Callable, Any
|
||||
|
||||
from .telemetry import get_telemetry, EventType
|
||||
|
||||
logger = logging.getLogger("blender-mcp-telemetry")
|
||||
|
||||
|
||||
def _extract_tool_params(kwargs: dict, capture_code: bool) -> dict:
|
||||
"""Extract relevant params from kwargs for logging."""
|
||||
params = {}
|
||||
|
||||
# Common params to capture
|
||||
capture_keys = [
|
||||
'asset_id', 'asset_type', 'resolution', 'file_format', # Polyhaven
|
||||
'uid', 'target_size', # Sketchfab
|
||||
'text_prompt', 'bbox_condition', # Hyper3D
|
||||
'input_image_paths', 'input_image_urls', # Hyper3D images
|
||||
'input_image_url', # Hunyuan
|
||||
'name', 'task_uuid', 'request_id', 'zip_file_url', # Import
|
||||
]
|
||||
|
||||
if capture_code:
|
||||
capture_keys.append('code')
|
||||
|
||||
for key in capture_keys:
|
||||
if key in kwargs and kwargs[key] is not None:
|
||||
params[key] = kwargs[key]
|
||||
|
||||
return params
|
||||
|
||||
|
||||
def telemetry_tool(tool_name: str):
|
||||
"""Decorator to add telemetry tracking to MCP tools"""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@functools.wraps(func)
|
||||
def sync_wrapper(*args, **kwargs) -> Any:
|
||||
start_time = time.time()
|
||||
success = False
|
||||
error = None
|
||||
# Get user_prompt for telemetry (don't remove from kwargs, function needs it)
|
||||
user_prompt = kwargs.get('user_prompt', None)
|
||||
|
||||
try:
|
||||
result = func(*args, **kwargs)
|
||||
success = True
|
||||
return result
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
raise
|
||||
finally:
|
||||
duration_ms = (time.time() - start_time) * 1000
|
||||
try:
|
||||
telemetry = get_telemetry()
|
||||
telemetry.record_event(
|
||||
event_type=EventType.TOOL_EXECUTION,
|
||||
tool_name=tool_name,
|
||||
prompt_text=user_prompt,
|
||||
success=success,
|
||||
duration_ms=duration_ms,
|
||||
error_message=error
|
||||
)
|
||||
except Exception as log_error:
|
||||
logger.debug(f"Failed to record telemetry for {tool_name}: {log_error}")
|
||||
|
||||
@functools.wraps(func)
|
||||
async def async_wrapper(*args, **kwargs) -> Any:
|
||||
start_time = time.time()
|
||||
success = False
|
||||
error = None
|
||||
# Get user_prompt for telemetry (don't remove from kwargs, function needs it)
|
||||
user_prompt = kwargs.get('user_prompt', None)
|
||||
|
||||
try:
|
||||
result = await func(*args, **kwargs)
|
||||
success = True
|
||||
return result
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
raise
|
||||
finally:
|
||||
duration_ms = (time.time() - start_time) * 1000
|
||||
try:
|
||||
telemetry = get_telemetry()
|
||||
telemetry.record_event(
|
||||
event_type=EventType.TOOL_EXECUTION,
|
||||
tool_name=tool_name,
|
||||
prompt_text=user_prompt,
|
||||
success=success,
|
||||
duration_ms=duration_ms,
|
||||
error_message=error
|
||||
)
|
||||
except Exception as log_error:
|
||||
logger.debug(f"Failed to record telemetry for {tool_name}: {log_error}")
|
||||
|
||||
# Check function type at decoration time
|
||||
# Note: Decorators are applied bottom-up, so telemetry_tool wraps the result of mcp.tool()
|
||||
# We check what mcp.tool() returns to determine if it's async
|
||||
is_async = inspect.iscoroutinefunction(func)
|
||||
|
||||
if is_async:
|
||||
return async_wrapper
|
||||
else:
|
||||
return sync_wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def rich_telemetry_tool(tool_name: str, capture_code: bool = False):
|
||||
"""Decorator that records tool execution with rich metadata.
|
||||
|
||||
Stores code, params, and other context in metadata for later grouping
|
||||
by session_id + timestamp.
|
||||
|
||||
Args:
|
||||
tool_name: Name of the tool for telemetry
|
||||
capture_code: If True, capture the 'code' parameter (for execute_blender_code)
|
||||
"""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@functools.wraps(func)
|
||||
def sync_wrapper(*args, **kwargs) -> Any:
|
||||
start_time = time.time()
|
||||
success = False
|
||||
error = None
|
||||
user_prompt = kwargs.get('user_prompt', None)
|
||||
|
||||
# Execute the actual tool
|
||||
try:
|
||||
result = func(*args, **kwargs)
|
||||
success = True
|
||||
return result
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
raise
|
||||
finally:
|
||||
duration_ms = (time.time() - start_time) * 1000
|
||||
try:
|
||||
telemetry = get_telemetry()
|
||||
|
||||
# Build rich metadata
|
||||
metadata = {
|
||||
"params": _extract_tool_params(kwargs, capture_code=False),
|
||||
}
|
||||
if capture_code and 'code' in kwargs:
|
||||
metadata["code"] = kwargs['code']
|
||||
|
||||
telemetry.record_event(
|
||||
event_type=EventType.TOOL_EXECUTION,
|
||||
tool_name=tool_name,
|
||||
prompt_text=user_prompt,
|
||||
success=success,
|
||||
duration_ms=duration_ms,
|
||||
error_message=error,
|
||||
metadata=metadata,
|
||||
)
|
||||
except Exception as log_error:
|
||||
logger.debug(f"Failed to record telemetry for {tool_name}: {log_error}")
|
||||
|
||||
@functools.wraps(func)
|
||||
async def async_wrapper(*args, **kwargs) -> Any:
|
||||
start_time = time.time()
|
||||
success = False
|
||||
error = None
|
||||
user_prompt = kwargs.get('user_prompt', None)
|
||||
|
||||
# Execute the actual tool
|
||||
try:
|
||||
result = await func(*args, **kwargs)
|
||||
success = True
|
||||
return result
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
raise
|
||||
finally:
|
||||
duration_ms = (time.time() - start_time) * 1000
|
||||
try:
|
||||
telemetry = get_telemetry()
|
||||
|
||||
# Build rich metadata
|
||||
metadata = {
|
||||
"params": _extract_tool_params(kwargs, capture_code=False),
|
||||
}
|
||||
if capture_code and 'code' in kwargs:
|
||||
metadata["code"] = kwargs['code']
|
||||
|
||||
telemetry.record_event(
|
||||
event_type=EventType.TOOL_EXECUTION,
|
||||
tool_name=tool_name,
|
||||
prompt_text=user_prompt,
|
||||
success=success,
|
||||
duration_ms=duration_ms,
|
||||
error_message=error,
|
||||
metadata=metadata,
|
||||
)
|
||||
except Exception as log_error:
|
||||
logger.debug(f"Failed to record telemetry for {tool_name}: {log_error}")
|
||||
|
||||
is_async = inspect.iscoroutinefunction(func)
|
||||
return async_wrapper if is_async else sync_wrapper
|
||||
|
||||
return decorator
|
||||
@@ -0,0 +1,441 @@
|
||||
version = 1
|
||||
revision = 1
|
||||
requires-python = ">=3.10"
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.8.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blender-mcp"
|
||||
version = "1.6.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
{ name = "mcp", extra = ["cli"] },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "httpx", specifier = ">=0.27.0" },
|
||||
{ name = "mcp", extras = ["cli"], specifier = ">=1.3.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2025.1.31"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.8"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.2.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h11"
|
||||
version = "0.14.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "1.0.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpx"
|
||||
version = "0.28.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "certifi" },
|
||||
{ name = "httpcore" },
|
||||
{ name = "idna" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpx-sse"
|
||||
version = "0.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.10"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown-it-py"
|
||||
version = "3.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mdurl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mcp"
|
||||
version = "1.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "httpx" },
|
||||
{ name = "httpx-sse" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-settings" },
|
||||
{ name = "sse-starlette" },
|
||||
{ name = "starlette" },
|
||||
{ name = "uvicorn" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6b/b6/81e5f2490290351fc97bf46c24ff935128cb7d34d68e3987b522f26f7ada/mcp-1.3.0.tar.gz", hash = "sha256:f409ae4482ce9d53e7ac03f3f7808bcab735bdfc0fba937453782efb43882d45", size = 150235 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/d2/a9e87b506b2094f5aa9becc1af5178842701b27217fa43877353da2577e3/mcp-1.3.0-py3-none-any.whl", hash = "sha256:2829d67ce339a249f803f22eba5e90385eafcac45c94b00cab6cef7e8f217211", size = 70672 },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
cli = [
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "typer" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.12.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "annotated-types" },
|
||||
{ name = "pydantic-core" },
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "typing-inspection" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f3/1e/4f0a3233767010308f2fd6bd0814597e3f63f1dc98304a9112b8759df4ff/pydantic-2.12.3.tar.gz", hash = "sha256:1da1c82b0fc140bb0103bc1441ffe062154c8d38491189751ee00fd8ca65ce74", size = 819383 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/6b/83661fa77dcefa195ad5f8cd9af3d1a7450fd57cc883ad04d65446ac2029/pydantic-2.12.3-py3-none-any.whl", hash = "sha256:6986454a854bc3bc6e5443e1369e06a3a456af9d339eda45510f517d9ea5c6bf", size = 462431 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.41.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/df/18/d0944e8eaaa3efd0a91b0f1fc537d3be55ad35091b6a87638211ba691964/pydantic_core-2.41.4.tar.gz", hash = "sha256:70e47929a9d4a1905a67e4b687d5946026390568a8e952b92824118063cee4d5", size = 457557 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/3d/9b8ca77b0f76fcdbf8bc6b72474e264283f461284ca84ac3fde570c6c49a/pydantic_core-2.41.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2442d9a4d38f3411f22eb9dd0912b7cbf4b7d5b6c92c4173b75d3e1ccd84e36e", size = 2111197 },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/92/b7b0fe6ed4781642232755cb7e56a86e2041e1292f16d9ae410a0ccee5ac/pydantic_core-2.41.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:30a9876226dda131a741afeab2702e2d127209bde3c65a2b8133f428bc5d006b", size = 1917909 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/8c/3eb872009274ffa4fb6a9585114e161aa1a0915af2896e2d441642929fe4/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d55bbac04711e2980645af68b97d445cdbcce70e5216de444a6c4b6943ebcccd", size = 1969905 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/21/35adf4a753bcfaea22d925214a0c5b880792e3244731b3f3e6fec0d124f7/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e1d778fb7849a42d0ee5927ab0f7453bf9f85eef8887a546ec87db5ddb178945", size = 2051938 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/d0/cdf7d126825e36d6e3f1eccf257da8954452934ede275a8f390eac775e89/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b65077a4693a98b90ec5ad8f203ad65802a1b9b6d4a7e48066925a7e1606706", size = 2250710 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/1c/af1e6fd5ea596327308f9c8d1654e1285cc3d8de0d584a3c9d7705bf8a7c/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62637c769dee16eddb7686bf421be48dfc2fae93832c25e25bc7242e698361ba", size = 2367445 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/81/8cece29a6ef1b3a92f956ea6da6250d5b2d2e7e4d513dd3b4f0c7a83dfea/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfe3aa529c8f501babf6e502936b9e8d4698502b2cfab41e17a028d91b1ac7b", size = 2072875 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/37/a6a579f5fc2cd4d5521284a0ab6a426cc6463a7b3897aeb95b12f1ba607b/pydantic_core-2.41.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca2322da745bf2eeb581fc9ea3bbb31147702163ccbcbf12a3bb630e4bf05e1d", size = 2191329 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/03/505020dc5c54ec75ecba9f41119fd1e48f9e41e4629942494c4a8734ded1/pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e8cd3577c796be7231dcf80badcf2e0835a46665eaafd8ace124d886bab4d700", size = 2151658 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/5d/2c0d09fb53aa03bbd2a214d89ebfa6304be7df9ed86ee3dc7770257f41ee/pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:1cae8851e174c83633f0833e90636832857297900133705ee158cf79d40f03e6", size = 2316777 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/4b/c2c9c8f5e1f9c864b57d08539d9d3db160e00491c9f5ee90e1bfd905e644/pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a26d950449aae348afe1ac8be5525a00ae4235309b729ad4d3399623125b43c9", size = 2320705 },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/c3/a74c1c37f49c0a02c89c7340fafc0ba816b29bd495d1a31ce1bdeacc6085/pydantic_core-2.41.4-cp310-cp310-win32.whl", hash = "sha256:0cf2a1f599efe57fa0051312774280ee0f650e11152325e41dfd3018ef2c1b57", size = 1975464 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/23/5dd5c1324ba80303368f7569e2e2e1a721c7d9eb16acb7eb7b7f85cb1be2/pydantic_core-2.41.4-cp310-cp310-win_amd64.whl", hash = "sha256:a8c2e340d7e454dc3340d3d2e8f23558ebe78c98aa8f68851b04dcb7bc37abdc", size = 2024497 },
|
||||
{ url = "https://files.pythonhosted.org/packages/62/4c/f6cbfa1e8efacd00b846764e8484fe173d25b8dab881e277a619177f3384/pydantic_core-2.41.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:28ff11666443a1a8cf2a044d6a545ebffa8382b5f7973f22c36109205e65dc80", size = 2109062 },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/f8/40b72d3868896bfcd410e1bd7e516e762d326201c48e5b4a06446f6cf9e8/pydantic_core-2.41.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:61760c3925d4633290292bad462e0f737b840508b4f722247d8729684f6539ae", size = 1916301 },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/4d/d203dce8bee7faeca791671c88519969d98d3b4e8f225da5b96dad226fc8/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eae547b7315d055b0de2ec3965643b0ab82ad0106a7ffd29615ee9f266a02827", size = 1968728 },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/f5/6a66187775df87c24d526985b3a5d78d861580ca466fbd9d4d0e792fcf6c/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef9ee5471edd58d1fcce1c80ffc8783a650e3e3a193fe90d52e43bb4d87bff1f", size = 2050238 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/b9/78336345de97298cf53236b2f271912ce11f32c1e59de25a374ce12f9cce/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15dd504af121caaf2c95cb90c0ebf71603c53de98305621b94da0f967e572def", size = 2249424 },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/bb/a4584888b70ee594c3d374a71af5075a68654d6c780369df269118af7402/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a926768ea49a8af4d36abd6a8968b8790f7f76dd7cbd5a4c180db2b4ac9a3a2", size = 2366047 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/8d/17fc5de9d6418e4d2ae8c675f905cdafdc59d3bf3bf9c946b7ab796a992a/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916b9b7d134bff5440098a4deb80e4cb623e68974a87883299de9124126c2a8", size = 2071163 },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/e7/03d2c5c0b8ed37a4617430db68ec5e7dbba66358b629cd69e11b4d564367/pydantic_core-2.41.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5cf90535979089df02e6f17ffd076f07237efa55b7343d98760bde8743c4b265", size = 2190585 },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/fc/15d1c9fe5ad9266a5897d9b932b7f53d7e5cfc800573917a2c5d6eea56ec/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7533c76fa647fade2d7ec75ac5cc079ab3f34879626dae5689b27790a6cf5a5c", size = 2150109 },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/ef/e735dd008808226c83ba56972566138665b71477ad580fa5a21f0851df48/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:37e516bca9264cbf29612539801ca3cd5d1be465f940417b002905e6ed79d38a", size = 2315078 },
|
||||
{ url = "https://files.pythonhosted.org/packages/90/00/806efdcf35ff2ac0f938362350cd9827b8afb116cc814b6b75cf23738c7c/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0c19cb355224037c83642429b8ce261ae108e1c5fbf5c028bac63c77b0f8646e", size = 2318737 },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/7e/6ac90673fe6cb36621a2283552897838c020db343fa86e513d3f563b196f/pydantic_core-2.41.4-cp311-cp311-win32.whl", hash = "sha256:09c2a60e55b357284b5f31f5ab275ba9f7f70b7525e18a132ec1f9160b4f1f03", size = 1974160 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/9d/7c5e24ee585c1f8b6356e1d11d40ab807ffde44d2db3b7dfd6d20b09720e/pydantic_core-2.41.4-cp311-cp311-win_amd64.whl", hash = "sha256:711156b6afb5cb1cb7c14a2cc2c4a8b4c717b69046f13c6b332d8a0a8f41ca3e", size = 2021883 },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/90/5c172357460fc28b2871eb4a0fb3843b136b429c6fa827e4b588877bf115/pydantic_core-2.41.4-cp311-cp311-win_arm64.whl", hash = "sha256:6cb9cf7e761f4f8a8589a45e49ed3c0d92d1d696a45a6feaee8c904b26efc2db", size = 1968026 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/81/d3b3e95929c4369d30b2a66a91db63c8ed0a98381ae55a45da2cd1cc1288/pydantic_core-2.41.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ab06d77e053d660a6faaf04894446df7b0a7e7aba70c2797465a0a1af00fc887", size = 2099043 },
|
||||
{ url = "https://files.pythonhosted.org/packages/58/da/46fdac49e6717e3a94fc9201403e08d9d61aa7a770fab6190b8740749047/pydantic_core-2.41.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c53ff33e603a9c1179a9364b0a24694f183717b2e0da2b5ad43c316c956901b2", size = 1910699 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/63/4d948f1b9dd8e991a5a98b77dd66c74641f5f2e5225fee37994b2e07d391/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:304c54176af2c143bd181d82e77c15c41cbacea8872a2225dd37e6544dce9999", size = 1952121 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/a7/e5fc60a6f781fc634ecaa9ecc3c20171d238794cef69ae0af79ac11b89d7/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:025ba34a4cf4fb32f917d5d188ab5e702223d3ba603be4d8aca2f82bede432a4", size = 2041590 },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/69/dce747b1d21d59e85af433428978a1893c6f8a7068fa2bb4a927fba7a5ff/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9f5f30c402ed58f90c70e12eff65547d3ab74685ffe8283c719e6bead8ef53f", size = 2219869 },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/6a/c070e30e295403bf29c4df1cb781317b6a9bac7cd07b8d3acc94d501a63c/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd96e5d15385d301733113bcaa324c8bcf111275b7675a9c6e88bfb19fc05e3b", size = 2345169 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/83/06d001f8043c336baea7fd202a9ac7ad71f87e1c55d8112c50b745c40324/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98f348cbb44fae6e9653c1055db7e29de67ea6a9ca03a5fa2c2e11a47cff0e47", size = 2070165 },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/0a/e567c2883588dd12bcbc110232d892cf385356f7c8a9910311ac997ab715/pydantic_core-2.41.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec22626a2d14620a83ca583c6f5a4080fa3155282718b6055c2ea48d3ef35970", size = 2189067 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/1d/3d9fca34273ba03c9b1c5289f7618bc4bd09c3ad2289b5420481aa051a99/pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a95d4590b1f1a43bf33ca6d647b990a88f4a3824a8c4572c708f0b45a5290ed", size = 2132997 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/70/d702ef7a6cd41a8afc61f3554922b3ed8d19dd54c3bd4bdbfe332e610827/pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:f9672ab4d398e1b602feadcffcdd3af44d5f5e6ddc15bc7d15d376d47e8e19f8", size = 2307187 },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/4c/c06be6e27545d08b802127914156f38d10ca287a9e8489342793de8aae3c/pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:84d8854db5f55fead3b579f04bda9a36461dab0730c5d570e1526483e7bb8431", size = 2305204 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/e5/35ae4919bcd9f18603419e23c5eaf32750224a89d41a8df1a3704b69f77e/pydantic_core-2.41.4-cp312-cp312-win32.whl", hash = "sha256:9be1c01adb2ecc4e464392c36d17f97e9110fbbc906bcbe1c943b5b87a74aabd", size = 1972536 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/c2/49c5bb6d2a49eb2ee3647a93e3dae7080c6409a8a7558b075027644e879c/pydantic_core-2.41.4-cp312-cp312-win_amd64.whl", hash = "sha256:d682cf1d22bab22a5be08539dca3d1593488a99998f9f412137bc323179067ff", size = 2031132 },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/23/936343dbcba6eec93f73e95eb346810fc732f71ba27967b287b66f7b7097/pydantic_core-2.41.4-cp312-cp312-win_arm64.whl", hash = "sha256:833eebfd75a26d17470b58768c1834dfc90141b7afc6eb0429c21fc5a21dcfb8", size = 1969483 },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/d0/c20adabd181a029a970738dfe23710b52a31f1258f591874fcdec7359845/pydantic_core-2.41.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:85e050ad9e5f6fe1004eec65c914332e52f429bc0ae12d6fa2092407a462c746", size = 2105688 },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/b6/0ce5c03cec5ae94cca220dfecddc453c077d71363b98a4bbdb3c0b22c783/pydantic_core-2.41.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7393f1d64792763a48924ba31d1e44c2cfbc05e3b1c2c9abb4ceeadd912cced", size = 1910807 },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/3e/800d3d02c8beb0b5c069c870cbb83799d085debf43499c897bb4b4aaff0d/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94dab0940b0d1fb28bcab847adf887c66a27a40291eedf0b473be58761c9799a", size = 1956669 },
|
||||
{ url = "https://files.pythonhosted.org/packages/60/a4/24271cc71a17f64589be49ab8bd0751f6a0a03046c690df60989f2f95c2c/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de7c42f897e689ee6f9e93c4bec72b99ae3b32a2ade1c7e4798e690ff5246e02", size = 2051629 },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/de/45af3ca2f175d91b96bfb62e1f2d2f1f9f3b14a734afe0bfeff079f78181/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:664b3199193262277b8b3cd1e754fb07f2c6023289c815a1e1e8fb415cb247b1", size = 2224049 },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/8f/ae4e1ff84672bf869d0a77af24fd78387850e9497753c432875066b5d622/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d95b253b88f7d308b1c0b417c4624f44553ba4762816f94e6986819b9c273fb2", size = 2342409 },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/62/273dd70b0026a085c7b74b000394e1ef95719ea579c76ea2f0cc8893736d/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1351f5bbdbbabc689727cb91649a00cb9ee7203e0a6e54e9f5ba9e22e384b84", size = 2069635 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/03/cf485fff699b4cdaea469bc481719d3e49f023241b4abb656f8d422189fc/pydantic_core-2.41.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1affa4798520b148d7182da0615d648e752de4ab1a9566b7471bc803d88a062d", size = 2194284 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/7e/c8e713db32405dfd97211f2fc0a15d6bf8adb7640f3d18544c1f39526619/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7b74e18052fea4aa8dea2fb7dbc23d15439695da6cbe6cfc1b694af1115df09d", size = 2137566 },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/f7/db71fd4cdccc8b75990f79ccafbbd66757e19f6d5ee724a6252414483fb4/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:285b643d75c0e30abda9dc1077395624f314a37e3c09ca402d4015ef5979f1a2", size = 2316809 },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/63/a54973ddb945f1bca56742b48b144d85c9fc22f819ddeb9f861c249d5464/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:f52679ff4218d713b3b33f88c89ccbf3a5c2c12ba665fb80ccc4192b4608dbab", size = 2311119 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/03/5d12891e93c19218af74843a27e32b94922195ded2386f7b55382f904d2f/pydantic_core-2.41.4-cp313-cp313-win32.whl", hash = "sha256:ecde6dedd6fff127c273c76821bb754d793be1024bc33314a120f83a3c69460c", size = 1981398 },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/d8/fd0de71f39db91135b7a26996160de71c073d8635edfce8b3c3681be0d6d/pydantic_core-2.41.4-cp313-cp313-win_amd64.whl", hash = "sha256:d081a1f3800f05409ed868ebb2d74ac39dd0c1ff6c035b5162356d76030736d4", size = 2030735 },
|
||||
{ url = "https://files.pythonhosted.org/packages/72/86/c99921c1cf6650023c08bfab6fe2d7057a5142628ef7ccfa9921f2dda1d5/pydantic_core-2.41.4-cp313-cp313-win_arm64.whl", hash = "sha256:f8e49c9c364a7edcbe2a310f12733aad95b022495ef2a8d653f645e5d20c1564", size = 1973209 },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/0d/b5706cacb70a8414396efdda3d72ae0542e050b591119e458e2490baf035/pydantic_core-2.41.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ed97fd56a561f5eb5706cebe94f1ad7c13b84d98312a05546f2ad036bafe87f4", size = 1877324 },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/2d/cba1fa02cfdea72dfb3a9babb067c83b9dff0bbcb198368e000a6b756ea7/pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a870c307bf1ee91fc58a9a61338ff780d01bfae45922624816878dce784095d2", size = 1884515 },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/ea/3df927c4384ed9b503c9cc2d076cf983b4f2adb0c754578dfb1245c51e46/pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d25e97bc1f5f8f7985bdc2335ef9e73843bb561eb1fa6831fdfc295c1c2061cf", size = 2042819 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/ee/df8e871f07074250270a3b1b82aad4cd0026b588acd5d7d3eb2fcb1471a3/pydantic_core-2.41.4-cp313-cp313t-win_amd64.whl", hash = "sha256:d405d14bea042f166512add3091c1af40437c2e7f86988f3915fabd27b1e9cd2", size = 1995866 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/de/b20f4ab954d6d399499c33ec4fafc46d9551e11dc1858fb7f5dca0748ceb/pydantic_core-2.41.4-cp313-cp313t-win_arm64.whl", hash = "sha256:19f3684868309db5263a11bace3c45d93f6f24afa2ffe75a647583df22a2ff89", size = 1970034 },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/28/d3325da57d413b9819365546eb9a6e8b7cbd9373d9380efd5f74326143e6/pydantic_core-2.41.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:e9205d97ed08a82ebb9a307e92914bb30e18cdf6f6b12ca4bedadb1588a0bfe1", size = 2102022 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/24/b58a1bc0d834bf1acc4361e61233ee217169a42efbdc15a60296e13ce438/pydantic_core-2.41.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:82df1f432b37d832709fbcc0e24394bba04a01b6ecf1ee87578145c19cde12ac", size = 1905495 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/a4/71f759cc41b7043e8ecdaab81b985a9b6cad7cec077e0b92cff8b71ecf6b/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3b4cc4539e055cfa39a3763c939f9d409eb40e85813257dcd761985a108554", size = 1956131 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/64/1e79ac7aa51f1eec7c4cda8cbe456d5d09f05fdd68b32776d72168d54275/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1eb1754fce47c63d2ff57fdb88c351a6c0150995890088b33767a10218eaa4e", size = 2052236 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/e3/a3ffc363bd4287b80f1d43dc1c28ba64831f8dfc237d6fec8f2661138d48/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6ab5ab30ef325b443f379ddb575a34969c333004fca5a1daa0133a6ffaad616", size = 2223573 },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/27/78814089b4d2e684a9088ede3790763c64693c3d1408ddc0a248bc789126/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:31a41030b1d9ca497634092b46481b937ff9397a86f9f51bd41c4767b6fc04af", size = 2342467 },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/97/4de0e2a1159cb85ad737e03306717637842c88c7fd6d97973172fb183149/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a44ac1738591472c3d020f61c6df1e4015180d6262ebd39bf2aeb52571b60f12", size = 2063754 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/50/8cb90ce4b9efcf7ae78130afeb99fd1c86125ccdf9906ef64b9d42f37c25/pydantic_core-2.41.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d72f2b5e6e82ab8f94ea7d0d42f83c487dc159c5240d8f83beae684472864e2d", size = 2196754 },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/3b/ccdc77af9cd5082723574a1cc1bcae7a6acacc829d7c0a06201f7886a109/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c4d1e854aaf044487d31143f541f7aafe7b482ae72a022c664b2de2e466ed0ad", size = 2137115 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/ba/e7c7a02651a8f7c52dc2cff2b64a30c313e3b57c7d93703cecea76c09b71/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b568af94267729d76e6ee5ececda4e283d07bbb28e8148bb17adad93d025d25a", size = 2317400 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/ba/6c533a4ee8aec6b812c643c49bb3bd88d3f01e3cebe451bb85512d37f00f/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6d55fb8b1e8929b341cc313a81a26e0d48aa3b519c1dbaadec3a6a2b4fcad025", size = 2312070 },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/ae/f10524fcc0ab8d7f96cf9a74c880243576fd3e72bd8ce4f81e43d22bcab7/pydantic_core-2.41.4-cp314-cp314-win32.whl", hash = "sha256:5b66584e549e2e32a1398df11da2e0a7eff45d5c2d9db9d5667c5e6ac764d77e", size = 1982277 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/dc/e5aa27aea1ad4638f0c3fb41132f7eb583bd7420ee63204e2d4333a3bbf9/pydantic_core-2.41.4-cp314-cp314-win_amd64.whl", hash = "sha256:557a0aab88664cc552285316809cab897716a372afaf8efdbef756f8b890e894", size = 2024608 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/61/51d89cc2612bd147198e120a13f150afbf0bcb4615cddb049ab10b81b79e/pydantic_core-2.41.4-cp314-cp314-win_arm64.whl", hash = "sha256:3f1ea6f48a045745d0d9f325989d8abd3f1eaf47dd00485912d1a3a63c623a8d", size = 1967614 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/c2/472f2e31b95eff099961fa050c376ab7156a81da194f9edb9f710f68787b/pydantic_core-2.41.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6c1fe4c5404c448b13188dd8bd2ebc2bdd7e6727fa61ff481bcc2cca894018da", size = 1876904 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/07/ea8eeb91173807ecdae4f4a5f4b150a520085b35454350fc219ba79e66a3/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:523e7da4d43b113bf8e7b49fa4ec0c35bf4fe66b2230bfc5c13cc498f12c6c3e", size = 1882538 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/29/b53a9ca6cd366bfc928823679c6a76c7a4c69f8201c0ba7903ad18ebae2f/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5729225de81fb65b70fdb1907fcf08c75d498f4a6f15af005aabb1fdadc19dfa", size = 2041183 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/3d/f8c1a371ceebcaf94d6dd2d77c6cf4b1c078e13a5837aee83f760b4f7cfd/pydantic_core-2.41.4-cp314-cp314t-win_amd64.whl", hash = "sha256:de2cfbb09e88f0f795fd90cf955858fc2c691df65b1f21f0aa00b99f3fbc661d", size = 1993542 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/ac/9fc61b4f9d079482a290afe8d206b8f490e9fd32d4fc03ed4fc698214e01/pydantic_core-2.41.4-cp314-cp314t-win_arm64.whl", hash = "sha256:d34f950ae05a83e0ede899c595f312ca976023ea1db100cd5aa188f7005e3ab0", size = 1973897 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/d4/912e976a2dd0b49f31c98a060ca90b353f3b73ee3ea2fd0030412f6ac5ec/pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e5ab4fc177dd41536b3c32b2ea11380dd3d4619a385860621478ac2d25ceb00", size = 2106739 },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/f0/66ec5a626c81eba326072d6ee2b127f8c139543f1bf609b4842978d37833/pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3d88d0054d3fa11ce936184896bed3c1c5441d6fa483b498fac6a5d0dd6f64a9", size = 1932549 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/af/625626278ca801ea0a658c2dcf290dc9f21bb383098e99e7c6a029fccfc0/pydantic_core-2.41.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b2a054a8725f05b4b6503357e0ac1c4e8234ad3b0c2ac130d6ffc66f0e170e2", size = 2135093 },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/f6/2fba049f54e0f4975fef66be654c597a1d005320fa141863699180c7697d/pydantic_core-2.41.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0d9db5a161c99375a0c68c058e227bee1d89303300802601d76a3d01f74e258", size = 2187971 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/80/65ab839a2dfcd3b949202f9d920c34f9de5a537c3646662bdf2f7d999680/pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:6273ea2c8ffdac7b7fda2653c49682db815aebf4a89243a6feccf5e36c18c347", size = 2147939 },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/58/627565d3d182ce6dfda18b8e1c841eede3629d59c9d7cbc1e12a03aeb328/pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:4c973add636efc61de22530b2ef83a65f39b6d6f656df97f678720e20de26caa", size = 2311400 },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/06/8a84711162ad5a5f19a88cead37cca81b4b1f294f46260ef7334ae4f24d3/pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b69d1973354758007f46cf2d44a4f3d0933f10b6dc9bf15cf1356e037f6f731a", size = 2316840 },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/8b/b7bb512a4682a2f7fbfae152a755d37351743900226d29bd953aaf870eaa/pydantic_core-2.41.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3619320641fd212aaf5997b6ca505e97540b7e16418f4a241f44cdf108ffb50d", size = 2149135 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/7d/138e902ed6399b866f7cfe4435d22445e16fff888a1c00560d9dc79a780f/pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:491535d45cd7ad7e4a2af4a5169b0d07bebf1adfd164b0368da8aa41e19907a5", size = 2104721 },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/13/0525623cf94627f7b53b4c2034c81edc8491cbfc7c28d5447fa318791479/pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:54d86c0cada6aba4ec4c047d0e348cbad7063b87ae0f005d9f8c9ad04d4a92a2", size = 1931608 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/f9/744bc98137d6ef0a233f808bfc9b18cf94624bf30836a18d3b05d08bf418/pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca1124aced216b2500dc2609eade086d718e8249cb9696660ab447d50a758bd", size = 2132986 },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/c8/629e88920171173f6049386cc71f893dff03209a9ef32b4d2f7e7c264bcf/pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c9024169becccf0cb470ada03ee578d7348c119a0d42af3dcf9eda96e3a247c", size = 2187516 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/0f/4f2734688d98488782218ca61bcc118329bf5de05bb7fe3adc7dd79b0b86/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:26895a4268ae5a2849269f4991cdc97236e4b9c010e51137becf25182daac405", size = 2146146 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/f2/ab385dbd94a052c62224b99cf99002eee99dbec40e10006c78575aead256/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:ca4df25762cf71308c446e33c9b1fdca2923a3f13de616e2a949f38bf21ff5a8", size = 2311296 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/8e/e4f12afe1beeb9823bba5375f8f258df0cc61b056b0195fb1cf9f62a1a58/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5a28fcedd762349519276c36634e71853b4541079cab4acaaac60c4421827308", size = 2315386 },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/f7/925f65d930802e3ea2eb4d5afa4cb8730c8dc0d2cb89a59dc4ed2fcb2d74/pydantic_core-2.41.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c173ddcd86afd2535e2b695217e82191580663a1d1928239f877f5a1649ef39f", size = 2147775 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-settings"
|
||||
version = "2.8.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pydantic" },
|
||||
{ name = "python-dotenv" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/88/82/c79424d7d8c29b994fb01d277da57b0a9b09cc03c3ff875f9bd8a86b2145/pydantic_settings-2.8.1.tar.gz", hash = "sha256:d5c663dfbe9db9d5e1c646b2e161da12f0d734d422ee56f567d0ea2cee4e8585", size = 83550 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/53/a64f03044927dc47aafe029c42a5b7aabc38dfb813475e0e1bf71c4a59d0/pydantic_settings-2.8.1-py3-none-any.whl", hash = "sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c", size = 30839 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.19.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.0.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "13.9.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "pygments" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellingham"
|
||||
version = "1.5.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sse-starlette"
|
||||
version = "2.2.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "starlette" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/71/a4/80d2a11af59fe75b48230846989e93979c892d3a20016b42bb44edb9e398/sse_starlette-2.2.1.tar.gz", hash = "sha256:54470d5f19274aeed6b2d473430b08b4b379ea851d953b11d7f1c4a2c118b419", size = 17376 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/e0/5b8bd393f27f4a62461c5cf2479c75a2cc2ffa330976f9f00f5f6e4f50eb/sse_starlette-2.2.1-py3-none-any.whl", hash = "sha256:6410a3d3ba0c89e7675d4c273a301d64649c03a5ef1ca101f10b47f895fd0e99", size = 10120 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "starlette"
|
||||
version = "0.46.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/44/b6/fb9a32e3c5d59b1e383c357534c63c2d3caa6f25bf3c59dd89d296ecbaec/starlette-0.46.0.tar.gz", hash = "sha256:b359e4567456b28d473d0193f34c0de0ed49710d75ef183a74a5ce0499324f50", size = 2575568 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/41/94/8af675a62e3c91c2dee47cf92e602cfac86e8767b1a1ac3caf1b327c2ab0/starlette-0.46.0-py3-none-any.whl", hash = "sha256:913f0798bd90ba90a9156383bcf1350a17d6259451d0d8ee27fc0cf2db609038", size = 71991 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typer"
|
||||
version = "0.15.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "rich" },
|
||||
{ name = "shellingham" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8b/6f/3991f0f1c7fcb2df31aef28e0594d8d54b05393a0e4e34c65e475c2a5d41/typer-0.15.2.tar.gz", hash = "sha256:ab2fab47533a813c49fe1f16b1a370fd5819099c00b119e0633df65f22144ba5", size = 100711 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/fc/5b29fea8cee020515ca82cc68e3b8e1e34bb19a3535ad854cac9257b414c/typer-0.15.2-py3-none-any.whl", hash = "sha256:46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc", size = 45061 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-inspection"
|
||||
version = "0.4.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.34.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "h11" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4b/4d/938bd85e5bf2edeec766267a5015ad969730bb91e31b44021dfe8b22df6c/uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9", size = 76568 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/61/14/33a3a1352cfa71812a3a21e8c9bfb83f60b0011f5e36f2b1399d51928209/uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4", size = 62315 },
|
||||
]
|
||||
Reference in New Issue
Block a user