diff --git a/UnityMcpBridge/Editor/Helpers/ServerInstaller.cs b/UnityMcpBridge/Editor/Helpers/ServerInstaller.cs index 56b2343..ed92786 100644 --- a/UnityMcpBridge/Editor/Helpers/ServerInstaller.cs +++ b/UnityMcpBridge/Editor/Helpers/ServerInstaller.cs @@ -75,14 +75,11 @@ namespace UnityMcpBridge.Editor.Helpers } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - string path = "/usr/local/bin"; - return !Directory.Exists(path) || !IsDirectoryWritable(path) - ? Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), - "Applications", - RootFolder - ) - : Path.Combine(path, RootFolder); + // Use Application Support for a stable, user-writable location + return Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "UnityMCP" + ); } throw new Exception("Unsupported operating system."); } @@ -213,5 +210,189 @@ namespace UnityMcpBridge.Editor.Helpers CopyDirectoryRecursive(dirPath, destSubDir); } } + + public static bool RepairPythonEnvironment() + { + try + { + string serverSrc = GetServerPath(); + bool hasServer = File.Exists(Path.Combine(serverSrc, "server.py")); + if (!hasServer) + { + // In dev mode or if not installed yet, try the embedded/dev source + if (TryGetEmbeddedServerSource(out string embeddedSrc) && File.Exists(Path.Combine(embeddedSrc, "server.py"))) + { + serverSrc = embeddedSrc; + hasServer = true; + } + else + { + // Attempt to install then retry + EnsureServerInstalled(); + serverSrc = GetServerPath(); + hasServer = File.Exists(Path.Combine(serverSrc, "server.py")); + } + } + + if (!hasServer) + { + Debug.LogWarning("RepairPythonEnvironment: server.py not found; ensure server is installed first."); + return false; + } + + // Remove stale venv and pinned version file if present + string venvPath = Path.Combine(serverSrc, ".venv"); + if (Directory.Exists(venvPath)) + { + try { Directory.Delete(venvPath, recursive: true); } catch (Exception ex) { Debug.LogWarning($"Failed to delete .venv: {ex.Message}"); } + } + string pyPin = Path.Combine(serverSrc, ".python-version"); + if (File.Exists(pyPin)) + { + try { File.Delete(pyPin); } catch (Exception ex) { Debug.LogWarning($"Failed to delete .python-version: {ex.Message}"); } + } + + string uvPath = FindUvPath(); + if (uvPath == null) + { + Debug.LogError("UV not found. Please install uv (https://docs.astral.sh/uv/)." ); + return false; + } + + var psi = new System.Diagnostics.ProcessStartInfo + { + FileName = uvPath, + Arguments = "sync", + WorkingDirectory = serverSrc, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + + using var p = System.Diagnostics.Process.Start(psi); + string stdout = p.StandardOutput.ReadToEnd(); + string stderr = p.StandardError.ReadToEnd(); + p.WaitForExit(60000); + + if (p.ExitCode != 0) + { + Debug.LogError($"uv sync failed: {stderr}\n{stdout}"); + return false; + } + + Debug.Log("Unity MCP: Python environment repaired successfully."); + return true; + } + catch (Exception ex) + { + Debug.LogError($"RepairPythonEnvironment failed: {ex.Message}"); + return false; + } + } + + private static string FindUvPath() + { + // Allow user override via EditorPrefs + try + { + string overridePath = EditorPrefs.GetString("UnityMCP.UvPath", string.Empty); + if (!string.IsNullOrEmpty(overridePath) && File.Exists(overridePath)) + { + if (ValidateUvBinary(overridePath)) return overridePath; + } + } + catch { } + + string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty; + string[] candidates = + { + "/opt/homebrew/bin/uv", + "/usr/local/bin/uv", + "/usr/bin/uv", + "/opt/local/bin/uv", + Path.Combine(home, ".local", "bin", "uv"), + "/opt/homebrew/opt/uv/bin/uv", + // Framework Python installs + "/Library/Frameworks/Python.framework/Versions/3.13/bin/uv", + "/Library/Frameworks/Python.framework/Versions/3.12/bin/uv", + // Fallback to PATH resolution by name + "uv" + }; + foreach (string c in candidates) + { + try + { + if (ValidateUvBinary(c)) return c; + } + catch { /* ignore */ } + } + + // Try which uv (explicit path) + try + { + var whichPsi = new System.Diagnostics.ProcessStartInfo + { + FileName = "/usr/bin/which", + Arguments = "uv", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + using var wp = System.Diagnostics.Process.Start(whichPsi); + string output = wp.StandardOutput.ReadToEnd().Trim(); + wp.WaitForExit(3000); + if (wp.ExitCode == 0 && !string.IsNullOrEmpty(output) && File.Exists(output)) + { + if (ValidateUvBinary(output)) return output; + } + } + catch { } + + // Manual PATH scan + try + { + string pathEnv = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; + string[] parts = pathEnv.Split(Path.PathSeparator); + foreach (string part in parts) + { + try + { + string candidate = Path.Combine(part, "uv"); + if (File.Exists(candidate) && ValidateUvBinary(candidate)) return candidate; + } + catch { } + } + } + catch { } + + return null; + } + + private static bool ValidateUvBinary(string uvPath) + { + try + { + var psi = new System.Diagnostics.ProcessStartInfo + { + FileName = uvPath, + Arguments = "--version", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + using var p = System.Diagnostics.Process.Start(psi); + if (!p.WaitForExit(5000)) { try { p.Kill(); } catch { } return false; } + if (p.ExitCode == 0) + { + string output = p.StandardOutput.ReadToEnd().Trim(); + return output.StartsWith("uv "); + } + } + catch { } + return false; + } } } diff --git a/UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs b/UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs index 4a2a27a..408a63b 100644 --- a/UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs +++ b/UnityMcpBridge/Editor/Windows/UnityMcpEditorWindow.cs @@ -102,14 +102,32 @@ namespace UnityMcpBridge.Editor.Windows private void UpdatePythonServerInstallationStatus() { - string serverPath = ServerInstaller.GetServerPath(); - - if (File.Exists(Path.Combine(serverPath, "server.py"))) + try { - pythonServerInstallationStatus = "Installed (Embedded)"; - pythonServerInstallationStatusColor = Color.green; + string installedPath = ServerInstaller.GetServerPath(); + bool installedOk = !string.IsNullOrEmpty(installedPath) && File.Exists(Path.Combine(installedPath, "server.py")); + if (installedOk) + { + pythonServerInstallationStatus = "Installed"; + pythonServerInstallationStatusColor = Color.green; + return; + } + + // Fall back to embedded/dev source via our existing resolution logic + string embeddedPath = FindPackagePythonDirectory(); + bool embeddedOk = !string.IsNullOrEmpty(embeddedPath) && File.Exists(Path.Combine(embeddedPath, "server.py")); + if (embeddedOk) + { + pythonServerInstallationStatus = "Installed (Embedded)"; + pythonServerInstallationStatusColor = Color.green; + } + else + { + pythonServerInstallationStatus = "Not Installed"; + pythonServerInstallationStatusColor = Color.red; + } } - else + catch { pythonServerInstallationStatus = "Not Installed"; pythonServerInstallationStatusColor = Color.red; @@ -215,6 +233,16 @@ namespace UnityMcpBridge.Editor.Windows "Unity MCP Editor", titleStyle ); + + // Place the Show Debug Logs toggle on the same header row, right-aligned + float toggleWidth = 160f; + Rect toggleRect = new Rect(titleRect.xMax - toggleWidth - 12f, titleRect.y + 10f, toggleWidth, 20f); + bool newDebug = GUI.Toggle(toggleRect, debugLogsEnabled, "Show Debug Logs"); + if (newDebug != debugLogsEnabled) + { + debugLogsEnabled = newDebug; + EditorPrefs.SetBool("UnityMCP.DebugLogs", debugLogsEnabled); + } EditorGUILayout.Space(15); } @@ -243,7 +271,6 @@ namespace UnityMcpBridge.Editor.Windows EditorGUILayout.Space(5); - // Connection mode EditorGUILayout.BeginHorizontal(); bool isAutoMode = UnityMcpBridge.IsAutoConnectMode(); GUIStyle modeStyle = new GUIStyle(EditorStyles.miniLabel) { fontSize = 11 }; @@ -251,7 +278,6 @@ namespace UnityMcpBridge.Editor.Windows GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); - // Current ports display int currentUnityPort = UnityMcpBridge.GetCurrentPort(); GUIStyle portStyle = new GUIStyle(EditorStyles.miniLabel) { @@ -260,7 +286,7 @@ namespace UnityMcpBridge.Editor.Windows EditorGUILayout.LabelField($"Ports: Unity {currentUnityPort}, MCP {mcpPort}", portStyle); EditorGUILayout.Space(5); - // Auto-Setup button below ports + /// Auto-Setup button below ports string setupButtonText = (lastClientRegisteredOk && lastBridgeVerifiedOk) ? "Connected ✓" : "Auto-Setup"; if (GUILayout.Button(setupButtonText, GUILayout.Height(24))) { @@ -268,20 +294,47 @@ namespace UnityMcpBridge.Editor.Windows } EditorGUILayout.Space(4); - // Debug logs toggle inside Server Status + // Repair Python Env button with tooltip tag using (new EditorGUILayout.HorizontalScope()) { GUILayout.FlexibleSpace(); - bool newDebug = EditorGUILayout.ToggleLeft("Show Debug Logs", debugLogsEnabled, GUILayout.Width(150)); - if (newDebug != debugLogsEnabled) + GUIContent repairLabel = new GUIContent( + "Repair Python Env", + "Deletes the server's .venv and runs 'uv sync' to rebuild a clean environment. Use this if modules are missing or Python upgraded." + ); + if (GUILayout.Button(repairLabel, GUILayout.Width(160), GUILayout.Height(22))) { - debugLogsEnabled = newDebug; - EditorPrefs.SetBool("UnityMCP.DebugLogs", debugLogsEnabled); + bool ok = global::UnityMcpBridge.Editor.Helpers.ServerInstaller.RepairPythonEnvironment(); + if (ok) + { + EditorUtility.DisplayDialog("Unity MCP", "Python environment repaired.", "OK"); + UpdatePythonServerInstallationStatus(); + } + else + { + EditorUtility.DisplayDialog("Unity MCP", "Repair failed. Please check Console for details.", "OK"); + } } } + // (Removed descriptive tool tag under the Repair button) + + // (Show Debug Logs toggle moved to header) EditorGUILayout.Space(2); - // Removed redundant inline badges to streamline UI + // Python detection warning with link + if (!IsPythonDetected()) + { + GUIStyle warnStyle = new GUIStyle(EditorStyles.label) { richText = true, wordWrap = true }; + EditorGUILayout.LabelField("Warning: No Python installation found.", warnStyle); + using (new EditorGUILayout.HorizontalScope()) + { + if (GUILayout.Button("Open install instructions", GUILayout.Width(200))) + { + Application.OpenURL("https://www.python.org/downloads/"); + } + } + EditorGUILayout.Space(4); + } // Troubleshooting helpers if (pythonServerInstallationStatusColor != Color.green) @@ -369,16 +422,7 @@ namespace UnityMcpBridge.Editor.Windows string description = GetValidationLevelDescription(validationLevelIndex); EditorGUILayout.HelpBox(description, MessageType.Info); EditorGUILayout.Space(4); - // Inline debug logs toggle under Script Validation - EditorGUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - bool newDebug = EditorGUILayout.ToggleLeft("Show Debug Logs", debugLogsEnabled, GUILayout.Width(150)); - if (newDebug != debugLogsEnabled) - { - debugLogsEnabled = newDebug; - EditorPrefs.SetBool("UnityMCP.DebugLogs", debugLogsEnabled); - } - EditorGUILayout.EndHorizontal(); + // (Show Debug Logs toggle moved to header) EditorGUILayout.Space(2); EditorGUILayout.EndVertical(); } @@ -845,7 +889,10 @@ namespace UnityMcpBridge.Editor.Windows return "Configured successfully"; } - private void ShowManualConfigurationInstructions(string configPath, McpClient mcpClient) + private void ShowManualConfigurationInstructions( + string configPath, + McpClient mcpClient + ) { mcpClient.SetStatus(McpStatus.Error, "Manual configuration required"); @@ -1938,5 +1985,45 @@ namespace UnityMcpBridge.Editor.Windows mcpClient.SetStatus(McpStatus.Error, e.Message); } } + + private bool IsPythonDetected() + { + try + { + // Common absolute paths + string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty; + string[] candidates = + { + "/opt/homebrew/bin/python3", + "/usr/local/bin/python3", + "/usr/bin/python3", + "/opt/local/bin/python3", + Path.Combine(home, ".local", "bin", "python3"), + "/Library/Frameworks/Python.framework/Versions/3.13/bin/python3", + "/Library/Frameworks/Python.framework/Versions/3.12/bin/python3", + }; + foreach (string c in candidates) + { + if (File.Exists(c)) return true; + } + + // Try 'which python3' + var psi = new ProcessStartInfo + { + FileName = "/usr/bin/which", + Arguments = "python3", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + using var p = Process.Start(psi); + string outp = p.StandardOutput.ReadToEnd().Trim(); + p.WaitForExit(2000); + if (p.ExitCode == 0 && !string.IsNullOrEmpty(outp) && File.Exists(outp)) return true; + } + catch { } + return false; + } } } diff --git a/UnityMcpBridge/UnityMcpServer/src/.python-version b/UnityMcpBridge/UnityMcpServer/src/.python-version deleted file mode 100644 index e4fba21..0000000 --- a/UnityMcpBridge/UnityMcpServer/src/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.12 diff --git a/UnityMcpBridge/UnityMcpServer/src/pyproject.toml b/UnityMcpBridge/UnityMcpServer/src/pyproject.toml index eebcde1..2c05fb8 100644 --- a/UnityMcpBridge/UnityMcpServer/src/pyproject.toml +++ b/UnityMcpBridge/UnityMcpServer/src/pyproject.toml @@ -3,7 +3,7 @@ name = "UnityMcpServer" version = "2.0.0" description = "Unity MCP Server: A Unity package for Unity Editor integration via the Model Context Protocol (MCP)." readme = "README.md" -requires-python = ">=3.12" +requires-python = ">=3.10" dependencies = ["httpx>=0.27.2", "mcp[cli]>=1.4.1"] [build-system] diff --git a/UnityMcpServer/src/.python-version b/UnityMcpServer/src/.python-version deleted file mode 100644 index e4fba21..0000000 --- a/UnityMcpServer/src/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.12 diff --git a/UnityMcpServer/src/pyproject.toml b/UnityMcpServer/src/pyproject.toml index eebcde1..2c05fb8 100644 --- a/UnityMcpServer/src/pyproject.toml +++ b/UnityMcpServer/src/pyproject.toml @@ -3,7 +3,7 @@ name = "UnityMcpServer" version = "2.0.0" description = "Unity MCP Server: A Unity package for Unity Editor integration via the Model Context Protocol (MCP)." readme = "README.md" -requires-python = ">=3.12" +requires-python = ">=3.10" dependencies = ["httpx>=0.27.2", "mcp[cli]>=1.4.1"] [build-system] diff --git a/UnityMcpServer/src/uv.lock b/UnityMcpServer/src/uv.lock index bc3e54c..de0cd44 100644 --- a/UnityMcpServer/src/uv.lock +++ b/UnityMcpServer/src/uv.lock @@ -1,6 +1,6 @@ version = 1 revision = 1 -requires-python = ">=3.12" +requires-python = ">=3.10" [[package]] name = "annotated-types" @@ -16,6 +16,7 @@ name = "anyio" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, { name = "sniffio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -55,6 +56,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] +[[package]] +name = "exceptiongroup" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674 }, +] + [[package]] name = "h11" version = "0.14.0" @@ -179,6 +192,33 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 } wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938 }, + { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684 }, + { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169 }, + { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227 }, + { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695 }, + { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662 }, + { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370 }, + { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813 }, + { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287 }, + { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414 }, + { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301 }, + { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685 }, + { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876 }, + { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421 }, + { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998 }, + { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167 }, + { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071 }, + { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244 }, + { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470 }, + { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291 }, + { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613 }, + { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355 }, + { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661 }, + { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261 }, + { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361 }, + { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484 }, + { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102 }, { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127 }, { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340 }, { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900 }, @@ -207,6 +247,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 }, { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 }, { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 }, + { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159 }, + { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331 }, + { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467 }, + { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797 }, + { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839 }, + { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861 }, + { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582 }, + { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985 }, + { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715 }, ] [[package]] @@ -247,6 +296,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } wheels = [ @@ -342,6 +392,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4b/4d/938bd85e5bf2edeec766267a5015ad969730bb91e31b44021dfe8b22df6c/uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9", size = 76568 } wheels = [