feat: add dnfile-based metadata tools and platform-aware installation
Major update with new capabilities:
- Rename package from ilspy_mcp_server to mcilspy
- Add 6 new dnfile-based tools that work without ilspycmd:
- search_methods, search_fields, search_properties
- list_events, list_resources, get_metadata_summary
- Add installation/diagnostic tools:
- check_ilspy_installation: verify toolchain status
- install_ilspy: platform-aware installer with auto-detection
for pacman, apt, dnf, zypper, homebrew, winget, chocolatey
- Fix metadata_reader bugs:
- Use _get_row_index helper consistently for dnfile compatibility
- Handle HeapItemBinary conversion for public key tokens
- Update documentation with all 14 tools
This commit is contained in:
parent
57472070e2
commit
4354408588
229
README.md
229
README.md
@ -1,13 +1,28 @@
|
|||||||
# ILSpy MCP Server
|
# mcilspy
|
||||||
|
|
||||||
A Model Context Protocol (MCP) server that provides .NET assembly decompilation capabilities using ILSpy.
|
A Model Context Protocol (MCP) server that provides .NET assembly decompilation capabilities using ILSpy.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
### ILSpy-based Tools (requires ilspycmd)
|
||||||
- **Decompile Assemblies**: Convert .NET assemblies back to readable C# source code
|
- **Decompile Assemblies**: Convert .NET assemblies back to readable C# source code
|
||||||
- **List Types**: Enumerate classes, interfaces, structs, delegates, and enums in assemblies
|
- **List Types**: Enumerate classes, interfaces, structs, delegates, and enums in assemblies
|
||||||
|
- **Search Types**: Find types by name pattern with regex support
|
||||||
|
- **Search Strings**: Find hardcoded strings in assembly code (URLs, credentials, etc.)
|
||||||
- **Generate Diagrammer**: Create interactive HTML visualizations of assembly structure
|
- **Generate Diagrammer**: Create interactive HTML visualizations of assembly structure
|
||||||
- **Assembly Information**: Get metadata about .NET assemblies
|
- **Assembly Information**: Get metadata about .NET assemblies (version, target framework, etc.)
|
||||||
|
|
||||||
|
### Direct Metadata Tools (no ilspycmd required)
|
||||||
|
- **Search Methods**: Find methods by name pattern directly from metadata tables
|
||||||
|
- **Search Fields**: Find fields and constants in assemblies
|
||||||
|
- **Search Properties**: Find properties by name pattern
|
||||||
|
- **List Events**: Enumerate all events defined in an assembly
|
||||||
|
- **List Resources**: List embedded resources (files, images, etc.)
|
||||||
|
- **Metadata Summary**: Get comprehensive assembly metadata with statistics
|
||||||
|
|
||||||
|
### Installation & Diagnostics
|
||||||
|
- **Check Installation**: Verify ilspycmd and dotnet CLI status
|
||||||
|
- **Install ILSpy**: Automatically install or update ilspycmd
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@ -16,21 +31,21 @@ A Model Context Protocol (MCP) server that provides .NET assembly decompilation
|
|||||||
dotnet tool install --global ilspycmd
|
dotnet tool install --global ilspycmd
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Python 3.8+**: Required for running the MCP server
|
2. **Python 3.10+**: Required for running the MCP server
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Install from PyPI:
|
Install from PyPI:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install ilspy-mcp-server
|
pip install mcilspy
|
||||||
```
|
```
|
||||||
|
|
||||||
Or for development:
|
Or for development:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/Borealin/ilspy-mcp-server.git
|
git clone https://github.com/Borealin/mcilspy.git
|
||||||
cd ilspy-mcp-server
|
cd mcilspy
|
||||||
pip install -e .
|
pip install -e .
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -45,7 +60,7 @@ Configure your MCP client (e.g., Claude Desktop) to use the server:
|
|||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"ilspy": {
|
"ilspy": {
|
||||||
"command": "python",
|
"command": "python",
|
||||||
"args": ["-m", "ilspy_mcp_server.server"]
|
"args": ["-m", "mcilspy.server"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,16 +69,18 @@ Configure your MCP client (e.g., Claude Desktop) to use the server:
|
|||||||
### Available Tools
|
### Available Tools
|
||||||
|
|
||||||
#### 1. `decompile_assembly`
|
#### 1. `decompile_assembly`
|
||||||
Decompile a .NET assembly to C# source code.
|
Decompile a .NET assembly to C# source code. This is the primary tool for reverse-engineering .NET binaries.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
- `assembly_path` (required): Path to the .NET assembly file
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
- `output_dir` (optional): Output directory for decompiled files
|
- `output_dir` (optional): Output directory for decompiled files
|
||||||
- `type_name` (optional): Specific type to decompile
|
- `type_name` (optional): Fully qualified type name to decompile (e.g., "MyNamespace.MyClass")
|
||||||
- `language_version` (optional): C# language version (default: "Latest")
|
- `language_version` (optional): C# language version (default: "Latest")
|
||||||
- `create_project` (optional): Create a compilable project structure
|
- `create_project` (optional): Create a compilable project structure
|
||||||
- `show_il_code` (optional): Show IL code instead of C#
|
- `show_il_code` (optional): Show IL bytecode instead of C#
|
||||||
- `remove_dead_code` (optional): Remove dead code during decompilation
|
- `remove_dead_code` (optional): Remove unreachable code during decompilation
|
||||||
|
- `remove_dead_stores` (optional): Remove unused variable assignments
|
||||||
|
- `show_il_sequence_points` (optional): Include debugging sequence points in IL output
|
||||||
- `nested_directories` (optional): Use nested directories for namespaces
|
- `nested_directories` (optional): Use nested directories for namespaces
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
@ -79,11 +96,16 @@ Decompile a .NET assembly to C# source code.
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### 2. `list_types`
|
#### 2. `list_types`
|
||||||
List types in a .NET assembly.
|
List types in a .NET assembly. Typically the **first tool to use** when analyzing an unknown assembly.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
- `assembly_path` (required): Path to the .NET assembly file
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
- `entity_types` (optional): Array of entity types to list ("c", "i", "s", "d", "e")
|
- `entity_types` (optional): Types to include (accepts full names or single letters):
|
||||||
|
- `"class"` or `"c"` (default)
|
||||||
|
- `"interface"` or `"i"`
|
||||||
|
- `"struct"` or `"s"`
|
||||||
|
- `"delegate"` or `"d"`
|
||||||
|
- `"enum"` or `"e"`
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```json
|
```json
|
||||||
@ -91,13 +113,57 @@ List types in a .NET assembly.
|
|||||||
"name": "list_types",
|
"name": "list_types",
|
||||||
"arguments": {
|
"arguments": {
|
||||||
"assembly_path": "/path/to/MyAssembly.dll",
|
"assembly_path": "/path/to/MyAssembly.dll",
|
||||||
"entity_types": ["c", "i"]
|
"entity_types": ["class", "interface"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 3. `generate_diagrammer`
|
#### 3. `search_types`
|
||||||
Generate an interactive HTML diagrammer.
|
Search for types by name pattern. Essential for finding specific classes in large assemblies.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
|
- `pattern` (required): Search pattern to match against type names
|
||||||
|
- `namespace_filter` (optional): Only search in namespaces containing this string
|
||||||
|
- `entity_types` (optional): Types to search (default: all types)
|
||||||
|
- `case_sensitive` (optional): Case-sensitive matching (default: false)
|
||||||
|
- `use_regex` (optional): Treat pattern as regular expression (default: false)
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "search_types",
|
||||||
|
"arguments": {
|
||||||
|
"assembly_path": "/path/to/MyAssembly.dll",
|
||||||
|
"pattern": "Service",
|
||||||
|
"namespace_filter": "MyApp.Services"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. `search_strings`
|
||||||
|
Search for string literals in assembly code. Crucial for reverse engineering - finds hardcoded URLs, credentials, configuration, etc.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
|
- `pattern` (required): String pattern to search for
|
||||||
|
- `case_sensitive` (optional): Case-sensitive matching (default: false)
|
||||||
|
- `use_regex` (optional): Treat pattern as regular expression (default: false)
|
||||||
|
- `max_results` (optional): Maximum matches to return (default: 100)
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "search_strings",
|
||||||
|
"arguments": {
|
||||||
|
"assembly_path": "/path/to/MyAssembly.dll",
|
||||||
|
"pattern": "api.example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5. `generate_diagrammer`
|
||||||
|
Generate an interactive HTML diagram showing assembly type relationships.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
- `assembly_path` (required): Path to the .NET assembly file
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
@ -105,12 +171,130 @@ Generate an interactive HTML diagrammer.
|
|||||||
- `include_pattern` (optional): Regex pattern for types to include
|
- `include_pattern` (optional): Regex pattern for types to include
|
||||||
- `exclude_pattern` (optional): Regex pattern for types to exclude
|
- `exclude_pattern` (optional): Regex pattern for types to exclude
|
||||||
|
|
||||||
#### 4. `get_assembly_info`
|
#### 6. `get_assembly_info`
|
||||||
Get basic information about an assembly.
|
Get metadata and version information about an assembly.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
- `assembly_path` (required): Path to the .NET assembly file
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
|
|
||||||
|
Returns: Assembly name, version, target framework, signing status, and debug info availability.
|
||||||
|
|
||||||
|
### Direct Metadata Tools
|
||||||
|
|
||||||
|
These tools use direct PE/metadata parsing via [dnfile](https://github.com/malwarefrank/dnfile) and don't require ilspycmd to be installed.
|
||||||
|
|
||||||
|
#### 7. `search_methods`
|
||||||
|
Search for methods in an assembly by name pattern. Useful for finding entry points, event handlers, and API endpoints.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
|
- `pattern` (required): Search pattern to match against method names
|
||||||
|
- `type_filter` (optional): Only search methods in types containing this string
|
||||||
|
- `namespace_filter` (optional): Only search in namespaces containing this string
|
||||||
|
- `public_only` (optional): Only return public methods (default: false)
|
||||||
|
- `case_sensitive` (optional): Case-sensitive matching (default: false)
|
||||||
|
- `use_regex` (optional): Treat pattern as regular expression (default: false)
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "search_methods",
|
||||||
|
"arguments": {
|
||||||
|
"assembly_path": "/path/to/MyAssembly.dll",
|
||||||
|
"pattern": "Handle",
|
||||||
|
"public_only": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 8. `search_fields`
|
||||||
|
Search for fields and constants in an assembly. Useful for finding configuration values and magic numbers.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
|
- `pattern` (required): Search pattern to match against field names
|
||||||
|
- `type_filter` (optional): Only search fields in types containing this string
|
||||||
|
- `namespace_filter` (optional): Only search in namespaces containing this string
|
||||||
|
- `public_only` (optional): Only return public fields (default: false)
|
||||||
|
- `constants_only` (optional): Only return constant (literal) fields (default: false)
|
||||||
|
- `case_sensitive` (optional): Case-sensitive matching (default: false)
|
||||||
|
- `use_regex` (optional): Treat pattern as regular expression (default: false)
|
||||||
|
|
||||||
|
#### 9. `search_properties`
|
||||||
|
Search for properties in an assembly by name pattern. Useful for finding data model fields and configuration properties.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
|
- `pattern` (required): Search pattern to match against property names
|
||||||
|
- `type_filter` (optional): Only search properties in types containing this string
|
||||||
|
- `namespace_filter` (optional): Only search in namespaces containing this string
|
||||||
|
- `case_sensitive` (optional): Case-sensitive matching (default: false)
|
||||||
|
- `use_regex` (optional): Treat pattern as regular expression (default: false)
|
||||||
|
|
||||||
|
#### 10. `list_events`
|
||||||
|
List all events defined in an assembly. Useful for understanding event-driven architecture and observer patterns.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
|
- `type_filter` (optional): Only list events in types containing this string
|
||||||
|
- `namespace_filter` (optional): Only list events in namespaces containing this string
|
||||||
|
|
||||||
|
#### 11. `list_resources`
|
||||||
|
List all embedded resources in an assembly. Finds embedded files, images, localization data, etc.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
|
|
||||||
|
#### 12. `get_metadata_summary`
|
||||||
|
Get a comprehensive metadata summary with statistics. More accurate than `get_assembly_info` for metadata counts.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `assembly_path` (required): Path to the .NET assembly file
|
||||||
|
|
||||||
|
Returns: Assembly identity, type/method/field/property/event/resource counts, and referenced assemblies.
|
||||||
|
|
||||||
|
### Installation & Diagnostics Tools
|
||||||
|
|
||||||
|
#### 13. `check_ilspy_installation`
|
||||||
|
Check if ilspycmd and dotnet CLI are installed and working. Use this to diagnose issues.
|
||||||
|
|
||||||
|
**Parameters:** None
|
||||||
|
|
||||||
|
Returns: Installation status with version information and troubleshooting tips.
|
||||||
|
|
||||||
|
#### 14. `install_ilspy`
|
||||||
|
Install or update ilspycmd automatically. Detects your platform and package manager for optimal installation experience.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `update` (optional): If true, update to the latest version even if already installed (default: false)
|
||||||
|
- `install_dotnet_sdk` (optional): If true, attempt to install .NET SDK when missing (default: false). Supports automatic detection for:
|
||||||
|
- **Arch Linux**: `pacman`
|
||||||
|
- **Ubuntu/Debian**: `apt`
|
||||||
|
- **Fedora/RHEL**: `dnf`
|
||||||
|
- **openSUSE**: `zypper`
|
||||||
|
- **macOS**: `homebrew`
|
||||||
|
- **Windows**: `winget` or `chocolatey`
|
||||||
|
|
||||||
|
**Example - Update ilspycmd:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "install_ilspy",
|
||||||
|
"arguments": {
|
||||||
|
"update": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example - Full installation (SDK + ilspycmd):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "install_ilspy",
|
||||||
|
"arguments": {
|
||||||
|
"install_dotnet_sdk": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Available Prompts
|
### Available Prompts
|
||||||
|
|
||||||
#### 1. `analyze_assembly`
|
#### 1. `analyze_assembly`
|
||||||
@ -135,7 +319,7 @@ Decompile a specific type and provide explanation of its functionality.
|
|||||||
|
|
||||||
1. **Install the package**:
|
1. **Install the package**:
|
||||||
```bash
|
```bash
|
||||||
pip install ilspy-mcp-server
|
pip install mcilspy
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Configure your MCP client** (Claude Desktop example):
|
2. **Configure your MCP client** (Claude Desktop example):
|
||||||
@ -144,7 +328,7 @@ Decompile a specific type and provide explanation of its functionality.
|
|||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"ilspy": {
|
"ilspy": {
|
||||||
"command": "python",
|
"command": "python",
|
||||||
"args": ["-m", "ilspy_mcp_server.server"]
|
"args": ["-m", "mcilspy.server"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,7 +363,7 @@ The server provides detailed error messages for common issues:
|
|||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"ilspy": {
|
"ilspy": {
|
||||||
"command": "python",
|
"command": "python",
|
||||||
"args": ["-m", "ilspy_mcp_server.server"],
|
"args": ["-m", "mcilspy.server"],
|
||||||
"env": {
|
"env": {
|
||||||
"LOGLEVEL": "INFO"
|
"LOGLEVEL": "INFO"
|
||||||
}
|
}
|
||||||
@ -194,7 +378,7 @@ The server provides detailed error messages for common issues:
|
|||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"ilspy": {
|
"ilspy": {
|
||||||
"command": "python",
|
"command": "python",
|
||||||
"args": ["-m", "ilspy_mcp_server.server"],
|
"args": ["-m", "mcilspy.server"],
|
||||||
"env": {
|
"env": {
|
||||||
"LOGLEVEL": "DEBUG"
|
"LOGLEVEL": "DEBUG"
|
||||||
}
|
}
|
||||||
@ -237,5 +421,6 @@ This project is licensed under the MIT License - see the LICENSE file for detail
|
|||||||
|
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
|
|
||||||
|
- **Original project by [Borealin](https://github.com/Borealin/ilspy-mcp-server)** - Thank you for creating the foundation for this MCP server!
|
||||||
- Built on top of the excellent [ILSpy](https://github.com/icsharpcode/ILSpy) decompiler
|
- Built on top of the excellent [ILSpy](https://github.com/icsharpcode/ILSpy) decompiler
|
||||||
- Uses the [Model Context Protocol](https://modelcontextprotocol.io/) for integration
|
- Uses the [Model Context Protocol](https://modelcontextprotocol.io/) for integration
|
||||||
503
docs/API.md
503
docs/API.md
@ -1,16 +1,34 @@
|
|||||||
# API Documentation
|
# API Documentation
|
||||||
|
|
||||||
This document provides detailed API documentation for the ILSpy MCP Server.
|
This document provides detailed API documentation for mcilspy.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The ILSpy MCP Server provides a Model Context Protocol (MCP) interface to the ILSpy .NET decompiler. It exposes four main tools and two prompts for interacting with .NET assemblies.
|
mcilspy provides a Model Context Protocol (MCP) interface to the ILSpy .NET decompiler. It exposes **14 tools** and two prompts for interacting with .NET assemblies.
|
||||||
|
|
||||||
|
### Tool Categories
|
||||||
|
|
||||||
|
1. **ILSpy-based tools** (require ilspycmd): Decompilation, type listing, diagram generation
|
||||||
|
2. **Direct metadata tools** (use dnfile): Method/field/property/event search, resource listing
|
||||||
|
3. **Installation tools**: Check and install ilspycmd automatically
|
||||||
|
|
||||||
|
## Recommended Workflow
|
||||||
|
|
||||||
|
When analyzing an unknown .NET assembly, follow this typical workflow:
|
||||||
|
|
||||||
|
1. **`get_metadata_summary`** - Quick reconnaissance with accurate metadata counts
|
||||||
|
2. **`list_types`** - Discover what types exist in the assembly
|
||||||
|
3. **`search_types`** / **`search_methods`** - Find specific types or methods by pattern
|
||||||
|
4. **`search_strings`** / **`search_fields`** - Find hardcoded strings and constants
|
||||||
|
5. **`decompile_assembly`** - Deep dive into specific types of interest
|
||||||
|
6. **`generate_diagrammer`** - Visualize type relationships
|
||||||
|
7. **`list_resources`** - Check for embedded files
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
|
|
||||||
### 1. decompile_assembly
|
### 1. decompile_assembly
|
||||||
|
|
||||||
Decompiles a .NET assembly to C# source code.
|
Decompiles a .NET assembly to C# source code. This is the primary tool for reverse-engineering .NET binaries.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
@ -21,8 +39,10 @@ Decompiles a .NET assembly to C# source code.
|
|||||||
| `type_name` | string | ✗ | null | Fully qualified name of specific type to decompile |
|
| `type_name` | string | ✗ | null | Fully qualified name of specific type to decompile |
|
||||||
| `language_version` | string | ✗ | "Latest" | C# language version to use |
|
| `language_version` | string | ✗ | "Latest" | C# language version to use |
|
||||||
| `create_project` | boolean | ✗ | false | Create a compilable project with multiple files |
|
| `create_project` | boolean | ✗ | false | Create a compilable project with multiple files |
|
||||||
| `show_il_code` | boolean | ✗ | false | Show IL code instead of C# |
|
| `show_il_code` | boolean | ✗ | false | Show IL bytecode instead of C# |
|
||||||
| `remove_dead_code` | boolean | ✗ | false | Remove dead code during decompilation |
|
| `remove_dead_code` | boolean | ✗ | false | Remove unreachable code during decompilation |
|
||||||
|
| `remove_dead_stores` | boolean | ✗ | false | Remove unused variable assignments |
|
||||||
|
| `show_il_sequence_points` | boolean | ✗ | false | Include debugging sequence points in IL output |
|
||||||
| `nested_directories` | boolean | ✗ | false | Use nested directories for namespaces |
|
| `nested_directories` | boolean | ✗ | false | Use nested directories for namespaces |
|
||||||
|
|
||||||
**Language Versions:**
|
**Language Versions:**
|
||||||
@ -48,21 +68,21 @@ Returns decompiled C# source code as text, or information about saved files if `
|
|||||||
|
|
||||||
### 2. list_types
|
### 2. list_types
|
||||||
|
|
||||||
Lists types (classes, interfaces, structs, etc.) in a .NET assembly.
|
Lists types (classes, interfaces, structs, etc.) in a .NET assembly. Typically the **first tool to use** when analyzing an unknown assembly.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
| Parameter | Type | Required | Default | Description |
|
| Parameter | Type | Required | Default | Description |
|
||||||
|-----------|------|----------|---------|-------------|
|
|-----------|------|----------|---------|-------------|
|
||||||
| `assembly_path` | string | ✓ | - | Path to the .NET assembly file (.dll or .exe) |
|
| `assembly_path` | string | ✓ | - | Path to the .NET assembly file (.dll or .exe) |
|
||||||
| `entity_types` | array[string] | ✗ | ["c"] | Types of entities to list |
|
| `entity_types` | array[string] | ✗ | ["class"] | Types of entities to list |
|
||||||
|
|
||||||
**Entity Types:**
|
**Entity Types (accepts full names or single letters):**
|
||||||
- `c` - Classes
|
- `class` or `c` - Classes
|
||||||
- `i` - Interfaces
|
- `interface` or `i` - Interfaces
|
||||||
- `s` - Structs
|
- `struct` or `s` - Structs
|
||||||
- `d` - Delegates
|
- `delegate` or `d` - Delegates
|
||||||
- `e` - Enums
|
- `enum` or `e` - Enums
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```json
|
```json
|
||||||
@ -70,7 +90,7 @@ Lists types (classes, interfaces, structs, etc.) in a .NET assembly.
|
|||||||
"name": "list_types",
|
"name": "list_types",
|
||||||
"arguments": {
|
"arguments": {
|
||||||
"assembly_path": "/path/to/MyAssembly.dll",
|
"assembly_path": "/path/to/MyAssembly.dll",
|
||||||
"entity_types": ["c", "i", "s"]
|
"entity_types": ["class", "interface", "struct"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -82,9 +102,84 @@ Returns a formatted list of types organized by namespace, including:
|
|||||||
- Type kind (Class, Interface, etc.)
|
- Type kind (Class, Interface, etc.)
|
||||||
- Namespace
|
- Namespace
|
||||||
|
|
||||||
### 3. generate_diagrammer
|
### 3. search_types
|
||||||
|
|
||||||
Generates an interactive HTML diagrammer for visualizing assembly structure.
|
Search for types by name pattern. Essential for finding specific classes in large assemblies.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Default | Description |
|
||||||
|
|-----------|------|----------|---------|-------------|
|
||||||
|
| `assembly_path` | string | ✓ | - | Path to the .NET assembly file (.dll or .exe) |
|
||||||
|
| `pattern` | string | ✓ | - | Search pattern to match against type names |
|
||||||
|
| `namespace_filter` | string | ✗ | null | Only return types in namespaces containing this string |
|
||||||
|
| `entity_types` | array[string] | ✗ | all | Types to search (class, interface, struct, delegate, enum) |
|
||||||
|
| `case_sensitive` | boolean | ✗ | false | Whether pattern matching is case-sensitive |
|
||||||
|
| `use_regex` | boolean | ✗ | false | Treat pattern as regular expression |
|
||||||
|
|
||||||
|
**Common Search Patterns:**
|
||||||
|
- `"Service"` - Find all service classes
|
||||||
|
- `"Controller"` - Find ASP.NET controllers
|
||||||
|
- `"Handler"` - Find command/event handlers
|
||||||
|
- `"Exception"` - Find custom exception types
|
||||||
|
- `"I.*Service"` (with `use_regex=true`) - Find service interfaces
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "search_types",
|
||||||
|
"arguments": {
|
||||||
|
"assembly_path": "/path/to/MyAssembly.dll",
|
||||||
|
"pattern": "Service",
|
||||||
|
"namespace_filter": "MyApp.Services",
|
||||||
|
"entity_types": ["class", "interface"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
Returns matching types grouped by namespace with full names for use with `decompile_assembly`.
|
||||||
|
|
||||||
|
### 4. search_strings
|
||||||
|
|
||||||
|
Search for string literals in assembly code. Crucial for reverse engineering - finds hardcoded strings.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Default | Description |
|
||||||
|
|-----------|------|----------|---------|-------------|
|
||||||
|
| `assembly_path` | string | ✓ | - | Path to the .NET assembly file (.dll or .exe) |
|
||||||
|
| `pattern` | string | ✓ | - | String pattern to search for in decompiled code |
|
||||||
|
| `case_sensitive` | boolean | ✗ | false | Whether search is case-sensitive |
|
||||||
|
| `use_regex` | boolean | ✗ | false | Treat pattern as regular expression |
|
||||||
|
| `max_results` | integer | ✗ | 100 | Maximum number of matches to return |
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Find hardcoded URLs and API endpoints
|
||||||
|
- Locate connection strings
|
||||||
|
- Discover error messages and logging text
|
||||||
|
- Find configuration keys and magic values
|
||||||
|
- Security analysis - find hardcoded credentials
|
||||||
|
- Locate registry keys and file paths
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "search_strings",
|
||||||
|
"arguments": {
|
||||||
|
"assembly_path": "/path/to/MyAssembly.dll",
|
||||||
|
"pattern": "api.example.com",
|
||||||
|
"max_results": 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
Returns matching code lines grouped by type, with context about the containing method.
|
||||||
|
|
||||||
|
### 5. generate_diagrammer
|
||||||
|
|
||||||
|
Generates an interactive HTML diagram showing assembly type relationships.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
@ -102,7 +197,8 @@ Generates an interactive HTML diagrammer for visualizing assembly structure.
|
|||||||
"arguments": {
|
"arguments": {
|
||||||
"assembly_path": "/path/to/MyAssembly.dll",
|
"assembly_path": "/path/to/MyAssembly.dll",
|
||||||
"output_dir": "./diagrams",
|
"output_dir": "./diagrams",
|
||||||
"include_pattern": "MyNamespace\\..+"
|
"include_pattern": "MyNamespace\\..+",
|
||||||
|
"exclude_pattern": ".*Generated.*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -110,9 +206,9 @@ Generates an interactive HTML diagrammer for visualizing assembly structure.
|
|||||||
**Response:**
|
**Response:**
|
||||||
Returns success status and output directory path. The HTML file can be opened in a web browser to view the interactive diagram.
|
Returns success status and output directory path. The HTML file can be opened in a web browser to view the interactive diagram.
|
||||||
|
|
||||||
### 4. get_assembly_info
|
### 6. get_assembly_info
|
||||||
|
|
||||||
Gets basic information about a .NET assembly.
|
Gets metadata and version information about a .NET assembly.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
@ -133,13 +229,236 @@ Gets basic information about a .NET assembly.
|
|||||||
**Response:**
|
**Response:**
|
||||||
Returns assembly metadata including:
|
Returns assembly metadata including:
|
||||||
- Assembly name
|
- Assembly name
|
||||||
- Version
|
- Version (extracted from AssemblyVersion attribute)
|
||||||
- Full name
|
- Full name
|
||||||
- Location
|
- Location
|
||||||
- Target framework (if available)
|
- Target framework (e.g., .NET Framework 4.8, .NET 6.0)
|
||||||
- Runtime version (if available)
|
- Runtime version (if available)
|
||||||
- Whether the assembly is signed
|
- Whether the assembly is signed
|
||||||
- Whether debug information is available
|
- Whether debug information (PDB) is available
|
||||||
|
|
||||||
|
## Direct Metadata Tools
|
||||||
|
|
||||||
|
These tools use [dnfile](https://github.com/malwarefrank/dnfile) for direct PE/metadata parsing. They do **not require ilspycmd** to be installed.
|
||||||
|
|
||||||
|
### 7. search_methods
|
||||||
|
|
||||||
|
Search for methods in an assembly by name pattern. Uses direct metadata parsing of the MethodDef table.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Default | Description |
|
||||||
|
|-----------|------|----------|---------|-------------|
|
||||||
|
| `assembly_path` | string | ✓ | - | Path to the .NET assembly file (.dll or .exe) |
|
||||||
|
| `pattern` | string | ✓ | - | Search pattern to match against method names |
|
||||||
|
| `type_filter` | string | ✗ | null | Only search methods in types containing this string |
|
||||||
|
| `namespace_filter` | string | ✗ | null | Only search in namespaces containing this string |
|
||||||
|
| `public_only` | boolean | ✗ | false | Only return public methods |
|
||||||
|
| `case_sensitive` | boolean | ✗ | false | Whether pattern matching is case-sensitive |
|
||||||
|
| `use_regex` | boolean | ✗ | false | Treat pattern as regular expression |
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Find entry points and main methods
|
||||||
|
- Locate event handlers (`OnClick`, `Handle*`)
|
||||||
|
- Find lifecycle methods (`Initialize`, `Dispose`)
|
||||||
|
- Discover API endpoints
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "search_methods",
|
||||||
|
"arguments": {
|
||||||
|
"assembly_path": "/path/to/MyAssembly.dll",
|
||||||
|
"pattern": "Handle",
|
||||||
|
"public_only": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
Returns matching methods grouped by declaring type, showing visibility modifiers (public, static, virtual, abstract).
|
||||||
|
|
||||||
|
### 8. search_fields
|
||||||
|
|
||||||
|
Search for fields and constants in an assembly. Uses direct metadata parsing of the Field table.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Default | Description |
|
||||||
|
|-----------|------|----------|---------|-------------|
|
||||||
|
| `assembly_path` | string | ✓ | - | Path to the .NET assembly file (.dll or .exe) |
|
||||||
|
| `pattern` | string | ✓ | - | Search pattern to match against field names |
|
||||||
|
| `type_filter` | string | ✗ | null | Only search fields in types containing this string |
|
||||||
|
| `namespace_filter` | string | ✗ | null | Only search in namespaces containing this string |
|
||||||
|
| `public_only` | boolean | ✗ | false | Only return public fields |
|
||||||
|
| `constants_only` | boolean | ✗ | false | Only return constant (literal) fields |
|
||||||
|
| `case_sensitive` | boolean | ✗ | false | Whether pattern matching is case-sensitive |
|
||||||
|
| `use_regex` | boolean | ✗ | false | Treat pattern as regular expression |
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Find configuration values and magic numbers
|
||||||
|
- Locate constant strings (URLs, error messages)
|
||||||
|
- Discover static fields (singletons, caches)
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "search_fields",
|
||||||
|
"arguments": {
|
||||||
|
"assembly_path": "/path/to/MyAssembly.dll",
|
||||||
|
"pattern": "ConnectionString",
|
||||||
|
"constants_only": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9. search_properties
|
||||||
|
|
||||||
|
Search for properties in an assembly by name pattern. Uses direct metadata parsing of the Property table.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Default | Description |
|
||||||
|
|-----------|------|----------|---------|-------------|
|
||||||
|
| `assembly_path` | string | ✓ | - | Path to the .NET assembly file (.dll or .exe) |
|
||||||
|
| `pattern` | string | ✓ | - | Search pattern to match against property names |
|
||||||
|
| `type_filter` | string | ✗ | null | Only search properties in types containing this string |
|
||||||
|
| `namespace_filter` | string | ✗ | null | Only search in namespaces containing this string |
|
||||||
|
| `case_sensitive` | boolean | ✗ | false | Whether pattern matching is case-sensitive |
|
||||||
|
| `use_regex` | boolean | ✗ | false | Treat pattern as regular expression |
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Find configuration properties
|
||||||
|
- Locate data model fields
|
||||||
|
- Discover API response/request properties
|
||||||
|
|
||||||
|
### 10. list_events
|
||||||
|
|
||||||
|
List all events defined in an assembly. Uses direct metadata parsing of the Event table.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Default | Description |
|
||||||
|
|-----------|------|----------|---------|-------------|
|
||||||
|
| `assembly_path` | string | ✓ | - | Path to the .NET assembly file (.dll or .exe) |
|
||||||
|
| `type_filter` | string | ✗ | null | Only list events in types containing this string |
|
||||||
|
| `namespace_filter` | string | ✗ | null | Only list events in namespaces containing this string |
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Understand event-driven architecture
|
||||||
|
- Discover observer patterns
|
||||||
|
- Analyze UI event handlers
|
||||||
|
|
||||||
|
### 11. list_resources
|
||||||
|
|
||||||
|
List all embedded resources in an assembly. Uses direct metadata parsing of the ManifestResource table.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Default | Description |
|
||||||
|
|-----------|------|----------|---------|-------------|
|
||||||
|
| `assembly_path` | string | ✓ | - | Path to the .NET assembly file (.dll or .exe) |
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Find embedded files (images, configs, data)
|
||||||
|
- Discover localization resources
|
||||||
|
- Locate embedded assemblies
|
||||||
|
|
||||||
|
### 12. get_metadata_summary
|
||||||
|
|
||||||
|
Get a comprehensive metadata summary with accurate statistics. Uses dnfile for direct metadata counts.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Default | Description |
|
||||||
|
|-----------|------|----------|---------|-------------|
|
||||||
|
| `assembly_path` | string | ✓ | - | Path to the .NET assembly file (.dll or .exe) |
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
Returns comprehensive assembly information including:
|
||||||
|
- Assembly identity (name, version, culture, public key token)
|
||||||
|
- Target framework (if available)
|
||||||
|
- Statistics table (type/method/field/property/event/resource counts)
|
||||||
|
- List of referenced assemblies
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "get_metadata_summary",
|
||||||
|
"arguments": {
|
||||||
|
"assembly_path": "/path/to/MyAssembly.dll"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation & Diagnostics Tools
|
||||||
|
|
||||||
|
These tools help manage ilspycmd installation and diagnose issues.
|
||||||
|
|
||||||
|
### 13. check_ilspy_installation
|
||||||
|
|
||||||
|
Check if ilspycmd and dotnet CLI are installed and working. Use this to diagnose issues with decompilation tools.
|
||||||
|
|
||||||
|
**Parameters:** None
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
Returns installation status including:
|
||||||
|
- dotnet CLI availability and version
|
||||||
|
- ilspycmd availability, version, and path
|
||||||
|
- Instructions if anything is missing
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "check_ilspy_installation",
|
||||||
|
"arguments": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 14. install_ilspy
|
||||||
|
|
||||||
|
Install or update ilspycmd, the ILSpy command-line decompiler. Automatically detects your platform and package manager to provide optimal installation instructions.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Default | Description |
|
||||||
|
|-----------|------|----------|---------|-------------|
|
||||||
|
| `update` | boolean | ✗ | false | Update to latest version even if already installed |
|
||||||
|
| `install_dotnet_sdk` | boolean | ✗ | false | Attempt to install .NET SDK if missing (may require sudo) |
|
||||||
|
|
||||||
|
**Supported Platforms for Auto-Install:**
|
||||||
|
- **Arch Linux/Manjaro**: `pacman -S dotnet-sdk`
|
||||||
|
- **Ubuntu/Debian/Mint**: `apt install dotnet-sdk-8.0`
|
||||||
|
- **Fedora/RHEL/CentOS**: `dnf install dotnet-sdk-8.0`
|
||||||
|
- **openSUSE**: `zypper install dotnet-sdk-8.0`
|
||||||
|
- **macOS**: `brew install dotnet-sdk` (Homebrew)
|
||||||
|
- **Windows**: `winget install Microsoft.DotNet.SDK.8` or `choco install dotnet-sdk`
|
||||||
|
|
||||||
|
**Example - Update ilspycmd:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "install_ilspy",
|
||||||
|
"arguments": {
|
||||||
|
"update": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example - Full installation (SDK + ilspycmd):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "install_ilspy",
|
||||||
|
"arguments": {
|
||||||
|
"install_dotnet_sdk": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
- Success message with version and path on successful installation
|
||||||
|
- Platform-specific installation instructions if dotnet CLI is missing
|
||||||
|
- Option to auto-install with `install_dotnet_sdk=true`
|
||||||
|
- PATH troubleshooting tips if installation succeeds but tool isn't found
|
||||||
|
|
||||||
## Prompts
|
## Prompts
|
||||||
|
|
||||||
@ -221,14 +540,15 @@ The server provides detailed error messages for common issues:
|
|||||||
```python
|
```python
|
||||||
class DecompileRequest(BaseModel):
|
class DecompileRequest(BaseModel):
|
||||||
assembly_path: str
|
assembly_path: str
|
||||||
output_dir: Optional[str] = None
|
output_dir: str | None = None
|
||||||
type_name: Optional[str] = None
|
type_name: str | None = None
|
||||||
language_version: LanguageVersion = LanguageVersion.LATEST
|
language_version: LanguageVersion = LanguageVersion.LATEST
|
||||||
create_project: bool = False
|
create_project: bool = False
|
||||||
show_il_code: bool = False
|
show_il_code: bool = False
|
||||||
remove_dead_code: bool = False
|
remove_dead_code: bool = False
|
||||||
|
remove_dead_stores: bool = False
|
||||||
|
show_il_sequence_points: bool = False
|
||||||
nested_directories: bool = False
|
nested_directories: bool = False
|
||||||
# ... additional fields
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### TypeInfo
|
### TypeInfo
|
||||||
@ -237,7 +557,7 @@ class TypeInfo(BaseModel):
|
|||||||
name: str
|
name: str
|
||||||
full_name: str
|
full_name: str
|
||||||
kind: str
|
kind: str
|
||||||
namespace: Optional[str] = None
|
namespace: str | None = None
|
||||||
```
|
```
|
||||||
|
|
||||||
### AssemblyInfo
|
### AssemblyInfo
|
||||||
@ -247,12 +567,61 @@ class AssemblyInfo(BaseModel):
|
|||||||
version: str
|
version: str
|
||||||
full_name: str
|
full_name: str
|
||||||
location: str
|
location: str
|
||||||
target_framework: Optional[str] = None
|
target_framework: str | None = None
|
||||||
runtime_version: Optional[str] = None
|
runtime_version: str | None = None
|
||||||
is_signed: bool = False
|
is_signed: bool = False
|
||||||
has_debug_info: bool = False
|
has_debug_info: bool = False
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### MethodInfo (metadata_reader)
|
||||||
|
```python
|
||||||
|
@dataclass
|
||||||
|
class MethodInfo:
|
||||||
|
name: str
|
||||||
|
full_name: str
|
||||||
|
declaring_type: str
|
||||||
|
namespace: str | None
|
||||||
|
return_type: str | None = None
|
||||||
|
is_public: bool = False
|
||||||
|
is_static: bool = False
|
||||||
|
is_virtual: bool = False
|
||||||
|
is_abstract: bool = False
|
||||||
|
parameters: list[str] = field(default_factory=list)
|
||||||
|
```
|
||||||
|
|
||||||
|
### FieldInfo (metadata_reader)
|
||||||
|
```python
|
||||||
|
@dataclass
|
||||||
|
class FieldInfo:
|
||||||
|
name: str
|
||||||
|
full_name: str
|
||||||
|
declaring_type: str
|
||||||
|
namespace: str | None
|
||||||
|
field_type: str | None = None
|
||||||
|
is_public: bool = False
|
||||||
|
is_static: bool = False
|
||||||
|
is_literal: bool = False # Constant
|
||||||
|
default_value: str | None = None
|
||||||
|
```
|
||||||
|
|
||||||
|
### AssemblyMetadata (metadata_reader)
|
||||||
|
```python
|
||||||
|
@dataclass
|
||||||
|
class AssemblyMetadata:
|
||||||
|
name: str
|
||||||
|
version: str
|
||||||
|
culture: str | None = None
|
||||||
|
public_key_token: str | None = None
|
||||||
|
target_framework: str | None = None
|
||||||
|
type_count: int = 0
|
||||||
|
method_count: int = 0
|
||||||
|
field_count: int = 0
|
||||||
|
property_count: int = 0
|
||||||
|
event_count: int = 0
|
||||||
|
resource_count: int = 0
|
||||||
|
referenced_assemblies: list[str] = field(default_factory=list)
|
||||||
|
```
|
||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
### Basic Decompilation
|
### Basic Decompilation
|
||||||
@ -271,7 +640,33 @@ result = await session.call_tool(
|
|||||||
"list_types",
|
"list_types",
|
||||||
{
|
{
|
||||||
"assembly_path": "MyApp.dll",
|
"assembly_path": "MyApp.dll",
|
||||||
"entity_types": ["c", "i"]
|
"entity_types": ["class", "interface"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Search for Service Classes
|
||||||
|
```python
|
||||||
|
# Find all classes with "Service" in their name
|
||||||
|
result = await session.call_tool(
|
||||||
|
"search_types",
|
||||||
|
{
|
||||||
|
"assembly_path": "MyApp.dll",
|
||||||
|
"pattern": "Service",
|
||||||
|
"entity_types": ["class", "interface"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Find Hardcoded URLs
|
||||||
|
```python
|
||||||
|
# Search for API endpoints
|
||||||
|
result = await session.call_tool(
|
||||||
|
"search_strings",
|
||||||
|
{
|
||||||
|
"assembly_path": "MyApp.dll",
|
||||||
|
"pattern": "https://",
|
||||||
|
"use_regex": False
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@ -285,11 +680,55 @@ result = await session.call_tool(
|
|||||||
"assembly_path": "MyApp.dll",
|
"assembly_path": "MyApp.dll",
|
||||||
"type_name": "MyApp.Core.Engine",
|
"type_name": "MyApp.Core.Engine",
|
||||||
"language_version": "CSharp11_0",
|
"language_version": "CSharp11_0",
|
||||||
"remove_dead_code": true
|
"remove_dead_code": True
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Search for Event Handlers (Direct Metadata)
|
||||||
|
```python
|
||||||
|
# Find all methods with "Handle" in their name
|
||||||
|
result = await session.call_tool(
|
||||||
|
"search_methods",
|
||||||
|
{
|
||||||
|
"assembly_path": "MyApp.dll",
|
||||||
|
"pattern": "Handle",
|
||||||
|
"public_only": True
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Find Constants
|
||||||
|
```python
|
||||||
|
# Search for connection string constants
|
||||||
|
result = await session.call_tool(
|
||||||
|
"search_fields",
|
||||||
|
{
|
||||||
|
"assembly_path": "MyApp.dll",
|
||||||
|
"pattern": "Connection",
|
||||||
|
"constants_only": True
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Assembly Statistics
|
||||||
|
```python
|
||||||
|
# Get comprehensive metadata summary
|
||||||
|
result = await session.call_tool(
|
||||||
|
"get_metadata_summary",
|
||||||
|
{"assembly_path": "MyApp.dll"}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### List Embedded Resources
|
||||||
|
```python
|
||||||
|
# Find what resources are embedded
|
||||||
|
result = await session.call_tool(
|
||||||
|
"list_resources",
|
||||||
|
{"assembly_path": "MyApp.dll"}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### Environment Variables
|
### Environment Variables
|
||||||
@ -305,7 +744,7 @@ For Claude Desktop:
|
|||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"ilspy": {
|
"ilspy": {
|
||||||
"command": "ilspy-mcp-server"
|
"command": "mcilspy"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,7 +756,7 @@ For development:
|
|||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"ilspy": {
|
"ilspy": {
|
||||||
"command": "python",
|
"command": "python",
|
||||||
"args": ["-m", "ilspy_mcp_server.server"],
|
"args": ["-m", "mcilspy.server"],
|
||||||
"env": {
|
"env": {
|
||||||
"LOGLEVEL": "DEBUG"
|
"LOGLEVEL": "DEBUG"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "ilspy-mcp-server"
|
name = "mcilspy"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
description = "MCP Server for ILSpy .NET Decompiler"
|
description = "MCP Server for ILSpy .NET Decompiler"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "Borealin", email = "me@borealin.cn"}
|
{name = "Borealin", email = "me@borealin.cn"}
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"mcp>=0.1.0",
|
"mcp>=1.0.0",
|
||||||
"pydantic>=2.0.0",
|
"pydantic>=2.7.0",
|
||||||
|
"dnfile>=0.15.0", # Direct .NET metadata parsing
|
||||||
]
|
]
|
||||||
requires-python = ">=3.8"
|
requires-python = ">=3.10"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = {text = "MIT"}
|
license = {text = "MIT"}
|
||||||
keywords = ["mcp", "ilspy", "decompiler", "dotnet", "csharp", "reverse-engineering"]
|
keywords = ["mcp", "ilspy", "decompiler", "dotnet", "csharp", "reverse-engineering"]
|
||||||
@ -18,11 +19,10 @@ classifiers = [
|
|||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"License :: OSI Approved :: MIT License",
|
"License :: OSI Approved :: MIT License",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.8",
|
|
||||||
"Programming Language :: Python :: 3.9",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
|
"Programming Language :: Python :: 3.13",
|
||||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||||
"Topic :: Software Development :: Debuggers",
|
"Topic :: Software Development :: Debuggers",
|
||||||
"Topic :: System :: Software Distribution",
|
"Topic :: System :: Software Distribution",
|
||||||
@ -34,14 +34,14 @@ Repository = "https://github.com/Borealin/ilspy-mcp-server.git"
|
|||||||
Issues = "https://github.com/Borealin/ilspy-mcp-server/issues"
|
Issues = "https://github.com/Borealin/ilspy-mcp-server/issues"
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
ilspy-mcp-server = "ilspy_mcp_server.server:main"
|
mcilspy = "mcilspy.server:main"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling"]
|
||||||
build-backend = "hatchling.build"
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
packages = ["src/ilspy_mcp_server"]
|
packages = ["src/mcilspy"]
|
||||||
|
|
||||||
[tool.hatch.build.targets.sdist]
|
[tool.hatch.build.targets.sdist]
|
||||||
include = [
|
include = [
|
||||||
@ -49,3 +49,15 @@ include = [
|
|||||||
"/README.md",
|
"/README.md",
|
||||||
"/LICENSE",
|
"/LICENSE",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
target-version = "py310"
|
||||||
|
line-length = 100
|
||||||
|
src = ["src"]
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = ["E", "F", "W", "I", "UP", "B", "SIM"]
|
||||||
|
ignore = ["E501"] # line length handled by formatter
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
quote-style = "double"
|
||||||
@ -1,96 +0,0 @@
|
|||||||
from typing import Optional, List
|
|
||||||
from pydantic import BaseModel, Field
|
|
||||||
from enum import Enum
|
|
||||||
|
|
||||||
class LanguageVersion(str, Enum):
|
|
||||||
"""C# Language versions supported by ILSpy."""
|
|
||||||
CSHARP1 = "CSharp1"
|
|
||||||
CSHARP2 = "CSharp2"
|
|
||||||
CSHARP3 = "CSharp3"
|
|
||||||
CSHARP4 = "CSharp4"
|
|
||||||
CSHARP5 = "CSharp5"
|
|
||||||
CSHARP6 = "CSharp6"
|
|
||||||
CSHARP7 = "CSharp7"
|
|
||||||
CSHARP7_1 = "CSharp7_1"
|
|
||||||
CSHARP7_2 = "CSharp7_2"
|
|
||||||
CSHARP7_3 = "CSharp7_3"
|
|
||||||
CSHARP8_0 = "CSharp8_0"
|
|
||||||
CSHARP9_0 = "CSharp9_0"
|
|
||||||
CSHARP10_0 = "CSharp10_0"
|
|
||||||
CSHARP11_0 = "CSharp11_0"
|
|
||||||
CSHARP12_0 = "CSharp12_0"
|
|
||||||
PREVIEW = "Preview"
|
|
||||||
LATEST = "Latest"
|
|
||||||
|
|
||||||
class EntityType(str, Enum):
|
|
||||||
"""Entity types that can be listed."""
|
|
||||||
CLASS = "c"
|
|
||||||
INTERFACE = "i"
|
|
||||||
STRUCT = "s"
|
|
||||||
DELEGATE = "d"
|
|
||||||
ENUM = "e"
|
|
||||||
class DecompileRequest(BaseModel):
|
|
||||||
"""Request to decompile a .NET assembly."""
|
|
||||||
assembly_path: str
|
|
||||||
output_dir: Optional[str] = None
|
|
||||||
type_name: Optional[str] = None
|
|
||||||
language_version: LanguageVersion = LanguageVersion.LATEST
|
|
||||||
create_project: bool = False
|
|
||||||
show_il_code: bool = False
|
|
||||||
reference_paths: List[str] = Field(default_factory=list)
|
|
||||||
remove_dead_code: bool = False
|
|
||||||
nested_directories: bool = False
|
|
||||||
|
|
||||||
class ListTypesRequest(BaseModel):
|
|
||||||
"""Request to list types in an assembly."""
|
|
||||||
assembly_path: str
|
|
||||||
entity_types: List[EntityType] = Field(default_factory=lambda: [EntityType.CLASS])
|
|
||||||
reference_paths: List[str] = Field(default_factory=list)
|
|
||||||
|
|
||||||
class TypeInfo(BaseModel):
|
|
||||||
"""Information about a type in an assembly."""
|
|
||||||
name: str
|
|
||||||
full_name: str
|
|
||||||
kind: str
|
|
||||||
namespace: Optional[str] = None
|
|
||||||
|
|
||||||
class DecompileResponse(BaseModel):
|
|
||||||
"""Response from decompilation operation."""
|
|
||||||
success: bool
|
|
||||||
source_code: Optional[str] = None
|
|
||||||
output_path: Optional[str] = None
|
|
||||||
error_message: Optional[str] = None
|
|
||||||
assembly_name: str
|
|
||||||
type_name: Optional[str] = None
|
|
||||||
|
|
||||||
class ListTypesResponse(BaseModel):
|
|
||||||
"""Response from list types operation."""
|
|
||||||
success: bool
|
|
||||||
types: List[TypeInfo] = Field(default_factory=list)
|
|
||||||
total_count: int = 0
|
|
||||||
error_message: Optional[str] = None
|
|
||||||
|
|
||||||
class GenerateDiagrammerRequest(BaseModel):
|
|
||||||
"""Request to generate HTML diagrammer."""
|
|
||||||
assembly_path: str
|
|
||||||
output_dir: Optional[str] = None
|
|
||||||
include_pattern: Optional[str] = None
|
|
||||||
exclude_pattern: Optional[str] = None
|
|
||||||
docs_path: Optional[str] = None
|
|
||||||
strip_namespaces: List[str] = Field(default_factory=list)
|
|
||||||
report_excluded: bool = False
|
|
||||||
|
|
||||||
class AssemblyInfoRequest(BaseModel):
|
|
||||||
"""Request to get assembly information."""
|
|
||||||
assembly_path: str
|
|
||||||
|
|
||||||
class AssemblyInfo(BaseModel):
|
|
||||||
"""Information about an assembly."""
|
|
||||||
name: str
|
|
||||||
version: str
|
|
||||||
full_name: str
|
|
||||||
location: str
|
|
||||||
target_framework: Optional[str] = None
|
|
||||||
runtime_version: Optional[str] = None
|
|
||||||
is_signed: bool = False
|
|
||||||
has_debug_info: bool = False
|
|
||||||
@ -1,268 +0,0 @@
|
|||||||
import logging
|
|
||||||
import os
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from mcp.server.fastmcp import FastMCP, Context
|
|
||||||
from .ilspy_wrapper import ILSpyWrapper
|
|
||||||
from .models import LanguageVersion, EntityType
|
|
||||||
|
|
||||||
# Setup logging
|
|
||||||
log_level = os.getenv('LOGLEVEL', 'INFO').upper()
|
|
||||||
logging.basicConfig(
|
|
||||||
level=getattr(logging, log_level, logging.INFO),
|
|
||||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
||||||
)
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# Create FastMCP server - much simpler than before!
|
|
||||||
mcp = FastMCP("ilspy-mcp-server")
|
|
||||||
|
|
||||||
# Global ILSpy wrapper
|
|
||||||
ilspy_wrapper: Optional[ILSpyWrapper] = None
|
|
||||||
|
|
||||||
def get_wrapper() -> ILSpyWrapper:
|
|
||||||
"""Get ILSpy wrapper instance"""
|
|
||||||
global ilspy_wrapper
|
|
||||||
if ilspy_wrapper is None:
|
|
||||||
ilspy_wrapper = ILSpyWrapper()
|
|
||||||
return ilspy_wrapper
|
|
||||||
|
|
||||||
@mcp.tool()
|
|
||||||
async def decompile_assembly(
|
|
||||||
assembly_path: str,
|
|
||||||
output_dir: str = None,
|
|
||||||
type_name: str = None,
|
|
||||||
language_version: str = "Latest",
|
|
||||||
create_project: bool = False,
|
|
||||||
show_il_code: bool = False,
|
|
||||||
remove_dead_code: bool = False,
|
|
||||||
nested_directories: bool = False,
|
|
||||||
ctx: Context = None
|
|
||||||
) -> str:
|
|
||||||
"""Decompile a .NET assembly to C# source code
|
|
||||||
|
|
||||||
Args:
|
|
||||||
assembly_path: Path to the .NET assembly file (.dll or .exe)
|
|
||||||
output_dir: Output directory for decompiled files (optional)
|
|
||||||
type_name: Fully qualified name of specific type to decompile (optional)
|
|
||||||
language_version: C# language version to use (default: Latest)
|
|
||||||
create_project: Create a compilable project with multiple files
|
|
||||||
show_il_code: Show IL code instead of C#
|
|
||||||
remove_dead_code: Remove dead code during decompilation
|
|
||||||
nested_directories: Use nested directories for namespaces
|
|
||||||
"""
|
|
||||||
if ctx:
|
|
||||||
await ctx.info(f"Starting decompilation of assembly: {assembly_path}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
wrapper = get_wrapper()
|
|
||||||
|
|
||||||
# Use simplified request object (no complex pydantic validation needed)
|
|
||||||
from .models import DecompileRequest
|
|
||||||
request = DecompileRequest(
|
|
||||||
assembly_path=assembly_path,
|
|
||||||
output_dir=output_dir,
|
|
||||||
type_name=type_name,
|
|
||||||
language_version=LanguageVersion(language_version),
|
|
||||||
create_project=create_project,
|
|
||||||
show_il_code=show_il_code,
|
|
||||||
remove_dead_code=remove_dead_code,
|
|
||||||
nested_directories=nested_directories
|
|
||||||
)
|
|
||||||
|
|
||||||
response = await wrapper.decompile(request)
|
|
||||||
|
|
||||||
if response.success:
|
|
||||||
if response.source_code:
|
|
||||||
content = f"# Decompilation result: {response.assembly_name}"
|
|
||||||
if response.type_name:
|
|
||||||
content += f" - {response.type_name}"
|
|
||||||
content += f"\n\n```csharp\n{response.source_code}\n```"
|
|
||||||
return content
|
|
||||||
else:
|
|
||||||
return f"Decompilation successful! Files saved to: {response.output_path}"
|
|
||||||
else:
|
|
||||||
return f"Decompilation failed: {response.error_message}"
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Decompilation error: {e}")
|
|
||||||
return f"Error: {str(e)}"
|
|
||||||
|
|
||||||
@mcp.tool()
|
|
||||||
async def list_types(
|
|
||||||
assembly_path: str,
|
|
||||||
entity_types: list[str] = None,
|
|
||||||
ctx: Context = None
|
|
||||||
) -> str:
|
|
||||||
"""List types (classes, interfaces, structs, etc.) in a .NET assembly
|
|
||||||
|
|
||||||
Args:
|
|
||||||
assembly_path: Path to the .NET assembly file (.dll or .exe)
|
|
||||||
entity_types: Types of entities to list (c=class, i=interface, s=struct, d=delegate, e=enum)
|
|
||||||
"""
|
|
||||||
if ctx:
|
|
||||||
await ctx.info(f"Listing types in assembly: {assembly_path}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
wrapper = get_wrapper()
|
|
||||||
|
|
||||||
# Default to list only classes
|
|
||||||
if entity_types is None:
|
|
||||||
entity_types = ["c"]
|
|
||||||
|
|
||||||
# Convert to EntityType enums
|
|
||||||
entity_type_enums = []
|
|
||||||
for et in entity_types:
|
|
||||||
try:
|
|
||||||
entity_type_enums.append(EntityType(et))
|
|
||||||
except ValueError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
from .models import ListTypesRequest
|
|
||||||
request = ListTypesRequest(
|
|
||||||
assembly_path=assembly_path,
|
|
||||||
entity_types=entity_type_enums
|
|
||||||
)
|
|
||||||
|
|
||||||
response = await wrapper.list_types(request)
|
|
||||||
|
|
||||||
if response.success and response.types:
|
|
||||||
content = f"# Types in {assembly_path}\n\n"
|
|
||||||
content += f"Found {response.total_count} types:\n\n"
|
|
||||||
|
|
||||||
# Group by namespace
|
|
||||||
by_namespace = {}
|
|
||||||
for type_info in response.types:
|
|
||||||
ns = type_info.namespace or "(Global)"
|
|
||||||
if ns not in by_namespace:
|
|
||||||
by_namespace[ns] = []
|
|
||||||
by_namespace[ns].append(type_info)
|
|
||||||
|
|
||||||
for namespace, types in sorted(by_namespace.items()):
|
|
||||||
content += f"## {namespace}\n\n"
|
|
||||||
for type_info in sorted(types, key=lambda t: t.name):
|
|
||||||
content += f"- **{type_info.name}** ({type_info.kind})\n"
|
|
||||||
content += f" - Full name: `{type_info.full_name}`\n"
|
|
||||||
content += "\n"
|
|
||||||
|
|
||||||
return content
|
|
||||||
else:
|
|
||||||
return response.error_message or "No types found in assembly"
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error listing types: {e}")
|
|
||||||
return f"Error: {str(e)}"
|
|
||||||
|
|
||||||
@mcp.tool()
|
|
||||||
async def generate_diagrammer(
|
|
||||||
assembly_path: str,
|
|
||||||
output_dir: str = None,
|
|
||||||
include_pattern: str = None,
|
|
||||||
exclude_pattern: str = None,
|
|
||||||
ctx: Context = None
|
|
||||||
) -> str:
|
|
||||||
"""Generate an interactive HTML diagrammer for visualizing assembly structure
|
|
||||||
|
|
||||||
Args:
|
|
||||||
assembly_path: Path to the .NET assembly file (.dll or .exe)
|
|
||||||
output_dir: Output directory for the diagrammer (optional)
|
|
||||||
include_pattern: Regex pattern for types to include (optional)
|
|
||||||
exclude_pattern: Regex pattern for types to exclude (optional)
|
|
||||||
"""
|
|
||||||
if ctx:
|
|
||||||
await ctx.info(f"Generating assembly diagram: {assembly_path}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
wrapper = get_wrapper()
|
|
||||||
|
|
||||||
from .models import GenerateDiagrammerRequest
|
|
||||||
request = GenerateDiagrammerRequest(
|
|
||||||
assembly_path=assembly_path,
|
|
||||||
output_dir=output_dir,
|
|
||||||
include_pattern=include_pattern,
|
|
||||||
exclude_pattern=exclude_pattern
|
|
||||||
)
|
|
||||||
|
|
||||||
response = await wrapper.generate_diagrammer(request)
|
|
||||||
|
|
||||||
if response["success"]:
|
|
||||||
return f"HTML diagram generated successfully!\nOutput directory: {response['output_directory']}\nOpen the HTML file in a web browser to view the interactive diagram."
|
|
||||||
else:
|
|
||||||
return f"Failed to generate diagram: {response['error_message']}"
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error generating diagram: {e}")
|
|
||||||
return f"Error: {str(e)}"
|
|
||||||
|
|
||||||
@mcp.tool()
|
|
||||||
async def get_assembly_info(
|
|
||||||
assembly_path: str,
|
|
||||||
ctx: Context = None
|
|
||||||
) -> str:
|
|
||||||
"""Get basic information about a .NET assembly
|
|
||||||
|
|
||||||
Args:
|
|
||||||
assembly_path: Path to the .NET assembly file (.dll or .exe)
|
|
||||||
"""
|
|
||||||
if ctx:
|
|
||||||
await ctx.info(f"Getting assembly info: {assembly_path}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
wrapper = get_wrapper()
|
|
||||||
|
|
||||||
from .models import AssemblyInfoRequest
|
|
||||||
request = AssemblyInfoRequest(assembly_path=assembly_path)
|
|
||||||
|
|
||||||
info = await wrapper.get_assembly_info(request)
|
|
||||||
|
|
||||||
content = f"# Assembly Information\n\n"
|
|
||||||
content += f"- **Name**: {info.name}\n"
|
|
||||||
content += f"- **Full Name**: {info.full_name}\n"
|
|
||||||
content += f"- **Location**: {info.location}\n"
|
|
||||||
content += f"- **Version**: {info.version}\n"
|
|
||||||
if info.target_framework:
|
|
||||||
content += f"- **Target Framework**: {info.target_framework}\n"
|
|
||||||
if info.runtime_version:
|
|
||||||
content += f"- **Runtime Version**: {info.runtime_version}\n"
|
|
||||||
content += f"- **Is Signed**: {info.is_signed}\n"
|
|
||||||
content += f"- **Has Debug Info**: {info.has_debug_info}\n"
|
|
||||||
|
|
||||||
return content
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error getting assembly info: {e}")
|
|
||||||
return f"Error: {str(e)}"
|
|
||||||
|
|
||||||
# FastMCP automatically handles prompts
|
|
||||||
@mcp.prompt()
|
|
||||||
def analyze_assembly_prompt(assembly_path: str, focus_area: str = "types") -> str:
|
|
||||||
"""Prompt template for analyzing .NET assemblies"""
|
|
||||||
return f"""I need to analyze the .NET assembly at "{assembly_path}".
|
|
||||||
|
|
||||||
Please help me understand:
|
|
||||||
1. The overall structure and organization of the assembly
|
|
||||||
2. Key types and their relationships
|
|
||||||
3. Main namespaces and their purposes
|
|
||||||
4. Any notable patterns or architectural decisions
|
|
||||||
|
|
||||||
Focus area: {focus_area}
|
|
||||||
|
|
||||||
Start by listing the types in the assembly, then provide insights based on what you find."""
|
|
||||||
|
|
||||||
@mcp.prompt()
|
|
||||||
def decompile_and_explain_prompt(assembly_path: str, type_name: str) -> str:
|
|
||||||
"""Prompt template for decompiling and explaining specific types"""
|
|
||||||
return f"""I want to understand the type "{type_name}" from the assembly "{assembly_path}".
|
|
||||||
|
|
||||||
Please:
|
|
||||||
1. Decompile this specific type
|
|
||||||
2. Explain what this type does and its purpose
|
|
||||||
3. Highlight any interesting patterns, design decisions, or potential issues
|
|
||||||
4. Suggest how this type fits into the overall architecture
|
|
||||||
|
|
||||||
Type to analyze: {type_name}
|
|
||||||
Assembly: {assembly_path}"""
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# FastMCP automatically handles running
|
|
||||||
mcp.run()
|
|
||||||
@ -1,3 +1,3 @@
|
|||||||
"""ILSpy MCP Server - Model Context Protocol server for .NET decompilation."""
|
"""ILSpy MCP Server - Model Context Protocol server for .NET decompilation."""
|
||||||
|
|
||||||
__version__ = "0.1.0"
|
__version__ = "0.1.1"
|
||||||
6
src/mcilspy/__main__.py
Normal file
6
src/mcilspy/__main__.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
"""Allow running as python -m mcilspy."""
|
||||||
|
|
||||||
|
from mcilspy.server import main
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -1,20 +1,23 @@
|
|||||||
"""Wrapper for ICSharpCode.ILSpyCmd command line tool."""
|
"""Wrapper for ICSharpCode.ILSpyCmd command line tool."""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Tuple, Dict, Any
|
from typing import Any
|
||||||
import re
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
DecompileRequest, DecompileResponse,
|
AssemblyInfo,
|
||||||
ListTypesRequest, ListTypesResponse, TypeInfo,
|
AssemblyInfoRequest,
|
||||||
GenerateDiagrammerRequest, AssemblyInfoRequest, AssemblyInfo,
|
DecompileRequest,
|
||||||
EntityType
|
DecompileResponse,
|
||||||
|
GenerateDiagrammerRequest,
|
||||||
|
ListTypesRequest,
|
||||||
|
ListTypesResponse,
|
||||||
|
TypeInfo,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -23,7 +26,7 @@ logger = logging.getLogger(__name__)
|
|||||||
class ILSpyWrapper:
|
class ILSpyWrapper:
|
||||||
"""Wrapper class for ILSpy command line tool."""
|
"""Wrapper class for ILSpy command line tool."""
|
||||||
|
|
||||||
def __init__(self, ilspycmd_path: Optional[str] = None):
|
def __init__(self, ilspycmd_path: str | None = None):
|
||||||
"""Initialize the wrapper.
|
"""Initialize the wrapper.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -31,9 +34,11 @@ class ILSpyWrapper:
|
|||||||
"""
|
"""
|
||||||
self.ilspycmd_path = ilspycmd_path or self._find_ilspycmd()
|
self.ilspycmd_path = ilspycmd_path or self._find_ilspycmd()
|
||||||
if not self.ilspycmd_path:
|
if not self.ilspycmd_path:
|
||||||
raise RuntimeError("ILSpyCmd not found. Please install it with: dotnet tool install --global ilspycmd")
|
raise RuntimeError(
|
||||||
|
"ILSpyCmd not found. Please install it with: dotnet tool install --global ilspycmd"
|
||||||
|
)
|
||||||
|
|
||||||
def _find_ilspycmd(self) -> Optional[str]:
|
def _find_ilspycmd(self) -> str | None:
|
||||||
"""Find ilspycmd executable in PATH."""
|
"""Find ilspycmd executable in PATH."""
|
||||||
# Try common names
|
# Try common names
|
||||||
for cmd_name in ["ilspycmd", "ilspycmd.exe"]:
|
for cmd_name in ["ilspycmd", "ilspycmd.exe"]:
|
||||||
@ -42,7 +47,9 @@ class ILSpyWrapper:
|
|||||||
return path
|
return path
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def _run_command(self, args: List[str], input_data: Optional[str] = None) -> Tuple[int, str, str]:
|
async def _run_command(
|
||||||
|
self, args: list[str], input_data: str | None = None
|
||||||
|
) -> tuple[int, str, str]:
|
||||||
"""Run ilspycmd with given arguments.
|
"""Run ilspycmd with given arguments.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -60,14 +67,14 @@ class ILSpyWrapper:
|
|||||||
*cmd,
|
*cmd,
|
||||||
stdin=asyncio.subprocess.PIPE if input_data else None,
|
stdin=asyncio.subprocess.PIPE if input_data else None,
|
||||||
stdout=asyncio.subprocess.PIPE,
|
stdout=asyncio.subprocess.PIPE,
|
||||||
stderr=asyncio.subprocess.PIPE
|
stderr=asyncio.subprocess.PIPE,
|
||||||
)
|
)
|
||||||
|
|
||||||
input_bytes = input_data.encode('utf-8') if input_data else None
|
input_bytes = input_data.encode("utf-8") if input_data else None
|
||||||
stdout_bytes, stderr_bytes = await process.communicate(input=input_bytes)
|
stdout_bytes, stderr_bytes = await process.communicate(input=input_bytes)
|
||||||
|
|
||||||
stdout = stdout_bytes.decode('utf-8', errors='replace') if stdout_bytes else ""
|
stdout = stdout_bytes.decode("utf-8", errors="replace") if stdout_bytes else ""
|
||||||
stderr = stderr_bytes.decode('utf-8', errors='replace') if stderr_bytes else ""
|
stderr = stderr_bytes.decode("utf-8", errors="replace") if stderr_bytes else ""
|
||||||
|
|
||||||
return process.returncode, stdout, stderr
|
return process.returncode, stdout, stderr
|
||||||
|
|
||||||
@ -88,7 +95,7 @@ class ILSpyWrapper:
|
|||||||
return DecompileResponse(
|
return DecompileResponse(
|
||||||
success=False,
|
success=False,
|
||||||
error_message=f"Assembly file not found: {request.assembly_path}",
|
error_message=f"Assembly file not found: {request.assembly_path}",
|
||||||
assembly_name=os.path.basename(request.assembly_path)
|
assembly_name=os.path.basename(request.assembly_path),
|
||||||
)
|
)
|
||||||
|
|
||||||
args = [request.assembly_path]
|
args = [request.assembly_path]
|
||||||
@ -121,10 +128,17 @@ class ILSpyWrapper:
|
|||||||
for ref_path in request.reference_paths:
|
for ref_path in request.reference_paths:
|
||||||
args.extend(["-r", ref_path])
|
args.extend(["-r", ref_path])
|
||||||
|
|
||||||
# Add optimization flag
|
# Add optimization flags
|
||||||
if request.remove_dead_code:
|
if request.remove_dead_code:
|
||||||
args.append("--no-dead-code")
|
args.append("--no-dead-code")
|
||||||
|
|
||||||
|
if request.remove_dead_stores:
|
||||||
|
args.append("--no-dead-stores")
|
||||||
|
|
||||||
|
# Add IL sequence points flag
|
||||||
|
if request.show_il_sequence_points:
|
||||||
|
args.append("--il-sequence-points")
|
||||||
|
|
||||||
# Add directory structure flag
|
# Add directory structure flag
|
||||||
if request.nested_directories:
|
if request.nested_directories:
|
||||||
args.append("--nested-directories")
|
args.append("--nested-directories")
|
||||||
@ -149,15 +163,17 @@ class ILSpyWrapper:
|
|||||||
# Try to read the main generated file if it exists
|
# Try to read the main generated file if it exists
|
||||||
if request.type_name:
|
if request.type_name:
|
||||||
# Single type decompilation
|
# Single type decompilation
|
||||||
type_file = os.path.join(output_dir, f"{request.type_name.split('.')[-1]}.cs")
|
type_file = os.path.join(
|
||||||
|
output_dir, f"{request.type_name.split('.')[-1]}.cs"
|
||||||
|
)
|
||||||
if os.path.exists(type_file):
|
if os.path.exists(type_file):
|
||||||
with open(type_file, 'r', encoding='utf-8') as f:
|
with open(type_file, encoding="utf-8") as f:
|
||||||
source_code = f.read()
|
source_code = f.read()
|
||||||
elif not request.create_project:
|
elif not request.create_project:
|
||||||
# Single file decompilation
|
# Single file decompilation
|
||||||
cs_file = os.path.join(output_dir, f"{assembly_name}.cs")
|
cs_file = os.path.join(output_dir, f"{assembly_name}.cs")
|
||||||
if os.path.exists(cs_file):
|
if os.path.exists(cs_file):
|
||||||
with open(cs_file, 'r', encoding='utf-8') as f:
|
with open(cs_file, encoding="utf-8") as f:
|
||||||
source_code = f.read()
|
source_code = f.read()
|
||||||
|
|
||||||
return DecompileResponse(
|
return DecompileResponse(
|
||||||
@ -165,7 +181,7 @@ class ILSpyWrapper:
|
|||||||
source_code=source_code,
|
source_code=source_code,
|
||||||
output_path=output_path,
|
output_path=output_path,
|
||||||
assembly_name=assembly_name,
|
assembly_name=assembly_name,
|
||||||
type_name=request.type_name
|
type_name=request.type_name,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
error_msg = stderr or stdout or "Unknown error occurred"
|
error_msg = stderr or stdout or "Unknown error occurred"
|
||||||
@ -173,7 +189,7 @@ class ILSpyWrapper:
|
|||||||
success=False,
|
success=False,
|
||||||
error_message=error_msg,
|
error_message=error_msg,
|
||||||
assembly_name=assembly_name,
|
assembly_name=assembly_name,
|
||||||
type_name=request.type_name
|
type_name=request.type_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -181,7 +197,7 @@ class ILSpyWrapper:
|
|||||||
success=False,
|
success=False,
|
||||||
error_message=str(e),
|
error_message=str(e),
|
||||||
assembly_name=os.path.basename(request.assembly_path),
|
assembly_name=os.path.basename(request.assembly_path),
|
||||||
type_name=request.type_name
|
type_name=request.type_name,
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
# Clean up temporary directory
|
# Clean up temporary directory
|
||||||
@ -199,8 +215,7 @@ class ILSpyWrapper:
|
|||||||
"""
|
"""
|
||||||
if not os.path.exists(request.assembly_path):
|
if not os.path.exists(request.assembly_path):
|
||||||
return ListTypesResponse(
|
return ListTypesResponse(
|
||||||
success=False,
|
success=False, error_message=f"Assembly file not found: {request.assembly_path}"
|
||||||
error_message=f"Assembly file not found: {request.assembly_path}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
args = [request.assembly_path]
|
args = [request.assembly_path]
|
||||||
@ -221,25 +236,15 @@ class ILSpyWrapper:
|
|||||||
|
|
||||||
if return_code == 0:
|
if return_code == 0:
|
||||||
types = self._parse_types_output(stdout)
|
types = self._parse_types_output(stdout)
|
||||||
return ListTypesResponse(
|
return ListTypesResponse(success=True, types=types, total_count=len(types))
|
||||||
success=True,
|
|
||||||
types=types,
|
|
||||||
total_count=len(types)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
error_msg = stderr or stdout or "Unknown error occurred"
|
error_msg = stderr or stdout or "Unknown error occurred"
|
||||||
return ListTypesResponse(
|
return ListTypesResponse(success=False, error_message=error_msg)
|
||||||
success=False,
|
|
||||||
error_message=error_msg
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return ListTypesResponse(
|
return ListTypesResponse(success=False, error_message=str(e))
|
||||||
success=False,
|
|
||||||
error_message=str(e)
|
|
||||||
)
|
|
||||||
|
|
||||||
def _parse_types_output(self, output: str) -> List[TypeInfo]:
|
def _parse_types_output(self, output: str) -> list[TypeInfo]:
|
||||||
"""Parse the output from list types command.
|
"""Parse the output from list types command.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -249,7 +254,7 @@ class ILSpyWrapper:
|
|||||||
List of TypeInfo objects
|
List of TypeInfo objects
|
||||||
"""
|
"""
|
||||||
types = []
|
types = []
|
||||||
lines = output.strip().split('\n')
|
lines = output.strip().split("\n")
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
@ -257,30 +262,27 @@ class ILSpyWrapper:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Parse the line format: "TypeKind: FullTypeName"
|
# Parse the line format: "TypeKind: FullTypeName"
|
||||||
match = re.match(r'^(\w+):\s*(.+)$', line)
|
match = re.match(r"^(\w+):\s*(.+)$", line)
|
||||||
if match:
|
if match:
|
||||||
kind = match.group(1)
|
kind = match.group(1)
|
||||||
full_name = match.group(2)
|
full_name = match.group(2)
|
||||||
|
|
||||||
# Extract namespace and name
|
# Extract namespace and name
|
||||||
parts = full_name.split('.')
|
parts = full_name.split(".")
|
||||||
if len(parts) > 1:
|
if len(parts) > 1:
|
||||||
namespace = '.'.join(parts[:-1])
|
namespace = ".".join(parts[:-1])
|
||||||
name = parts[-1]
|
name = parts[-1]
|
||||||
else:
|
else:
|
||||||
namespace = None
|
namespace = None
|
||||||
name = full_name
|
name = full_name
|
||||||
|
|
||||||
types.append(TypeInfo(
|
types.append(
|
||||||
name=name,
|
TypeInfo(name=name, full_name=full_name, kind=kind, namespace=namespace)
|
||||||
full_name=full_name,
|
)
|
||||||
kind=kind,
|
|
||||||
namespace=namespace
|
|
||||||
))
|
|
||||||
|
|
||||||
return types
|
return types
|
||||||
|
|
||||||
async def generate_diagrammer(self, request: GenerateDiagrammerRequest) -> Dict[str, Any]:
|
async def generate_diagrammer(self, request: GenerateDiagrammerRequest) -> dict[str, Any]:
|
||||||
"""Generate HTML diagrammer for an assembly.
|
"""Generate HTML diagrammer for an assembly.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -292,7 +294,7 @@ class ILSpyWrapper:
|
|||||||
if not os.path.exists(request.assembly_path):
|
if not os.path.exists(request.assembly_path):
|
||||||
return {
|
return {
|
||||||
"success": False,
|
"success": False,
|
||||||
"error_message": f"Assembly file not found: {request.assembly_path}"
|
"error_message": f"Assembly file not found: {request.assembly_path}",
|
||||||
}
|
}
|
||||||
|
|
||||||
args = [request.assembly_path, "--generate-diagrammer"]
|
args = [request.assembly_path, "--generate-diagrammer"]
|
||||||
@ -334,44 +336,113 @@ class ILSpyWrapper:
|
|||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"output_directory": output_dir,
|
"output_directory": output_dir,
|
||||||
"message": "HTML diagrammer generated successfully"
|
"message": "HTML diagrammer generated successfully",
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
error_msg = stderr or stdout or "Unknown error occurred"
|
error_msg = stderr or stdout or "Unknown error occurred"
|
||||||
return {
|
return {"success": False, "error_message": error_msg}
|
||||||
"success": False,
|
|
||||||
"error_message": error_msg
|
|
||||||
}
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {
|
return {"success": False, "error_message": str(e)}
|
||||||
"success": False,
|
|
||||||
"error_message": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
async def get_assembly_info(self, request: AssemblyInfoRequest) -> AssemblyInfo:
|
async def get_assembly_info(self, request: AssemblyInfoRequest) -> AssemblyInfo:
|
||||||
"""Get basic information about an assembly.
|
"""Get detailed information about an assembly by decompiling assembly attributes.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
request: Assembly info request
|
request: Assembly info request
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Assembly information
|
Assembly information including version, target framework, etc.
|
||||||
"""
|
"""
|
||||||
if not os.path.exists(request.assembly_path):
|
if not os.path.exists(request.assembly_path):
|
||||||
raise FileNotFoundError(f"Assembly file not found: {request.assembly_path}")
|
raise FileNotFoundError(f"Assembly file not found: {request.assembly_path}")
|
||||||
|
|
||||||
# For now, we'll extract basic info from the file path
|
|
||||||
# In a more complete implementation, we could use reflection or metadata reading
|
|
||||||
assembly_path = Path(request.assembly_path)
|
assembly_path = Path(request.assembly_path)
|
||||||
|
|
||||||
return AssemblyInfo(
|
# Use ilspycmd to list types and extract assembly info from output
|
||||||
name=assembly_path.stem,
|
args = [request.assembly_path, "-l", "c", "--disable-updatecheck"]
|
||||||
version="Unknown",
|
return_code, stdout, stderr = await self._run_command(args)
|
||||||
full_name=assembly_path.name,
|
|
||||||
location=str(assembly_path.absolute()),
|
# Initialize with defaults
|
||||||
target_framework=None,
|
name = assembly_path.stem
|
||||||
runtime_version=None,
|
version = "Unknown"
|
||||||
is_signed=False,
|
full_name = assembly_path.name
|
||||||
has_debug_info=os.path.exists(assembly_path.with_suffix('.pdb'))
|
target_framework = None
|
||||||
|
runtime_version = None
|
||||||
|
is_signed = False
|
||||||
|
|
||||||
|
# Try to extract more info by decompiling assembly attributes
|
||||||
|
# Decompile with minimal output to get assembly-level attributes
|
||||||
|
temp_dir = tempfile.mkdtemp()
|
||||||
|
try:
|
||||||
|
args = [
|
||||||
|
request.assembly_path,
|
||||||
|
"-o",
|
||||||
|
temp_dir,
|
||||||
|
"-lv",
|
||||||
|
"Latest",
|
||||||
|
"--disable-updatecheck",
|
||||||
|
]
|
||||||
|
return_code, stdout, stderr = await self._run_command(args)
|
||||||
|
|
||||||
|
if return_code == 0:
|
||||||
|
# Look for AssemblyInfo or assembly attributes in output
|
||||||
|
# Parse common patterns from decompiled code
|
||||||
|
output_text = stdout
|
||||||
|
|
||||||
|
# Try to read main decompiled file for assembly attributes
|
||||||
|
main_file = os.path.join(temp_dir, f"{name}.cs")
|
||||||
|
if os.path.exists(main_file):
|
||||||
|
with open(main_file, encoding="utf-8") as f:
|
||||||
|
output_text = f.read()
|
||||||
|
|
||||||
|
# Extract version from AssemblyVersion attribute
|
||||||
|
version_match = re.search(
|
||||||
|
r'\[assembly:\s*AssemblyVersion\s*\(\s*"([^"]+)"\s*\)\s*\]', output_text
|
||||||
|
)
|
||||||
|
if version_match:
|
||||||
|
version = version_match.group(1)
|
||||||
|
|
||||||
|
# Extract file version as fallback
|
||||||
|
if version == "Unknown":
|
||||||
|
file_version_match = re.search(
|
||||||
|
r'\[assembly:\s*AssemblyFileVersion\s*\(\s*"([^"]+)"\s*\)\s*\]', output_text
|
||||||
|
)
|
||||||
|
if file_version_match:
|
||||||
|
version = file_version_match.group(1)
|
||||||
|
|
||||||
|
# Extract target framework
|
||||||
|
framework_match = re.search(
|
||||||
|
r'\[assembly:\s*TargetFramework\s*\(\s*"([^"]+)"', output_text
|
||||||
|
)
|
||||||
|
if framework_match:
|
||||||
|
target_framework = framework_match.group(1)
|
||||||
|
|
||||||
|
# Check for signing
|
||||||
|
is_signed = (
|
||||||
|
"[assembly: AssemblyKeyFile" in output_text
|
||||||
|
or "[assembly: AssemblyDelaySign" in output_text
|
||||||
|
or "PublicKeyToken=" in output_text
|
||||||
|
)
|
||||||
|
|
||||||
|
# Extract full name from assembly title or product
|
||||||
|
title_match = re.search(
|
||||||
|
r'\[assembly:\s*AssemblyTitle\s*\(\s*"([^"]+)"\s*\)\s*\]', output_text
|
||||||
|
)
|
||||||
|
if title_match:
|
||||||
|
full_name = f"{title_match.group(1)}, Version={version}"
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Clean up temp directory
|
||||||
|
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||||
|
|
||||||
|
return AssemblyInfo(
|
||||||
|
name=name,
|
||||||
|
version=version,
|
||||||
|
full_name=full_name,
|
||||||
|
location=str(assembly_path.absolute()),
|
||||||
|
target_framework=target_framework,
|
||||||
|
runtime_version=runtime_version,
|
||||||
|
is_signed=is_signed,
|
||||||
|
has_debug_info=os.path.exists(assembly_path.with_suffix(".pdb")),
|
||||||
)
|
)
|
||||||
596
src/mcilspy/metadata_reader.py
Normal file
596
src/mcilspy/metadata_reader.py
Normal file
@ -0,0 +1,596 @@
|
|||||||
|
"""Direct .NET metadata reader using dnfile.
|
||||||
|
|
||||||
|
Provides access to all 34+ CLR metadata tables without requiring ilspycmd.
|
||||||
|
This enables searching for methods, fields, properties, events, and resources
|
||||||
|
that are not exposed via the ilspycmd CLI.
|
||||||
|
|
||||||
|
Note: dnfile provides flag attributes as boolean properties (e.g., mdPublic, fdStatic)
|
||||||
|
rather than traditional IntFlag enums, so we use those directly.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import dnfile
|
||||||
|
from dnfile.mdtable import TypeDefRow
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MethodInfo:
|
||||||
|
"""Information about a method in an assembly."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
full_name: str
|
||||||
|
declaring_type: str
|
||||||
|
namespace: str | None
|
||||||
|
return_type: str | None = None
|
||||||
|
is_public: bool = False
|
||||||
|
is_static: bool = False
|
||||||
|
is_virtual: bool = False
|
||||||
|
is_abstract: bool = False
|
||||||
|
parameters: list[str] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FieldInfo:
|
||||||
|
"""Information about a field in an assembly."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
full_name: str
|
||||||
|
declaring_type: str
|
||||||
|
namespace: str | None
|
||||||
|
field_type: str | None = None
|
||||||
|
is_public: bool = False
|
||||||
|
is_static: bool = False
|
||||||
|
is_literal: bool = False # Constant
|
||||||
|
default_value: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PropertyInfo:
|
||||||
|
"""Information about a property in an assembly."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
full_name: str
|
||||||
|
declaring_type: str
|
||||||
|
namespace: str | None
|
||||||
|
property_type: str | None = None
|
||||||
|
has_getter: bool = False
|
||||||
|
has_setter: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class EventInfo:
|
||||||
|
"""Information about an event in an assembly."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
full_name: str
|
||||||
|
declaring_type: str
|
||||||
|
namespace: str | None
|
||||||
|
event_type: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ResourceInfo:
|
||||||
|
"""Information about an embedded resource."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
size: int
|
||||||
|
is_public: bool = True
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AssemblyMetadata:
|
||||||
|
"""Complete assembly metadata from dnfile."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
version: str
|
||||||
|
culture: str | None = None
|
||||||
|
public_key_token: str | None = None
|
||||||
|
target_framework: str | None = None
|
||||||
|
type_count: int = 0
|
||||||
|
method_count: int = 0
|
||||||
|
field_count: int = 0
|
||||||
|
property_count: int = 0
|
||||||
|
event_count: int = 0
|
||||||
|
resource_count: int = 0
|
||||||
|
referenced_assemblies: list[str] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
class MetadataReader:
|
||||||
|
"""Read .NET assembly metadata directly using dnfile."""
|
||||||
|
|
||||||
|
def __init__(self, assembly_path: str):
|
||||||
|
"""Initialize the metadata reader.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
assembly_path: Path to the .NET assembly file
|
||||||
|
"""
|
||||||
|
self.assembly_path = Path(assembly_path)
|
||||||
|
if not self.assembly_path.exists():
|
||||||
|
raise FileNotFoundError(f"Assembly not found: {assembly_path}")
|
||||||
|
|
||||||
|
self._pe: dnfile.dnPE | None = None
|
||||||
|
self._type_cache: dict[int, TypeDefRow] = {}
|
||||||
|
|
||||||
|
def _ensure_loaded(self) -> dnfile.dnPE:
|
||||||
|
"""Ensure the PE file is loaded."""
|
||||||
|
if self._pe is None:
|
||||||
|
try:
|
||||||
|
self._pe = dnfile.dnPE(str(self.assembly_path))
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError(f"Failed to parse assembly: {e}") from e
|
||||||
|
|
||||||
|
# Build type cache for lookups
|
||||||
|
if self._pe.net and self._pe.net.mdtables and self._pe.net.mdtables.TypeDef:
|
||||||
|
for i, td in enumerate(self._pe.net.mdtables.TypeDef):
|
||||||
|
self._type_cache[i + 1] = td # Metadata tokens are 1-indexed
|
||||||
|
|
||||||
|
return self._pe
|
||||||
|
|
||||||
|
def get_assembly_metadata(self) -> AssemblyMetadata:
|
||||||
|
"""Get comprehensive assembly metadata."""
|
||||||
|
pe = self._ensure_loaded()
|
||||||
|
|
||||||
|
name = self.assembly_path.stem
|
||||||
|
version = "0.0.0.0"
|
||||||
|
culture = None
|
||||||
|
public_key_token = None
|
||||||
|
target_framework = None
|
||||||
|
referenced_assemblies = []
|
||||||
|
|
||||||
|
if pe.net and pe.net.mdtables:
|
||||||
|
# Assembly info
|
||||||
|
if pe.net.mdtables.Assembly:
|
||||||
|
for asm in pe.net.mdtables.Assembly:
|
||||||
|
name = str(asm.Name) if asm.Name else name
|
||||||
|
version = f"{asm.MajorVersion}.{asm.MinorVersion}.{asm.BuildNumber}.{asm.RevisionNumber}"
|
||||||
|
culture = str(asm.Culture) if asm.Culture else None
|
||||||
|
if asm.PublicKey:
|
||||||
|
# Convert to token format - handle various dnfile representations
|
||||||
|
try:
|
||||||
|
pk = asm.PublicKey
|
||||||
|
if hasattr(pk, "value"):
|
||||||
|
pk_bytes = bytes(pk.value)
|
||||||
|
elif hasattr(pk, "__bytes__") or isinstance(pk, (bytes, bytearray)):
|
||||||
|
pk_bytes = bytes(pk)
|
||||||
|
else:
|
||||||
|
pk_bytes = b""
|
||||||
|
if pk_bytes:
|
||||||
|
public_key_token = (
|
||||||
|
pk_bytes[-8:].hex() if len(pk_bytes) >= 8 else pk_bytes.hex()
|
||||||
|
)
|
||||||
|
except (TypeError, AttributeError):
|
||||||
|
# Some dnfile versions can't convert HeapItemBinary directly
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Assembly references
|
||||||
|
if pe.net.mdtables.AssemblyRef:
|
||||||
|
for ref in pe.net.mdtables.AssemblyRef:
|
||||||
|
ref_name = str(ref.Name) if ref.Name else "Unknown"
|
||||||
|
ref_version = f"{ref.MajorVersion}.{ref.MinorVersion}.{ref.BuildNumber}.{ref.RevisionNumber}"
|
||||||
|
referenced_assemblies.append(f"{ref_name}, Version={ref_version}")
|
||||||
|
|
||||||
|
# Try to find TargetFramework from custom attributes
|
||||||
|
if pe.net.mdtables.CustomAttribute:
|
||||||
|
for ca in pe.net.mdtables.CustomAttribute:
|
||||||
|
# Look for TargetFrameworkAttribute
|
||||||
|
try:
|
||||||
|
if hasattr(ca, "Type") and ca.Type:
|
||||||
|
type_name = str(ca.Type) if ca.Type else ""
|
||||||
|
if "TargetFramework" in type_name and hasattr(ca, "Value") and ca.Value:
|
||||||
|
target_framework = str(ca.Value)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
type_count = (
|
||||||
|
len(pe.net.mdtables.TypeDef)
|
||||||
|
if pe.net and pe.net.mdtables and pe.net.mdtables.TypeDef
|
||||||
|
else 0
|
||||||
|
)
|
||||||
|
method_count = (
|
||||||
|
len(pe.net.mdtables.MethodDef)
|
||||||
|
if pe.net and pe.net.mdtables and pe.net.mdtables.MethodDef
|
||||||
|
else 0
|
||||||
|
)
|
||||||
|
field_count = (
|
||||||
|
len(pe.net.mdtables.Field)
|
||||||
|
if pe.net and pe.net.mdtables and pe.net.mdtables.Field
|
||||||
|
else 0
|
||||||
|
)
|
||||||
|
property_count = (
|
||||||
|
len(pe.net.mdtables.Property)
|
||||||
|
if pe.net and pe.net.mdtables and pe.net.mdtables.Property
|
||||||
|
else 0
|
||||||
|
)
|
||||||
|
event_count = (
|
||||||
|
len(pe.net.mdtables.Event)
|
||||||
|
if pe.net and pe.net.mdtables and pe.net.mdtables.Event
|
||||||
|
else 0
|
||||||
|
)
|
||||||
|
resource_count = (
|
||||||
|
len(pe.net.mdtables.ManifestResource)
|
||||||
|
if pe.net and pe.net.mdtables and pe.net.mdtables.ManifestResource
|
||||||
|
else 0
|
||||||
|
)
|
||||||
|
|
||||||
|
return AssemblyMetadata(
|
||||||
|
name=name,
|
||||||
|
version=version,
|
||||||
|
culture=culture,
|
||||||
|
public_key_token=public_key_token,
|
||||||
|
target_framework=target_framework,
|
||||||
|
type_count=type_count,
|
||||||
|
method_count=method_count,
|
||||||
|
field_count=field_count,
|
||||||
|
property_count=property_count,
|
||||||
|
event_count=event_count,
|
||||||
|
resource_count=resource_count,
|
||||||
|
referenced_assemblies=referenced_assemblies,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_row_index(self, reference) -> int:
|
||||||
|
"""Safely extract row_index from a metadata reference.
|
||||||
|
|
||||||
|
dnfile references can be either objects with .row_index attribute
|
||||||
|
or raw integers. This helper handles both cases.
|
||||||
|
"""
|
||||||
|
if reference is None:
|
||||||
|
return 0
|
||||||
|
if hasattr(reference, "row_index"):
|
||||||
|
return reference.row_index
|
||||||
|
if isinstance(reference, int):
|
||||||
|
return reference
|
||||||
|
# Some dnfile versions return the index directly as an attribute
|
||||||
|
if hasattr(reference, "value"):
|
||||||
|
return reference.value
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def list_methods(
|
||||||
|
self,
|
||||||
|
type_filter: str | None = None,
|
||||||
|
namespace_filter: str | None = None,
|
||||||
|
public_only: bool = False,
|
||||||
|
) -> list[MethodInfo]:
|
||||||
|
"""List all methods in the assembly.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type_filter: Only return methods from types containing this string
|
||||||
|
namespace_filter: Only return methods from types in namespaces containing this string
|
||||||
|
public_only: Only return public methods
|
||||||
|
"""
|
||||||
|
pe = self._ensure_loaded()
|
||||||
|
methods = []
|
||||||
|
|
||||||
|
if not (
|
||||||
|
pe.net and pe.net.mdtables and pe.net.mdtables.TypeDef and pe.net.mdtables.MethodDef
|
||||||
|
):
|
||||||
|
return methods
|
||||||
|
|
||||||
|
# Build method-to-type mapping
|
||||||
|
# TypeDef.MethodList points to the first method of each type
|
||||||
|
type_method_ranges: list[tuple[TypeDefRow, int, int]] = []
|
||||||
|
type_defs = list(pe.net.mdtables.TypeDef)
|
||||||
|
method_count = len(pe.net.mdtables.MethodDef)
|
||||||
|
|
||||||
|
for i, td in enumerate(type_defs):
|
||||||
|
start_idx = self._get_row_index(td.MethodList)
|
||||||
|
if i + 1 < len(type_defs):
|
||||||
|
next_method_list = type_defs[i + 1].MethodList
|
||||||
|
end_idx = self._get_row_index(next_method_list) or (method_count + 1)
|
||||||
|
else:
|
||||||
|
end_idx = method_count + 1
|
||||||
|
type_method_ranges.append((td, start_idx, end_idx))
|
||||||
|
|
||||||
|
# Iterate through methods
|
||||||
|
for md_idx, md in enumerate(pe.net.mdtables.MethodDef, start=1):
|
||||||
|
# Find declaring type
|
||||||
|
declaring_type = None
|
||||||
|
namespace = None
|
||||||
|
for td, start, end in type_method_ranges:
|
||||||
|
if start <= md_idx < end:
|
||||||
|
declaring_type = str(td.TypeName) if td.TypeName else "Unknown"
|
||||||
|
namespace = str(td.TypeNamespace) if td.TypeNamespace else None
|
||||||
|
break
|
||||||
|
|
||||||
|
if declaring_type is None:
|
||||||
|
declaring_type = "Unknown"
|
||||||
|
|
||||||
|
# Apply filters
|
||||||
|
if type_filter and type_filter.lower() not in declaring_type.lower():
|
||||||
|
continue
|
||||||
|
if namespace_filter and (
|
||||||
|
namespace is None or namespace_filter.lower() not in namespace.lower()
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Parse attributes using dnfile's boolean properties on ClrMethodAttr
|
||||||
|
flags = md.Flags if hasattr(md, "Flags") else None
|
||||||
|
is_public = flags.mdPublic if flags and hasattr(flags, "mdPublic") else False
|
||||||
|
is_static = flags.mdStatic if flags and hasattr(flags, "mdStatic") else False
|
||||||
|
is_virtual = flags.mdVirtual if flags and hasattr(flags, "mdVirtual") else False
|
||||||
|
is_abstract = flags.mdAbstract if flags and hasattr(flags, "mdAbstract") else False
|
||||||
|
|
||||||
|
if public_only and not is_public:
|
||||||
|
continue
|
||||||
|
|
||||||
|
method_name = str(md.Name) if md.Name else "Unknown"
|
||||||
|
full_name = (
|
||||||
|
f"{namespace}.{declaring_type}.{method_name}"
|
||||||
|
if namespace
|
||||||
|
else f"{declaring_type}.{method_name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
methods.append(
|
||||||
|
MethodInfo(
|
||||||
|
name=method_name,
|
||||||
|
full_name=full_name,
|
||||||
|
declaring_type=declaring_type,
|
||||||
|
namespace=namespace,
|
||||||
|
is_public=is_public,
|
||||||
|
is_static=is_static,
|
||||||
|
is_virtual=is_virtual,
|
||||||
|
is_abstract=is_abstract,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return methods
|
||||||
|
|
||||||
|
def list_fields(
|
||||||
|
self,
|
||||||
|
type_filter: str | None = None,
|
||||||
|
namespace_filter: str | None = None,
|
||||||
|
public_only: bool = False,
|
||||||
|
constants_only: bool = False,
|
||||||
|
) -> list[FieldInfo]:
|
||||||
|
"""List all fields in the assembly.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type_filter: Only return fields from types containing this string
|
||||||
|
namespace_filter: Only return fields from types in namespaces containing this string
|
||||||
|
public_only: Only return public fields
|
||||||
|
constants_only: Only return constant (literal) fields
|
||||||
|
"""
|
||||||
|
pe = self._ensure_loaded()
|
||||||
|
fields = []
|
||||||
|
|
||||||
|
if not (pe.net and pe.net.mdtables and pe.net.mdtables.TypeDef and pe.net.mdtables.Field):
|
||||||
|
return fields
|
||||||
|
|
||||||
|
# Build field-to-type mapping
|
||||||
|
type_defs = list(pe.net.mdtables.TypeDef)
|
||||||
|
field_count = len(pe.net.mdtables.Field)
|
||||||
|
|
||||||
|
type_field_ranges: list[tuple[TypeDefRow, int, int]] = []
|
||||||
|
for i, td in enumerate(type_defs):
|
||||||
|
start_idx = self._get_row_index(td.FieldList)
|
||||||
|
if i + 1 < len(type_defs):
|
||||||
|
next_field_list = type_defs[i + 1].FieldList
|
||||||
|
end_idx = self._get_row_index(next_field_list) or (field_count + 1)
|
||||||
|
else:
|
||||||
|
end_idx = field_count + 1
|
||||||
|
type_field_ranges.append((td, start_idx, end_idx))
|
||||||
|
|
||||||
|
# Iterate through fields
|
||||||
|
for f_idx, fld in enumerate(pe.net.mdtables.Field, start=1):
|
||||||
|
# Find declaring type
|
||||||
|
declaring_type = None
|
||||||
|
namespace = None
|
||||||
|
for td, start, end in type_field_ranges:
|
||||||
|
if start <= f_idx < end:
|
||||||
|
declaring_type = str(td.TypeName) if td.TypeName else "Unknown"
|
||||||
|
namespace = str(td.TypeNamespace) if td.TypeNamespace else None
|
||||||
|
break
|
||||||
|
|
||||||
|
if declaring_type is None:
|
||||||
|
declaring_type = "Unknown"
|
||||||
|
|
||||||
|
# Apply filters
|
||||||
|
if type_filter and type_filter.lower() not in declaring_type.lower():
|
||||||
|
continue
|
||||||
|
if namespace_filter and (
|
||||||
|
namespace is None or namespace_filter.lower() not in namespace.lower()
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Parse attributes using dnfile's boolean properties on ClrFieldAttr
|
||||||
|
flags = fld.Flags if hasattr(fld, "Flags") else None
|
||||||
|
is_public = flags.fdPublic if flags and hasattr(flags, "fdPublic") else False
|
||||||
|
is_static = flags.fdStatic if flags and hasattr(flags, "fdStatic") else False
|
||||||
|
is_literal = flags.fdLiteral if flags and hasattr(flags, "fdLiteral") else False
|
||||||
|
|
||||||
|
if public_only and not is_public:
|
||||||
|
continue
|
||||||
|
if constants_only and not is_literal:
|
||||||
|
continue
|
||||||
|
|
||||||
|
field_name = str(fld.Name) if fld.Name else "Unknown"
|
||||||
|
full_name = (
|
||||||
|
f"{namespace}.{declaring_type}.{field_name}"
|
||||||
|
if namespace
|
||||||
|
else f"{declaring_type}.{field_name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
fields.append(
|
||||||
|
FieldInfo(
|
||||||
|
name=field_name,
|
||||||
|
full_name=full_name,
|
||||||
|
declaring_type=declaring_type,
|
||||||
|
namespace=namespace,
|
||||||
|
is_public=is_public,
|
||||||
|
is_static=is_static,
|
||||||
|
is_literal=is_literal,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return fields
|
||||||
|
|
||||||
|
def list_properties(
|
||||||
|
self,
|
||||||
|
type_filter: str | None = None,
|
||||||
|
namespace_filter: str | None = None,
|
||||||
|
) -> list[PropertyInfo]:
|
||||||
|
"""List all properties in the assembly."""
|
||||||
|
pe = self._ensure_loaded()
|
||||||
|
properties = []
|
||||||
|
|
||||||
|
if not (pe.net and pe.net.mdtables and pe.net.mdtables.Property):
|
||||||
|
return properties
|
||||||
|
|
||||||
|
# PropertyMap links types to properties
|
||||||
|
property_type_map: dict[int, tuple[str, str | None]] = {}
|
||||||
|
if pe.net.mdtables.PropertyMap and pe.net.mdtables.TypeDef:
|
||||||
|
prop_maps = list(pe.net.mdtables.PropertyMap)
|
||||||
|
type_defs = list(pe.net.mdtables.TypeDef)
|
||||||
|
for i, pm in enumerate(prop_maps):
|
||||||
|
if pm.Parent and pm.PropertyList:
|
||||||
|
parent_idx = self._get_row_index(pm.Parent)
|
||||||
|
if parent_idx > 0 and parent_idx <= len(type_defs):
|
||||||
|
td = type_defs[parent_idx - 1]
|
||||||
|
type_name = str(td.TypeName) if td.TypeName else "Unknown"
|
||||||
|
ns = str(td.TypeNamespace) if td.TypeNamespace else None
|
||||||
|
|
||||||
|
# Determine property range
|
||||||
|
start_idx = self._get_row_index(pm.PropertyList)
|
||||||
|
if i + 1 < len(prop_maps):
|
||||||
|
end_idx = self._get_row_index(prop_maps[i + 1].PropertyList)
|
||||||
|
else:
|
||||||
|
end_idx = len(pe.net.mdtables.Property) + 1
|
||||||
|
|
||||||
|
for p_idx in range(start_idx, end_idx):
|
||||||
|
property_type_map[p_idx] = (type_name, ns)
|
||||||
|
|
||||||
|
# Iterate through properties
|
||||||
|
for p_idx, prop in enumerate(pe.net.mdtables.Property, start=1):
|
||||||
|
declaring_type, namespace = property_type_map.get(p_idx, ("Unknown", None))
|
||||||
|
|
||||||
|
# Apply filters
|
||||||
|
if type_filter and type_filter.lower() not in declaring_type.lower():
|
||||||
|
continue
|
||||||
|
if namespace_filter and (
|
||||||
|
namespace is None or namespace_filter.lower() not in namespace.lower()
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
prop_name = str(prop.Name) if prop.Name else "Unknown"
|
||||||
|
full_name = (
|
||||||
|
f"{namespace}.{declaring_type}.{prop_name}"
|
||||||
|
if namespace
|
||||||
|
else f"{declaring_type}.{prop_name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
properties.append(
|
||||||
|
PropertyInfo(
|
||||||
|
name=prop_name,
|
||||||
|
full_name=full_name,
|
||||||
|
declaring_type=declaring_type,
|
||||||
|
namespace=namespace,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return properties
|
||||||
|
|
||||||
|
def list_events(
|
||||||
|
self,
|
||||||
|
type_filter: str | None = None,
|
||||||
|
namespace_filter: str | None = None,
|
||||||
|
) -> list[EventInfo]:
|
||||||
|
"""List all events in the assembly."""
|
||||||
|
pe = self._ensure_loaded()
|
||||||
|
events = []
|
||||||
|
|
||||||
|
if not (pe.net and pe.net.mdtables and pe.net.mdtables.Event):
|
||||||
|
return events
|
||||||
|
|
||||||
|
# EventMap links types to events
|
||||||
|
event_type_map: dict[int, tuple[str, str | None]] = {}
|
||||||
|
if pe.net.mdtables.EventMap and pe.net.mdtables.TypeDef:
|
||||||
|
event_maps = list(pe.net.mdtables.EventMap)
|
||||||
|
type_defs = list(pe.net.mdtables.TypeDef)
|
||||||
|
for i, em in enumerate(event_maps):
|
||||||
|
if em.Parent and em.EventList:
|
||||||
|
parent_idx = self._get_row_index(em.Parent)
|
||||||
|
if parent_idx > 0 and parent_idx <= len(type_defs):
|
||||||
|
td = type_defs[parent_idx - 1]
|
||||||
|
type_name = str(td.TypeName) if td.TypeName else "Unknown"
|
||||||
|
ns = str(td.TypeNamespace) if td.TypeNamespace else None
|
||||||
|
|
||||||
|
start_idx = self._get_row_index(em.EventList)
|
||||||
|
if i + 1 < len(event_maps):
|
||||||
|
end_idx = self._get_row_index(event_maps[i + 1].EventList)
|
||||||
|
else:
|
||||||
|
end_idx = len(pe.net.mdtables.Event) + 1
|
||||||
|
|
||||||
|
for e_idx in range(start_idx, end_idx):
|
||||||
|
event_type_map[e_idx] = (type_name, ns)
|
||||||
|
|
||||||
|
for e_idx, evt in enumerate(pe.net.mdtables.Event, start=1):
|
||||||
|
declaring_type, namespace = event_type_map.get(e_idx, ("Unknown", None))
|
||||||
|
|
||||||
|
if type_filter and type_filter.lower() not in declaring_type.lower():
|
||||||
|
continue
|
||||||
|
if namespace_filter and (
|
||||||
|
namespace is None or namespace_filter.lower() not in namespace.lower()
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
evt_name = str(evt.Name) if evt.Name else "Unknown"
|
||||||
|
full_name = (
|
||||||
|
f"{namespace}.{declaring_type}.{evt_name}"
|
||||||
|
if namespace
|
||||||
|
else f"{declaring_type}.{evt_name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
events.append(
|
||||||
|
EventInfo(
|
||||||
|
name=evt_name,
|
||||||
|
full_name=full_name,
|
||||||
|
declaring_type=declaring_type,
|
||||||
|
namespace=namespace,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return events
|
||||||
|
|
||||||
|
def list_resources(self) -> list[ResourceInfo]:
|
||||||
|
"""List all embedded resources in the assembly."""
|
||||||
|
pe = self._ensure_loaded()
|
||||||
|
resources = []
|
||||||
|
|
||||||
|
if not (pe.net and pe.net.mdtables and pe.net.mdtables.ManifestResource):
|
||||||
|
return resources
|
||||||
|
|
||||||
|
for res in pe.net.mdtables.ManifestResource:
|
||||||
|
name = str(res.Name) if res.Name else "Unknown"
|
||||||
|
# dnfile exposes flags as boolean properties (mrPublic, mrPrivate)
|
||||||
|
is_public = (
|
||||||
|
res.Flags.mrPublic
|
||||||
|
if hasattr(res, "Flags") and hasattr(res.Flags, "mrPublic")
|
||||||
|
else True
|
||||||
|
)
|
||||||
|
|
||||||
|
resources.append(
|
||||||
|
ResourceInfo(
|
||||||
|
name=name,
|
||||||
|
size=0, # Size requires reading the actual resource data
|
||||||
|
is_public=is_public,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return resources
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Close the PE file."""
|
||||||
|
if self._pe:
|
||||||
|
self._pe.close()
|
||||||
|
self._pe = None
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
self.close()
|
||||||
|
return False
|
||||||
163
src/mcilspy/models.py
Normal file
163
src/mcilspy/models.py
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class LanguageVersion(str, Enum):
|
||||||
|
"""C# Language versions supported by ILSpy."""
|
||||||
|
|
||||||
|
CSHARP1 = "CSharp1"
|
||||||
|
CSHARP2 = "CSharp2"
|
||||||
|
CSHARP3 = "CSharp3"
|
||||||
|
CSHARP4 = "CSharp4"
|
||||||
|
CSHARP5 = "CSharp5"
|
||||||
|
CSHARP6 = "CSharp6"
|
||||||
|
CSHARP7 = "CSharp7"
|
||||||
|
CSHARP7_1 = "CSharp7_1"
|
||||||
|
CSHARP7_2 = "CSharp7_2"
|
||||||
|
CSHARP7_3 = "CSharp7_3"
|
||||||
|
CSHARP8_0 = "CSharp8_0"
|
||||||
|
CSHARP9_0 = "CSharp9_0"
|
||||||
|
CSHARP10_0 = "CSharp10_0"
|
||||||
|
CSHARP11_0 = "CSharp11_0"
|
||||||
|
CSHARP12_0 = "CSharp12_0"
|
||||||
|
PREVIEW = "Preview"
|
||||||
|
LATEST = "Latest"
|
||||||
|
|
||||||
|
|
||||||
|
class EntityType(str, Enum):
|
||||||
|
"""Entity types that can be listed.
|
||||||
|
|
||||||
|
Accepts both full names and single-letter codes:
|
||||||
|
- "class" or "c" for classes
|
||||||
|
- "interface" or "i" for interfaces
|
||||||
|
- "struct" or "s" for structs
|
||||||
|
- "delegate" or "d" for delegates
|
||||||
|
- "enum" or "e" for enums
|
||||||
|
"""
|
||||||
|
|
||||||
|
CLASS = "c"
|
||||||
|
INTERFACE = "i"
|
||||||
|
STRUCT = "s"
|
||||||
|
DELEGATE = "d"
|
||||||
|
ENUM = "e"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_string(cls, value: str) -> "EntityType":
|
||||||
|
"""Convert a string (full name or single letter) to EntityType.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: Either a single letter (c, i, s, d, e) or full name (class, interface, etc.)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The corresponding EntityType enum value
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the value doesn't match any known entity type
|
||||||
|
"""
|
||||||
|
value_lower = value.lower().strip()
|
||||||
|
|
||||||
|
# Map full names to single letters
|
||||||
|
name_map = {
|
||||||
|
"class": "c",
|
||||||
|
"interface": "i",
|
||||||
|
"struct": "s",
|
||||||
|
"delegate": "d",
|
||||||
|
"enum": "e",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert full name to letter if needed
|
||||||
|
if value_lower in name_map:
|
||||||
|
value_lower = name_map[value_lower]
|
||||||
|
|
||||||
|
# Try to match against enum values
|
||||||
|
for member in cls:
|
||||||
|
if member.value == value_lower:
|
||||||
|
return member
|
||||||
|
|
||||||
|
valid_options = list(name_map.keys()) + list(name_map.values())
|
||||||
|
raise ValueError(f"Invalid entity type: '{value}'. Valid options: {valid_options}")
|
||||||
|
|
||||||
|
|
||||||
|
class DecompileRequest(BaseModel):
|
||||||
|
"""Request to decompile a .NET assembly."""
|
||||||
|
|
||||||
|
assembly_path: str
|
||||||
|
output_dir: str | None = None
|
||||||
|
type_name: str | None = None
|
||||||
|
language_version: LanguageVersion = LanguageVersion.LATEST
|
||||||
|
create_project: bool = False
|
||||||
|
show_il_code: bool = False
|
||||||
|
reference_paths: list[str] = Field(default_factory=list)
|
||||||
|
remove_dead_code: bool = False
|
||||||
|
remove_dead_stores: bool = False
|
||||||
|
show_il_sequence_points: bool = False
|
||||||
|
nested_directories: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
class ListTypesRequest(BaseModel):
|
||||||
|
"""Request to list types in an assembly."""
|
||||||
|
|
||||||
|
assembly_path: str
|
||||||
|
entity_types: list[EntityType] = Field(default_factory=lambda: [EntityType.CLASS])
|
||||||
|
reference_paths: list[str] = Field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
class TypeInfo(BaseModel):
|
||||||
|
"""Information about a type in an assembly."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
full_name: str
|
||||||
|
kind: str
|
||||||
|
namespace: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class DecompileResponse(BaseModel):
|
||||||
|
"""Response from decompilation operation."""
|
||||||
|
|
||||||
|
success: bool
|
||||||
|
source_code: str | None = None
|
||||||
|
output_path: str | None = None
|
||||||
|
error_message: str | None = None
|
||||||
|
assembly_name: str
|
||||||
|
type_name: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class ListTypesResponse(BaseModel):
|
||||||
|
"""Response from list types operation."""
|
||||||
|
|
||||||
|
success: bool
|
||||||
|
types: list[TypeInfo] = Field(default_factory=list)
|
||||||
|
total_count: int = 0
|
||||||
|
error_message: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class GenerateDiagrammerRequest(BaseModel):
|
||||||
|
"""Request to generate HTML diagrammer."""
|
||||||
|
|
||||||
|
assembly_path: str
|
||||||
|
output_dir: str | None = None
|
||||||
|
include_pattern: str | None = None
|
||||||
|
exclude_pattern: str | None = None
|
||||||
|
docs_path: str | None = None
|
||||||
|
strip_namespaces: list[str] = Field(default_factory=list)
|
||||||
|
report_excluded: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
class AssemblyInfoRequest(BaseModel):
|
||||||
|
"""Request to get assembly information."""
|
||||||
|
|
||||||
|
assembly_path: str
|
||||||
|
|
||||||
|
|
||||||
|
class AssemblyInfo(BaseModel):
|
||||||
|
"""Information about an assembly."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
version: str
|
||||||
|
full_name: str
|
||||||
|
location: str
|
||||||
|
target_framework: str | None = None
|
||||||
|
runtime_version: str | None = None
|
||||||
|
is_signed: bool = False
|
||||||
|
has_debug_info: bool = False
|
||||||
1475
src/mcilspy/server.py
Normal file
1475
src/mcilspy/server.py
Normal file
File diff suppressed because it is too large
Load Diff
771
uv.lock
generated
Normal file
771
uv.lock
generated
Normal file
@ -0,0 +1,771 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
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, upload-time = "2024-05-20T21:33:25.928Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyio"
|
||||||
|
version = "4.12.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||||
|
{ name = "idna" },
|
||||||
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "attrs"
|
||||||
|
version = "25.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "certifi"
|
||||||
|
version = "2026.1.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cffi"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "8.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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, upload-time = "2022-10-25T02:36:22.414Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cryptography"
|
||||||
|
version = "46.0.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
||||||
|
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/78/19/f748958276519adf6a0c1e79e7b8860b4830dda55ccdf29f2719b5fc499c/cryptography-46.0.4.tar.gz", hash = "sha256:bfd019f60f8abc2ed1b9be4ddc21cfef059c841d86d710bb69909a688cbb8f59", size = 749301, upload-time = "2026-01-28T00:24:37.379Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8d/99/157aae7949a5f30d51fcb1a9851e8ebd5c74bf99b5285d8bb4b8b9ee641e/cryptography-46.0.4-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:281526e865ed4166009e235afadf3a4c4cba6056f99336a99efba65336fd5485", size = 7173686, upload-time = "2026-01-28T00:23:07.515Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/91/874b8910903159043b5c6a123b7e79c4559ddd1896e38967567942635778/cryptography-46.0.4-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5f14fba5bf6f4390d7ff8f086c566454bff0411f6d8aa7af79c88b6f9267aecc", size = 4275871, upload-time = "2026-01-28T00:23:09.439Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/35/690e809be77896111f5b195ede56e4b4ed0435b428c2f2b6d35046fbb5e8/cryptography-46.0.4-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:47bcd19517e6389132f76e2d5303ded6cf3f78903da2158a671be8de024f4cd0", size = 4423124, upload-time = "2026-01-28T00:23:11.529Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1a/5b/a26407d4f79d61ca4bebaa9213feafdd8806dc69d3d290ce24996d3cfe43/cryptography-46.0.4-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:01df4f50f314fbe7009f54046e908d1754f19d0c6d3070df1e6268c5a4af09fa", size = 4277090, upload-time = "2026-01-28T00:23:13.123Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/d8/4bb7aec442a9049827aa34cee1aa83803e528fa55da9a9d45d01d1bb933e/cryptography-46.0.4-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5aa3e463596b0087b3da0dbe2b2487e9fc261d25da85754e30e3b40637d61f81", size = 4947652, upload-time = "2026-01-28T00:23:14.554Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/08/f83e2e0814248b844265802d081f2fac2f1cbe6cd258e72ba14ff006823a/cryptography-46.0.4-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0a9ad24359fee86f131836a9ac3bffc9329e956624a2d379b613f8f8abaf5255", size = 4455157, upload-time = "2026-01-28T00:23:16.443Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/05/19d849cf4096448779d2dcc9bb27d097457dac36f7273ffa875a93b5884c/cryptography-46.0.4-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:dc1272e25ef673efe72f2096e92ae39dea1a1a450dd44918b15351f72c5a168e", size = 3981078, upload-time = "2026-01-28T00:23:17.838Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/89/f7bac81d66ba7cde867a743ea5b37537b32b5c633c473002b26a226f703f/cryptography-46.0.4-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:de0f5f4ec8711ebc555f54735d4c673fc34b65c44283895f1a08c2b49d2fd99c", size = 4276213, upload-time = "2026-01-28T00:23:19.257Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/9f/7133e41f24edd827020ad21b068736e792bc68eecf66d93c924ad4719fb3/cryptography-46.0.4-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:eeeb2e33d8dbcccc34d64651f00a98cb41b2dc69cef866771a5717e6734dfa32", size = 4912190, upload-time = "2026-01-28T00:23:21.244Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a6/f7/6d43cbaddf6f65b24816e4af187d211f0bc536a29961f69faedc48501d8e/cryptography-46.0.4-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3d425eacbc9aceafd2cb429e42f4e5d5633c6f873f5e567077043ef1b9bbf616", size = 4454641, upload-time = "2026-01-28T00:23:22.866Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/4f/ebd0473ad656a0ac912a16bd07db0f5d85184924e14fc88feecae2492834/cryptography-46.0.4-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91627ebf691d1ea3976a031b61fb7bac1ccd745afa03602275dda443e11c8de0", size = 4405159, upload-time = "2026-01-28T00:23:25.278Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/f7/7923886f32dc47e27adeff8246e976d77258fd2aa3efdd1754e4e323bf49/cryptography-46.0.4-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2d08bc22efd73e8854b0b7caff402d735b354862f1145d7be3b9c0f740fef6a0", size = 4666059, upload-time = "2026-01-28T00:23:26.766Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/eb/a7/0fca0fd3591dffc297278a61813d7f661a14243dd60f499a7a5b48acb52a/cryptography-46.0.4-cp311-abi3-win32.whl", hash = "sha256:82a62483daf20b8134f6e92898da70d04d0ef9a75829d732ea1018678185f4f5", size = 3026378, upload-time = "2026-01-28T00:23:28.317Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/12/652c84b6f9873f0909374864a57b003686c642ea48c84d6c7e2c515e6da5/cryptography-46.0.4-cp311-abi3-win_amd64.whl", hash = "sha256:6225d3ebe26a55dbc8ead5ad1265c0403552a63336499564675b29eb3184c09b", size = 3478614, upload-time = "2026-01-28T00:23:30.275Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/27/542b029f293a5cce59349d799d4d8484b3b1654a7b9a0585c266e974a488/cryptography-46.0.4-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:485e2b65d25ec0d901bca7bcae0f53b00133bf3173916d8e421f6fddde103908", size = 7116417, upload-time = "2026-01-28T00:23:31.958Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/f5/559c25b77f40b6bf828eabaf988efb8b0e17b573545edb503368ca0a2a03/cryptography-46.0.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:078e5f06bd2fa5aea5a324f2a09f914b1484f1d0c2a4d6a8a28c74e72f65f2da", size = 4264508, upload-time = "2026-01-28T00:23:34.264Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/a1/551fa162d33074b660dc35c9bc3616fefa21a0e8c1edd27b92559902e408/cryptography-46.0.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dce1e4f068f03008da7fa51cc7abc6ddc5e5de3e3d1550334eaf8393982a5829", size = 4409080, upload-time = "2026-01-28T00:23:35.793Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/6a/4d8d129a755f5d6df1bbee69ea2f35ebfa954fa1847690d1db2e8bca46a5/cryptography-46.0.4-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:2067461c80271f422ee7bdbe79b9b4be54a5162e90345f86a23445a0cf3fd8a2", size = 4270039, upload-time = "2026-01-28T00:23:37.263Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4c/f5/ed3fcddd0a5e39321e595e144615399e47e7c153a1fb8c4862aec3151ff9/cryptography-46.0.4-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:c92010b58a51196a5f41c3795190203ac52edfd5dc3ff99149b4659eba9d2085", size = 4926748, upload-time = "2026-01-28T00:23:38.884Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/43/ae/9f03d5f0c0c00e85ecb34f06d3b79599f20630e4db91b8a6e56e8f83d410/cryptography-46.0.4-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:829c2b12bbc5428ab02d6b7f7e9bbfd53e33efd6672d21341f2177470171ad8b", size = 4442307, upload-time = "2026-01-28T00:23:40.56Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8b/22/e0f9f2dae8040695103369cf2283ef9ac8abe4d51f68710bec2afd232609/cryptography-46.0.4-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:62217ba44bf81b30abaeda1488686a04a702a261e26f87db51ff61d9d3510abd", size = 3959253, upload-time = "2026-01-28T00:23:42.827Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/01/5b/6a43fcccc51dae4d101ac7d378a8724d1ba3de628a24e11bf2f4f43cba4d/cryptography-46.0.4-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:9c2da296c8d3415b93e6053f5a728649a87a48ce084a9aaf51d6e46c87c7f2d2", size = 4269372, upload-time = "2026-01-28T00:23:44.655Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/b7/0f6b8c1dd0779df2b526e78978ff00462355e31c0a6f6cff8a3e99889c90/cryptography-46.0.4-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:9b34d8ba84454641a6bf4d6762d15847ecbd85c1316c0a7984e6e4e9f748ec2e", size = 4891908, upload-time = "2026-01-28T00:23:46.48Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/83/17/259409b8349aa10535358807a472c6a695cf84f106022268d31cea2b6c97/cryptography-46.0.4-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:df4a817fa7138dd0c96c8c8c20f04b8aaa1fac3bbf610913dcad8ea82e1bfd3f", size = 4441254, upload-time = "2026-01-28T00:23:48.403Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/fe/e4a1b0c989b00cee5ffa0764401767e2d1cf59f45530963b894129fd5dce/cryptography-46.0.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b1de0ebf7587f28f9190b9cb526e901bf448c9e6a99655d2b07fff60e8212a82", size = 4396520, upload-time = "2026-01-28T00:23:50.26Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/81/ba8fd9657d27076eb40d6a2f941b23429a3c3d2f56f5a921d6b936a27bc9/cryptography-46.0.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9b4d17bc7bd7cdd98e3af40b441feaea4c68225e2eb2341026c84511ad246c0c", size = 4651479, upload-time = "2026-01-28T00:23:51.674Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/03/0de4ed43c71c31e4fe954edd50b9d28d658fef56555eba7641696370a8e2/cryptography-46.0.4-cp314-cp314t-win32.whl", hash = "sha256:c411f16275b0dea722d76544a61d6421e2cc829ad76eec79280dbdc9ddf50061", size = 3001986, upload-time = "2026-01-28T00:23:53.485Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/70/81830b59df7682917d7a10f833c4dab2a5574cd664e86d18139f2b421329/cryptography-46.0.4-cp314-cp314t-win_amd64.whl", hash = "sha256:728fedc529efc1439eb6107b677f7f7558adab4553ef8669f0d02d42d7b959a7", size = 3468288, upload-time = "2026-01-28T00:23:55.09Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/56/f7/f648fdbb61d0d45902d3f374217451385edc7e7768d1b03ff1d0e5ffc17b/cryptography-46.0.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a9556ba711f7c23f77b151d5798f3ac44a13455cc68db7697a1096e6d0563cab", size = 7169583, upload-time = "2026-01-28T00:23:56.558Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/cc/8f3224cbb2a928de7298d6ed4790f5ebc48114e02bdc9559196bfb12435d/cryptography-46.0.4-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8bf75b0259e87fa70bddc0b8b4078b76e7fd512fd9afae6c1193bcf440a4dbef", size = 4275419, upload-time = "2026-01-28T00:23:58.364Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/43/4a18faa7a872d00e4264855134ba82d23546c850a70ff209e04ee200e76f/cryptography-46.0.4-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3c268a3490df22270955966ba236d6bc4a8f9b6e4ffddb78aac535f1a5ea471d", size = 4419058, upload-time = "2026-01-28T00:23:59.867Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/64/6651969409821d791ba12346a124f55e1b76f66a819254ae840a965d4b9c/cryptography-46.0.4-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:812815182f6a0c1d49a37893a303b44eaac827d7f0d582cecfc81b6427f22973", size = 4278151, upload-time = "2026-01-28T00:24:01.731Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/0b/a7fce65ee08c3c02f7a8310cc090a732344066b990ac63a9dfd0a655d321/cryptography-46.0.4-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:a90e43e3ef65e6dcf969dfe3bb40cbf5aef0d523dff95bfa24256be172a845f4", size = 4939441, upload-time = "2026-01-28T00:24:03.175Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/db/a7/20c5701e2cd3e1dfd7a19d2290c522a5f435dd30957d431dcb531d0f1413/cryptography-46.0.4-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a05177ff6296644ef2876fce50518dffb5bcdf903c85250974fc8bc85d54c0af", size = 4451617, upload-time = "2026-01-28T00:24:05.403Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/dc/3e16030ea9aa47b63af6524c354933b4fb0e352257c792c4deeb0edae367/cryptography-46.0.4-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:daa392191f626d50f1b136c9b4cf08af69ca8279d110ea24f5c2700054d2e263", size = 3977774, upload-time = "2026-01-28T00:24:06.851Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/c8/ad93f14118252717b465880368721c963975ac4b941b7ef88f3c56bf2897/cryptography-46.0.4-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e07ea39c5b048e085f15923511d8121e4a9dc45cee4e3b970ca4f0d338f23095", size = 4277008, upload-time = "2026-01-28T00:24:08.926Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/cf/89c99698151c00a4631fbfcfcf459d308213ac29e321b0ff44ceeeac82f1/cryptography-46.0.4-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:d5a45ddc256f492ce42a4e35879c5e5528c09cd9ad12420828c972951d8e016b", size = 4903339, upload-time = "2026-01-28T00:24:12.009Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/c3/c90a2cb358de4ac9309b26acf49b2a100957e1ff5cc1e98e6c4996576710/cryptography-46.0.4-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:6bb5157bf6a350e5b28aee23beb2d84ae6f5be390b2f8ee7ea179cda077e1019", size = 4451216, upload-time = "2026-01-28T00:24:13.975Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/2c/8d7f4171388a10208671e181ca43cdc0e596d8259ebacbbcfbd16de593da/cryptography-46.0.4-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dd5aba870a2c40f87a3af043e0dee7d9eb02d4aff88a797b48f2b43eff8c3ab4", size = 4404299, upload-time = "2026-01-28T00:24:16.169Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e9/23/cbb2036e450980f65c6e0a173b73a56ff3bccd8998965dea5cc9ddd424a5/cryptography-46.0.4-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:93d8291da8d71024379ab2cb0b5c57915300155ad42e07f76bea6ad838d7e59b", size = 4664837, upload-time = "2026-01-28T00:24:17.629Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/21/f7433d18fe6d5845329cbdc597e30caf983229c7a245bcf54afecc555938/cryptography-46.0.4-cp38-abi3-win32.whl", hash = "sha256:0563655cb3c6d05fb2afe693340bc050c30f9f34e15763361cf08e94749401fc", size = 3009779, upload-time = "2026-01-28T00:24:20.198Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/6a/bd2e7caa2facffedf172a45c1a02e551e6d7d4828658c9a245516a598d94/cryptography-46.0.4-cp38-abi3-win_amd64.whl", hash = "sha256:fa0900b9ef9c49728887d1576fd8d9e7e3ea872fa9b25ef9b64888adc434e976", size = 3466633, upload-time = "2026-01-28T00:24:21.851Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/e0/f9c6c53e1f2a1c2507f00f2faba00f01d2f334b35b0fbfe5286715da2184/cryptography-46.0.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:766330cce7416c92b5e90c3bb71b1b79521760cdcfc3a6a1a182d4c9fab23d2b", size = 3476316, upload-time = "2026-01-28T00:24:24.144Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/27/7a/f8d2d13227a9a1a9fe9c7442b057efecffa41f1e3c51d8622f26b9edbe8f/cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c236a44acfb610e70f6b3e1c3ca20ff24459659231ef2f8c48e879e2d32b73da", size = 4216693, upload-time = "2026-01-28T00:24:25.758Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/de/3787054e8f7972658370198753835d9d680f6cd4a39df9f877b57f0dd69c/cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8a15fb869670efa8f83cbffbc8753c1abf236883225aed74cd179b720ac9ec80", size = 4382765, upload-time = "2026-01-28T00:24:27.577Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/5f/60e0afb019973ba6a0b322e86b3d61edf487a4f5597618a430a2a15f2d22/cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:fdc3daab53b212472f1524d070735b2f0c214239df131903bae1d598016fa822", size = 4216066, upload-time = "2026-01-28T00:24:29.056Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/8e/bf4a0de294f147fee66f879d9bae6f8e8d61515558e3d12785dd90eca0be/cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:44cc0675b27cadb71bdbb96099cca1fa051cd11d2ade09e5cd3a2edb929ed947", size = 4382025, upload-time = "2026-01-28T00:24:30.681Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/f4/9ceb90cfd6a3847069b0b0b353fd3075dc69b49defc70182d8af0c4ca390/cryptography-46.0.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be8c01a7d5a55f9a47d1888162b76c8f49d62b234d88f0ff91a9fbebe32ffbc3", size = 3406043, upload-time = "2026-01-28T00:24:32.236Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dnfile"
|
||||||
|
version = "0.18.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pefile" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/01/c3/89dbe3a48dfa303060d59b74b97b8401cc70b9b4d4c24982202861fd82e9/dnfile-0.18.0.tar.gz", hash = "sha256:24eec63d65535b702236001e648bbf2fa139d1a7bea191fdca17c3be337eb4db", size = 51519, upload-time = "2026-01-31T05:09:11.212Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/39/ad/4f945155a78800cea02cb258bc0b7704c43cf94f50f75c808f0618694153/dnfile-0.18.0-py3-none-any.whl", hash = "sha256:7579fe2d6bb1d854aa154929c309fbf34e70b622053a043a51d42f079fad1772", size = 48044, upload-time = "2026-01-31T05:09:09.703Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "exceptiongroup"
|
||||||
|
version = "1.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h11"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpcore"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "h11" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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, upload-time = "2024-12-06T15:37:23.222Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpx-sse"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/0f/4c/751061ffa58615a32c31b2d82e8482be8dd4a89154f003147acee90f2be9/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d", size = 15943, upload-time = "2025-10-10T21:48:22.271Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "3.11"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jsonschema"
|
||||||
|
version = "4.26.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "attrs" },
|
||||||
|
{ name = "jsonschema-specifications" },
|
||||||
|
{ name = "referencing" },
|
||||||
|
{ name = "rpds-py" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jsonschema-specifications"
|
||||||
|
version = "2025.9.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "referencing" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mcilspy"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = { editable = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "dnfile" },
|
||||||
|
{ name = "mcp" },
|
||||||
|
{ name = "pydantic" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "dnfile", specifier = ">=0.15.0" },
|
||||||
|
{ name = "mcp", specifier = ">=1.0.0" },
|
||||||
|
{ name = "pydantic", specifier = ">=2.7.0" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mcp"
|
||||||
|
version = "1.26.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "anyio" },
|
||||||
|
{ name = "httpx" },
|
||||||
|
{ name = "httpx-sse" },
|
||||||
|
{ name = "jsonschema" },
|
||||||
|
{ name = "pydantic" },
|
||||||
|
{ name = "pydantic-settings" },
|
||||||
|
{ name = "pyjwt", extra = ["crypto"] },
|
||||||
|
{ name = "python-multipart" },
|
||||||
|
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
||||||
|
{ name = "sse-starlette" },
|
||||||
|
{ name = "starlette" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
{ name = "typing-inspection" },
|
||||||
|
{ name = "uvicorn", marker = "sys_platform != 'emscripten'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/fc/6d/62e76bbb8144d6ed86e202b5edd8a4cb631e7c8130f3f4893c3f90262b10/mcp-1.26.0.tar.gz", hash = "sha256:db6e2ef491eecc1a0d93711a76f28dec2e05999f93afd48795da1c1137142c66", size = 608005, upload-time = "2026-01-24T19:40:32.468Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/d9/eaa1f80170d2b7c5ba23f3b59f766f3a0bb41155fbc32a69adfa1adaaef9/mcp-1.26.0-py3-none-any.whl", hash = "sha256:904a21c33c25aa98ddbeb47273033c435e595bbacfdb177f4bd87f6dceebe1ca", size = 233615, upload-time = "2026-01-24T19:40:30.652Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pefile"
|
||||||
|
version = "2024.8.26"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/03/4f/2750f7f6f025a1507cd3b7218691671eecfd0bbebebe8b39aa0fe1d360b8/pefile-2024.8.26.tar.gz", hash = "sha256:3ff6c5d8b43e8c37bb6e6dd5085658d658a7a0bdcd20b6a07b1fcfc1c4e9d632", size = 76008, upload-time = "2024-08-26T20:58:38.155Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl", hash = "sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f", size = 74766, upload-time = "2024-08-26T21:01:02.632Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycparser"
|
||||||
|
version = "3.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic"
|
||||||
|
version = "2.12.5"
|
||||||
|
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/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic-core"
|
||||||
|
version = "2.41.5"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic-settings"
|
||||||
|
version = "2.12.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pydantic" },
|
||||||
|
{ name = "python-dotenv" },
|
||||||
|
{ name = "typing-inspection" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyjwt"
|
||||||
|
version = "2.11.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
crypto = [
|
||||||
|
{ name = "cryptography" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-dotenv"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-multipart"
|
||||||
|
version = "0.0.22"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pywin32"
|
||||||
|
version = "311"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "referencing"
|
||||||
|
version = "0.37.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "attrs" },
|
||||||
|
{ name = "rpds-py" },
|
||||||
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rpds-py"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490, upload-time = "2025-11-30T20:21:33.256Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751, upload-time = "2025-11-30T20:21:34.591Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696, upload-time = "2025-11-30T20:21:36.122Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136, upload-time = "2025-11-30T20:21:37.728Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699, upload-time = "2025-11-30T20:21:38.92Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022, upload-time = "2025-11-30T20:21:40.407Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522, upload-time = "2025-11-30T20:21:42.17Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579, upload-time = "2025-11-30T20:21:43.769Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305, upload-time = "2025-11-30T20:21:44.994Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503, upload-time = "2025-11-30T20:21:46.91Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322, upload-time = "2025-11-30T20:21:48.709Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792, upload-time = "2025-11-30T20:21:50.024Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901, upload-time = "2025-11-30T20:21:51.32Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823, upload-time = "2025-11-30T20:21:52.505Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/6e/f964e88b3d2abee2a82c1ac8366da848fce1c6d834dc2132c3fda3970290/rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425", size = 370157, upload-time = "2025-11-30T20:21:53.789Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/ba/24e5ebb7c1c82e74c4e4f33b2112a5573ddc703915b13a073737b59b86e0/rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d", size = 359676, upload-time = "2025-11-30T20:21:55.475Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/86/04dbba1b087227747d64d80c3b74df946b986c57af0a9f0c98726d4d7a3b/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4", size = 389938, upload-time = "2025-11-30T20:21:57.079Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/bb/1463f0b1722b7f45431bdd468301991d1328b16cffe0b1c2918eba2c4eee/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f", size = 402932, upload-time = "2025-11-30T20:21:58.47Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/99/ee/2520700a5c1f2d76631f948b0736cdf9b0acb25abd0ca8e889b5c62ac2e3/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4", size = 525830, upload-time = "2025-11-30T20:21:59.699Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/ad/bd0331f740f5705cc555a5e17fdf334671262160270962e69a2bdef3bf76/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97", size = 412033, upload-time = "2025-11-30T20:22:00.991Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/1e/372195d326549bb51f0ba0f2ecb9874579906b97e08880e7a65c3bef1a99/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89", size = 390828, upload-time = "2025-11-30T20:22:02.723Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/2b/d88bb33294e3e0c76bc8f351a3721212713629ffca1700fa94979cb3eae8/rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d", size = 404683, upload-time = "2025-11-30T20:22:04.367Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/32/c759a8d42bcb5289c1fac697cd92f6fe01a018dd937e62ae77e0e7f15702/rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038", size = 421583, upload-time = "2025-11-30T20:22:05.814Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/81/e729761dbd55ddf5d84ec4ff1f47857f4374b0f19bdabfcf929164da3e24/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7", size = 572496, upload-time = "2025-11-30T20:22:07.713Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/f6/69066a924c3557c9c30baa6ec3a0aa07526305684c6f86c696b08860726c/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed", size = 598669, upload-time = "2025-11-30T20:22:09.312Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/48/905896b1eb8a05630d20333d1d8ffd162394127b74ce0b0784ae04498d32/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85", size = 561011, upload-time = "2025-11-30T20:22:11.309Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/16/cd3027c7e279d22e5eb431dd3c0fbc677bed58797fe7581e148f3f68818b/rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c", size = 221406, upload-time = "2025-11-30T20:22:13.101Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/5b/e7b7aa136f28462b344e652ee010d4de26ee9fd16f1bfd5811f5153ccf89/rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825", size = 236024, upload-time = "2025-11-30T20:22:14.853Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/a6/364bba985e4c13658edb156640608f2c9e1d3ea3c81b27aa9d889fff0e31/rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229", size = 229069, upload-time = "2025-11-30T20:22:16.577Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/e7/98a2f4ac921d82f33e03f3835f5bf3a4a40aa1bfdc57975e74a97b2b4bdd/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad", size = 375086, upload-time = "2025-11-30T20:22:17.93Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05", size = 359053, upload-time = "2025-11-30T20:22:19.297Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/65/1c/ae157e83a6357eceff62ba7e52113e3ec4834a84cfe07fa4b0757a7d105f/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28", size = 390763, upload-time = "2025-11-30T20:22:21.661Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d4/36/eb2eb8515e2ad24c0bd43c3ee9cd74c33f7ca6430755ccdb240fd3144c44/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd", size = 408951, upload-time = "2025-11-30T20:22:23.408Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/65/ad8dc1784a331fabbd740ef6f71ce2198c7ed0890dab595adb9ea2d775a1/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f", size = 514622, upload-time = "2025-11-30T20:22:25.16Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/63/8e/0cfa7ae158e15e143fe03993b5bcd743a59f541f5952e1546b1ac1b5fd45/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1", size = 414492, upload-time = "2025-11-30T20:22:26.505Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/60/1b/6f8f29f3f995c7ffdde46a626ddccd7c63aefc0efae881dc13b6e5d5bb16/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23", size = 394080, upload-time = "2025-11-30T20:22:27.934Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6d/d5/a266341051a7a3ca2f4b750a3aa4abc986378431fc2da508c5034d081b70/rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6", size = 408680, upload-time = "2025-11-30T20:22:29.341Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/10/3b/71b725851df9ab7a7a4e33cf36d241933da66040d195a84781f49c50490c/rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51", size = 423589, upload-time = "2025-11-30T20:22:31.469Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/2b/e59e58c544dc9bd8bd8384ecdb8ea91f6727f0e37a7131baeff8d6f51661/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5", size = 573289, upload-time = "2025-11-30T20:22:32.997Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/3e/a18e6f5b460893172a7d6a680e86d3b6bc87a54c1f0b03446a3c8c7b588f/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e", size = 599737, upload-time = "2025-11-30T20:22:34.419Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/e2/714694e4b87b85a18e2c243614974413c60aa107fd815b8cbc42b873d1d7/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394", size = 563120, upload-time = "2025-11-30T20:22:35.903Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6f/ab/d5d5e3bcedb0a77f4f613706b750e50a5a3ba1c15ccd3665ecc636c968fd/rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf", size = 223782, upload-time = "2025-11-30T20:22:37.271Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/39/3b/f786af9957306fdc38a74cef405b7b93180f481fb48453a114bb6465744a/rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b", size = 240463, upload-time = "2025-11-30T20:22:39.021Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/d2/b91dc748126c1559042cfe41990deb92c4ee3e2b415f6b5234969ffaf0cc/rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e", size = 230868, upload-time = "2025-11-30T20:22:40.493Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/dc/d61221eb88ff410de3c49143407f6f3147acf2538c86f2ab7ce65ae7d5f9/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2", size = 374887, upload-time = "2025-11-30T20:22:41.812Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/32/55fb50ae104061dbc564ef15cc43c013dc4a9f4527a1f4d99baddf56fe5f/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8", size = 358904, upload-time = "2025-11-30T20:22:43.479Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/58/70/faed8186300e3b9bdd138d0273109784eea2396c68458ed580f885dfe7ad/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4", size = 389945, upload-time = "2025-11-30T20:22:44.819Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/a8/073cac3ed2c6387df38f71296d002ab43496a96b92c823e76f46b8af0543/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136", size = 407783, upload-time = "2025-11-30T20:22:46.103Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/57/5999eb8c58671f1c11eba084115e77a8899d6e694d2a18f69f0ba471ec8b/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7", size = 515021, upload-time = "2025-11-30T20:22:47.458Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/af/5ab4833eadc36c0a8ed2bc5c0de0493c04f6c06de223170bd0798ff98ced/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2", size = 414589, upload-time = "2025-11-30T20:22:48.872Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/de/f7192e12b21b9e9a68a6d0f249b4af3fdcdff8418be0767a627564afa1f1/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6", size = 394025, upload-time = "2025-11-30T20:22:50.196Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/91/c4/fc70cd0249496493500e7cc2de87504f5aa6509de1e88623431fec76d4b6/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e", size = 408895, upload-time = "2025-11-30T20:22:51.87Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/58/95/d9275b05ab96556fefff73a385813eb66032e4c99f411d0795372d9abcea/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d", size = 422799, upload-time = "2025-11-30T20:22:53.341Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/c1/3088fc04b6624eb12a57eb814f0d4997a44b0d208d6cace713033ff1a6ba/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7", size = 572731, upload-time = "2025-11-30T20:22:54.778Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/42/c612a833183b39774e8ac8fecae81263a68b9583ee343db33ab571a7ce55/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31", size = 599027, upload-time = "2025-11-30T20:22:56.212Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/60/525a50f45b01d70005403ae0e25f43c0384369ad24ffe46e8d9068b50086/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95", size = 563020, upload-time = "2025-11-30T20:22:58.2Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/5d/47c4655e9bcd5ca907148535c10e7d489044243cc9941c16ed7cd53be91d/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d", size = 223139, upload-time = "2025-11-30T20:23:00.209Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/e1/485132437d20aa4d3e1d8b3fb5a5e65aa8139f1e097080c2a8443201742c/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15", size = 240224, upload-time = "2025-11-30T20:23:02.008Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/24/95/ffd128ed1146a153d928617b0ef673960130be0009c77d8fbf0abe306713/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1", size = 230645, upload-time = "2025-11-30T20:23:03.43Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/1b/b10de890a0def2a319a2626334a7f0ae388215eb60914dbac8a3bae54435/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a", size = 364443, upload-time = "2025-11-30T20:23:04.878Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/bf/27e39f5971dc4f305a4fb9c672ca06f290f7c4e261c568f3dea16a410d47/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e", size = 353375, upload-time = "2025-11-30T20:23:06.342Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/40/58/442ada3bba6e8e6615fc00483135c14a7538d2ffac30e2d933ccf6852232/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000", size = 383850, upload-time = "2025-11-30T20:23:07.825Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/14/f59b0127409a33c6ef6f5c1ebd5ad8e32d7861c9c7adfa9a624fc3889f6c/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db", size = 392812, upload-time = "2025-11-30T20:23:09.228Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/66/e0be3e162ac299b3a22527e8913767d869e6cc75c46bd844aa43fb81ab62/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2", size = 517841, upload-time = "2025-11-30T20:23:11.186Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/55/fa3b9cf31d0c963ecf1ba777f7cf4b2a2c976795ac430d24a1f43d25a6ba/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa", size = 408149, upload-time = "2025-11-30T20:23:12.864Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/60/ca/780cf3b1a32b18c0f05c441958d3758f02544f1d613abf9488cd78876378/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083", size = 383843, upload-time = "2025-11-30T20:23:14.638Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/86/d5f2e04f2aa6247c613da0c1dd87fcd08fa17107e858193566048a1e2f0a/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9", size = 396507, upload-time = "2025-11-30T20:23:16.105Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/9a/453255d2f769fe44e07ea9785c8347edaf867f7026872e76c1ad9f7bed92/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0", size = 414949, upload-time = "2025-11-30T20:23:17.539Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a3/31/622a86cdc0c45d6df0e9ccb6becdba5074735e7033c20e401a6d9d0e2ca0/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94", size = 565790, upload-time = "2025-11-30T20:23:19.029Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1c/5d/15bbf0fb4a3f58a3b1c67855ec1efcc4ceaef4e86644665fff03e1b66d8d/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08", size = 590217, upload-time = "2025-11-30T20:23:20.885Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload-time = "2025-11-30T20:23:22.488Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload-time = "2025-11-30T20:23:24.449Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload-time = "2025-11-30T20:23:25.908Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/81/dad16382ebbd3d0e0328776d8fd7ca94220e4fa0798d1dc5e7da48cb3201/rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0", size = 362099, upload-time = "2025-11-30T20:23:27.316Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/60/19f7884db5d5603edf3c6bce35408f45ad3e97e10007df0e17dd57af18f8/rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be", size = 353192, upload-time = "2025-11-30T20:23:29.151Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/c4/76eb0e1e72d1a9c4703c69607cec123c29028bff28ce41588792417098ac/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f", size = 384080, upload-time = "2025-11-30T20:23:30.785Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/87/87ea665e92f3298d1b26d78814721dc39ed8d2c74b86e83348d6b48a6f31/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f", size = 394841, upload-time = "2025-11-30T20:23:32.209Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/ad/7783a89ca0587c15dcbf139b4a8364a872a25f861bdb88ed99f9b0dec985/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87", size = 516670, upload-time = "2025-11-30T20:23:33.742Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5b/3c/2882bdac942bd2172f3da574eab16f309ae10a3925644e969536553cb4ee/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18", size = 408005, upload-time = "2025-11-30T20:23:35.253Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/81/9a91c0111ce1758c92516a3e44776920b579d9a7c09b2b06b642d4de3f0f/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad", size = 382112, upload-time = "2025-11-30T20:23:36.842Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/8e/1da49d4a107027e5fbc64daeab96a0706361a2918da10cb41769244b805d/rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07", size = 399049, upload-time = "2025-11-30T20:23:38.343Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/5a/7ee239b1aa48a127570ec03becbb29c9d5a9eb092febbd1699d567cae859/rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f", size = 415661, upload-time = "2025-11-30T20:23:40.263Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/70/ea/caa143cf6b772f823bc7929a45da1fa83569ee49b11d18d0ada7f5ee6fd6/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65", size = 565606, upload-time = "2025-11-30T20:23:42.186Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/64/91/ac20ba2d69303f961ad8cf55bf7dbdb4763f627291ba3d0d7d67333cced9/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f", size = 591126, upload-time = "2025-11-30T20:23:44.086Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/21/20/7ff5f3c8b00c8a95f75985128c26ba44503fb35b8e0259d812766ea966c7/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53", size = 553371, upload-time = "2025-11-30T20:23:46.004Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/c7/81dadd7b27c8ee391c132a6b192111ca58d866577ce2d9b0ca157552cce0/rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed", size = 215298, upload-time = "2025-11-30T20:23:47.696Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/d2/1aaac33287e8cfb07aab2e6b8ac1deca62f6f65411344f1433c55e6f3eb8/rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950", size = 228604, upload-time = "2025-11-30T20:23:49.501Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/95/ab005315818cc519ad074cb7784dae60d939163108bd2b394e60dc7b5461/rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6", size = 222391, upload-time = "2025-11-30T20:23:50.96Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/68/154fe0194d83b973cdedcdcc88947a2752411165930182ae41d983dcefa6/rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb", size = 364868, upload-time = "2025-11-30T20:23:52.494Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8", size = 353747, upload-time = "2025-11-30T20:23:54.036Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/00/ba2e50183dbd9abcce9497fa5149c62b4ff3e22d338a30d690f9af970561/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7", size = 383795, upload-time = "2025-11-30T20:23:55.556Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/6f/86f0272b84926bcb0e4c972262f54223e8ecc556b3224d281e6598fc9268/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898", size = 393330, upload-time = "2025-11-30T20:23:57.033Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/e9/0e02bb2e6dc63d212641da45df2b0bf29699d01715913e0d0f017ee29438/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e", size = 518194, upload-time = "2025-11-30T20:23:58.637Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/ca/be7bca14cf21513bdf9c0606aba17d1f389ea2b6987035eb4f62bd923f25/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419", size = 408340, upload-time = "2025-11-30T20:24:00.2Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/c7/736e00ebf39ed81d75544c0da6ef7b0998f8201b369acf842f9a90dc8fce/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551", size = 383765, upload-time = "2025-11-30T20:24:01.759Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/3f/da50dfde9956aaf365c4adc9533b100008ed31aea635f2b8d7b627e25b49/rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8", size = 396834, upload-time = "2025-11-30T20:24:03.687Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/00/34bcc2565b6020eab2623349efbdec810676ad571995911f1abdae62a3a0/rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5", size = 415470, upload-time = "2025-11-30T20:24:05.232Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8c/28/882e72b5b3e6f718d5453bd4d0d9cf8df36fddeb4ddbbab17869d5868616/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404", size = 565630, upload-time = "2025-11-30T20:24:06.878Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3b/97/04a65539c17692de5b85c6e293520fd01317fd878ea1995f0367d4532fb1/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856", size = 591148, upload-time = "2025-11-30T20:24:08.445Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/85/70/92482ccffb96f5441aab93e26c4d66489eb599efdcf96fad90c14bbfb976/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40", size = 556030, upload-time = "2025-11-30T20:24:10.956Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/53/7c7e784abfa500a2b6b583b147ee4bb5a2b3747a9166bab52fec4b5b5e7d/rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0", size = 211570, upload-time = "2025-11-30T20:24:12.735Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/02/fa464cdfbe6b26e0600b62c528b72d8608f5cc49f96b8d6e38c95d60c676/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3", size = 226532, upload-time = "2025-11-30T20:24:14.634Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/71/3f34339ee70521864411f8b6992e7ab13ac30d8e4e3309e07c7361767d91/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58", size = 372292, upload-time = "2025-11-30T20:24:16.537Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/57/09/f183df9b8f2d66720d2ef71075c59f7e1b336bec7ee4c48f0a2b06857653/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a", size = 362128, upload-time = "2025-11-30T20:24:18.086Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7a/68/5c2594e937253457342e078f0cc1ded3dd7b2ad59afdbf2d354869110a02/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb", size = 391542, upload-time = "2025-11-30T20:24:20.092Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/5c/31ef1afd70b4b4fbdb2800249f34c57c64beb687495b10aec0365f53dfc4/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c", size = 404004, upload-time = "2025-11-30T20:24:22.231Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/63/0cfbea38d05756f3440ce6534d51a491d26176ac045e2707adc99bb6e60a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3", size = 527063, upload-time = "2025-11-30T20:24:24.302Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/e6/01e1f72a2456678b0f618fc9a1a13f882061690893c192fcad9f2926553a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5", size = 413099, upload-time = "2025-11-30T20:24:25.916Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/25/8df56677f209003dcbb180765520c544525e3ef21ea72279c98b9aa7c7fb/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738", size = 392177, upload-time = "2025-11-30T20:24:27.834Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/b4/0a771378c5f16f8115f796d1f437950158679bcd2a7c68cf251cfb00ed5b/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f", size = 406015, upload-time = "2025-11-30T20:24:29.457Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/d8/456dbba0af75049dc6f63ff295a2f92766b9d521fa00de67a2bd6427d57a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877", size = 423736, upload-time = "2025-11-30T20:24:31.22Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/13/64/b4d76f227d5c45a7e0b796c674fd81b0a6c4fbd48dc29271857d8219571c/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a", size = 573981, upload-time = "2025-11-30T20:24:32.934Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/91/092bacadeda3edf92bf743cc96a7be133e13a39cdbfd7b5082e7ab638406/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4", size = 599782, upload-time = "2025-11-30T20:24:35.169Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sse-starlette"
|
||||||
|
version = "3.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "anyio" },
|
||||||
|
{ name = "starlette" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8b/8d/00d280c03ffd39aaee0e86ec81e2d3b9253036a0f93f51d10503adef0e65/sse_starlette-3.2.0.tar.gz", hash = "sha256:8127594edfb51abe44eac9c49e59b0b01f1039d0c7461c6fd91d4e03b70da422", size = 27253, upload-time = "2026-01-17T13:11:05.62Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl", hash = "sha256:5876954bd51920fc2cd51baee47a080eb88a37b5b784e615abb0b283f801cdbf", size = 12763, upload-time = "2026-01-17T13:11:03.775Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "starlette"
|
||||||
|
version = "0.52.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "anyio" },
|
||||||
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702, upload-time = "2026-01-18T13:34:11.062Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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, upload-time = "2025-08-25T13:49:26.313Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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, upload-time = "2025-10-01T02:14:41.687Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uvicorn"
|
||||||
|
version = "0.40.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/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502, upload-time = "2025-12-21T14:16:21.041Z" },
|
||||||
|
]
|
||||||
Loading…
x
Reference in New Issue
Block a user