diff --git a/.gitignore b/.gitignore index de3edd7..de63b7d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,9 @@ __pycache__ *.pyc .nox *.g4 -.antlr \ No newline at end of file +.antlr + +target +client/node_modules +client/dist +client/out \ No newline at end of file diff --git a/.vscode/README.md b/.vscode/README.md new file mode 100644 index 0000000..056e4bf --- /dev/null +++ b/.vscode/README.md @@ -0,0 +1,10 @@ +This folder contains debug and task configurations for developing the extension and the Rust language server. + +- `launch.json`: Debug configurations for the Extension Host and for the Rust server (expects `CodeLLDB` extension). +- `tasks.json`: Tasks to build the client (`npm run build`) and server (`cargo build`). + +Usage: + +1. Install the `vadimcn.vscode-lldb` (CodeLLDB) extension for Rust debugging. +2. Run the `npm: build (client)` task or use the Run Extension configuration which will run it as a preLaunchTask. +3. Use `Launch Rust server (CodeLLDB)` to build and run the server under the debugger. diff --git a/.vscode/launch.json b/.vscode/launch.json index ccaf648..c2f3b1e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,74 +1,28 @@ -// A launch configuration that compiles the extension and then opens it inside a new window -// Use IntelliSense to learn about possible attributes. -// Hover to view descriptions of existing attributes. -// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 { + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { - "name": "Run Extension", "type": "extensionHost", "request": "launch", - "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceFolder}"], - "outFiles": ["${workspaceFolder}/client/**/*.js"], + "name": "Run TCL LSP", + "runtimeExecutable": "${execPath}/", + "args": ["--extensionDevelopmentPath=${workspaceFolder}/", "${workspaceFolder}/test/"], + "outFiles": ["${workspaceFolder}/client/out/**/*.js"], "autoAttachChildProcesses": true, - "preLaunchTask": { - "type": "npm", - "script": "watch" - } + "preLaunchTask": "npm: build" }, { - "name": "Python Attach", - "type": "debugpy", - "request": "attach", - "processId": "${command:pickProcess}", - "justMyCode": false, - "presentation": { - "hidden": false, - "group": "", - "order": 3 - } - }, - { - "name": "Debug Extension (hidden)", - "type": "extensionHost", + "name": "Debug Rust LSP Server (debug)", + "type": "lldb", "request": "launch", - "args": ["--extensionDevelopmentPath=${workspaceFolder}"], - "outFiles": ["${workspaceFolder}/client/**/*.js"], - "env": { - "USE_DEBUGPY": "True" - }, - "presentation": { - "hidden": true, - "group": "", - "order": 4 - } - }, - { - "name": "Python debug server (hidden)", - "type": "debugpy", - "request": "attach", - "listen": { "host": "localhost", "port": 5678 }, - "justMyCode": true, - "presentation": { - "hidden": true, - "group": "", - "order": 4 - } - } - ], - "compounds": [ - { - "name": "Debug Extension and Python", - "configurations": ["Python debug server (hidden)", "Debug Extension (hidden)"], - "stopAll": true, - "preLaunchTask": "npm: watch", - "presentation": { - "hidden": false, - "group": "", - "order": 1 - } + "program": "${workspaceFolder}/server/target/debug/server.exe", + "args": [], + "env": { "RUST_BACKTRACE": "1" }, + "preLaunchTask": "cargo: build server", + "stopOnEntry": true } ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..ec8d0b9 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,11 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "build", + "label": "npm: build", + "path": "./" + } + ] +} diff --git a/client/bin/esbuild.js b/client/bin/esbuild.js new file mode 100644 index 0000000..8d27dd4 --- /dev/null +++ b/client/bin/esbuild.js @@ -0,0 +1,56 @@ +//@ts-check +const esbuild = require('esbuild'); + +/** + * @typedef {import('esbuild').BuildOptions} BuildOptions + */ + +/** @type BuildOptions */ +const sharedDesktopOptions = { + bundle: true, + external: ['vscode'], + target: 'es2020', + platform: 'node', + sourcemap: true, +}; + +/** @type BuildOptions */ +const desktopOptions = { + entryPoints: ['src/extension.ts'], + outfile: 'dist/desktop/extension.js', + format: 'cjs', + ...sharedDesktopOptions, +}; + +function createContexts() { + return Promise.all([esbuild.context(desktopOptions)]); +} + +createContexts() + .then((contexts) => { + if (process.argv[2] === '--watch') { + const promises = []; + for (const context of contexts) { + promises.push(context.watch()); + } + return Promise.all(promises).then(() => { + return undefined; + }); + } else { + const promises = []; + for (const context of contexts) { + promises.push(context.rebuild()); + } + Promise.all(promises) + .then(async () => { + for (const context of contexts) { + await context.dispose(); + } + }) + .then(() => { + return undefined; + }) + .catch(console.error); + } + }) + .catch(console.error); diff --git a/client/package-lock.json b/client/package-lock.json index f2fa6f6..22175e1 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -10,31 +10,31 @@ "license": "MIT", "dependencies": { "@vscode/python-extension": "^1.0.5", - "fs-extra": "^11.3.0", - "vscode-languageclient": "^9.0.1" + "fs-extra": "11.3.1" }, "devDependencies": { - "@types/node": "^22.10.5", - "@types/vscode": "^1.96.0" + "@types/node": "^22.18.0", + "@types/vscode": "^1.96.0", + "vscode-languageclient": "^9.0.1" }, "engines": { "vscode": "^1.96.0" } }, "node_modules/@types/node": { - "version": "22.10.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", - "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", + "version": "22.18.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.0.tgz", + "integrity": "sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~6.21.0" } }, "node_modules/@types/vscode": { - "version": "1.96.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.96.0.tgz", - "integrity": "sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg==", + "version": "1.103.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.103.0.tgz", + "integrity": "sha512-o4hanZAQdNfsKecexq9L3eHICd0AAvdbLk6hA60UzGXbGH/q8b/9xv2RgR7vV3ZcHuyKVq7b37IGd/+gM4Tu+Q==", "dev": true, "license": "MIT" }, @@ -52,21 +52,23 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, "license": "MIT" }, "node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/fs-extra": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -84,9 +86,9 @@ "license": "ISC" }, "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -99,6 +101,7 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -108,9 +111,10 @@ } }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -120,9 +124,9 @@ } }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, @@ -139,6 +143,7 @@ "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" @@ -148,6 +153,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz", "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==", + "dev": true, "license": "MIT", "dependencies": { "minimatch": "^5.1.0", @@ -162,6 +168,7 @@ "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dev": true, "license": "MIT", "dependencies": { "vscode-jsonrpc": "8.2.0", @@ -172,6 +179,7 @@ "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true, "license": "MIT" } } diff --git a/client/package.json b/client/package.json index 4db362e..89535b7 100644 --- a/client/package.json +++ b/client/package.json @@ -8,11 +8,17 @@ }, "dependencies": { "@vscode/python-extension": "^1.0.5", - "fs-extra": "^11.3.0", - "vscode-languageclient": "^9.0.1" + "fs-extra": "11.3.1" }, "devDependencies": { - "@types/node": "^22.10.5", - "@types/vscode": "^1.96.0" + "@types/node": "^22.18.0", + "@types/vscode": "^1.96.0", + "vscode-languageclient": "^9.0.1" + }, + "scripts": { + "compile": "tsc -b", + "watch": "tsc -b -w", + "lint": "eslint", + "esbuild": "^0.25.0" } -} +} \ No newline at end of file diff --git a/client/src/common/constants.ts b/client/src/common/constants.ts deleted file mode 100644 index 35d809a..0000000 --- a/client/src/common/constants.ts +++ /dev/null @@ -1,14 +0,0 @@ -import * as path from "path" - -const folderName = path.basename(__dirname) -export const EXTENSION_ROOT_DIR = - folderName === "common" - ? path.dirname(path.dirname(path.dirname(__dirname))) - : path.dirname(__dirname) -export const BUNDLED_PYTHON_SCRIPTS_DIR = path.join(EXTENSION_ROOT_DIR, "server") -export const SERVER_SCRIPT_PATH = path.join(BUNDLED_PYTHON_SCRIPTS_DIR, "src", `lsp_server.py`) -export const DEBUG_SERVER_SCRIPT_PATH = path.join( - BUNDLED_PYTHON_SCRIPTS_DIR, - "src", - `_debug_server.py` -) diff --git a/client/src/common/python.ts b/client/src/common/python.ts deleted file mode 100644 index f300201..0000000 --- a/client/src/common/python.ts +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -/* eslint-disable @typescript-eslint/naming-convention */ -import { commands, Disposable, Event, EventEmitter, Uri } from "vscode" -import { traceError, traceLog } from "./log/logging" -import { PythonExtension, ResolvedEnvironment } from "@vscode/python-extension" - -export interface IInterpreterDetails { - path?: string[] - resource?: Uri -} - -const onDidChangePythonInterpreterEvent = new EventEmitter() -export const onDidChangePythonInterpreter: Event = - onDidChangePythonInterpreterEvent.event - -let _api: PythonExtension | undefined -async function getPythonExtensionAPI(): Promise { - if (_api) { - return _api - } - _api = await PythonExtension.api() - return _api -} - -export async function initializePython(disposables: Disposable[]): Promise { - try { - const api = await getPythonExtensionAPI() - - if (api) { - disposables.push( - api.environments.onDidChangeActiveEnvironmentPath((e) => { - onDidChangePythonInterpreterEvent.fire({ - path: [e.path], - resource: e.resource?.uri - }) - }) - ) - - traceLog("Waiting for interpreter from python extension.") - onDidChangePythonInterpreterEvent.fire(await getInterpreterDetails()) - } - } catch (error) { - traceError("Error initializing python: ", error) - } -} - -export async function resolveInterpreter( - interpreter: string[] -): Promise { - const api = await getPythonExtensionAPI() - return api?.environments.resolveEnvironment(interpreter[0]) -} - -export async function getInterpreterDetails(resource?: Uri): Promise { - const api = await getPythonExtensionAPI() - const environment = await api?.environments.resolveEnvironment( - api?.environments.getActiveEnvironmentPath(resource) - ) - if (environment?.executable.uri && checkVersion(environment)) { - return { path: [environment?.executable.uri.fsPath], resource } - } - return { path: undefined, resource } -} - -export async function getDebuggerPath(): Promise { - const api = await getPythonExtensionAPI() - return api?.debug.getDebuggerPackagePath() -} - -export async function runPythonExtensionCommand(command: string, ...rest: any[]) { - await getPythonExtensionAPI() - return await commands.executeCommand(command, ...rest) -} - -export function checkVersion(resolved: ResolvedEnvironment | undefined): boolean { - const version = resolved?.version - if (version?.major === 3 && version?.minor >= 11) { - return true - } - traceError(`Python version ${version?.major}.${version?.minor} is not supported.`) - traceError(`Selected python path: ${resolved?.executable.uri?.fsPath}`) - traceError("Supported versions are 3.11 and above.") - return false -} diff --git a/client/src/common/server.ts b/client/src/common/server.ts deleted file mode 100644 index a3dffc6..0000000 --- a/client/src/common/server.ts +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as fsapi from "fs-extra" -import { Disposable, env, LogOutputChannel } from "vscode" -import { State } from "vscode-languageclient" -import { - LanguageClient, - LanguageClientOptions, - RevealOutputChannelOn, - ServerOptions -} from "vscode-languageclient/node" -import { DEBUG_SERVER_SCRIPT_PATH, SERVER_SCRIPT_PATH } from "./constants" -import { traceError, traceInfo, traceVerbose } from "./log/logging" -import { getDebuggerPath } from "./python" -import { - getExtensionSettings, - getGlobalSettings, - getWorkspaceSettings, - ISettings -} from "./settings" -import { getLSClientTraceLevel, getProjectRoot } from "./utilities" -import { isVirtualWorkspace } from "./vscodeapi" - -export type IInitOptions = { settings: ISettings[]; globalSettings: ISettings } - -async function createServer( - settings: ISettings, - serverId: string, - serverName: string, - outputChannel: LogOutputChannel, - initializationOptions: IInitOptions -): Promise { - const command = settings.interpreter[0] - const cwd = settings.cwd - - // Set debugger path needed for debugging python code. - const newEnv = { ...process.env } - const debuggerPath = await getDebuggerPath() - const isDebugScript = await fsapi.pathExists(DEBUG_SERVER_SCRIPT_PATH) - if (newEnv.USE_DEBUGPY && debuggerPath) { - newEnv.DEBUGPY_PATH = debuggerPath - } else { - newEnv.USE_DEBUGPY = "False" - } - - // Set import strategy - newEnv.LS_IMPORT_STRATEGY = settings.importStrategy - - // Set notification type - newEnv.LS_SHOW_NOTIFICATION = settings.showNotifications - - const args = - newEnv.USE_DEBUGPY === "False" || !isDebugScript - ? settings.interpreter.slice(1).concat([SERVER_SCRIPT_PATH]) - : settings.interpreter.slice(1).concat([DEBUG_SERVER_SCRIPT_PATH]) - traceInfo(`Server run command: ${[command, ...args].join(" ")}`) - - const serverOptions: ServerOptions = { - command, - args, - options: { cwd, env: newEnv } - } - - // Options to control the language client - const clientOptions: LanguageClientOptions = { - // Register the server for python documents - documentSelector: isVirtualWorkspace() - ? [{ language: "tcl" }] - : [ - { scheme: "file", language: "tcl" }, - { scheme: "untitled", language: "tcl" }, - { scheme: "vscode-notebook", language: "tcl" }, - { scheme: "vscode-notebook-cell", language: "tcl" } - ], - outputChannel: outputChannel, - traceOutputChannel: outputChannel, - revealOutputChannelOn: RevealOutputChannelOn.Never, - initializationOptions - } - - return new LanguageClient(serverId, serverName, serverOptions, clientOptions) -} - -let _disposables: Disposable[] = [] -export async function restartServer( - serverId: string, - serverName: string, - outputChannel: LogOutputChannel, - lsClient?: LanguageClient -): Promise { - if (lsClient) { - traceInfo(`Server: Stop requested`) - await lsClient.stop() - _disposables.forEach((d) => d.dispose()) - _disposables = [] - } - const projectRoot = await getProjectRoot() - const workspaceSetting = await getWorkspaceSettings(serverId, projectRoot, true) - - const newLSClient = await createServer(workspaceSetting, serverId, serverName, outputChannel, { - settings: await getExtensionSettings(serverId, true), - globalSettings: await getGlobalSettings(serverId, false) - }) - traceInfo(`Server: Start requested.`) - _disposables.push( - newLSClient.onDidChangeState((e) => { - switch (e.newState) { - case State.Stopped: - traceVerbose(`Server State: Stopped`) - break - case State.Starting: - traceVerbose(`Server State: Starting`) - break - case State.Running: - traceVerbose(`Server State: Running`) - break - } - }) - ) - try { - await newLSClient.start() - } catch (ex) { - traceError(`Server: Start failed: ${ex}`) - return undefined - } - - const level = getLSClientTraceLevel(outputChannel.logLevel, env.logLevel) - await newLSClient.setTrace(level) - return newLSClient -} diff --git a/client/src/common/settings.ts b/client/src/common/settings.ts deleted file mode 100644 index 8263532..0000000 --- a/client/src/common/settings.ts +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { - ConfigurationChangeEvent, - ConfigurationScope, - WorkspaceConfiguration, - WorkspaceFolder -} from "vscode" -import { getInterpreterDetails } from "./python" -import { getConfiguration, getWorkspaceFolders } from "./vscodeapi" - -export interface ISettings { - cwd: string - workspace: string - args: string[] - path: string[] - interpreter: string[] - importStrategy: string - showNotifications: string -} - -export function getExtensionSettings( - namespace: string, - includeInterpreter?: boolean -): Promise { - return Promise.all( - getWorkspaceFolders().map((w) => getWorkspaceSettings(namespace, w, includeInterpreter)) - ) -} - -function resolveVariables(value: string[], workspace?: WorkspaceFolder): string[] { - const substitutions = new Map() - const home = process.env.HOME || process.env.USERPROFILE - if (home) { - substitutions.set("${userHome}", home) - } - if (workspace) { - substitutions.set("${workspaceFolder}", workspace.uri.fsPath) - } - substitutions.set("${cwd}", process.cwd()) - getWorkspaceFolders().forEach((w) => { - substitutions.set("${workspaceFolder:" + w.name + "}", w.uri.fsPath) - }) - - return value.map((s) => { - for (const [key, value] of substitutions) { - s = s.replace(key, value) - } - return s - }) -} - -export function getInterpreterFromSetting(namespace: string, scope?: ConfigurationScope) { - const config = getConfiguration(namespace, scope) - return config.get("interpreter") -} - -export async function getWorkspaceSettings( - namespace: string, - workspace: WorkspaceFolder, - includeInterpreter?: boolean -): Promise { - const config = getConfiguration(namespace, workspace.uri) - - let interpreter: string[] = [] - if (includeInterpreter) { - interpreter = getInterpreterFromSetting(namespace, workspace) ?? [] - if (interpreter.length === 0) { - interpreter = (await getInterpreterDetails(workspace.uri)).path ?? [] - } - } - - const workspaceSetting = { - cwd: workspace.uri.fsPath, - workspace: workspace.uri.toString(), - args: resolveVariables(config.get(`args`) ?? [], workspace), - path: resolveVariables(config.get(`path`) ?? [], workspace), - interpreter: resolveVariables(interpreter, workspace), - importStrategy: config.get(`importStrategy`) ?? "useBundled", - showNotifications: config.get(`showNotifications`) ?? "off", - formatter: config.get(`formatter`) ?? true, - inlayHint: config.get(`inlayHint`) ?? true - } - return workspaceSetting -} - -function getGlobalValue(config: WorkspaceConfiguration, key: string, defaultValue: T): T { - const inspect = config.inspect(key) - return inspect?.globalValue ?? inspect?.defaultValue ?? defaultValue -} - -export async function getGlobalSettings( - namespace: string, - includeInterpreter?: boolean -): Promise { - const config = getConfiguration(namespace) - - let interpreter: string[] = [] - if (includeInterpreter) { - interpreter = getGlobalValue(config, "interpreter", []) - if (interpreter === undefined || interpreter.length === 0) { - interpreter = (await getInterpreterDetails()).path ?? [] - } - } - - const setting = { - cwd: process.cwd(), - workspace: process.cwd(), - args: getGlobalValue(config, "args", []), - path: getGlobalValue(config, "path", []), - interpreter: interpreter, - importStrategy: getGlobalValue(config, "importStrategy", "useBundled"), - showNotifications: getGlobalValue(config, "showNotifications", "off"), - formatter: config.get(`formatter`) ?? true, - inlayHint: config.get(`inlayHint`) ?? true - } - return setting -} - -export function checkIfConfigurationChanged( - e: ConfigurationChangeEvent, - namespace: string -): boolean { - const settings = [ - `${namespace}.args`, - `${namespace}.path`, - `${namespace}.interpreter`, - `${namespace}.importStrategy`, - `${namespace}.showNotifications`, - `${namespace}.formatter`, - `${namespace}.inlayHint` - ] - const changed = settings.map((s) => e.affectsConfiguration(s)) - return changed.includes(true) -} diff --git a/client/src/common/setup.ts b/client/src/common/setup.ts deleted file mode 100644 index d6c32e8..0000000 --- a/client/src/common/setup.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as path from "path" -import * as fs from "fs-extra" -import { EXTENSION_ROOT_DIR } from "./constants" - -export interface IServerInfo { - name: string - module: string -} - -export function loadServerDefaults(): IServerInfo { - const packageJson = path.join(EXTENSION_ROOT_DIR, "package.json") - const content = fs.readFileSync(packageJson).toString() - const config = JSON.parse(content) - return config.serverInfo as IServerInfo -} diff --git a/client/src/common/utilities.ts b/client/src/common/utilities.ts deleted file mode 100644 index 74d4e37..0000000 --- a/client/src/common/utilities.ts +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as fs from "fs-extra" -import * as path from "path" -import { LogLevel, Uri, WorkspaceFolder } from "vscode" -import { Trace } from "vscode-jsonrpc/node" -import { getWorkspaceFolders } from "./vscodeapi" - -function logLevelToTrace(logLevel: LogLevel): Trace { - switch (logLevel) { - case LogLevel.Error: - case LogLevel.Warning: - case LogLevel.Info: - return Trace.Messages - - case LogLevel.Debug: - case LogLevel.Trace: - return Trace.Verbose - - case LogLevel.Off: - default: - return Trace.Off - } -} - -export function getLSClientTraceLevel(channelLogLevel: LogLevel, globalLogLevel: LogLevel): Trace { - if (channelLogLevel === LogLevel.Off) { - return logLevelToTrace(globalLogLevel) - } - if (globalLogLevel === LogLevel.Off) { - return logLevelToTrace(channelLogLevel) - } - const level = logLevelToTrace( - channelLogLevel <= globalLogLevel ? channelLogLevel : globalLogLevel - ) - return level -} - -export async function getProjectRoot(): Promise { - const workspaces: readonly WorkspaceFolder[] = getWorkspaceFolders() - if (workspaces.length === 0) { - return { - uri: Uri.file(process.cwd()), - name: path.basename(process.cwd()), - index: 0 - } - } else if (workspaces.length === 1) { - return workspaces[0] - } else { - let rootWorkspace = workspaces[0] - let root = undefined - for (const w of workspaces) { - if (await fs.pathExists(w.uri.fsPath)) { - root = w.uri.fsPath - rootWorkspace = w - break - } - } - - for (const w of workspaces) { - if (root && root.length > w.uri.fsPath.length && (await fs.pathExists(w.uri.fsPath))) { - root = w.uri.fsPath - rootWorkspace = w - } - } - return rootWorkspace - } -} diff --git a/client/src/common/vscodeapi.ts b/client/src/common/vscodeapi.ts deleted file mode 100644 index 8304022..0000000 --- a/client/src/common/vscodeapi.ts +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { - commands, - ConfigurationScope, - Disposable, - LogOutputChannel, - Uri, - window, - workspace, - WorkspaceConfiguration, - WorkspaceFolder -} from "vscode" - -export function createOutputChannel(name: string): LogOutputChannel { - return window.createOutputChannel(name, { log: true }) -} - -export function getConfiguration( - config: string, - scope?: ConfigurationScope -): WorkspaceConfiguration { - return workspace.getConfiguration(config, scope) -} - -export function registerCommand( - command: string, - callback: (...args: any[]) => any, - thisArg?: any -): Disposable { - return commands.registerCommand(command, callback, thisArg) -} - -export const { onDidChangeConfiguration } = workspace - -export function isVirtualWorkspace(): boolean { - const isVirtual = - workspace.workspaceFolders && - workspace.workspaceFolders.every((f) => f.uri.scheme !== "file") - return !!isVirtual -} - -export function getWorkspaceFolders(): readonly WorkspaceFolder[] { - return workspace.workspaceFolders ?? [] -} - -export function getWorkspaceFolder(uri: Uri): WorkspaceFolder | undefined { - return workspace.getWorkspaceFolder(uri) -} diff --git a/client/src/extension.ts b/client/src/extension.ts index 8460e3b..948aa3c 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -3,7 +3,7 @@ import { LanguageClient, LanguageClientOptions, ServerOptions, - TransportKind + Executable } from "vscode-languageclient/node" import { formatCdlFile, @@ -15,105 +15,59 @@ import { cdlDocumentSymbolProvider, defDocumentSymbolProvider } from "./common/handlers" -import { registerLogger, traceError, traceLog, traceVerbose } from "./common/log/logging" -import { - checkVersion, - getInterpreterDetails, - initializePython, - onDidChangePythonInterpreter, - resolveInterpreter -} from "./common/python" -import { restartServer } from "./common/server" -import { checkIfConfigurationChanged, getInterpreterFromSetting } from "./common/settings" -import { loadServerDefaults } from "./common/setup" -import { getLSClientTraceLevel } from "./common/utilities" -import { createOutputChannel, onDidChangeConfiguration, registerCommand } from "./common/vscodeapi" let client: LanguageClient - +interface InitializationOptions { + perFileParser: Record +} export async function activate(context: vscode.ExtensionContext) { - // This is required to get server name and module. This should be - // the first thing that we do in this extension. - const serverInfo = loadServerDefaults() - const serverName = serverInfo.name - const serverId = serverInfo.module + // Allow overriding the server executable path via environment variable so + // the extension can attach to a debug-run server started externally. + // If `TCL_LSP_SERVER_PATH` is set, use that path; otherwise fall back to + // the packaged server inside the extension. + let serverCommand: string + const serverModule = vscode.Uri.joinPath( + context.extensionUri, + "server", + "target", + ...(process.platform === "win32" + ? ["x86_64-pc-windows-gnu", "release", "lsp-main.exe"] + : ["x86_64-unknown-linux-gnu", "release", "lsp-main"]) + ) + serverCommand = serverModule.fsPath - // Setup logging - const outputChannel = createOutputChannel(serverName) - context.subscriptions.push(outputChannel, registerLogger(outputChannel)) - - const changeLogLevel = async (c: vscode.LogLevel, g: vscode.LogLevel) => { - const level = getLSClientTraceLevel(c, g) - await client?.setTrace(level) + const channel = vscode.window.createOutputChannel("TCL LSP Server", "log") + const run: Executable = { + command: serverCommand, + options: { env: process.env } + } + const serverOptions: ServerOptions = { + run, + debug: run } - context.subscriptions.push( - outputChannel.onDidChangeLogLevel(async (e) => { - await changeLogLevel(e, vscode.env.logLevel) - }), - vscode.env.onDidChangeLogLevel(async (e) => { - await changeLogLevel(outputChannel.logLevel, e) - }) - ) - - // Log Server information - traceLog(`Name: ${serverInfo.name}`) - traceLog(`Module: ${serverInfo.module}`) - traceVerbose(`Full Server Info: ${JSON.stringify(serverInfo)}`) - - const runServer = async () => { - const interpreter = getInterpreterFromSetting(serverId) - if (interpreter && interpreter.length > 0) { - if (checkVersion(await resolveInterpreter(interpreter))) { - traceVerbose( - `Using interpreter from ${serverInfo.module}.interpreter: ${interpreter.join(" ")}` - ) - client = await restartServer(serverId, serverName, outputChannel, client) - } - return + const initializationOptions: InitializationOptions = { + perFileParser: { + tcl: "tcl" } - - const interpreterDetails = await getInterpreterDetails() - if (interpreterDetails.path) { - traceVerbose( - `Using interpreter from Python extension: ${interpreterDetails.path.join(" ")}` - ) - client = await restartServer(serverId, serverName, outputChannel, client) - return - } - - traceError( - "Python interpreter missing:\r\n" + - "[Option 1] Select python interpreter using the ms-python.python.\r\n" + - `[Option 2] Set an interpreter using "${serverId}.interpreter" setting.\r\n` + - "Please use Python 3.8 or greater." - ) } - context.subscriptions.push( - onDidChangePythonInterpreter(async () => { - await runServer() - }), - onDidChangeConfiguration(async (e: vscode.ConfigurationChangeEvent) => { - if (checkIfConfigurationChanged(e, serverId)) { - await runServer() - } - }), - registerCommand(`${serverId}.restart`, async () => { - await runServer() - }) - ) + const clientOptions: LanguageClientOptions = { + documentSelector: [{ language: "tcl" }], + synchronize: { + fileEvents: vscode.workspace.createFileSystemWatcher("**/*.tcl") + }, + outputChannel: channel, + initializationOptions + } - setImmediate(async () => { - const interpreter = getInterpreterFromSetting(serverId) - if (interpreter === undefined || interpreter.length === 0) { - traceLog(`Python extension loading`) - await initializePython(context.subscriptions) - traceLog(`Python extension loaded`) - } else { - await runServer() - } - }) + client = new LanguageClient("lspClient", "LSP Client", serverOptions, clientOptions) + + try { + await client.start() + } catch (error) { + client.error(`Start failed`, error, "force") + } // const formatCdlProvider = vscode.languages.registerDocumentFormattingEditProvider( diff --git a/client/tsconfig.json b/client/tsconfig.json index d7e4250..3070bf0 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -1,12 +1,21 @@ { "compilerOptions": { - "module": "commonjs", - "target": "es2019", - "lib": ["ES2019"], + "rootDir": "./src", + "skipLibCheck": true, + "lib": ["ES2024", "webworker"], + "types": ["vscode"], + "module": "Node16", + "moduleResolution": "Node16", "outDir": "./out", - "rootDir": "src", - "sourceMap": true - }, - "include": ["src"], - "exclude": ["node_modules", ".vscode-test"] + "strict": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "declaration": true, + "stripInternal": true, + "sourceMap": true, + "declarationMap": true, + "noUnusedLocals": false, + "noUnusedParameters": false + } } diff --git a/client/tsconfig.tsbuildinfo b/client/tsconfig.tsbuildinfo new file mode 100644 index 0000000..4d9be52 --- /dev/null +++ b/client/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./src/extension.ts","./src/common/handlers.ts","./src/common/log/logging.ts"],"version":"5.7.2"} \ No newline at end of file diff --git a/package.json b/package.json index 1d436a6..0129983 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "type": "git", "url": "https://git.cbsk-tech.de/Christoph/nx_post_support.git" }, - "main": "./dist/extension.js", + "main": "./client/out/extension", "keywords": [ "cdl", "NX CDL", @@ -120,9 +120,12 @@ } }, "scripts": { - "compile": "node esbuild.js --production", - "watch": "node esbuild.js --watch", - "package": "node esbuild.js --production" + "postinstall": "cd client && npm install && cd ..", + "vscode:prepublish": "npm run build", + "debug": "cd client && npm run compile", + "build": "cd client && npm run compile && cd ../server && npm run build && cd ..", + "lint": "cd client && npm run lint && cd ..", + "esbuild": "node ./bin/esbuild.js" }, "devDependencies": { "@types/vscode": "^1.96.0", @@ -132,4 +135,4 @@ "prettier": "^3.4.2", "typescript": "^5.7.2" } -} +} \ No newline at end of file diff --git a/server/Cargo.lock b/server/Cargo.lock new file mode 100644 index 0000000..9eac86b --- /dev/null +++ b/server/Cargo.lock @@ -0,0 +1,833 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "analysis" +version = "0.1.0" +dependencies = [ + "anyhow", + "lsp-types", + "serde", + "serde_json", + "tree-sitter", +] + +[[package]] +name = "anstream" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "features" +version = "0.1.0" +dependencies = [ + "analysis", + "anyhow", + "lsp-types", + "text", + "url", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650" + +[[package]] +name = "fluent-uri" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lsp-main" +version = "0.1.0" +dependencies = [ + "analysis", + "anyhow", + "env_logger", + "features", + "log", + "lsp-server", + "lsp-types", + "serde", + "serde_json", + "text", +] + +[[package]] +name = "lsp-server" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d6ada348dbc2703cbe7637b2dda05cff84d3da2819c24abcb305dd613e0ba2e" +dependencies = [ + "crossbeam-channel", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "lsp-types" +version = "0.97.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53353550a17c04ac46c585feb189c2db82154fc84b79c7a66c96c2c644f66071" +dependencies = [ + "bitflags", + "fluent-uri", + "serde", + "serde_json", + "serde_repr", +] + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.143" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +dependencies = [ + "indexmap", + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "text" +version = "0.1.0" +dependencies = [ + "anyhow", + "lsp-types", + "tree-sitter", + "tree-sitter-tcl", + "url", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tree-sitter" +version = "0.25.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7b8994f367f16e6fa14b5aebbcb350de5d7cbea82dc5b00ae997dd71680dd2" +dependencies = [ + "cc", + "regex", + "regex-syntax", + "serde_json", + "streaming-iterator", + "tree-sitter-language", +] + +[[package]] +name = "tree-sitter-language" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4013970217383f67b18aef68f6fb2e8d409bc5755227092d32efb0422ba24b8" + +[[package]] +name = "tree-sitter-tcl" +version = "1.1.0" +source = "git+https://github.com/tree-sitter-grammars/tree-sitter-tcl#8f11ac7206a54ed11210491cee1e0657e2962c47" +dependencies = [ + "cc", + "tree-sitter-language", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/server/Cargo.toml b/server/Cargo.toml new file mode 100644 index 0000000..30a0c71 --- /dev/null +++ b/server/Cargo.toml @@ -0,0 +1,24 @@ +[workspace] +members = [ + "crates/lsp-main", + "crates/text", + "crates/analysis", + "crates/features", +] +resolver = "2" + +[workspace.package] +edition = "2021" +resolver = "2" + +[workspace.dependencies] +anyhow = "1" +env_logger = "0.11" +log = "0.4.28" +lsp-server = "0.7" +lsp-types = "0.97" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +tree-sitter = "0.25.8" +tree-sitter-tcl = { git = "https://github.com/tree-sitter-grammars/tree-sitter-tcl" } +url = "2" \ No newline at end of file diff --git a/server/src/common/completion_list.json b/server/common/completion_list.json similarity index 100% rename from server/src/common/completion_list.json rename to server/common/completion_list.json diff --git a/server/crates/analysis/Cargo.toml b/server/crates/analysis/Cargo.toml new file mode 100644 index 0000000..0346d17 --- /dev/null +++ b/server/crates/analysis/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "analysis" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = { workspace = true } +lsp-types = { workspace = true } +tree-sitter = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } + diff --git a/server/crates/analysis/src/lib.rs b/server/crates/analysis/src/lib.rs new file mode 100644 index 0000000..7e5ea72 --- /dev/null +++ b/server/crates/analysis/src/lib.rs @@ -0,0 +1,99 @@ +use serde::{ Deserialize, Serialize }; +use std::collections::HashMap; +use tree_sitter::{ Node, Tree }; +use lsp_types as lsp; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ProcDef { + pub name: String, + pub params: Vec, + pub byte_start: usize, + pub byte_end: usize, +} + +#[derive(Default)] +pub struct ProcIndex { + by_uri: HashMap>, +} + +impl ProcIndex { + pub fn insert(&mut self, uri: lsp::Uri, procs: Vec) { + self.by_uri.insert(uri, procs); + } + pub fn get(&self, uri: &lsp::Uri) -> Option<&[ProcDef]> { + self.by_uri.get(uri).map(|v| v.as_slice()) + } + pub fn remove(&mut self, uri: &lsp::Uri) { + self.by_uri.remove(uri); + } +} + +pub fn collect_procs(tree: &Tree, source: &str) -> Vec { + let root = tree.root_node(); + let mut out = Vec::new(); + collect_from_node(root, source.as_bytes(), &mut out); + out +} + +fn collect_from_node(node: Node, src: &[u8], out: &mut Vec) { + let mut stack = vec![node]; + let mut cursor = node.walk(); + + while let Some(n) = stack.pop() { + if n.kind() == "command" { + if let Some(p) = try_extract_proc(n, src) { + out.push(p); + } + } + let mut it = n.children(&mut cursor); + while let Some(c) = it.next() { + stack.push(c); + } + } +} + +fn try_extract_proc(cmd: Node, src: &[u8]) -> Option { + // Gather word-like named children + let mut cursor = cmd.walk(); + let mut words: Vec<(Node, String)> = Vec::new(); + for ch in cmd.named_children(&mut cursor) { + match ch.kind() { + "word" | "braced_word" | "quoted_word" => { + if let Ok(t) = ch.utf8_text(src) { + words.push((ch, t.to_string())); + } + } + _ => {} + } + } + if words.len() < 2 { + return None; + } + if words[0].1 != "proc" { + return None; + } + + let name = words[1].1.trim().to_string(); + let params = if words.len() >= 3 { parse_params(&words[2].0, &words[2].1) } else { vec![] }; + + Some(ProcDef { + name, + params, + byte_start: cmd.start_byte(), + byte_end: cmd.end_byte(), + }) +} + +fn parse_params(node: &Node, text: &str) -> Vec { + // naive split; good enough for a starter + let is_braced = + node.kind() == "braced_word" && + text.starts_with('{') && + text.ends_with('}') && + text.len() >= 2; + let inner = if is_braced { &text[1..text.len() - 1] } else { text }; + inner + .split_whitespace() + .map(|s| s.to_string()) + .collect() +} diff --git a/server/crates/features/Cargo.toml b/server/crates/features/Cargo.toml new file mode 100644 index 0000000..2d46483 --- /dev/null +++ b/server/crates/features/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "features" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = { workspace = true } +lsp-types = { workspace = true } +analysis = { path = "../analysis" } +text = { path = "../text" } +url = { workspace = true } \ No newline at end of file diff --git a/server/crates/features/src/completion.rs b/server/crates/features/src/completion.rs new file mode 100644 index 0000000..e435a4d --- /dev/null +++ b/server/crates/features/src/completion.rs @@ -0,0 +1,31 @@ +use anyhow::Result; +use analysis::ProcIndex; +use lsp_types as lsp; +use text::DocumentStore; + +pub fn completion( + docs: &DocumentStore, + index: &ProcIndex, + params: &lsp::CompletionParams +) -> Result> { + let uri = ¶ms.text_document_position.text_document.uri; + let Some(_doc) = docs.get(uri) else { + return Ok(None); + }; + let Some(procs) = index.get(uri) else { + return Ok(None); + }; + + let items: Vec = procs + .iter() + .map(|p| lsp::CompletionItem { + label: p.name.clone(), + kind: Some(lsp::CompletionItemKind::FUNCTION), + detail: Some(format!("proc {}", p.params.join(" "))), + insert_text: Some(p.name.clone()), + ..Default::default() + }) + .collect(); + + Ok(Some(lsp::CompletionResponse::Array(items))) +} diff --git a/server/crates/features/src/definition.rs b/server/crates/features/src/definition.rs new file mode 100644 index 0000000..e7cbc5d --- /dev/null +++ b/server/crates/features/src/definition.rs @@ -0,0 +1,33 @@ +use anyhow::Result; +use analysis::ProcIndex; +use lsp_types as lsp; +use text::DocumentStore; + +pub fn definition( + docs: &DocumentStore, + index: &ProcIndex, + params: &lsp::GotoDefinitionParams +) -> Result> { + let uri = ¶ms.text_document_position_params.text_document.uri; + let pos = params.text_document_position_params.position; + let Some(doc) = docs.get(uri) else { + return Ok(None); + }; + let Some((word, _range)) = doc.word_under_position(pos) else { + return Ok(None); + }; + + let Some(procs) = index.get(uri) else { + return Ok(None); + }; + + if let Some(p) = procs.iter().find(|p| p.name == word) { + let loc = lsp::Location { + uri: uri.clone(), + range: doc.byte_range_to_lsp_range(p.byte_start, p.byte_end), + }; + return Ok(Some(lsp::GotoDefinitionResponse::Scalar(loc))); + } + + Ok(None) +} diff --git a/server/crates/features/src/document_symbol.rs b/server/crates/features/src/document_symbol.rs new file mode 100644 index 0000000..bc8ad07 --- /dev/null +++ b/server/crates/features/src/document_symbol.rs @@ -0,0 +1,34 @@ +use anyhow::Result; +use analysis::ProcIndex; +use lsp_types as lsp; +use text::DocumentStore; + +pub fn document_symbol( + docs: &DocumentStore, + index: &ProcIndex, + uri: &lsp::Uri +) -> Result> { + let Some(doc) = docs.get(uri) else { + return Ok(None); + }; + let Some(procs) = index.get(uri) else { + return Ok(None); + }; + + let mut symbols = Vec::new(); + for p in procs { + let range = doc.byte_range_to_lsp_range(p.byte_start, p.byte_end); + symbols.push(lsp::DocumentSymbol { + name: p.name.clone(), + detail: Some(format!("proc {}", p.params.join(" "))), + kind: lsp::SymbolKind::FUNCTION, + range, + selection_range: range, + children: None, + tags: None, + deprecated: None, + }); + } + + Ok(Some(lsp::DocumentSymbolResponse::Nested(symbols))) +} diff --git a/server/crates/features/src/lib.rs b/server/crates/features/src/lib.rs new file mode 100644 index 0000000..ade8e6e --- /dev/null +++ b/server/crates/features/src/lib.rs @@ -0,0 +1,7 @@ +mod document_symbol; +mod definition; +mod completion; + +pub use document_symbol::document_symbol; +pub use definition::definition; +pub use completion::completion; diff --git a/server/crates/lsp-main/Cargo.toml b/server/crates/lsp-main/Cargo.toml new file mode 100644 index 0000000..427c763 --- /dev/null +++ b/server/crates/lsp-main/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "lsp-main" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = { workspace = true } +env_logger = { workspace = true } +log = { workspace = true } +lsp-server = { workspace = true } +lsp-types = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +analysis = { path = "../analysis" } +features = { path = "../features" } +text = { path = "../text" } \ No newline at end of file diff --git a/server/crates/lsp-main/src/main.rs b/server/crates/lsp-main/src/main.rs new file mode 100644 index 0000000..f4d058d --- /dev/null +++ b/server/crates/lsp-main/src/main.rs @@ -0,0 +1,13 @@ +use anyhow::Result; +use env_logger::Env; +use lsp_server::Connection; + +mod server; + +fn main() -> Result<()> { + env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); + let (connection, io_threads) = Connection::stdio(); + server::Server::new(connection).run()?; + io_threads.join()?; + Ok(()) +} diff --git a/server/crates/lsp-main/src/server.rs b/server/crates/lsp-main/src/server.rs new file mode 100644 index 0000000..8e94c0a --- /dev/null +++ b/server/crates/lsp-main/src/server.rs @@ -0,0 +1,177 @@ +use anyhow::Result; +use log; +use lsp_server::{ Connection, Message, Response }; +use lsp_server::Notification as ServerNotification; +use lsp_server::Request as ServerRequest; +use lsp_types as lsp; +use lsp_types::notification::{ + DidChangeTextDocument, + DidCloseTextDocument, + DidOpenTextDocument, + LogMessage, + Notification as LspNotification, +}; +use lsp_types::request::{ + Completion, + DocumentSymbolRequest, + GotoDefinition, + Request as LspRequest, +}; +use serde_json::Value; + +use analysis::{ collect_procs, ProcIndex }; +use features::{ completion, definition, document_symbol }; +use text::DocumentStore; + +pub struct Server { + conn: Connection, + docs: DocumentStore, + procs: ProcIndex, +} + +impl Server { + pub fn new(conn: Connection) -> Self { + Self { + conn, + docs: DocumentStore::default(), + procs: ProcIndex::default(), + } + } + + pub fn run(mut self) -> Result<()> { + // Initialize handshake + let (id, _params) = self.conn.initialize_start()?; + let result = lsp::InitializeResult { + capabilities: server_capabilities(), + server_info: Some(lsp::ServerInfo { + name: "tcl-lsp".into(), + version: Some(env!("CARGO_PKG_VERSION").into()), + }), + }; + self.conn.initialize_finish(id, serde_json::to_value(result)?)?; + + let _ = self.log("tcl-lsp ready"); + + let receiver = self.conn.receiver.clone(); + + // main loop + for msg in receiver.iter() { + match msg { + lsp_server::Message::Request(req) => { + if self.conn.handle_shutdown(&req)? { + break; + } + if let Err(e) = self.on_request(req) { + log::error!("request error: {e:#}"); + } + } + lsp_server::Message::Notification(n) => { + if let Err(e) = self.on_notification(n) { + log::error!("notification error: {e:#}"); + } + } + lsp_server::Message::Response(_) => {} + } + } + + let _ = self.log("tcl-lsp stopped"); + Ok(()) + } + + fn on_notification(&mut self, n: ServerNotification) -> Result<()> { + match n.method.as_str() { + DidOpenTextDocument::METHOD => { + let params: lsp::DidOpenTextDocumentParams = serde_json::from_value(n.params)?; + let uri = params.text_document.uri.clone(); + self.docs.open(params.text_document)?; + self.reindex(&uri)?; + self.log(&format!("Opened {:?}", uri))?; + } + DidChangeTextDocument::METHOD => { + let params: lsp::DidChangeTextDocumentParams = serde_json::from_value(n.params)?; + let uri = params.text_document.uri.clone(); + // FULL sync: we expect one change with whole text + self.docs.apply_full_change(&uri, ¶ms.content_changes)?; + self.reindex(&uri)?; + } + DidCloseTextDocument::METHOD => { + let params: lsp::DidCloseTextDocumentParams = serde_json::from_value(n.params)?; + self.procs.remove(¶ms.text_document.uri); + self.docs.close(¶ms.text_document.uri); + } + _ => {} + } + Ok(()) + } + + fn on_request(&mut self, req: ServerRequest) -> Result<()> { + match req.method.as_str() { + DocumentSymbolRequest::METHOD => { + let params: lsp::DocumentSymbolParams = serde_json::from_value(req.params)?; + let uri = params.text_document.uri; + let result = document_symbol(&self.docs, &self.procs, &uri)?; + send_ok(&self.conn, req.id, result)?; + } + GotoDefinition::METHOD => { + let params: lsp::GotoDefinitionParams = serde_json::from_value(req.params)?; + let result = definition(&self.docs, &self.procs, ¶ms)?; + send_ok(&self.conn, req.id, result)?; + } + Completion::METHOD => { + let params: lsp::CompletionParams = serde_json::from_value(req.params)?; + let _ = self.log("Completion"); + let result = completion(&self.docs, &self.procs, ¶ms)?; + send_ok(&self.conn, req.id, result)?; + } + other => { + let resp = Response::new_err( + req.id, + lsp::error_codes::REQUEST_FAILED as i32, + format!("Unknown method: {other}") + ); + self.conn.sender.send(Message::Response(resp))?; + } + } + Ok(()) + } + + fn reindex(&mut self, uri: &lsp::Uri) -> Result<()> { + if let Some(doc) = self.docs.get(uri) { + if let Some(tree) = doc.tree() { + let text = doc.text(); + let procs = collect_procs(tree, &text); + self.procs.insert(uri.clone(), procs); + } + } + Ok(()) + } + + fn log(&self, message: &str) -> Result<()> { + let notif = LogMessage::METHOD.to_string(); + let params = lsp::LogMessageParams { + typ: lsp::MessageType::INFO, + message: message.to_string(), + }; + self.conn.sender.send(Message::Notification(ServerNotification::new(notif, params)))?; + Ok(()) + } +} + +fn send_ok( + conn: &Connection, + id: lsp_server::RequestId, + result: T +) -> Result<()> { + let v: Value = serde_json::to_value(result)?; + conn.sender.send(Message::Response(Response::new_ok(id, v)))?; + Ok(()) +} + +fn server_capabilities() -> lsp::ServerCapabilities { + lsp::ServerCapabilities { + completion_provider: Some(lsp::CompletionOptions { + ..Default::default() + }), + ..Default::default() + } +} diff --git a/server/crates/text/Cargo.toml b/server/crates/text/Cargo.toml new file mode 100644 index 0000000..1ace35c --- /dev/null +++ b/server/crates/text/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "text" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = { workspace = true } +lsp-types = { workspace = true } +tree-sitter = { workspace = true } +tree-sitter-tcl = { workspace = true } +url = { workspace = true } \ No newline at end of file diff --git a/server/crates/text/src/lib.rs b/server/crates/text/src/lib.rs new file mode 100644 index 0000000..40840e1 --- /dev/null +++ b/server/crates/text/src/lib.rs @@ -0,0 +1,179 @@ +use anyhow::{ bail, Context, Result }; +use lsp_types as lsp; +use std::collections::HashMap; +use tree_sitter::{ Parser, Tree }; + +#[derive(Default)] +pub struct DocumentStore { + docs: HashMap, +} + +impl DocumentStore { + pub fn open(&mut self, item: lsp::TextDocumentItem) -> Result<()> { + let uri = item.uri.clone(); + let doc = Document::open(item.text)?; + self.docs.insert(uri, doc); + Ok(()) + } + + pub fn apply_full_change( + &mut self, + uri: &lsp::Uri, + changes: &[lsp::TextDocumentContentChangeEvent] + ) -> Result<()> { + let Some(doc) = self.docs.get_mut(uri) else { + bail!("no such document: {:?}", uri); + }; + // FULL sync: assume single change with whole text + let new_text = changes.last().context("empty changes for full sync")?.text.clone(); + doc.reparse(&new_text)?; + Ok(()) + } + + pub fn close(&mut self, uri: &lsp::Uri) { + self.docs.remove(uri); + } + + pub fn get(&self, uri: &lsp::Uri) -> Option<&Document> { + self.docs.get(uri) + } +} + +pub struct Document { + text: String, + parser: Parser, + tree: Option, +} + +impl Document { + pub fn open(text: String) -> Result { + let mut parser = Parser::new(); + parser.set_language(&tree_sitter_tcl::LANGUAGE.into()).context("load tcl grammar")?; + let tree = parser.parse(&text, None); + Ok(Self { text, parser, tree }) + } + + pub fn reparse(&mut self, new_text: &str) -> Result<()> { + self.text.clear(); + self.text.push_str(new_text); + self.tree = self.parser.parse(&self.text, None); + Ok(()) + } + + pub fn text(&self) -> String { + self.text.clone() + } + + pub fn tree(&self) -> Option<&Tree> { + self.tree.as_ref() + } + + /// Convert a byte range (UTF-8) into an LSP Range (UTF-16 columns). + pub fn byte_range_to_lsp_range(&self, start: usize, end: usize) -> lsp::Range { + fn byte_to_line_col_utf16(s: &str, byte: usize) -> (u32, u32) { + let clamped = byte.min(s.len()); + let slice = &s[..clamped]; + let mut line = 0u32; + let mut col_u16 = 0u32; + let mut last_nl = 0usize; + + for (i, b) in slice.bytes().enumerate() { + if b == b'\n' { + line += 1; + last_nl = i + 1; + } + } + // compute utf16 col from last newline to clamped + let seg = &slice[last_nl..]; + col_u16 = seg.encode_utf16().count() as u32; + (line, col_u16) + } + + let (sl, sc) = byte_to_line_col_utf16(&self.text, start); + let (el, ec) = byte_to_line_col_utf16(&self.text, end); + lsp::Range { + start: lsp::Position { + line: sl, + character: sc, + }, + end: lsp::Position { + line: el, + character: ec, + }, + } + } + + /// Get the UTF-8 byte offset of the "word" under a UTF-16 position (very naive). + pub fn word_under_position( + &self, + pos: lsp::Position + ) -> Option<(String, std::ops::Range)> { + // Convert UTF-16 (LSP) position -> UTF-8 byte offset in self.text + fn line_col_utf16_to_byte(s: &str, line: u32, col_u16: u32) -> usize { + // Find start byte of the requested line + let mut cur_line: u32 = 0; + let mut line_start_byte: usize = 0; + + if line == 0 { + line_start_byte = 0; + } else { + for (i, b) in s.bytes().enumerate() { + if b == b'\n' { + cur_line += 1; + if cur_line == line { + line_start_byte = i + 1; + break; + } + } + } + // If line beyond EOF, clamp to end + if cur_line < line { + return s.len(); + } + } + + // Advance by UTF-16 code units from line_start_byte + let mut remaining = col_u16 as isize; + let tail = &s[line_start_byte..]; + for (off, ch) in tail.char_indices() { + if remaining <= 0 { + return line_start_byte + off; + } + // subtract the number of UTF-16 code units this char occupies (1 for BMP, 2 for surrogates) + let mut buf = [0u16; 2]; + remaining -= ch.encode_utf16(&mut buf).len() as isize; + } + // If column beyond EOL, clamp to end + s.len() + } + + let bytes = self.text.as_bytes(); + let byte = line_col_utf16_to_byte(&self.text, pos.line, pos.character); + if byte > self.text.len() { + return None; + } + + // Expand to simple Tcl-ish identifier characters: letters/digits/_ : / . - + fn is_ident(c: u8) -> bool { + c.is_ascii_alphanumeric() || matches!(c, b'_' | b':' | b'/' | b'.' | b'-') + } + + // Walk backward to start + let mut start = byte; + while start > 0 && is_ident(bytes[start - 1]) { + start -= 1; + } + // Walk forward to end + let mut end = byte; + while end < bytes.len() && is_ident(bytes[end]) { + end += 1; + } + + if start >= end { + return None; + } + + let text = self.text[start..end].to_string(); + Some((text, start..end)) // <-- no semicolon here, this is the tail expression + } +} diff --git a/server/libs/attr/__init__.py b/server/libs/attr/__init__.py deleted file mode 100644 index 5c6e065..0000000 --- a/server/libs/attr/__init__.py +++ /dev/null @@ -1,104 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Classes Without Boilerplate -""" - -from functools import partial -from typing import Callable, Literal, Protocol - -from . import converters, exceptions, filters, setters, validators -from ._cmp import cmp_using -from ._config import get_run_validators, set_run_validators -from ._funcs import asdict, assoc, astuple, has, resolve_types -from ._make import ( - NOTHING, - Attribute, - Converter, - Factory, - _Nothing, - attrib, - attrs, - evolve, - fields, - fields_dict, - make_class, - validate, -) -from ._next_gen import define, field, frozen, mutable -from ._version_info import VersionInfo - - -s = attributes = attrs -ib = attr = attrib -dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) - - -class AttrsInstance(Protocol): - pass - - -NothingType = Literal[_Nothing.NOTHING] - -__all__ = [ - "NOTHING", - "Attribute", - "AttrsInstance", - "Converter", - "Factory", - "NothingType", - "asdict", - "assoc", - "astuple", - "attr", - "attrib", - "attributes", - "attrs", - "cmp_using", - "converters", - "define", - "evolve", - "exceptions", - "field", - "fields", - "fields_dict", - "filters", - "frozen", - "get_run_validators", - "has", - "ib", - "make_class", - "mutable", - "resolve_types", - "s", - "set_run_validators", - "setters", - "validate", - "validators", -] - - -def _make_getattr(mod_name: str) -> Callable: - """ - Create a metadata proxy for packaging information that uses *mod_name* in - its warnings and errors. - """ - - def __getattr__(name: str) -> str: - if name not in ("__version__", "__version_info__"): - msg = f"module {mod_name} has no attribute {name}" - raise AttributeError(msg) - - from importlib.metadata import metadata - - meta = metadata("attrs") - - if name == "__version_info__": - return VersionInfo._from_version_string(meta["version"]) - - return meta["version"] - - return __getattr__ - - -__getattr__ = _make_getattr(__name__) diff --git a/server/libs/attr/__init__.pyi b/server/libs/attr/__init__.pyi deleted file mode 100644 index 133e501..0000000 --- a/server/libs/attr/__init__.pyi +++ /dev/null @@ -1,389 +0,0 @@ -import enum -import sys - -from typing import ( - Any, - Callable, - Generic, - Literal, - Mapping, - Protocol, - Sequence, - TypeVar, - overload, -) - -# `import X as X` is required to make these public -from . import converters as converters -from . import exceptions as exceptions -from . import filters as filters -from . import setters as setters -from . import validators as validators -from ._cmp import cmp_using as cmp_using -from ._typing_compat import AttrsInstance_ -from ._version_info import VersionInfo -from attrs import ( - define as define, - field as field, - mutable as mutable, - frozen as frozen, - _EqOrderType, - _ValidatorType, - _ConverterType, - _ReprArgType, - _OnSetAttrType, - _OnSetAttrArgType, - _FieldTransformer, - _ValidatorArgType, -) - -if sys.version_info >= (3, 10): - from typing import TypeGuard, TypeAlias -else: - from typing_extensions import TypeGuard, TypeAlias - -if sys.version_info >= (3, 11): - from typing import dataclass_transform -else: - from typing_extensions import dataclass_transform - -__version__: str -__version_info__: VersionInfo -__title__: str -__description__: str -__url__: str -__uri__: str -__author__: str -__email__: str -__license__: str -__copyright__: str - -_T = TypeVar("_T") -_C = TypeVar("_C", bound=type) - -_FilterType = Callable[["Attribute[_T]", _T], bool] - -# We subclass this here to keep the protocol's qualified name clean. -class AttrsInstance(AttrsInstance_, Protocol): - pass - -_A = TypeVar("_A", bound=type[AttrsInstance]) - -class _Nothing(enum.Enum): - NOTHING = enum.auto() - -NOTHING = _Nothing.NOTHING -NothingType: TypeAlias = Literal[_Nothing.NOTHING] - -# NOTE: Factory lies about its return type to make this possible: -# `x: List[int] # = Factory(list)` -# Work around mypy issue #4554 in the common case by using an overload. - -@overload -def Factory(factory: Callable[[], _T]) -> _T: ... -@overload -def Factory( - factory: Callable[[Any], _T], - takes_self: Literal[True], -) -> _T: ... -@overload -def Factory( - factory: Callable[[], _T], - takes_self: Literal[False], -) -> _T: ... - -In = TypeVar("In") -Out = TypeVar("Out") - -class Converter(Generic[In, Out]): - @overload - def __init__(self, converter: Callable[[In], Out]) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, AttrsInstance, Attribute], Out], - *, - takes_self: Literal[True], - takes_field: Literal[True], - ) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, Attribute], Out], - *, - takes_field: Literal[True], - ) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, AttrsInstance], Out], - *, - takes_self: Literal[True], - ) -> None: ... - -class Attribute(Generic[_T]): - name: str - default: _T | None - validator: _ValidatorType[_T] | None - repr: _ReprArgType - cmp: _EqOrderType - eq: _EqOrderType - order: _EqOrderType - hash: bool | None - init: bool - converter: Converter | None - metadata: dict[Any, Any] - type: type[_T] | None - kw_only: bool - on_setattr: _OnSetAttrType - alias: str | None - - def evolve(self, **changes: Any) -> "Attribute[Any]": ... - -# NOTE: We had several choices for the annotation to use for type arg: -# 1) Type[_T] -# - Pros: Handles simple cases correctly -# - Cons: Might produce less informative errors in the case of conflicting -# TypeVars e.g. `attr.ib(default='bad', type=int)` -# 2) Callable[..., _T] -# - Pros: Better error messages than #1 for conflicting TypeVars -# - Cons: Terrible error messages for validator checks. -# e.g. attr.ib(type=int, validator=validate_str) -# -> error: Cannot infer function type argument -# 3) type (and do all of the work in the mypy plugin) -# - Pros: Simple here, and we could customize the plugin with our own errors. -# - Cons: Would need to write mypy plugin code to handle all the cases. -# We chose option #1. - -# `attr` lies about its return type to make the following possible: -# attr() -> Any -# attr(8) -> int -# attr(validator=) -> Whatever the callable expects. -# This makes this type of assignments possible: -# x: int = attr(8) -# -# This form catches explicit None or no default but with no other arguments -# returns Any. -@overload -def attrib( - default: None = ..., - validator: None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: None = ..., - converter: None = ..., - factory: None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> Any: ... - -# This form catches an explicit None or no default and infers the type from the -# other arguments. -@overload -def attrib( - default: None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: type[_T] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> _T: ... - -# This form catches an explicit default argument. -@overload -def attrib( - default: _T, - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: type[_T] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> _T: ... - -# This form covers type=non-Type: e.g. forward references (str), Any -@overload -def attrib( - default: _T | None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: object = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> Any: ... -@overload -@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) -def attrs( - maybe_cls: _C, - these: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - auto_detect: bool = ..., - collect_by_mro: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., - unsafe_hash: bool | None = ..., -) -> _C: ... -@overload -@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) -def attrs( - maybe_cls: None = ..., - these: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - auto_detect: bool = ..., - collect_by_mro: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., - unsafe_hash: bool | None = ..., -) -> Callable[[_C], _C]: ... -def fields(cls: type[AttrsInstance]) -> Any: ... -def fields_dict(cls: type[AttrsInstance]) -> dict[str, Attribute[Any]]: ... -def validate(inst: AttrsInstance) -> None: ... -def resolve_types( - cls: _A, - globalns: dict[str, Any] | None = ..., - localns: dict[str, Any] | None = ..., - attribs: list[Attribute[Any]] | None = ..., - include_extras: bool = ..., -) -> _A: ... - -# TODO: add support for returning a proper attrs class from the mypy plugin -# we use Any instead of _CountingAttr so that e.g. `make_class('Foo', -# [attr.ib()])` is valid -def make_class( - name: str, - attrs: list[str] | tuple[str, ...] | dict[str, Any], - bases: tuple[type, ...] = ..., - class_body: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - collect_by_mro: bool = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., -) -> type: ... - -# _funcs -- - -# TODO: add support for returning TypedDict from the mypy plugin -# FIXME: asdict/astuple do not honor their factory args. Waiting on one of -# these: -# https://github.com/python/mypy/issues/4236 -# https://github.com/python/typing/issues/253 -# XXX: remember to fix attrs.asdict/astuple too! -def asdict( - inst: AttrsInstance, - recurse: bool = ..., - filter: _FilterType[Any] | None = ..., - dict_factory: type[Mapping[Any, Any]] = ..., - retain_collection_types: bool = ..., - value_serializer: Callable[[type, Attribute[Any], Any], Any] | None = ..., - tuple_keys: bool | None = ..., -) -> dict[str, Any]: ... - -# TODO: add support for returning NamedTuple from the mypy plugin -def astuple( - inst: AttrsInstance, - recurse: bool = ..., - filter: _FilterType[Any] | None = ..., - tuple_factory: type[Sequence[Any]] = ..., - retain_collection_types: bool = ..., -) -> tuple[Any, ...]: ... -def has(cls: type) -> TypeGuard[type[AttrsInstance]]: ... -def assoc(inst: _T, **changes: Any) -> _T: ... -def evolve(inst: _T, **changes: Any) -> _T: ... - -# _config -- - -def set_run_validators(run: bool) -> None: ... -def get_run_validators() -> bool: ... - -# aliases -- - -s = attributes = attrs -ib = attr = attrib -dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;) diff --git a/server/libs/attr/_cmp.py b/server/libs/attr/_cmp.py deleted file mode 100644 index 09bab49..0000000 --- a/server/libs/attr/_cmp.py +++ /dev/null @@ -1,160 +0,0 @@ -# SPDX-License-Identifier: MIT - - -import functools -import types - -from ._make import __ne__ - - -_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="} - - -def cmp_using( - eq=None, - lt=None, - le=None, - gt=None, - ge=None, - require_same_type=True, - class_name="Comparable", -): - """ - Create a class that can be passed into `attrs.field`'s ``eq``, ``order``, - and ``cmp`` arguments to customize field comparison. - - The resulting class will have a full set of ordering methods if at least - one of ``{lt, le, gt, ge}`` and ``eq`` are provided. - - Args: - eq (typing.Callable | None): - Callable used to evaluate equality of two objects. - - lt (typing.Callable | None): - Callable used to evaluate whether one object is less than another - object. - - le (typing.Callable | None): - Callable used to evaluate whether one object is less than or equal - to another object. - - gt (typing.Callable | None): - Callable used to evaluate whether one object is greater than - another object. - - ge (typing.Callable | None): - Callable used to evaluate whether one object is greater than or - equal to another object. - - require_same_type (bool): - When `True`, equality and ordering methods will return - `NotImplemented` if objects are not of the same type. - - class_name (str | None): Name of class. Defaults to "Comparable". - - See `comparison` for more details. - - .. versionadded:: 21.1.0 - """ - - body = { - "__slots__": ["value"], - "__init__": _make_init(), - "_requirements": [], - "_is_comparable_to": _is_comparable_to, - } - - # Add operations. - num_order_functions = 0 - has_eq_function = False - - if eq is not None: - has_eq_function = True - body["__eq__"] = _make_operator("eq", eq) - body["__ne__"] = __ne__ - - if lt is not None: - num_order_functions += 1 - body["__lt__"] = _make_operator("lt", lt) - - if le is not None: - num_order_functions += 1 - body["__le__"] = _make_operator("le", le) - - if gt is not None: - num_order_functions += 1 - body["__gt__"] = _make_operator("gt", gt) - - if ge is not None: - num_order_functions += 1 - body["__ge__"] = _make_operator("ge", ge) - - type_ = types.new_class( - class_name, (object,), {}, lambda ns: ns.update(body) - ) - - # Add same type requirement. - if require_same_type: - type_._requirements.append(_check_same_type) - - # Add total ordering if at least one operation was defined. - if 0 < num_order_functions < 4: - if not has_eq_function: - # functools.total_ordering requires __eq__ to be defined, - # so raise early error here to keep a nice stack. - msg = "eq must be define is order to complete ordering from lt, le, gt, ge." - raise ValueError(msg) - type_ = functools.total_ordering(type_) - - return type_ - - -def _make_init(): - """ - Create __init__ method. - """ - - def __init__(self, value): - """ - Initialize object with *value*. - """ - self.value = value - - return __init__ - - -def _make_operator(name, func): - """ - Create operator method. - """ - - def method(self, other): - if not self._is_comparable_to(other): - return NotImplemented - - result = func(self.value, other.value) - if result is NotImplemented: - return NotImplemented - - return result - - method.__name__ = f"__{name}__" - method.__doc__ = ( - f"Return a {_operation_names[name]} b. Computed by attrs." - ) - - return method - - -def _is_comparable_to(self, other): - """ - Check whether `other` is comparable to `self`. - """ - return all(func(self, other) for func in self._requirements) - - -def _check_same_type(self, other): - """ - Return True if *self* and *other* are of the same type, False otherwise. - """ - return other.value.__class__ is self.value.__class__ diff --git a/server/libs/attr/_cmp.pyi b/server/libs/attr/_cmp.pyi deleted file mode 100644 index cc7893b..0000000 --- a/server/libs/attr/_cmp.pyi +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Any, Callable - -_CompareWithType = Callable[[Any, Any], bool] - -def cmp_using( - eq: _CompareWithType | None = ..., - lt: _CompareWithType | None = ..., - le: _CompareWithType | None = ..., - gt: _CompareWithType | None = ..., - ge: _CompareWithType | None = ..., - require_same_type: bool = ..., - class_name: str = ..., -) -> type: ... diff --git a/server/libs/attr/_compat.py b/server/libs/attr/_compat.py deleted file mode 100644 index 22fcd78..0000000 --- a/server/libs/attr/_compat.py +++ /dev/null @@ -1,94 +0,0 @@ -# SPDX-License-Identifier: MIT - -import inspect -import platform -import sys -import threading - -from collections.abc import Mapping, Sequence # noqa: F401 -from typing import _GenericAlias - - -PYPY = platform.python_implementation() == "PyPy" -PY_3_9_PLUS = sys.version_info[:2] >= (3, 9) -PY_3_10_PLUS = sys.version_info[:2] >= (3, 10) -PY_3_11_PLUS = sys.version_info[:2] >= (3, 11) -PY_3_12_PLUS = sys.version_info[:2] >= (3, 12) -PY_3_13_PLUS = sys.version_info[:2] >= (3, 13) -PY_3_14_PLUS = sys.version_info[:2] >= (3, 14) - - -if PY_3_14_PLUS: # pragma: no cover - import annotationlib - - _get_annotations = annotationlib.get_annotations - -else: - - def _get_annotations(cls): - """ - Get annotations for *cls*. - """ - return cls.__dict__.get("__annotations__", {}) - - -class _AnnotationExtractor: - """ - Extract type annotations from a callable, returning None whenever there - is none. - """ - - __slots__ = ["sig"] - - def __init__(self, callable): - try: - self.sig = inspect.signature(callable) - except (ValueError, TypeError): # inspect failed - self.sig = None - - def get_first_param_type(self): - """ - Return the type annotation of the first argument if it's not empty. - """ - if not self.sig: - return None - - params = list(self.sig.parameters.values()) - if params and params[0].annotation is not inspect.Parameter.empty: - return params[0].annotation - - return None - - def get_return_type(self): - """ - Return the return type if it's not empty. - """ - if ( - self.sig - and self.sig.return_annotation is not inspect.Signature.empty - ): - return self.sig.return_annotation - - return None - - -# Thread-local global to track attrs instances which are already being repr'd. -# This is needed because there is no other (thread-safe) way to pass info -# about the instances that are already being repr'd through the call stack -# in order to ensure we don't perform infinite recursion. -# -# For instance, if an instance contains a dict which contains that instance, -# we need to know that we're already repr'ing the outside instance from within -# the dict's repr() call. -# -# This lives here rather than in _make.py so that the functions in _make.py -# don't have a direct reference to the thread-local in their globals dict. -# If they have such a reference, it breaks cloudpickle. -repr_context = threading.local() - - -def get_generic_base(cl): - """If this is a generic class (A[str]), return the generic base for it.""" - if cl.__class__ is _GenericAlias: - return cl.__origin__ - return None diff --git a/server/libs/attr/_config.py b/server/libs/attr/_config.py deleted file mode 100644 index 4b25772..0000000 --- a/server/libs/attr/_config.py +++ /dev/null @@ -1,31 +0,0 @@ -# SPDX-License-Identifier: MIT - -__all__ = ["get_run_validators", "set_run_validators"] - -_run_validators = True - - -def set_run_validators(run): - """ - Set whether or not validators are run. By default, they are run. - - .. deprecated:: 21.3.0 It will not be removed, but it also will not be - moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()` - instead. - """ - if not isinstance(run, bool): - msg = "'run' must be bool." - raise TypeError(msg) - global _run_validators - _run_validators = run - - -def get_run_validators(): - """ - Return whether or not validators are run. - - .. deprecated:: 21.3.0 It will not be removed, but it also will not be - moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()` - instead. - """ - return _run_validators diff --git a/server/libs/attr/_funcs.py b/server/libs/attr/_funcs.py deleted file mode 100644 index c39fb8a..0000000 --- a/server/libs/attr/_funcs.py +++ /dev/null @@ -1,468 +0,0 @@ -# SPDX-License-Identifier: MIT - - -import copy - -from ._compat import PY_3_9_PLUS, get_generic_base -from ._make import _OBJ_SETATTR, NOTHING, fields -from .exceptions import AttrsAttributeNotFoundError - - -def asdict( - inst, - recurse=True, - filter=None, - dict_factory=dict, - retain_collection_types=False, - value_serializer=None, -): - """ - Return the *attrs* attribute values of *inst* as a dict. - - Optionally recurse into other *attrs*-decorated classes. - - Args: - inst: Instance of an *attrs*-decorated class. - - recurse (bool): Recurse into classes that are also *attrs*-decorated. - - filter (~typing.Callable): - A callable whose return code determines whether an attribute or - element is included (`True`) or dropped (`False`). Is called with - the `attrs.Attribute` as the first argument and the value as the - second argument. - - dict_factory (~typing.Callable): - A callable to produce dictionaries from. For example, to produce - ordered dictionaries instead of normal Python dictionaries, pass in - ``collections.OrderedDict``. - - retain_collection_types (bool): - Do not convert to `list` when encountering an attribute whose type - is `tuple` or `set`. Only meaningful if *recurse* is `True`. - - value_serializer (typing.Callable | None): - A hook that is called for every attribute or dict key/value. It - receives the current instance, field and value and must return the - (updated) value. The hook is run *after* the optional *filter* has - been applied. - - Returns: - Return type of *dict_factory*. - - Raises: - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 16.0.0 *dict_factory* - .. versionadded:: 16.1.0 *retain_collection_types* - .. versionadded:: 20.3.0 *value_serializer* - .. versionadded:: 21.3.0 - If a dict has a collection for a key, it is serialized as a tuple. - """ - attrs = fields(inst.__class__) - rv = dict_factory() - for a in attrs: - v = getattr(inst, a.name) - if filter is not None and not filter(a, v): - continue - - if value_serializer is not None: - v = value_serializer(inst, a, v) - - if recurse is True: - if has(v.__class__): - rv[a.name] = asdict( - v, - recurse=True, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - elif isinstance(v, (tuple, list, set, frozenset)): - cf = v.__class__ if retain_collection_types is True else list - items = [ - _asdict_anything( - i, - is_key=False, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - for i in v - ] - try: - rv[a.name] = cf(items) - except TypeError: - if not issubclass(cf, tuple): - raise - # Workaround for TypeError: cf.__new__() missing 1 required - # positional argument (which appears, for a namedturle) - rv[a.name] = cf(*items) - elif isinstance(v, dict): - df = dict_factory - rv[a.name] = df( - ( - _asdict_anything( - kk, - is_key=True, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - _asdict_anything( - vv, - is_key=False, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - ) - for kk, vv in v.items() - ) - else: - rv[a.name] = v - else: - rv[a.name] = v - return rv - - -def _asdict_anything( - val, - is_key, - filter, - dict_factory, - retain_collection_types, - value_serializer, -): - """ - ``asdict`` only works on attrs instances, this works on anything. - """ - if getattr(val.__class__, "__attrs_attrs__", None) is not None: - # Attrs class. - rv = asdict( - val, - recurse=True, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - elif isinstance(val, (tuple, list, set, frozenset)): - if retain_collection_types is True: - cf = val.__class__ - elif is_key: - cf = tuple - else: - cf = list - - rv = cf( - [ - _asdict_anything( - i, - is_key=False, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - for i in val - ] - ) - elif isinstance(val, dict): - df = dict_factory - rv = df( - ( - _asdict_anything( - kk, - is_key=True, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - _asdict_anything( - vv, - is_key=False, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - ) - for kk, vv in val.items() - ) - else: - rv = val - if value_serializer is not None: - rv = value_serializer(None, None, rv) - - return rv - - -def astuple( - inst, - recurse=True, - filter=None, - tuple_factory=tuple, - retain_collection_types=False, -): - """ - Return the *attrs* attribute values of *inst* as a tuple. - - Optionally recurse into other *attrs*-decorated classes. - - Args: - inst: Instance of an *attrs*-decorated class. - - recurse (bool): - Recurse into classes that are also *attrs*-decorated. - - filter (~typing.Callable): - A callable whose return code determines whether an attribute or - element is included (`True`) or dropped (`False`). Is called with - the `attrs.Attribute` as the first argument and the value as the - second argument. - - tuple_factory (~typing.Callable): - A callable to produce tuples from. For example, to produce lists - instead of tuples. - - retain_collection_types (bool): - Do not convert to `list` or `dict` when encountering an attribute - which type is `tuple`, `dict` or `set`. Only meaningful if - *recurse* is `True`. - - Returns: - Return type of *tuple_factory* - - Raises: - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 16.2.0 - """ - attrs = fields(inst.__class__) - rv = [] - retain = retain_collection_types # Very long. :/ - for a in attrs: - v = getattr(inst, a.name) - if filter is not None and not filter(a, v): - continue - if recurse is True: - if has(v.__class__): - rv.append( - astuple( - v, - recurse=True, - filter=filter, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - ) - elif isinstance(v, (tuple, list, set, frozenset)): - cf = v.__class__ if retain is True else list - items = [ - ( - astuple( - j, - recurse=True, - filter=filter, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(j.__class__) - else j - ) - for j in v - ] - try: - rv.append(cf(items)) - except TypeError: - if not issubclass(cf, tuple): - raise - # Workaround for TypeError: cf.__new__() missing 1 required - # positional argument (which appears, for a namedturle) - rv.append(cf(*items)) - elif isinstance(v, dict): - df = v.__class__ if retain is True else dict - rv.append( - df( - ( - ( - astuple( - kk, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(kk.__class__) - else kk - ), - ( - astuple( - vv, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(vv.__class__) - else vv - ), - ) - for kk, vv in v.items() - ) - ) - else: - rv.append(v) - else: - rv.append(v) - - return rv if tuple_factory is list else tuple_factory(rv) - - -def has(cls): - """ - Check whether *cls* is a class with *attrs* attributes. - - Args: - cls (type): Class to introspect. - - Raises: - TypeError: If *cls* is not a class. - - Returns: - bool: - """ - attrs = getattr(cls, "__attrs_attrs__", None) - if attrs is not None: - return True - - # No attrs, maybe it's a specialized generic (A[str])? - generic_base = get_generic_base(cls) - if generic_base is not None: - generic_attrs = getattr(generic_base, "__attrs_attrs__", None) - if generic_attrs is not None: - # Stick it on here for speed next time. - cls.__attrs_attrs__ = generic_attrs - return generic_attrs is not None - return False - - -def assoc(inst, **changes): - """ - Copy *inst* and apply *changes*. - - This is different from `evolve` that applies the changes to the arguments - that create the new instance. - - `evolve`'s behavior is preferable, but there are `edge cases`_ where it - doesn't work. Therefore `assoc` is deprecated, but will not be removed. - - .. _`edge cases`: https://github.com/python-attrs/attrs/issues/251 - - Args: - inst: Instance of a class with *attrs* attributes. - - changes: Keyword changes in the new copy. - - Returns: - A copy of inst with *changes* incorporated. - - Raises: - attrs.exceptions.AttrsAttributeNotFoundError: - If *attr_name* couldn't be found on *cls*. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. deprecated:: 17.1.0 - Use `attrs.evolve` instead if you can. This function will not be - removed du to the slightly different approach compared to - `attrs.evolve`, though. - """ - new = copy.copy(inst) - attrs = fields(inst.__class__) - for k, v in changes.items(): - a = getattr(attrs, k, NOTHING) - if a is NOTHING: - msg = f"{k} is not an attrs attribute on {new.__class__}." - raise AttrsAttributeNotFoundError(msg) - _OBJ_SETATTR(new, k, v) - return new - - -def resolve_types( - cls, globalns=None, localns=None, attribs=None, include_extras=True -): - """ - Resolve any strings and forward annotations in type annotations. - - This is only required if you need concrete types in :class:`Attribute`'s - *type* field. In other words, you don't need to resolve your types if you - only use them for static type checking. - - With no arguments, names will be looked up in the module in which the class - was created. If this is not what you want, for example, if the name only - exists inside a method, you may pass *globalns* or *localns* to specify - other dictionaries in which to look up these names. See the docs of - `typing.get_type_hints` for more details. - - Args: - cls (type): Class to resolve. - - globalns (dict | None): Dictionary containing global variables. - - localns (dict | None): Dictionary containing local variables. - - attribs (list | None): - List of attribs for the given class. This is necessary when calling - from inside a ``field_transformer`` since *cls* is not an *attrs* - class yet. - - include_extras (bool): - Resolve more accurately, if possible. Pass ``include_extras`` to - ``typing.get_hints``, if supported by the typing module. On - supported Python versions (3.9+), this resolves the types more - accurately. - - Raises: - TypeError: If *cls* is not a class. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class and you didn't pass any attribs. - - NameError: If types cannot be resolved because of missing variables. - - Returns: - *cls* so you can use this function also as a class decorator. Please - note that you have to apply it **after** `attrs.define`. That means the - decorator has to come in the line **before** `attrs.define`. - - .. versionadded:: 20.1.0 - .. versionadded:: 21.1.0 *attribs* - .. versionadded:: 23.1.0 *include_extras* - """ - # Since calling get_type_hints is expensive we cache whether we've - # done it already. - if getattr(cls, "__attrs_types_resolved__", None) != cls: - import typing - - kwargs = {"globalns": globalns, "localns": localns} - - if PY_3_9_PLUS: - kwargs["include_extras"] = include_extras - - hints = typing.get_type_hints(cls, **kwargs) - for field in fields(cls) if attribs is None else attribs: - if field.name in hints: - # Since fields have been frozen we must work around it. - _OBJ_SETATTR(field, "type", hints[field.name]) - # We store the class we resolved so that subclasses know they haven't - # been resolved. - cls.__attrs_types_resolved__ = cls - - # Return the class so you can use it as a decorator too. - return cls diff --git a/server/libs/attr/_make.py b/server/libs/attr/_make.py deleted file mode 100644 index e84d979..0000000 --- a/server/libs/attr/_make.py +++ /dev/null @@ -1,3123 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - -import abc -import contextlib -import copy -import enum -import inspect -import itertools -import linecache -import sys -import types -import unicodedata - -from collections.abc import Callable, Mapping -from functools import cached_property -from typing import Any, NamedTuple, TypeVar - -# We need to import _compat itself in addition to the _compat members to avoid -# having the thread-local in the globals here. -from . import _compat, _config, setters -from ._compat import ( - PY_3_10_PLUS, - PY_3_11_PLUS, - PY_3_13_PLUS, - _AnnotationExtractor, - _get_annotations, - get_generic_base, -) -from .exceptions import ( - DefaultAlreadySetError, - FrozenInstanceError, - NotAnAttrsClassError, - UnannotatedAttributeError, -) - - -# This is used at least twice, so cache it here. -_OBJ_SETATTR = object.__setattr__ -_INIT_FACTORY_PAT = "__attr_factory_%s" -_CLASSVAR_PREFIXES = ( - "typing.ClassVar", - "t.ClassVar", - "ClassVar", - "typing_extensions.ClassVar", -) -# we don't use a double-underscore prefix because that triggers -# name mangling when trying to create a slot for the field -# (when slots=True) -_HASH_CACHE_FIELD = "_attrs_cached_hash" - -_EMPTY_METADATA_SINGLETON = types.MappingProxyType({}) - -# Unique object for unequivocal getattr() defaults. -_SENTINEL = object() - -_DEFAULT_ON_SETATTR = setters.pipe(setters.convert, setters.validate) - - -class _Nothing(enum.Enum): - """ - Sentinel to indicate the lack of a value when `None` is ambiguous. - - If extending attrs, you can use ``typing.Literal[NOTHING]`` to show - that a value may be ``NOTHING``. - - .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False. - .. versionchanged:: 22.2.0 ``NOTHING`` is now an ``enum.Enum`` variant. - """ - - NOTHING = enum.auto() - - def __repr__(self): - return "NOTHING" - - def __bool__(self): - return False - - -NOTHING = _Nothing.NOTHING -""" -Sentinel to indicate the lack of a value when `None` is ambiguous. - -When using in 3rd party code, use `attrs.NothingType` for type annotations. -""" - - -class _CacheHashWrapper(int): - """ - An integer subclass that pickles / copies as None - - This is used for non-slots classes with ``cache_hash=True``, to avoid - serializing a potentially (even likely) invalid hash value. Since `None` - is the default value for uncalculated hashes, whenever this is copied, - the copy's value for the hash should automatically reset. - - See GH #613 for more details. - """ - - def __reduce__(self, _none_constructor=type(None), _args=()): # noqa: B008 - return _none_constructor, _args - - -def attrib( - default=NOTHING, - validator=None, - repr=True, - cmp=None, - hash=None, - init=True, - metadata=None, - type=None, - converter=None, - factory=None, - kw_only=False, - eq=None, - order=None, - on_setattr=None, - alias=None, -): - """ - Create a new field / attribute on a class. - - Identical to `attrs.field`, except it's not keyword-only. - - Consider using `attrs.field` in new code (``attr.ib`` will *never* go away, - though). - - .. warning:: - - Does **nothing** unless the class is also decorated with - `attr.s` (or similar)! - - - .. versionadded:: 15.2.0 *convert* - .. versionadded:: 16.3.0 *metadata* - .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. - .. versionchanged:: 17.1.0 - *hash* is `None` and therefore mirrors *eq* by default. - .. versionadded:: 17.3.0 *type* - .. deprecated:: 17.4.0 *convert* - .. versionadded:: 17.4.0 - *converter* as a replacement for the deprecated *convert* to achieve - consistency with other noun-based arguments. - .. versionadded:: 18.1.0 - ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. - .. versionadded:: 18.2.0 *kw_only* - .. versionchanged:: 19.2.0 *convert* keyword argument removed. - .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. - .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. - .. versionadded:: 19.2.0 *eq* and *order* - .. versionadded:: 20.1.0 *on_setattr* - .. versionchanged:: 20.3.0 *kw_only* backported to Python 2 - .. versionchanged:: 21.1.0 - *eq*, *order*, and *cmp* also accept a custom callable - .. versionchanged:: 21.1.0 *cmp* undeprecated - .. versionadded:: 22.2.0 *alias* - """ - eq, eq_key, order, order_key = _determine_attrib_eq_order( - cmp, eq, order, True - ) - - if hash is not None and hash is not True and hash is not False: - msg = "Invalid value for hash. Must be True, False, or None." - raise TypeError(msg) - - if factory is not None: - if default is not NOTHING: - msg = ( - "The `default` and `factory` arguments are mutually exclusive." - ) - raise ValueError(msg) - if not callable(factory): - msg = "The `factory` argument must be a callable." - raise ValueError(msg) - default = Factory(factory) - - if metadata is None: - metadata = {} - - # Apply syntactic sugar by auto-wrapping. - if isinstance(on_setattr, (list, tuple)): - on_setattr = setters.pipe(*on_setattr) - - if validator and isinstance(validator, (list, tuple)): - validator = and_(*validator) - - if converter and isinstance(converter, (list, tuple)): - converter = pipe(*converter) - - return _CountingAttr( - default=default, - validator=validator, - repr=repr, - cmp=None, - hash=hash, - init=init, - converter=converter, - metadata=metadata, - type=type, - kw_only=kw_only, - eq=eq, - eq_key=eq_key, - order=order, - order_key=order_key, - on_setattr=on_setattr, - alias=alias, - ) - - -def _compile_and_eval( - script: str, - globs: dict[str, Any] | None, - locs: Mapping[str, object] | None = None, - filename: str = "", -) -> None: - """ - Evaluate the script with the given global (globs) and local (locs) - variables. - """ - bytecode = compile(script, filename, "exec") - eval(bytecode, globs, locs) - - -def _linecache_and_compile( - script: str, - filename: str, - globs: dict[str, Any] | None, - locals: Mapping[str, object] | None = None, -) -> dict[str, Any]: - """ - Cache the script with _linecache_, compile it and return the _locals_. - """ - - locs = {} if locals is None else locals - - # In order of debuggers like PDB being able to step through the code, - # we add a fake linecache entry. - count = 1 - base_filename = filename - while True: - linecache_tuple = ( - len(script), - None, - script.splitlines(True), - filename, - ) - old_val = linecache.cache.setdefault(filename, linecache_tuple) - if old_val == linecache_tuple: - break - - filename = f"{base_filename[:-1]}-{count}>" - count += 1 - - _compile_and_eval(script, globs, locs, filename) - - return locs - - -def _make_attr_tuple_class(cls_name: str, attr_names: list[str]) -> type: - """ - Create a tuple subclass to hold `Attribute`s for an `attrs` class. - - The subclass is a bare tuple with properties for names. - - class MyClassAttributes(tuple): - __slots__ = () - x = property(itemgetter(0)) - """ - attr_class_name = f"{cls_name}Attributes" - body = {} - for i, attr_name in enumerate(attr_names): - - def getter(self, i=i): - return self[i] - - body[attr_name] = property(getter) - return type(attr_class_name, (tuple,), body) - - -# Tuple class for extracted attributes from a class definition. -# `base_attrs` is a subset of `attrs`. -class _Attributes(NamedTuple): - attrs: type - base_attrs: list[Attribute] - base_attrs_map: dict[str, type] - - -def _is_class_var(annot): - """ - Check whether *annot* is a typing.ClassVar. - - The string comparison hack is used to avoid evaluating all string - annotations which would put attrs-based classes at a performance - disadvantage compared to plain old classes. - """ - annot = str(annot) - - # Annotation can be quoted. - if annot.startswith(("'", '"')) and annot.endswith(("'", '"')): - annot = annot[1:-1] - - return annot.startswith(_CLASSVAR_PREFIXES) - - -def _has_own_attribute(cls, attrib_name): - """ - Check whether *cls* defines *attrib_name* (and doesn't just inherit it). - """ - return attrib_name in cls.__dict__ - - -def _collect_base_attrs( - cls, taken_attr_names -) -> tuple[list[Attribute], dict[str, type]]: - """ - Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. - """ - base_attrs = [] - base_attr_map = {} # A dictionary of base attrs to their classes. - - # Traverse the MRO and collect attributes. - for base_cls in reversed(cls.__mro__[1:-1]): - for a in getattr(base_cls, "__attrs_attrs__", []): - if a.inherited or a.name in taken_attr_names: - continue - - a = a.evolve(inherited=True) # noqa: PLW2901 - base_attrs.append(a) - base_attr_map[a.name] = base_cls - - # For each name, only keep the freshest definition i.e. the furthest at the - # back. base_attr_map is fine because it gets overwritten with every new - # instance. - filtered = [] - seen = set() - for a in reversed(base_attrs): - if a.name in seen: - continue - filtered.insert(0, a) - seen.add(a.name) - - return filtered, base_attr_map - - -def _collect_base_attrs_broken(cls, taken_attr_names): - """ - Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. - - N.B. *taken_attr_names* will be mutated. - - Adhere to the old incorrect behavior. - - Notably it collects from the front and considers inherited attributes which - leads to the buggy behavior reported in #428. - """ - base_attrs = [] - base_attr_map = {} # A dictionary of base attrs to their classes. - - # Traverse the MRO and collect attributes. - for base_cls in cls.__mro__[1:-1]: - for a in getattr(base_cls, "__attrs_attrs__", []): - if a.name in taken_attr_names: - continue - - a = a.evolve(inherited=True) # noqa: PLW2901 - taken_attr_names.add(a.name) - base_attrs.append(a) - base_attr_map[a.name] = base_cls - - return base_attrs, base_attr_map - - -def _transform_attrs( - cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer -) -> _Attributes: - """ - Transform all `_CountingAttr`s on a class into `Attribute`s. - - If *these* is passed, use that and don't look for them on the class. - - If *collect_by_mro* is True, collect them in the correct MRO order, - otherwise use the old -- incorrect -- order. See #428. - - Return an `_Attributes`. - """ - cd = cls.__dict__ - anns = _get_annotations(cls) - - if these is not None: - ca_list = list(these.items()) - elif auto_attribs is True: - ca_names = { - name - for name, attr in cd.items() - if attr.__class__ is _CountingAttr - } - ca_list = [] - annot_names = set() - for attr_name, type in anns.items(): - if _is_class_var(type): - continue - annot_names.add(attr_name) - a = cd.get(attr_name, NOTHING) - - if a.__class__ is not _CountingAttr: - a = attrib(a) - ca_list.append((attr_name, a)) - - unannotated = ca_names - annot_names - if unannotated: - raise UnannotatedAttributeError( - "The following `attr.ib`s lack a type annotation: " - + ", ".join( - sorted(unannotated, key=lambda n: cd.get(n).counter) - ) - + "." - ) - else: - ca_list = sorted( - ( - (name, attr) - for name, attr in cd.items() - if attr.__class__ is _CountingAttr - ), - key=lambda e: e[1].counter, - ) - - fca = Attribute.from_counting_attr - own_attrs = [ - fca(attr_name, ca, anns.get(attr_name)) for attr_name, ca in ca_list - ] - - if collect_by_mro: - base_attrs, base_attr_map = _collect_base_attrs( - cls, {a.name for a in own_attrs} - ) - else: - base_attrs, base_attr_map = _collect_base_attrs_broken( - cls, {a.name for a in own_attrs} - ) - - if kw_only: - own_attrs = [a.evolve(kw_only=True) for a in own_attrs] - base_attrs = [a.evolve(kw_only=True) for a in base_attrs] - - attrs = base_attrs + own_attrs - - if field_transformer is not None: - attrs = tuple(field_transformer(cls, attrs)) - - # Check attr order after executing the field_transformer. - # Mandatory vs non-mandatory attr order only matters when they are part of - # the __init__ signature and when they aren't kw_only (which are moved to - # the end and can be mandatory or non-mandatory in any order, as they will - # be specified as keyword args anyway). Check the order of those attrs: - had_default = False - for a in (a for a in attrs if a.init is not False and a.kw_only is False): - if had_default is True and a.default is NOTHING: - msg = f"No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: {a!r}" - raise ValueError(msg) - - if had_default is False and a.default is not NOTHING: - had_default = True - - # Resolve default field alias after executing field_transformer. - # This allows field_transformer to differentiate between explicit vs - # default aliases and supply their own defaults. - for a in attrs: - if not a.alias: - # Evolve is very slow, so we hold our nose and do it dirty. - _OBJ_SETATTR.__get__(a)("alias", _default_init_alias_for(a.name)) - - # Create AttrsClass *after* applying the field_transformer since it may - # add or remove attributes! - attr_names = [a.name for a in attrs] - AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) - - return _Attributes(AttrsClass(attrs), base_attrs, base_attr_map) - - -def _make_cached_property_getattr(cached_properties, original_getattr, cls): - lines = [ - # Wrapped to get `__class__` into closure cell for super() - # (It will be replaced with the newly constructed class after construction). - "def wrapper(_cls):", - " __class__ = _cls", - " def __getattr__(self, item, cached_properties=cached_properties, original_getattr=original_getattr, _cached_setattr_get=_cached_setattr_get):", - " func = cached_properties.get(item)", - " if func is not None:", - " result = func(self)", - " _setter = _cached_setattr_get(self)", - " _setter(item, result)", - " return result", - ] - if original_getattr is not None: - lines.append( - " return original_getattr(self, item)", - ) - else: - lines.extend( - [ - " try:", - " return super().__getattribute__(item)", - " except AttributeError:", - " if not hasattr(super(), '__getattr__'):", - " raise", - " return super().__getattr__(item)", - " original_error = f\"'{self.__class__.__name__}' object has no attribute '{item}'\"", - " raise AttributeError(original_error)", - ] - ) - - lines.extend( - [ - " return __getattr__", - "__getattr__ = wrapper(_cls)", - ] - ) - - unique_filename = _generate_unique_filename(cls, "getattr") - - glob = { - "cached_properties": cached_properties, - "_cached_setattr_get": _OBJ_SETATTR.__get__, - "original_getattr": original_getattr, - } - - return _linecache_and_compile( - "\n".join(lines), unique_filename, glob, locals={"_cls": cls} - )["__getattr__"] - - -def _frozen_setattrs(self, name, value): - """ - Attached to frozen classes as __setattr__. - """ - if isinstance(self, BaseException) and name in ( - "__cause__", - "__context__", - "__traceback__", - "__suppress_context__", - "__notes__", - ): - BaseException.__setattr__(self, name, value) - return - - raise FrozenInstanceError - - -def _frozen_delattrs(self, name): - """ - Attached to frozen classes as __delattr__. - """ - if isinstance(self, BaseException) and name in ("__notes__",): - BaseException.__delattr__(self, name) - return - - raise FrozenInstanceError - - -def evolve(*args, **changes): - """ - Create a new instance, based on the first positional argument with - *changes* applied. - - .. tip:: - - On Python 3.13 and later, you can also use `copy.replace` instead. - - Args: - - inst: - Instance of a class with *attrs* attributes. *inst* must be passed - as a positional argument. - - changes: - Keyword changes in the new copy. - - Returns: - A copy of inst with *changes* incorporated. - - Raises: - TypeError: - If *attr_name* couldn't be found in the class ``__init__``. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 17.1.0 - .. deprecated:: 23.1.0 - It is now deprecated to pass the instance using the keyword argument - *inst*. It will raise a warning until at least April 2024, after which - it will become an error. Always pass the instance as a positional - argument. - .. versionchanged:: 24.1.0 - *inst* can't be passed as a keyword argument anymore. - """ - try: - (inst,) = args - except ValueError: - msg = ( - f"evolve() takes 1 positional argument, but {len(args)} were given" - ) - raise TypeError(msg) from None - - cls = inst.__class__ - attrs = fields(cls) - for a in attrs: - if not a.init: - continue - attr_name = a.name # To deal with private attributes. - init_name = a.alias - if init_name not in changes: - changes[init_name] = getattr(inst, attr_name) - - return cls(**changes) - - -class _ClassBuilder: - """ - Iteratively build *one* class. - """ - - __slots__ = ( - "_add_method_dunders", - "_attr_names", - "_attrs", - "_base_attr_map", - "_base_names", - "_cache_hash", - "_cls", - "_cls_dict", - "_delete_attribs", - "_frozen", - "_has_custom_setattr", - "_has_post_init", - "_has_pre_init", - "_is_exc", - "_on_setattr", - "_pre_init_has_args", - "_repr_added", - "_script_snippets", - "_slots", - "_weakref_slot", - "_wrote_own_setattr", - ) - - def __init__( - self, - cls: type, - these, - slots, - frozen, - weakref_slot, - getstate_setstate, - auto_attribs, - kw_only, - cache_hash, - is_exc, - collect_by_mro, - on_setattr, - has_custom_setattr, - field_transformer, - ): - attrs, base_attrs, base_map = _transform_attrs( - cls, - these, - auto_attribs, - kw_only, - collect_by_mro, - field_transformer, - ) - - self._cls = cls - self._cls_dict = dict(cls.__dict__) if slots else {} - self._attrs = attrs - self._base_names = {a.name for a in base_attrs} - self._base_attr_map = base_map - self._attr_names = tuple(a.name for a in attrs) - self._slots = slots - self._frozen = frozen - self._weakref_slot = weakref_slot - self._cache_hash = cache_hash - self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False)) - self._pre_init_has_args = False - if self._has_pre_init: - # Check if the pre init method has more arguments than just `self` - # We want to pass arguments if pre init expects arguments - pre_init_func = cls.__attrs_pre_init__ - pre_init_signature = inspect.signature(pre_init_func) - self._pre_init_has_args = len(pre_init_signature.parameters) > 1 - self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) - self._delete_attribs = not bool(these) - self._is_exc = is_exc - self._on_setattr = on_setattr - - self._has_custom_setattr = has_custom_setattr - self._wrote_own_setattr = False - - self._cls_dict["__attrs_attrs__"] = self._attrs - - if frozen: - self._cls_dict["__setattr__"] = _frozen_setattrs - self._cls_dict["__delattr__"] = _frozen_delattrs - - self._wrote_own_setattr = True - elif on_setattr in ( - _DEFAULT_ON_SETATTR, - setters.validate, - setters.convert, - ): - has_validator = has_converter = False - for a in attrs: - if a.validator is not None: - has_validator = True - if a.converter is not None: - has_converter = True - - if has_validator and has_converter: - break - if ( - ( - on_setattr == _DEFAULT_ON_SETATTR - and not (has_validator or has_converter) - ) - or (on_setattr == setters.validate and not has_validator) - or (on_setattr == setters.convert and not has_converter) - ): - # If class-level on_setattr is set to convert + validate, but - # there's no field to convert or validate, pretend like there's - # no on_setattr. - self._on_setattr = None - - if getstate_setstate: - ( - self._cls_dict["__getstate__"], - self._cls_dict["__setstate__"], - ) = self._make_getstate_setstate() - - # tuples of script, globs, hook - self._script_snippets: list[ - tuple[str, dict, Callable[[dict, dict], Any]] - ] = [] - self._repr_added = False - - # We want to only do this check once; in 99.9% of cases these - # exist. - if not hasattr(self._cls, "__module__") or not hasattr( - self._cls, "__qualname__" - ): - self._add_method_dunders = self._add_method_dunders_safe - else: - self._add_method_dunders = self._add_method_dunders_unsafe - - def __repr__(self): - return f"<_ClassBuilder(cls={self._cls.__name__})>" - - def _eval_snippets(self) -> None: - """ - Evaluate any registered snippets in one go. - """ - script = "\n".join([snippet[0] for snippet in self._script_snippets]) - globs = {} - for _, snippet_globs, _ in self._script_snippets: - globs.update(snippet_globs) - - locs = _linecache_and_compile( - script, - _generate_unique_filename(self._cls, "methods"), - globs, - ) - - for _, _, hook in self._script_snippets: - hook(self._cls_dict, locs) - - def build_class(self): - """ - Finalize class based on the accumulated configuration. - - Builder cannot be used after calling this method. - """ - self._eval_snippets() - if self._slots is True: - cls = self._create_slots_class() - else: - cls = self._patch_original_class() - if PY_3_10_PLUS: - cls = abc.update_abstractmethods(cls) - - # The method gets only called if it's not inherited from a base class. - # _has_own_attribute does NOT work properly for classmethods. - if ( - getattr(cls, "__attrs_init_subclass__", None) - and "__attrs_init_subclass__" not in cls.__dict__ - ): - cls.__attrs_init_subclass__() - - return cls - - def _patch_original_class(self): - """ - Apply accumulated methods and return the class. - """ - cls = self._cls - base_names = self._base_names - - # Clean class of attribute definitions (`attr.ib()`s). - if self._delete_attribs: - for name in self._attr_names: - if ( - name not in base_names - and getattr(cls, name, _SENTINEL) is not _SENTINEL - ): - # An AttributeError can happen if a base class defines a - # class variable and we want to set an attribute with the - # same name by using only a type annotation. - with contextlib.suppress(AttributeError): - delattr(cls, name) - - # Attach our dunder methods. - for name, value in self._cls_dict.items(): - setattr(cls, name, value) - - # If we've inherited an attrs __setattr__ and don't write our own, - # reset it to object's. - if not self._wrote_own_setattr and getattr( - cls, "__attrs_own_setattr__", False - ): - cls.__attrs_own_setattr__ = False - - if not self._has_custom_setattr: - cls.__setattr__ = _OBJ_SETATTR - - return cls - - def _create_slots_class(self): - """ - Build and return a new class with a `__slots__` attribute. - """ - cd = { - k: v - for k, v in self._cls_dict.items() - if k not in (*tuple(self._attr_names), "__dict__", "__weakref__") - } - - # If our class doesn't have its own implementation of __setattr__ - # (either from the user or by us), check the bases, if one of them has - # an attrs-made __setattr__, that needs to be reset. We don't walk the - # MRO because we only care about our immediate base classes. - # XXX: This can be confused by subclassing a slotted attrs class with - # XXX: a non-attrs class and subclass the resulting class with an attrs - # XXX: class. See `test_slotted_confused` for details. For now that's - # XXX: OK with us. - if not self._wrote_own_setattr: - cd["__attrs_own_setattr__"] = False - - if not self._has_custom_setattr: - for base_cls in self._cls.__bases__: - if base_cls.__dict__.get("__attrs_own_setattr__", False): - cd["__setattr__"] = _OBJ_SETATTR - break - - # Traverse the MRO to collect existing slots - # and check for an existing __weakref__. - existing_slots = {} - weakref_inherited = False - for base_cls in self._cls.__mro__[1:-1]: - if base_cls.__dict__.get("__weakref__", None) is not None: - weakref_inherited = True - existing_slots.update( - { - name: getattr(base_cls, name) - for name in getattr(base_cls, "__slots__", []) - } - ) - - base_names = set(self._base_names) - - names = self._attr_names - if ( - self._weakref_slot - and "__weakref__" not in getattr(self._cls, "__slots__", ()) - and "__weakref__" not in names - and not weakref_inherited - ): - names += ("__weakref__",) - - cached_properties = { - name: cached_prop.func - for name, cached_prop in cd.items() - if isinstance(cached_prop, cached_property) - } - - # Collect methods with a `__class__` reference that are shadowed in the new class. - # To know to update them. - additional_closure_functions_to_update = [] - if cached_properties: - class_annotations = _get_annotations(self._cls) - for name, func in cached_properties.items(): - # Add cached properties to names for slotting. - names += (name,) - # Clear out function from class to avoid clashing. - del cd[name] - additional_closure_functions_to_update.append(func) - annotation = inspect.signature(func).return_annotation - if annotation is not inspect.Parameter.empty: - class_annotations[name] = annotation - - original_getattr = cd.get("__getattr__") - if original_getattr is not None: - additional_closure_functions_to_update.append(original_getattr) - - cd["__getattr__"] = _make_cached_property_getattr( - cached_properties, original_getattr, self._cls - ) - - # We only add the names of attributes that aren't inherited. - # Setting __slots__ to inherited attributes wastes memory. - slot_names = [name for name in names if name not in base_names] - - # There are slots for attributes from current class - # that are defined in parent classes. - # As their descriptors may be overridden by a child class, - # we collect them here and update the class dict - reused_slots = { - slot: slot_descriptor - for slot, slot_descriptor in existing_slots.items() - if slot in slot_names - } - slot_names = [name for name in slot_names if name not in reused_slots] - cd.update(reused_slots) - if self._cache_hash: - slot_names.append(_HASH_CACHE_FIELD) - - cd["__slots__"] = tuple(slot_names) - - cd["__qualname__"] = self._cls.__qualname__ - - # Create new class based on old class and our methods. - cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) - - # The following is a fix for - # . - # If a method mentions `__class__` or uses the no-arg super(), the - # compiler will bake a reference to the class in the method itself - # as `method.__closure__`. Since we replace the class with a - # clone, we rewrite these references so it keeps working. - for item in itertools.chain( - cls.__dict__.values(), additional_closure_functions_to_update - ): - if isinstance(item, (classmethod, staticmethod)): - # Class- and staticmethods hide their functions inside. - # These might need to be rewritten as well. - closure_cells = getattr(item.__func__, "__closure__", None) - elif isinstance(item, property): - # Workaround for property `super()` shortcut (PY3-only). - # There is no universal way for other descriptors. - closure_cells = getattr(item.fget, "__closure__", None) - else: - closure_cells = getattr(item, "__closure__", None) - - if not closure_cells: # Catch None or the empty list. - continue - for cell in closure_cells: - try: - match = cell.cell_contents is self._cls - except ValueError: # noqa: PERF203 - # ValueError: Cell is empty - pass - else: - if match: - cell.cell_contents = cls - return cls - - def add_repr(self, ns): - script, globs = _make_repr_script(self._attrs, ns) - - def _attach_repr(cls_dict, globs): - cls_dict["__repr__"] = self._add_method_dunders(globs["__repr__"]) - - self._script_snippets.append((script, globs, _attach_repr)) - self._repr_added = True - return self - - def add_str(self): - if not self._repr_added: - msg = "__str__ can only be generated if a __repr__ exists." - raise ValueError(msg) - - def __str__(self): - return self.__repr__() - - self._cls_dict["__str__"] = self._add_method_dunders(__str__) - return self - - def _make_getstate_setstate(self): - """ - Create custom __setstate__ and __getstate__ methods. - """ - # __weakref__ is not writable. - state_attr_names = tuple( - an for an in self._attr_names if an != "__weakref__" - ) - - def slots_getstate(self): - """ - Automatically created by attrs. - """ - return {name: getattr(self, name) for name in state_attr_names} - - hash_caching_enabled = self._cache_hash - - def slots_setstate(self, state): - """ - Automatically created by attrs. - """ - __bound_setattr = _OBJ_SETATTR.__get__(self) - if isinstance(state, tuple): - # Backward compatibility with attrs instances pickled with - # attrs versions before v22.2.0 which stored tuples. - for name, value in zip(state_attr_names, state): - __bound_setattr(name, value) - else: - for name in state_attr_names: - if name in state: - __bound_setattr(name, state[name]) - - # The hash code cache is not included when the object is - # serialized, but it still needs to be initialized to None to - # indicate that the first call to __hash__ should be a cache - # miss. - if hash_caching_enabled: - __bound_setattr(_HASH_CACHE_FIELD, None) - - return slots_getstate, slots_setstate - - def make_unhashable(self): - self._cls_dict["__hash__"] = None - return self - - def add_hash(self): - script, globs = _make_hash_script( - self._cls, - self._attrs, - frozen=self._frozen, - cache_hash=self._cache_hash, - ) - - def attach_hash(cls_dict: dict, locs: dict) -> None: - cls_dict["__hash__"] = self._add_method_dunders(locs["__hash__"]) - - self._script_snippets.append((script, globs, attach_hash)) - - return self - - def add_init(self): - script, globs, annotations = _make_init_script( - self._cls, - self._attrs, - self._has_pre_init, - self._pre_init_has_args, - self._has_post_init, - self._frozen, - self._slots, - self._cache_hash, - self._base_attr_map, - self._is_exc, - self._on_setattr, - attrs_init=False, - ) - - def _attach_init(cls_dict, globs): - init = globs["__init__"] - init.__annotations__ = annotations - cls_dict["__init__"] = self._add_method_dunders(init) - - self._script_snippets.append((script, globs, _attach_init)) - - return self - - def add_replace(self): - self._cls_dict["__replace__"] = self._add_method_dunders( - lambda self, **changes: evolve(self, **changes) - ) - return self - - def add_match_args(self): - self._cls_dict["__match_args__"] = tuple( - field.name - for field in self._attrs - if field.init and not field.kw_only - ) - - def add_attrs_init(self): - script, globs, annotations = _make_init_script( - self._cls, - self._attrs, - self._has_pre_init, - self._pre_init_has_args, - self._has_post_init, - self._frozen, - self._slots, - self._cache_hash, - self._base_attr_map, - self._is_exc, - self._on_setattr, - attrs_init=True, - ) - - def _attach_attrs_init(cls_dict, globs): - init = globs["__attrs_init__"] - init.__annotations__ = annotations - cls_dict["__attrs_init__"] = self._add_method_dunders(init) - - self._script_snippets.append((script, globs, _attach_attrs_init)) - - return self - - def add_eq(self): - cd = self._cls_dict - - script, globs = _make_eq_script(self._attrs) - - def _attach_eq(cls_dict, globs): - cls_dict["__eq__"] = self._add_method_dunders(globs["__eq__"]) - - self._script_snippets.append((script, globs, _attach_eq)) - - cd["__ne__"] = __ne__ - - return self - - def add_order(self): - cd = self._cls_dict - - cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = ( - self._add_method_dunders(meth) - for meth in _make_order(self._cls, self._attrs) - ) - - return self - - def add_setattr(self): - sa_attrs = {} - for a in self._attrs: - on_setattr = a.on_setattr or self._on_setattr - if on_setattr and on_setattr is not setters.NO_OP: - sa_attrs[a.name] = a, on_setattr - - if not sa_attrs: - return self - - if self._has_custom_setattr: - # We need to write a __setattr__ but there already is one! - msg = "Can't combine custom __setattr__ with on_setattr hooks." - raise ValueError(msg) - - # docstring comes from _add_method_dunders - def __setattr__(self, name, val): - try: - a, hook = sa_attrs[name] - except KeyError: - nval = val - else: - nval = hook(self, a, val) - - _OBJ_SETATTR(self, name, nval) - - self._cls_dict["__attrs_own_setattr__"] = True - self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) - self._wrote_own_setattr = True - - return self - - def _add_method_dunders_unsafe(self, method: Callable) -> Callable: - """ - Add __module__ and __qualname__ to a *method*. - """ - method.__module__ = self._cls.__module__ - - method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" - - method.__doc__ = ( - f"Method generated by attrs for class {self._cls.__qualname__}." - ) - - return method - - def _add_method_dunders_safe(self, method: Callable) -> Callable: - """ - Add __module__ and __qualname__ to a *method* if possible. - """ - with contextlib.suppress(AttributeError): - method.__module__ = self._cls.__module__ - - with contextlib.suppress(AttributeError): - method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" - - with contextlib.suppress(AttributeError): - method.__doc__ = f"Method generated by attrs for class {self._cls.__qualname__}." - - return method - - -def _determine_attrs_eq_order(cmp, eq, order, default_eq): - """ - Validate the combination of *cmp*, *eq*, and *order*. Derive the effective - values of eq and order. If *eq* is None, set it to *default_eq*. - """ - if cmp is not None and any((eq is not None, order is not None)): - msg = "Don't mix `cmp` with `eq' and `order`." - raise ValueError(msg) - - # cmp takes precedence due to bw-compatibility. - if cmp is not None: - return cmp, cmp - - # If left None, equality is set to the specified default and ordering - # mirrors equality. - if eq is None: - eq = default_eq - - if order is None: - order = eq - - if eq is False and order is True: - msg = "`order` can only be True if `eq` is True too." - raise ValueError(msg) - - return eq, order - - -def _determine_attrib_eq_order(cmp, eq, order, default_eq): - """ - Validate the combination of *cmp*, *eq*, and *order*. Derive the effective - values of eq and order. If *eq* is None, set it to *default_eq*. - """ - if cmp is not None and any((eq is not None, order is not None)): - msg = "Don't mix `cmp` with `eq' and `order`." - raise ValueError(msg) - - def decide_callable_or_boolean(value): - """ - Decide whether a key function is used. - """ - if callable(value): - value, key = True, value - else: - key = None - return value, key - - # cmp takes precedence due to bw-compatibility. - if cmp is not None: - cmp, cmp_key = decide_callable_or_boolean(cmp) - return cmp, cmp_key, cmp, cmp_key - - # If left None, equality is set to the specified default and ordering - # mirrors equality. - if eq is None: - eq, eq_key = default_eq, None - else: - eq, eq_key = decide_callable_or_boolean(eq) - - if order is None: - order, order_key = eq, eq_key - else: - order, order_key = decide_callable_or_boolean(order) - - if eq is False and order is True: - msg = "`order` can only be True if `eq` is True too." - raise ValueError(msg) - - return eq, eq_key, order, order_key - - -def _determine_whether_to_implement( - cls, flag, auto_detect, dunders, default=True -): - """ - Check whether we should implement a set of methods for *cls*. - - *flag* is the argument passed into @attr.s like 'init', *auto_detect* the - same as passed into @attr.s and *dunders* is a tuple of attribute names - whose presence signal that the user has implemented it themselves. - - Return *default* if no reason for either for or against is found. - """ - if flag is True or flag is False: - return flag - - if flag is None and auto_detect is False: - return default - - # Logically, flag is None and auto_detect is True here. - for dunder in dunders: - if _has_own_attribute(cls, dunder): - return False - - return default - - -def attrs( - maybe_cls=None, - these=None, - repr_ns=None, - repr=None, - cmp=None, - hash=None, - init=None, - slots=False, - frozen=False, - weakref_slot=True, - str=False, - auto_attribs=False, - kw_only=False, - cache_hash=False, - auto_exc=False, - eq=None, - order=None, - auto_detect=False, - collect_by_mro=False, - getstate_setstate=None, - on_setattr=None, - field_transformer=None, - match_args=True, - unsafe_hash=None, -): - r""" - A class decorator that adds :term:`dunder methods` according to the - specified attributes using `attr.ib` or the *these* argument. - - Consider using `attrs.define` / `attrs.frozen` in new code (``attr.s`` will - *never* go away, though). - - Args: - repr_ns (str): - When using nested classes, there was no way in Python 2 to - automatically detect that. This argument allows to set a custom - name for a more meaningful ``repr`` output. This argument is - pointless in Python 3 and is therefore deprecated. - - .. caution:: - Refer to `attrs.define` for the rest of the parameters, but note that they - can have different defaults. - - Notably, leaving *on_setattr* as `None` will **not** add any hooks. - - .. versionadded:: 16.0.0 *slots* - .. versionadded:: 16.1.0 *frozen* - .. versionadded:: 16.3.0 *str* - .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. - .. versionchanged:: 17.1.0 - *hash* supports `None` as value which is also the default now. - .. versionadded:: 17.3.0 *auto_attribs* - .. versionchanged:: 18.1.0 - If *these* is passed, no attributes are deleted from the class body. - .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. - .. versionadded:: 18.2.0 *weakref_slot* - .. deprecated:: 18.2.0 - ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a - `DeprecationWarning` if the classes compared are subclasses of - each other. ``__eq`` and ``__ne__`` never tried to compared subclasses - to each other. - .. versionchanged:: 19.2.0 - ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider - subclasses comparable anymore. - .. versionadded:: 18.2.0 *kw_only* - .. versionadded:: 18.2.0 *cache_hash* - .. versionadded:: 19.1.0 *auto_exc* - .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. - .. versionadded:: 19.2.0 *eq* and *order* - .. versionadded:: 20.1.0 *auto_detect* - .. versionadded:: 20.1.0 *collect_by_mro* - .. versionadded:: 20.1.0 *getstate_setstate* - .. versionadded:: 20.1.0 *on_setattr* - .. versionadded:: 20.3.0 *field_transformer* - .. versionchanged:: 21.1.0 - ``init=False`` injects ``__attrs_init__`` - .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` - .. versionchanged:: 21.1.0 *cmp* undeprecated - .. versionadded:: 21.3.0 *match_args* - .. versionadded:: 22.2.0 - *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). - .. deprecated:: 24.1.0 *repr_ns* - .. versionchanged:: 24.1.0 - Instances are not compared as tuples of attributes anymore, but using a - big ``and`` condition. This is faster and has more correct behavior for - uncomparable values like `math.nan`. - .. versionadded:: 24.1.0 - If a class has an *inherited* classmethod called - ``__attrs_init_subclass__``, it is executed after the class is created. - .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. - """ - if repr_ns is not None: - import warnings - - warnings.warn( - DeprecationWarning( - "The `repr_ns` argument is deprecated and will be removed in or after August 2025." - ), - stacklevel=2, - ) - - eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None) - - # unsafe_hash takes precedence due to PEP 681. - if unsafe_hash is not None: - hash = unsafe_hash - - if isinstance(on_setattr, (list, tuple)): - on_setattr = setters.pipe(*on_setattr) - - def wrap(cls): - is_frozen = frozen or _has_frozen_base_class(cls) - is_exc = auto_exc is True and issubclass(cls, BaseException) - has_own_setattr = auto_detect and _has_own_attribute( - cls, "__setattr__" - ) - - if has_own_setattr and is_frozen: - msg = "Can't freeze a class with a custom __setattr__." - raise ValueError(msg) - - builder = _ClassBuilder( - cls, - these, - slots, - is_frozen, - weakref_slot, - _determine_whether_to_implement( - cls, - getstate_setstate, - auto_detect, - ("__getstate__", "__setstate__"), - default=slots, - ), - auto_attribs, - kw_only, - cache_hash, - is_exc, - collect_by_mro, - on_setattr, - has_own_setattr, - field_transformer, - ) - - if _determine_whether_to_implement( - cls, repr, auto_detect, ("__repr__",) - ): - builder.add_repr(repr_ns) - - if str is True: - builder.add_str() - - eq = _determine_whether_to_implement( - cls, eq_, auto_detect, ("__eq__", "__ne__") - ) - if not is_exc and eq is True: - builder.add_eq() - if not is_exc and _determine_whether_to_implement( - cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__") - ): - builder.add_order() - - if not frozen: - builder.add_setattr() - - nonlocal hash - if ( - hash is None - and auto_detect is True - and _has_own_attribute(cls, "__hash__") - ): - hash = False - - if hash is not True and hash is not False and hash is not None: - # Can't use `hash in` because 1 == True for example. - msg = "Invalid value for hash. Must be True, False, or None." - raise TypeError(msg) - - if hash is False or (hash is None and eq is False) or is_exc: - # Don't do anything. Should fall back to __object__'s __hash__ - # which is by id. - if cache_hash: - msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." - raise TypeError(msg) - elif hash is True or ( - hash is None and eq is True and is_frozen is True - ): - # Build a __hash__ if told so, or if it's safe. - builder.add_hash() - else: - # Raise TypeError on attempts to hash. - if cache_hash: - msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." - raise TypeError(msg) - builder.make_unhashable() - - if _determine_whether_to_implement( - cls, init, auto_detect, ("__init__",) - ): - builder.add_init() - else: - builder.add_attrs_init() - if cache_hash: - msg = "Invalid value for cache_hash. To use hash caching, init must be True." - raise TypeError(msg) - - if PY_3_13_PLUS and not _has_own_attribute(cls, "__replace__"): - builder.add_replace() - - if ( - PY_3_10_PLUS - and match_args - and not _has_own_attribute(cls, "__match_args__") - ): - builder.add_match_args() - - return builder.build_class() - - # maybe_cls's type depends on the usage of the decorator. It's a class - # if it's used as `@attrs` but `None` if used as `@attrs()`. - if maybe_cls is None: - return wrap - - return wrap(maybe_cls) - - -_attrs = attrs -""" -Internal alias so we can use it in functions that take an argument called -*attrs*. -""" - - -def _has_frozen_base_class(cls): - """ - Check whether *cls* has a frozen ancestor by looking at its - __setattr__. - """ - return cls.__setattr__ is _frozen_setattrs - - -def _generate_unique_filename(cls: type, func_name: str) -> str: - """ - Create a "filename" suitable for a function being generated. - """ - return ( - f"" - ) - - -def _make_hash_script( - cls: type, attrs: list[Attribute], frozen: bool, cache_hash: bool -) -> tuple[str, dict]: - attrs = tuple( - a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) - ) - - tab = " " - - type_hash = hash(_generate_unique_filename(cls, "hash")) - # If eq is custom generated, we need to include the functions in globs - globs = {} - - hash_def = "def __hash__(self" - hash_func = "hash((" - closing_braces = "))" - if not cache_hash: - hash_def += "):" - else: - hash_def += ", *" - - hash_def += ", _cache_wrapper=__import__('attr._make')._make._CacheHashWrapper):" - hash_func = "_cache_wrapper(" + hash_func - closing_braces += ")" - - method_lines = [hash_def] - - def append_hash_computation_lines(prefix, indent): - """ - Generate the code for actually computing the hash code. - Below this will either be returned directly or used to compute - a value which is then cached, depending on the value of cache_hash - """ - - method_lines.extend( - [ - indent + prefix + hash_func, - indent + f" {type_hash},", - ] - ) - - for a in attrs: - if a.eq_key: - cmp_name = f"_{a.name}_key" - globs[cmp_name] = a.eq_key - method_lines.append( - indent + f" {cmp_name}(self.{a.name})," - ) - else: - method_lines.append(indent + f" self.{a.name},") - - method_lines.append(indent + " " + closing_braces) - - if cache_hash: - method_lines.append(tab + f"if self.{_HASH_CACHE_FIELD} is None:") - if frozen: - append_hash_computation_lines( - f"object.__setattr__(self, '{_HASH_CACHE_FIELD}', ", tab * 2 - ) - method_lines.append(tab * 2 + ")") # close __setattr__ - else: - append_hash_computation_lines( - f"self.{_HASH_CACHE_FIELD} = ", tab * 2 - ) - method_lines.append(tab + f"return self.{_HASH_CACHE_FIELD}") - else: - append_hash_computation_lines("return ", tab) - - script = "\n".join(method_lines) - return script, globs - - -def _add_hash(cls: type, attrs: list[Attribute]): - """ - Add a hash method to *cls*. - """ - script, globs = _make_hash_script( - cls, attrs, frozen=False, cache_hash=False - ) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__hash__") - ) - cls.__hash__ = globs["__hash__"] - return cls - - -def __ne__(self, other): - """ - Check equality and either forward a NotImplemented or - return the result negated. - """ - result = self.__eq__(other) - if result is NotImplemented: - return NotImplemented - - return not result - - -def _make_eq_script(attrs: list) -> tuple[str, dict]: - """ - Create __eq__ method for *cls* with *attrs*. - """ - attrs = [a for a in attrs if a.eq] - - lines = [ - "def __eq__(self, other):", - " if other.__class__ is not self.__class__:", - " return NotImplemented", - ] - - globs = {} - if attrs: - lines.append(" return (") - for a in attrs: - if a.eq_key: - cmp_name = f"_{a.name}_key" - # Add the key function to the global namespace - # of the evaluated function. - globs[cmp_name] = a.eq_key - lines.append( - f" {cmp_name}(self.{a.name}) == {cmp_name}(other.{a.name})" - ) - else: - lines.append(f" self.{a.name} == other.{a.name}") - if a is not attrs[-1]: - lines[-1] = f"{lines[-1]} and" - lines.append(" )") - else: - lines.append(" return True") - - script = "\n".join(lines) - - return script, globs - - -def _make_order(cls, attrs): - """ - Create ordering methods for *cls* with *attrs*. - """ - attrs = [a for a in attrs if a.order] - - def attrs_to_tuple(obj): - """ - Save us some typing. - """ - return tuple( - key(value) if key else value - for value, key in ( - (getattr(obj, a.name), a.order_key) for a in attrs - ) - ) - - def __lt__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) < attrs_to_tuple(other) - - return NotImplemented - - def __le__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) <= attrs_to_tuple(other) - - return NotImplemented - - def __gt__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) > attrs_to_tuple(other) - - return NotImplemented - - def __ge__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) >= attrs_to_tuple(other) - - return NotImplemented - - return __lt__, __le__, __gt__, __ge__ - - -def _add_eq(cls, attrs=None): - """ - Add equality methods to *cls* with *attrs*. - """ - if attrs is None: - attrs = cls.__attrs_attrs__ - - script, globs = _make_eq_script(attrs) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__eq__") - ) - cls.__eq__ = globs["__eq__"] - cls.__ne__ = __ne__ - - return cls - - -def _make_repr_script(attrs, ns) -> tuple[str, dict]: - """ - Create the source and globs for a __repr__ and return it. - """ - # Figure out which attributes to include, and which function to use to - # format them. The a.repr value can be either bool or a custom - # callable. - attr_names_with_reprs = tuple( - (a.name, (repr if a.repr is True else a.repr), a.init) - for a in attrs - if a.repr is not False - ) - globs = { - name + "_repr": r for name, r, _ in attr_names_with_reprs if r != repr - } - globs["_compat"] = _compat - globs["AttributeError"] = AttributeError - globs["NOTHING"] = NOTHING - attribute_fragments = [] - for name, r, i in attr_names_with_reprs: - accessor = ( - "self." + name if i else 'getattr(self, "' + name + '", NOTHING)' - ) - fragment = ( - "%s={%s!r}" % (name, accessor) - if r == repr - else "%s={%s_repr(%s)}" % (name, name, accessor) - ) - attribute_fragments.append(fragment) - repr_fragment = ", ".join(attribute_fragments) - - if ns is None: - cls_name_fragment = '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}' - else: - cls_name_fragment = ns + ".{self.__class__.__name__}" - - lines = [ - "def __repr__(self):", - " try:", - " already_repring = _compat.repr_context.already_repring", - " except AttributeError:", - " already_repring = {id(self),}", - " _compat.repr_context.already_repring = already_repring", - " else:", - " if id(self) in already_repring:", - " return '...'", - " else:", - " already_repring.add(id(self))", - " try:", - f" return f'{cls_name_fragment}({repr_fragment})'", - " finally:", - " already_repring.remove(id(self))", - ] - - return "\n".join(lines), globs - - -def _add_repr(cls, ns=None, attrs=None): - """ - Add a repr method to *cls*. - """ - if attrs is None: - attrs = cls.__attrs_attrs__ - - script, globs = _make_repr_script(attrs, ns) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__repr__") - ) - cls.__repr__ = globs["__repr__"] - return cls - - -def fields(cls): - """ - Return the tuple of *attrs* attributes for a class. - - The tuple also allows accessing the fields by their names (see below for - examples). - - Args: - cls (type): Class to introspect. - - Raises: - TypeError: If *cls* is not a class. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - Returns: - tuple (with name accessors) of `attrs.Attribute` - - .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields - by name. - .. versionchanged:: 23.1.0 Add support for generic classes. - """ - generic_base = get_generic_base(cls) - - if generic_base is None and not isinstance(cls, type): - msg = "Passed object must be a class." - raise TypeError(msg) - - attrs = getattr(cls, "__attrs_attrs__", None) - - if attrs is None: - if generic_base is not None: - attrs = getattr(generic_base, "__attrs_attrs__", None) - if attrs is not None: - # Even though this is global state, stick it on here to speed - # it up. We rely on `cls` being cached for this to be - # efficient. - cls.__attrs_attrs__ = attrs - return attrs - msg = f"{cls!r} is not an attrs-decorated class." - raise NotAnAttrsClassError(msg) - - return attrs - - -def fields_dict(cls): - """ - Return an ordered dictionary of *attrs* attributes for a class, whose keys - are the attribute names. - - Args: - cls (type): Class to introspect. - - Raises: - TypeError: If *cls* is not a class. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - Returns: - dict[str, attrs.Attribute]: Dict of attribute name to definition - - .. versionadded:: 18.1.0 - """ - if not isinstance(cls, type): - msg = "Passed object must be a class." - raise TypeError(msg) - attrs = getattr(cls, "__attrs_attrs__", None) - if attrs is None: - msg = f"{cls!r} is not an attrs-decorated class." - raise NotAnAttrsClassError(msg) - return {a.name: a for a in attrs} - - -def validate(inst): - """ - Validate all attributes on *inst* that have a validator. - - Leaves all exceptions through. - - Args: - inst: Instance of a class with *attrs* attributes. - """ - if _config._run_validators is False: - return - - for a in fields(inst.__class__): - v = a.validator - if v is not None: - v(inst, a, getattr(inst, a.name)) - - -def _is_slot_attr(a_name, base_attr_map): - """ - Check if the attribute name comes from a slot class. - """ - cls = base_attr_map.get(a_name) - return cls and "__slots__" in cls.__dict__ - - -def _make_init_script( - cls, - attrs, - pre_init, - pre_init_has_args, - post_init, - frozen, - slots, - cache_hash, - base_attr_map, - is_exc, - cls_on_setattr, - attrs_init, -) -> tuple[str, dict, dict]: - has_cls_on_setattr = ( - cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP - ) - - if frozen and has_cls_on_setattr: - msg = "Frozen classes can't use on_setattr." - raise ValueError(msg) - - needs_cached_setattr = cache_hash or frozen - filtered_attrs = [] - attr_dict = {} - for a in attrs: - if not a.init and a.default is NOTHING: - continue - - filtered_attrs.append(a) - attr_dict[a.name] = a - - if a.on_setattr is not None: - if frozen is True: - msg = "Frozen classes can't use on_setattr." - raise ValueError(msg) - - needs_cached_setattr = True - elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP: - needs_cached_setattr = True - - script, globs, annotations = _attrs_to_init_script( - filtered_attrs, - frozen, - slots, - pre_init, - pre_init_has_args, - post_init, - cache_hash, - base_attr_map, - is_exc, - needs_cached_setattr, - has_cls_on_setattr, - "__attrs_init__" if attrs_init else "__init__", - ) - if cls.__module__ in sys.modules: - # This makes typing.get_type_hints(CLS.__init__) resolve string types. - globs.update(sys.modules[cls.__module__].__dict__) - - globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) - - if needs_cached_setattr: - # Save the lookup overhead in __init__ if we need to circumvent - # setattr hooks. - globs["_cached_setattr_get"] = _OBJ_SETATTR.__get__ - - return script, globs, annotations - - -def _setattr(attr_name: str, value_var: str, has_on_setattr: bool) -> str: - """ - Use the cached object.setattr to set *attr_name* to *value_var*. - """ - return f"_setattr('{attr_name}', {value_var})" - - -def _setattr_with_converter( - attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter -) -> str: - """ - Use the cached object.setattr to set *attr_name* to *value_var*, but run - its converter first. - """ - return f"_setattr('{attr_name}', {converter._fmt_converter_call(attr_name, value_var)})" - - -def _assign(attr_name: str, value: str, has_on_setattr: bool) -> str: - """ - Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise - relegate to _setattr. - """ - if has_on_setattr: - return _setattr(attr_name, value, True) - - return f"self.{attr_name} = {value}" - - -def _assign_with_converter( - attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter -) -> str: - """ - Unless *attr_name* has an on_setattr hook, use normal assignment after - conversion. Otherwise relegate to _setattr_with_converter. - """ - if has_on_setattr: - return _setattr_with_converter(attr_name, value_var, True, converter) - - return f"self.{attr_name} = {converter._fmt_converter_call(attr_name, value_var)}" - - -def _determine_setters( - frozen: bool, slots: bool, base_attr_map: dict[str, type] -): - """ - Determine the correct setter functions based on whether a class is frozen - and/or slotted. - """ - if frozen is True: - if slots is True: - return (), _setattr, _setattr_with_converter - - # Dict frozen classes assign directly to __dict__. - # But only if the attribute doesn't come from an ancestor slot - # class. - # Note _inst_dict will be used again below if cache_hash is True - - def fmt_setter( - attr_name: str, value_var: str, has_on_setattr: bool - ) -> str: - if _is_slot_attr(attr_name, base_attr_map): - return _setattr(attr_name, value_var, has_on_setattr) - - return f"_inst_dict['{attr_name}'] = {value_var}" - - def fmt_setter_with_converter( - attr_name: str, - value_var: str, - has_on_setattr: bool, - converter: Converter, - ) -> str: - if has_on_setattr or _is_slot_attr(attr_name, base_attr_map): - return _setattr_with_converter( - attr_name, value_var, has_on_setattr, converter - ) - - return f"_inst_dict['{attr_name}'] = {converter._fmt_converter_call(attr_name, value_var)}" - - return ( - ("_inst_dict = self.__dict__",), - fmt_setter, - fmt_setter_with_converter, - ) - - # Not frozen -- we can just assign directly. - return (), _assign, _assign_with_converter - - -def _attrs_to_init_script( - attrs: list[Attribute], - is_frozen: bool, - is_slotted: bool, - call_pre_init: bool, - pre_init_has_args: bool, - call_post_init: bool, - does_cache_hash: bool, - base_attr_map: dict[str, type], - is_exc: bool, - needs_cached_setattr: bool, - has_cls_on_setattr: bool, - method_name: str, -) -> tuple[str, dict, dict]: - """ - Return a script of an initializer for *attrs*, a dict of globals, and - annotations for the initializer. - - The globals are required by the generated script. - """ - lines = ["self.__attrs_pre_init__()"] if call_pre_init else [] - - if needs_cached_setattr: - lines.append( - # Circumvent the __setattr__ descriptor to save one lookup per - # assignment. Note _setattr will be used again below if - # does_cache_hash is True. - "_setattr = _cached_setattr_get(self)" - ) - - extra_lines, fmt_setter, fmt_setter_with_converter = _determine_setters( - is_frozen, is_slotted, base_attr_map - ) - lines.extend(extra_lines) - - args = [] - kw_only_args = [] - attrs_to_validate = [] - - # This is a dictionary of names to validator and converter callables. - # Injecting this into __init__ globals lets us avoid lookups. - names_for_globals = {} - annotations = {"return": None} - - for a in attrs: - if a.validator: - attrs_to_validate.append(a) - - attr_name = a.name - has_on_setattr = a.on_setattr is not None or ( - a.on_setattr is not setters.NO_OP and has_cls_on_setattr - ) - # a.alias is set to maybe-mangled attr_name in _ClassBuilder if not - # explicitly provided - arg_name = a.alias - - has_factory = isinstance(a.default, Factory) - maybe_self = "self" if has_factory and a.default.takes_self else "" - - if a.converter is not None and not isinstance(a.converter, Converter): - converter = Converter(a.converter) - else: - converter = a.converter - - if a.init is False: - if has_factory: - init_factory_name = _INIT_FACTORY_PAT % (a.name,) - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, - init_factory_name + f"({maybe_self})", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - fmt_setter( - attr_name, - init_factory_name + f"({maybe_self})", - has_on_setattr, - ) - ) - names_for_globals[init_factory_name] = a.default.factory - elif converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, - f"attr_dict['{attr_name}'].default", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - fmt_setter( - attr_name, - f"attr_dict['{attr_name}'].default", - has_on_setattr, - ) - ) - elif a.default is not NOTHING and not has_factory: - arg = f"{arg_name}=attr_dict['{attr_name}'].default" - if a.kw_only: - kw_only_args.append(arg) - else: - args.append(arg) - - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) - - elif has_factory: - arg = f"{arg_name}=NOTHING" - if a.kw_only: - kw_only_args.append(arg) - else: - args.append(arg) - lines.append(f"if {arg_name} is not NOTHING:") - - init_factory_name = _INIT_FACTORY_PAT % (a.name,) - if converter is not None: - lines.append( - " " - + fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - lines.append("else:") - lines.append( - " " - + fmt_setter_with_converter( - attr_name, - init_factory_name + "(" + maybe_self + ")", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - " " + fmt_setter(attr_name, arg_name, has_on_setattr) - ) - lines.append("else:") - lines.append( - " " - + fmt_setter( - attr_name, - init_factory_name + "(" + maybe_self + ")", - has_on_setattr, - ) - ) - names_for_globals[init_factory_name] = a.default.factory - else: - if a.kw_only: - kw_only_args.append(arg_name) - else: - args.append(arg_name) - - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) - - if a.init is True: - if a.type is not None and converter is None: - annotations[arg_name] = a.type - elif converter is not None and converter._first_param_type: - # Use the type from the converter if present. - annotations[arg_name] = converter._first_param_type - - if attrs_to_validate: # we can skip this if there are no validators. - names_for_globals["_config"] = _config - lines.append("if _config._run_validators is True:") - for a in attrs_to_validate: - val_name = "__attr_validator_" + a.name - attr_name = "__attr_" + a.name - lines.append(f" {val_name}(self, {attr_name}, self.{a.name})") - names_for_globals[val_name] = a.validator - names_for_globals[attr_name] = a - - if call_post_init: - lines.append("self.__attrs_post_init__()") - - # Because this is set only after __attrs_post_init__ is called, a crash - # will result if post-init tries to access the hash code. This seemed - # preferable to setting this beforehand, in which case alteration to field - # values during post-init combined with post-init accessing the hash code - # would result in silent bugs. - if does_cache_hash: - if is_frozen: - if is_slotted: - init_hash_cache = f"_setattr('{_HASH_CACHE_FIELD}', None)" - else: - init_hash_cache = f"_inst_dict['{_HASH_CACHE_FIELD}'] = None" - else: - init_hash_cache = f"self.{_HASH_CACHE_FIELD} = None" - lines.append(init_hash_cache) - - # For exceptions we rely on BaseException.__init__ for proper - # initialization. - if is_exc: - vals = ",".join(f"self.{a.name}" for a in attrs if a.init) - - lines.append(f"BaseException.__init__(self, {vals})") - - args = ", ".join(args) - pre_init_args = args - if kw_only_args: - # leading comma & kw_only args - args += f"{', ' if args else ''}*, {', '.join(kw_only_args)}" - pre_init_kw_only_args = ", ".join( - [ - f"{kw_arg_name}={kw_arg_name}" - # We need to remove the defaults from the kw_only_args. - for kw_arg_name in (kwa.split("=")[0] for kwa in kw_only_args) - ] - ) - pre_init_args += ", " if pre_init_args else "" - pre_init_args += pre_init_kw_only_args - - if call_pre_init and pre_init_has_args: - # If pre init method has arguments, pass same arguments as `__init__`. - lines[0] = f"self.__attrs_pre_init__({pre_init_args})" - - # Python <3.12 doesn't allow backslashes in f-strings. - NL = "\n " - return ( - f"""def {method_name}(self, {args}): - {NL.join(lines) if lines else "pass"} -""", - names_for_globals, - annotations, - ) - - -def _default_init_alias_for(name: str) -> str: - """ - The default __init__ parameter name for a field. - - This performs private-name adjustment via leading-unscore stripping, - and is the default value of Attribute.alias if not provided. - """ - - return name.lstrip("_") - - -class Attribute: - """ - *Read-only* representation of an attribute. - - .. warning:: - - You should never instantiate this class yourself. - - The class has *all* arguments of `attr.ib` (except for ``factory`` which is - only syntactic sugar for ``default=Factory(...)`` plus the following: - - - ``name`` (`str`): The name of the attribute. - - ``alias`` (`str`): The __init__ parameter name of the attribute, after - any explicit overrides and default private-attribute-name handling. - - ``inherited`` (`bool`): Whether or not that attribute has been inherited - from a base class. - - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The - callables that are used for comparing and ordering objects by this - attribute, respectively. These are set by passing a callable to - `attr.ib`'s ``eq``, ``order``, or ``cmp`` arguments. See also - :ref:`comparison customization `. - - Instances of this class are frequently used for introspection purposes - like: - - - `fields` returns a tuple of them. - - Validators get them passed as the first argument. - - The :ref:`field transformer ` hook receives a list of - them. - - The ``alias`` property exposes the __init__ parameter name of the field, - with any overrides and default private-attribute handling applied. - - - .. versionadded:: 20.1.0 *inherited* - .. versionadded:: 20.1.0 *on_setattr* - .. versionchanged:: 20.2.0 *inherited* is not taken into account for - equality checks and hashing anymore. - .. versionadded:: 21.1.0 *eq_key* and *order_key* - .. versionadded:: 22.2.0 *alias* - - For the full version history of the fields, see `attr.ib`. - """ - - # These slots must NOT be reordered because we use them later for - # instantiation. - __slots__ = ( # noqa: RUF023 - "name", - "default", - "validator", - "repr", - "eq", - "eq_key", - "order", - "order_key", - "hash", - "init", - "metadata", - "type", - "converter", - "kw_only", - "inherited", - "on_setattr", - "alias", - ) - - def __init__( - self, - name, - default, - validator, - repr, - cmp, # XXX: unused, remove along with other cmp code. - hash, - init, - inherited, - metadata=None, - type=None, - converter=None, - kw_only=False, - eq=None, - eq_key=None, - order=None, - order_key=None, - on_setattr=None, - alias=None, - ): - eq, eq_key, order, order_key = _determine_attrib_eq_order( - cmp, eq_key or eq, order_key or order, True - ) - - # Cache this descriptor here to speed things up later. - bound_setattr = _OBJ_SETATTR.__get__(self) - - # Despite the big red warning, people *do* instantiate `Attribute` - # themselves. - bound_setattr("name", name) - bound_setattr("default", default) - bound_setattr("validator", validator) - bound_setattr("repr", repr) - bound_setattr("eq", eq) - bound_setattr("eq_key", eq_key) - bound_setattr("order", order) - bound_setattr("order_key", order_key) - bound_setattr("hash", hash) - bound_setattr("init", init) - bound_setattr("converter", converter) - bound_setattr( - "metadata", - ( - types.MappingProxyType(dict(metadata)) # Shallow copy - if metadata - else _EMPTY_METADATA_SINGLETON - ), - ) - bound_setattr("type", type) - bound_setattr("kw_only", kw_only) - bound_setattr("inherited", inherited) - bound_setattr("on_setattr", on_setattr) - bound_setattr("alias", alias) - - def __setattr__(self, name, value): - raise FrozenInstanceError - - @classmethod - def from_counting_attr(cls, name: str, ca: _CountingAttr, type=None): - # type holds the annotated value. deal with conflicts: - if type is None: - type = ca.type - elif ca.type is not None: - msg = f"Type annotation and type argument cannot both be present for '{name}'." - raise ValueError(msg) - return cls( - name, - ca._default, - ca._validator, - ca.repr, - None, - ca.hash, - ca.init, - False, - ca.metadata, - type, - ca.converter, - ca.kw_only, - ca.eq, - ca.eq_key, - ca.order, - ca.order_key, - ca.on_setattr, - ca.alias, - ) - - # Don't use attrs.evolve since fields(Attribute) doesn't work - def evolve(self, **changes): - """ - Copy *self* and apply *changes*. - - This works similarly to `attrs.evolve` but that function does not work - with :class:`attrs.Attribute`. - - It is mainly meant to be used for `transform-fields`. - - .. versionadded:: 20.3.0 - """ - new = copy.copy(self) - - new._setattrs(changes.items()) - - return new - - # Don't use _add_pickle since fields(Attribute) doesn't work - def __getstate__(self): - """ - Play nice with pickle. - """ - return tuple( - getattr(self, name) if name != "metadata" else dict(self.metadata) - for name in self.__slots__ - ) - - def __setstate__(self, state): - """ - Play nice with pickle. - """ - self._setattrs(zip(self.__slots__, state)) - - def _setattrs(self, name_values_pairs): - bound_setattr = _OBJ_SETATTR.__get__(self) - for name, value in name_values_pairs: - if name != "metadata": - bound_setattr(name, value) - else: - bound_setattr( - name, - ( - types.MappingProxyType(dict(value)) - if value - else _EMPTY_METADATA_SINGLETON - ), - ) - - -_a = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=(name != "metadata"), - init=True, - inherited=False, - alias=_default_init_alias_for(name), - ) - for name in Attribute.__slots__ -] - -Attribute = _add_hash( - _add_eq( - _add_repr(Attribute, attrs=_a), - attrs=[a for a in _a if a.name != "inherited"], - ), - attrs=[a for a in _a if a.hash and a.name != "inherited"], -) - - -class _CountingAttr: - """ - Intermediate representation of attributes that uses a counter to preserve - the order in which the attributes have been defined. - - *Internal* data structure of the attrs library. Running into is most - likely the result of a bug like a forgotten `@attr.s` decorator. - """ - - __slots__ = ( - "_default", - "_validator", - "alias", - "converter", - "counter", - "eq", - "eq_key", - "hash", - "init", - "kw_only", - "metadata", - "on_setattr", - "order", - "order_key", - "repr", - "type", - ) - __attrs_attrs__ = ( - *tuple( - Attribute( - name=name, - alias=_default_init_alias_for(name), - default=NOTHING, - validator=None, - repr=True, - cmp=None, - hash=True, - init=True, - kw_only=False, - eq=True, - eq_key=None, - order=False, - order_key=None, - inherited=False, - on_setattr=None, - ) - for name in ( - "counter", - "_default", - "repr", - "eq", - "order", - "hash", - "init", - "on_setattr", - "alias", - ) - ), - Attribute( - name="metadata", - alias="metadata", - default=None, - validator=None, - repr=True, - cmp=None, - hash=False, - init=True, - kw_only=False, - eq=True, - eq_key=None, - order=False, - order_key=None, - inherited=False, - on_setattr=None, - ), - ) - cls_counter = 0 - - def __init__( - self, - default, - validator, - repr, - cmp, - hash, - init, - converter, - metadata, - type, - kw_only, - eq, - eq_key, - order, - order_key, - on_setattr, - alias, - ): - _CountingAttr.cls_counter += 1 - self.counter = _CountingAttr.cls_counter - self._default = default - self._validator = validator - self.converter = converter - self.repr = repr - self.eq = eq - self.eq_key = eq_key - self.order = order - self.order_key = order_key - self.hash = hash - self.init = init - self.metadata = metadata - self.type = type - self.kw_only = kw_only - self.on_setattr = on_setattr - self.alias = alias - - def validator(self, meth): - """ - Decorator that adds *meth* to the list of validators. - - Returns *meth* unchanged. - - .. versionadded:: 17.1.0 - """ - if self._validator is None: - self._validator = meth - else: - self._validator = and_(self._validator, meth) - return meth - - def default(self, meth): - """ - Decorator that allows to set the default for an attribute. - - Returns *meth* unchanged. - - Raises: - DefaultAlreadySetError: If default has been set before. - - .. versionadded:: 17.1.0 - """ - if self._default is not NOTHING: - raise DefaultAlreadySetError - - self._default = Factory(meth, takes_self=True) - - return meth - - -_CountingAttr = _add_eq(_add_repr(_CountingAttr)) - - -class Factory: - """ - Stores a factory callable. - - If passed as the default value to `attrs.field`, the factory is used to - generate a new value. - - Args: - factory (typing.Callable): - A callable that takes either none or exactly one mandatory - positional argument depending on *takes_self*. - - takes_self (bool): - Pass the partially initialized instance that is being initialized - as a positional argument. - - .. versionadded:: 17.1.0 *takes_self* - """ - - __slots__ = ("factory", "takes_self") - - def __init__(self, factory, takes_self=False): - self.factory = factory - self.takes_self = takes_self - - def __getstate__(self): - """ - Play nice with pickle. - """ - return tuple(getattr(self, name) for name in self.__slots__) - - def __setstate__(self, state): - """ - Play nice with pickle. - """ - for name, value in zip(self.__slots__, state): - setattr(self, name, value) - - -_f = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=True, - init=True, - inherited=False, - ) - for name in Factory.__slots__ -] - -Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f) - - -class Converter: - """ - Stores a converter callable. - - Allows for the wrapped converter to take additional arguments. The - arguments are passed in the order they are documented. - - Args: - converter (Callable): A callable that converts the passed value. - - takes_self (bool): - Pass the partially initialized instance that is being initialized - as a positional argument. (default: `False`) - - takes_field (bool): - Pass the field definition (an :class:`Attribute`) into the - converter as a positional argument. (default: `False`) - - .. versionadded:: 24.1.0 - """ - - __slots__ = ( - "__call__", - "_first_param_type", - "_global_name", - "converter", - "takes_field", - "takes_self", - ) - - def __init__(self, converter, *, takes_self=False, takes_field=False): - self.converter = converter - self.takes_self = takes_self - self.takes_field = takes_field - - ex = _AnnotationExtractor(converter) - self._first_param_type = ex.get_first_param_type() - - if not (self.takes_self or self.takes_field): - self.__call__ = lambda value, _, __: self.converter(value) - elif self.takes_self and not self.takes_field: - self.__call__ = lambda value, instance, __: self.converter( - value, instance - ) - elif not self.takes_self and self.takes_field: - self.__call__ = lambda value, __, field: self.converter( - value, field - ) - else: - self.__call__ = lambda value, instance, field: self.converter( - value, instance, field - ) - - rt = ex.get_return_type() - if rt is not None: - self.__call__.__annotations__["return"] = rt - - @staticmethod - def _get_global_name(attr_name: str) -> str: - """ - Return the name that a converter for an attribute name *attr_name* - would have. - """ - return f"__attr_converter_{attr_name}" - - def _fmt_converter_call(self, attr_name: str, value_var: str) -> str: - """ - Return a string that calls the converter for an attribute name - *attr_name* and the value in variable named *value_var* according to - `self.takes_self` and `self.takes_field`. - """ - if not (self.takes_self or self.takes_field): - return f"{self._get_global_name(attr_name)}({value_var})" - - if self.takes_self and self.takes_field: - return f"{self._get_global_name(attr_name)}({value_var}, self, attr_dict['{attr_name}'])" - - if self.takes_self: - return f"{self._get_global_name(attr_name)}({value_var}, self)" - - return f"{self._get_global_name(attr_name)}({value_var}, attr_dict['{attr_name}'])" - - def __getstate__(self): - """ - Return a dict containing only converter and takes_self -- the rest gets - computed when loading. - """ - return { - "converter": self.converter, - "takes_self": self.takes_self, - "takes_field": self.takes_field, - } - - def __setstate__(self, state): - """ - Load instance from state. - """ - self.__init__(**state) - - -_f = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=True, - init=True, - inherited=False, - ) - for name in ("converter", "takes_self", "takes_field") -] - -Converter = _add_hash( - _add_eq(_add_repr(Converter, attrs=_f), attrs=_f), attrs=_f -) - - -def make_class( - name, attrs, bases=(object,), class_body=None, **attributes_arguments -): - r""" - A quick way to create a new class called *name* with *attrs*. - - .. note:: - - ``make_class()`` is a thin wrapper around `attr.s`, not `attrs.define` - which means that it doesn't come with some of the improved defaults. - - For example, if you want the same ``on_setattr`` behavior as in - `attrs.define`, you have to pass the hooks yourself: ``make_class(..., - on_setattr=setters.pipe(setters.convert, setters.validate)`` - - .. warning:: - - It is *your* duty to ensure that the class name and the attribute names - are valid identifiers. ``make_class()`` will *not* validate them for - you. - - Args: - name (str): The name for the new class. - - attrs (list | dict): - A list of names or a dictionary of mappings of names to `attr.ib`\ - s / `attrs.field`\ s. - - The order is deduced from the order of the names or attributes - inside *attrs*. Otherwise the order of the definition of the - attributes is used. - - bases (tuple[type, ...]): Classes that the new class will subclass. - - class_body (dict): - An optional dictionary of class attributes for the new class. - - attributes_arguments: Passed unmodified to `attr.s`. - - Returns: - type: A new class with *attrs*. - - .. versionadded:: 17.1.0 *bases* - .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. - .. versionchanged:: 23.2.0 *class_body* - .. versionchanged:: 25.2.0 Class names can now be unicode. - """ - # Class identifiers are converted into the normal form NFKC while parsing - name = unicodedata.normalize("NFKC", name) - - if isinstance(attrs, dict): - cls_dict = attrs - elif isinstance(attrs, (list, tuple)): - cls_dict = {a: attrib() for a in attrs} - else: - msg = "attrs argument must be a dict or a list." - raise TypeError(msg) - - pre_init = cls_dict.pop("__attrs_pre_init__", None) - post_init = cls_dict.pop("__attrs_post_init__", None) - user_init = cls_dict.pop("__init__", None) - - body = {} - if class_body is not None: - body.update(class_body) - if pre_init is not None: - body["__attrs_pre_init__"] = pre_init - if post_init is not None: - body["__attrs_post_init__"] = post_init - if user_init is not None: - body["__init__"] = user_init - - type_ = types.new_class(name, bases, {}, lambda ns: ns.update(body)) - - # For pickling to work, the __module__ variable needs to be set to the - # frame where the class is created. Bypass this step in environments where - # sys._getframe is not defined (Jython for example) or sys._getframe is not - # defined for arguments greater than 0 (IronPython). - with contextlib.suppress(AttributeError, ValueError): - type_.__module__ = sys._getframe(1).f_globals.get( - "__name__", "__main__" - ) - - # We do it here for proper warnings with meaningful stacklevel. - cmp = attributes_arguments.pop("cmp", None) - ( - attributes_arguments["eq"], - attributes_arguments["order"], - ) = _determine_attrs_eq_order( - cmp, - attributes_arguments.get("eq"), - attributes_arguments.get("order"), - True, - ) - - cls = _attrs(these=cls_dict, **attributes_arguments)(type_) - # Only add type annotations now or "_attrs()" will complain: - cls.__annotations__ = { - k: v.type for k, v in cls_dict.items() if v.type is not None - } - return cls - - -# These are required by within this module so we define them here and merely -# import into .validators / .converters. - - -@attrs(slots=True, unsafe_hash=True) -class _AndValidator: - """ - Compose many validators to a single one. - """ - - _validators = attrib() - - def __call__(self, inst, attr, value): - for v in self._validators: - v(inst, attr, value) - - -def and_(*validators): - """ - A validator that composes multiple validators into one. - - When called on a value, it runs all wrapped validators. - - Args: - validators (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of validators. - - .. versionadded:: 17.1.0 - """ - vals = [] - for validator in validators: - vals.extend( - validator._validators - if isinstance(validator, _AndValidator) - else [validator] - ) - - return _AndValidator(tuple(vals)) - - -def pipe(*converters): - """ - A converter that composes multiple converters into one. - - When called on a value, it runs all wrapped converters, returning the - *last* value. - - Type annotations will be inferred from the wrapped converters', if they - have any. - - converters (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of converters. - - .. versionadded:: 20.1.0 - """ - - return_instance = any(isinstance(c, Converter) for c in converters) - - if return_instance: - - def pipe_converter(val, inst, field): - for c in converters: - val = ( - c(val, inst, field) if isinstance(c, Converter) else c(val) - ) - - return val - - else: - - def pipe_converter(val): - for c in converters: - val = c(val) - - return val - - if not converters: - # If the converter list is empty, pipe_converter is the identity. - A = TypeVar("A") - pipe_converter.__annotations__.update({"val": A, "return": A}) - else: - # Get parameter type from first converter. - t = _AnnotationExtractor(converters[0]).get_first_param_type() - if t: - pipe_converter.__annotations__["val"] = t - - last = converters[-1] - if not PY_3_11_PLUS and isinstance(last, Converter): - last = last.__call__ - - # Get return type from last converter. - rt = _AnnotationExtractor(last).get_return_type() - if rt: - pipe_converter.__annotations__["return"] = rt - - if return_instance: - return Converter(pipe_converter, takes_self=True, takes_field=True) - return pipe_converter diff --git a/server/libs/attr/_next_gen.py b/server/libs/attr/_next_gen.py deleted file mode 100644 index 9290664..0000000 --- a/server/libs/attr/_next_gen.py +++ /dev/null @@ -1,623 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -These are keyword-only APIs that call `attr.s` and `attr.ib` with different -default values. -""" - -from functools import partial - -from . import setters -from ._funcs import asdict as _asdict -from ._funcs import astuple as _astuple -from ._make import ( - _DEFAULT_ON_SETATTR, - NOTHING, - _frozen_setattrs, - attrib, - attrs, -) -from .exceptions import UnannotatedAttributeError - - -def define( - maybe_cls=None, - *, - these=None, - repr=None, - unsafe_hash=None, - hash=None, - init=None, - slots=True, - frozen=False, - weakref_slot=True, - str=False, - auto_attribs=None, - kw_only=False, - cache_hash=False, - auto_exc=True, - eq=None, - order=False, - auto_detect=True, - getstate_setstate=None, - on_setattr=None, - field_transformer=None, - match_args=True, -): - r""" - A class decorator that adds :term:`dunder methods` according to - :term:`fields ` specified using :doc:`type annotations `, - `field()` calls, or the *these* argument. - - Since *attrs* patches or replaces an existing class, you cannot use - `object.__init_subclass__` with *attrs* classes, because it runs too early. - As a replacement, you can define ``__attrs_init_subclass__`` on your class. - It will be called by *attrs* classes that subclass it after they're - created. See also :ref:`init-subclass`. - - Args: - slots (bool): - Create a :term:`slotted class ` that's more - memory-efficient. Slotted classes are generally superior to the - default dict classes, but have some gotchas you should know about, - so we encourage you to read the :term:`glossary entry `. - - auto_detect (bool): - Instead of setting the *init*, *repr*, *eq*, and *hash* arguments - explicitly, assume they are set to True **unless any** of the - involved methods for one of the arguments is implemented in the - *current* class (meaning, it is *not* inherited from some base - class). - - So, for example by implementing ``__eq__`` on a class yourself, - *attrs* will deduce ``eq=False`` and will create *neither* - ``__eq__`` *nor* ``__ne__`` (but Python classes come with a - sensible ``__ne__`` by default, so it *should* be enough to only - implement ``__eq__`` in most cases). - - Passing True or False` to *init*, *repr*, *eq*, or *hash* - overrides whatever *auto_detect* would determine. - - auto_exc (bool): - If the class subclasses `BaseException` (which implicitly includes - any subclass of any exception), the following happens to behave - like a well-behaved Python exception class: - - - the values for *eq*, *order*, and *hash* are ignored and the - instances compare and hash by the instance's ids [#]_ , - - all attributes that are either passed into ``__init__`` or have a - default value are additionally available as a tuple in the - ``args`` attribute, - - the value of *str* is ignored leaving ``__str__`` to base - classes. - - .. [#] - Note that *attrs* will *not* remove existing implementations of - ``__hash__`` or the equality methods. It just won't add own - ones. - - on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): - A callable that is run whenever the user attempts to set an - attribute (either by assignment like ``i.x = 42`` or by using - `setattr` like ``setattr(i, "x", 42)``). It receives the same - arguments as validators: the instance, the attribute that is being - modified, and the new value. - - If no exception is raised, the attribute is set to the return value - of the callable. - - If a list of callables is passed, they're automatically wrapped in - an `attrs.setters.pipe`. - - If left None, the default behavior is to run converters and - validators whenever an attribute is set. - - init (bool): - Create a ``__init__`` method that initializes the *attrs* - attributes. Leading underscores are stripped for the argument name, - unless an alias is set on the attribute. - - .. seealso:: - `init` shows advanced ways to customize the generated - ``__init__`` method, including executing code before and after. - - repr(bool): - Create a ``__repr__`` method with a human readable representation - of *attrs* attributes. - - str (bool): - Create a ``__str__`` method that is identical to ``__repr__``. This - is usually not necessary except for `Exception`\ s. - - eq (bool | None): - If True or None (default), add ``__eq__`` and ``__ne__`` methods - that check two instances for equality. - - .. seealso:: - `comparison` describes how to customize the comparison behavior - going as far comparing NumPy arrays. - - order (bool | None): - If True, add ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` - methods that behave like *eq* above and allow instances to be - ordered. - - They compare the instances as if they were tuples of their *attrs* - attributes if and only if the types of both classes are - *identical*. - - If `None` mirror value of *eq*. - - .. seealso:: `comparison` - - unsafe_hash (bool | None): - If None (default), the ``__hash__`` method is generated according - how *eq* and *frozen* are set. - - 1. If *both* are True, *attrs* will generate a ``__hash__`` for - you. - 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set - to None, marking it unhashable (which it is). - 3. If *eq* is False, ``__hash__`` will be left untouched meaning - the ``__hash__`` method of the base class will be used. If the - base class is `object`, this means it will fall back to id-based - hashing. - - Although not recommended, you can decide for yourself and force - *attrs* to create one (for example, if the class is immutable even - though you didn't freeze it programmatically) by passing True or - not. Both of these cases are rather special and should be used - carefully. - - .. seealso:: - - - Our documentation on `hashing`, - - Python's documentation on `object.__hash__`, - - and the `GitHub issue that led to the default \ behavior - `_ for more - details. - - hash (bool | None): - Deprecated alias for *unsafe_hash*. *unsafe_hash* takes precedence. - - cache_hash (bool): - Ensure that the object's hash code is computed only once and stored - on the object. If this is set to True, hashing must be either - explicitly or implicitly enabled for this class. If the hash code - is cached, avoid any reassignments of fields involved in hash code - computation or mutations of the objects those fields point to after - object creation. If such changes occur, the behavior of the - object's hash code is undefined. - - frozen (bool): - Make instances immutable after initialization. If someone attempts - to modify a frozen instance, `attrs.exceptions.FrozenInstanceError` - is raised. - - .. note:: - - 1. This is achieved by installing a custom ``__setattr__`` - method on your class, so you can't implement your own. - - 2. True immutability is impossible in Python. - - 3. This *does* have a minor a runtime performance `impact - ` when initializing new instances. In other - words: ``__init__`` is slightly slower with ``frozen=True``. - - 4. If a class is frozen, you cannot modify ``self`` in - ``__attrs_post_init__`` or a self-written ``__init__``. You - can circumvent that limitation by using - ``object.__setattr__(self, "attribute_name", value)``. - - 5. Subclasses of a frozen class are frozen too. - - kw_only (bool): - Make all attributes keyword-only in the generated ``__init__`` (if - *init* is False, this parameter is ignored). - - weakref_slot (bool): - Make instances weak-referenceable. This has no effect unless - *slots* is True. - - field_transformer (~typing.Callable | None): - A function that is called with the original class object and all - fields right before *attrs* finalizes the class. You can use this, - for example, to automatically add converters or validators to - fields based on their types. - - .. seealso:: `transform-fields` - - match_args (bool): - If True (default), set ``__match_args__`` on the class to support - :pep:`634` (*Structural Pattern Matching*). It is a tuple of all - non-keyword-only ``__init__`` parameter names on Python 3.10 and - later. Ignored on older Python versions. - - collect_by_mro (bool): - If True, *attrs* collects attributes from base classes correctly - according to the `method resolution order - `_. If False, *attrs* - will mimic the (wrong) behavior of `dataclasses` and :pep:`681`. - - See also `issue #428 - `_. - - getstate_setstate (bool | None): - .. note:: - - This is usually only interesting for slotted classes and you - should probably just set *auto_detect* to True. - - If True, ``__getstate__`` and ``__setstate__`` are generated and - attached to the class. This is necessary for slotted classes to be - pickleable. If left None, it's True by default for slotted classes - and False for dict classes. - - If *auto_detect* is True, and *getstate_setstate* is left None, and - **either** ``__getstate__`` or ``__setstate__`` is detected - directly on the class (meaning: not inherited), it is set to False - (this is usually what you want). - - auto_attribs (bool | None): - If True, look at type annotations to determine which attributes to - use, like `dataclasses`. If False, it will only look for explicit - :func:`field` class attributes, like classic *attrs*. - - If left None, it will guess: - - 1. If any attributes are annotated and no unannotated - `attrs.field`\ s are found, it assumes *auto_attribs=True*. - 2. Otherwise it assumes *auto_attribs=False* and tries to collect - `attrs.field`\ s. - - If *attrs* decides to look at type annotations, **all** fields - **must** be annotated. If *attrs* encounters a field that is set to - a :func:`field` / `attr.ib` but lacks a type annotation, an - `attrs.exceptions.UnannotatedAttributeError` is raised. Use - ``field_name: typing.Any = field(...)`` if you don't want to set a - type. - - .. warning:: - - For features that use the attribute name to create decorators - (for example, :ref:`validators `), you still *must* - assign :func:`field` / `attr.ib` to them. Otherwise Python will - either not find the name or try to use the default value to - call, for example, ``validator`` on it. - - Attributes annotated as `typing.ClassVar`, and attributes that are - neither annotated nor set to an `field()` are **ignored**. - - these (dict[str, object]): - A dictionary of name to the (private) return value of `field()` - mappings. This is useful to avoid the definition of your attributes - within the class body because you can't (for example, if you want - to add ``__repr__`` methods to Django models) or don't want to. - - If *these* is not `None`, *attrs* will *not* search the class body - for attributes and will *not* remove any attributes from it. - - The order is deduced from the order of the attributes inside - *these*. - - Arguably, this is a rather obscure feature. - - .. versionadded:: 20.1.0 - .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``. - .. versionadded:: 22.2.0 - *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). - .. versionchanged:: 24.1.0 - Instances are not compared as tuples of attributes anymore, but using a - big ``and`` condition. This is faster and has more correct behavior for - uncomparable values like `math.nan`. - .. versionadded:: 24.1.0 - If a class has an *inherited* classmethod called - ``__attrs_init_subclass__``, it is executed after the class is created. - .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. - .. versionadded:: 24.3.0 - Unless already present, a ``__replace__`` method is automatically - created for `copy.replace` (Python 3.13+ only). - - .. note:: - - The main differences to the classic `attr.s` are: - - - Automatically detect whether or not *auto_attribs* should be `True` - (c.f. *auto_attribs* parameter). - - Converters and validators run when attributes are set by default -- - if *frozen* is `False`. - - *slots=True* - - Usually, this has only upsides and few visible effects in everyday - programming. But it *can* lead to some surprising behaviors, so - please make sure to read :term:`slotted classes`. - - - *auto_exc=True* - - *auto_detect=True* - - *order=False* - - Some options that were only relevant on Python 2 or were kept around - for backwards-compatibility have been removed. - - """ - - def do_it(cls, auto_attribs): - return attrs( - maybe_cls=cls, - these=these, - repr=repr, - hash=hash, - unsafe_hash=unsafe_hash, - init=init, - slots=slots, - frozen=frozen, - weakref_slot=weakref_slot, - str=str, - auto_attribs=auto_attribs, - kw_only=kw_only, - cache_hash=cache_hash, - auto_exc=auto_exc, - eq=eq, - order=order, - auto_detect=auto_detect, - collect_by_mro=True, - getstate_setstate=getstate_setstate, - on_setattr=on_setattr, - field_transformer=field_transformer, - match_args=match_args, - ) - - def wrap(cls): - """ - Making this a wrapper ensures this code runs during class creation. - - We also ensure that frozen-ness of classes is inherited. - """ - nonlocal frozen, on_setattr - - had_on_setattr = on_setattr not in (None, setters.NO_OP) - - # By default, mutable classes convert & validate on setattr. - if frozen is False and on_setattr is None: - on_setattr = _DEFAULT_ON_SETATTR - - # However, if we subclass a frozen class, we inherit the immutability - # and disable on_setattr. - for base_cls in cls.__bases__: - if base_cls.__setattr__ is _frozen_setattrs: - if had_on_setattr: - msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)." - raise ValueError(msg) - - on_setattr = setters.NO_OP - break - - if auto_attribs is not None: - return do_it(cls, auto_attribs) - - try: - return do_it(cls, True) - except UnannotatedAttributeError: - return do_it(cls, False) - - # maybe_cls's type depends on the usage of the decorator. It's a class - # if it's used as `@attrs` but `None` if used as `@attrs()`. - if maybe_cls is None: - return wrap - - return wrap(maybe_cls) - - -mutable = define -frozen = partial(define, frozen=True, on_setattr=None) - - -def field( - *, - default=NOTHING, - validator=None, - repr=True, - hash=None, - init=True, - metadata=None, - type=None, - converter=None, - factory=None, - kw_only=False, - eq=None, - order=None, - on_setattr=None, - alias=None, -): - """ - Create a new :term:`field` / :term:`attribute` on a class. - - .. warning:: - - Does **nothing** unless the class is also decorated with - `attrs.define` (or similar)! - - Args: - default: - A value that is used if an *attrs*-generated ``__init__`` is used - and no value is passed while instantiating or the attribute is - excluded using ``init=False``. - - If the value is an instance of `attrs.Factory`, its callable will - be used to construct a new value (useful for mutable data types - like lists or dicts). - - If a default is not set (or set manually to `attrs.NOTHING`), a - value *must* be supplied when instantiating; otherwise a - `TypeError` will be raised. - - .. seealso:: `defaults` - - factory (~typing.Callable): - Syntactic sugar for ``default=attr.Factory(factory)``. - - validator (~typing.Callable | list[~typing.Callable]): - Callable that is called by *attrs*-generated ``__init__`` methods - after the instance has been initialized. They receive the - initialized instance, the :func:`~attrs.Attribute`, and the passed - value. - - The return value is *not* inspected so the validator has to throw - an exception itself. - - If a `list` is passed, its items are treated as validators and must - all pass. - - Validators can be globally disabled and re-enabled using - `attrs.validators.get_disabled` / `attrs.validators.set_disabled`. - - The validator can also be set using decorator notation as shown - below. - - .. seealso:: :ref:`validators` - - repr (bool | ~typing.Callable): - Include this attribute in the generated ``__repr__`` method. If - True, include the attribute; if False, omit it. By default, the - built-in ``repr()`` function is used. To override how the attribute - value is formatted, pass a ``callable`` that takes a single value - and returns a string. Note that the resulting string is used as-is, - which means it will be used directly *instead* of calling - ``repr()`` (the default). - - eq (bool | ~typing.Callable): - If True (default), include this attribute in the generated - ``__eq__`` and ``__ne__`` methods that check two instances for - equality. To override how the attribute value is compared, pass a - callable that takes a single value and returns the value to be - compared. - - .. seealso:: `comparison` - - order (bool | ~typing.Callable): - If True (default), include this attributes in the generated - ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To - override how the attribute value is ordered, pass a callable that - takes a single value and returns the value to be ordered. - - .. seealso:: `comparison` - - hash (bool | None): - Include this attribute in the generated ``__hash__`` method. If - None (default), mirror *eq*'s value. This is the correct behavior - according the Python spec. Setting this value to anything else - than None is *discouraged*. - - .. seealso:: `hashing` - - init (bool): - Include this attribute in the generated ``__init__`` method. - - It is possible to set this to False and set a default value. In - that case this attributed is unconditionally initialized with the - specified default value or factory. - - .. seealso:: `init` - - converter (typing.Callable | Converter): - A callable that is called by *attrs*-generated ``__init__`` methods - to convert attribute's value to the desired format. - - If a vanilla callable is passed, it is given the passed-in value as - the only positional argument. It is possible to receive additional - arguments by wrapping the callable in a `Converter`. - - Either way, the returned value will be used as the new value of the - attribute. The value is converted before being passed to the - validator, if any. - - .. seealso:: :ref:`converters` - - metadata (dict | None): - An arbitrary mapping, to be used by third-party code. - - .. seealso:: `extending-metadata`. - - type (type): - The type of the attribute. Nowadays, the preferred method to - specify the type is using a variable annotation (see :pep:`526`). - This argument is provided for backwards-compatibility and for usage - with `make_class`. Regardless of the approach used, the type will - be stored on ``Attribute.type``. - - Please note that *attrs* doesn't do anything with this metadata by - itself. You can use it as part of your own code or for `static type - checking `. - - kw_only (bool): - Make this attribute keyword-only in the generated ``__init__`` (if - ``init`` is False, this parameter is ignored). - - on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): - Allows to overwrite the *on_setattr* setting from `attr.s`. If left - None, the *on_setattr* value from `attr.s` is used. Set to - `attrs.setters.NO_OP` to run **no** `setattr` hooks for this - attribute -- regardless of the setting in `define()`. - - alias (str | None): - Override this attribute's parameter name in the generated - ``__init__`` method. If left None, default to ``name`` stripped - of leading underscores. See `private-attributes`. - - .. versionadded:: 20.1.0 - .. versionchanged:: 21.1.0 - *eq*, *order*, and *cmp* also accept a custom callable - .. versionadded:: 22.2.0 *alias* - .. versionadded:: 23.1.0 - The *type* parameter has been re-added; mostly for `attrs.make_class`. - Please note that type checkers ignore this metadata. - - .. seealso:: - - `attr.ib` - """ - return attrib( - default=default, - validator=validator, - repr=repr, - hash=hash, - init=init, - metadata=metadata, - type=type, - converter=converter, - factory=factory, - kw_only=kw_only, - eq=eq, - order=order, - on_setattr=on_setattr, - alias=alias, - ) - - -def asdict(inst, *, recurse=True, filter=None, value_serializer=None): - """ - Same as `attr.asdict`, except that collections types are always retained - and dict is always used as *dict_factory*. - - .. versionadded:: 21.3.0 - """ - return _asdict( - inst=inst, - recurse=recurse, - filter=filter, - value_serializer=value_serializer, - retain_collection_types=True, - ) - - -def astuple(inst, *, recurse=True, filter=None): - """ - Same as `attr.astuple`, except that collections types are always retained - and `tuple` is always used as the *tuple_factory*. - - .. versionadded:: 21.3.0 - """ - return _astuple( - inst=inst, recurse=recurse, filter=filter, retain_collection_types=True - ) diff --git a/server/libs/attr/_typing_compat.pyi b/server/libs/attr/_typing_compat.pyi deleted file mode 100644 index ca7b71e..0000000 --- a/server/libs/attr/_typing_compat.pyi +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Any, ClassVar, Protocol - -# MYPY is a special constant in mypy which works the same way as `TYPE_CHECKING`. -MYPY = False - -if MYPY: - # A protocol to be able to statically accept an attrs class. - class AttrsInstance_(Protocol): - __attrs_attrs__: ClassVar[Any] - -else: - # For type checkers without plug-in support use an empty protocol that - # will (hopefully) be combined into a union. - class AttrsInstance_(Protocol): - pass diff --git a/server/libs/attr/_version_info.py b/server/libs/attr/_version_info.py deleted file mode 100644 index 51a1312..0000000 --- a/server/libs/attr/_version_info.py +++ /dev/null @@ -1,86 +0,0 @@ -# SPDX-License-Identifier: MIT - - -from functools import total_ordering - -from ._funcs import astuple -from ._make import attrib, attrs - - -@total_ordering -@attrs(eq=False, order=False, slots=True, frozen=True) -class VersionInfo: - """ - A version object that can be compared to tuple of length 1--4: - - >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2) - True - >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1) - True - >>> vi = attr.VersionInfo(19, 2, 0, "final") - >>> vi < (19, 1, 1) - False - >>> vi < (19,) - False - >>> vi == (19, 2,) - True - >>> vi == (19, 2, 1) - False - - .. versionadded:: 19.2 - """ - - year = attrib(type=int) - minor = attrib(type=int) - micro = attrib(type=int) - releaselevel = attrib(type=str) - - @classmethod - def _from_version_string(cls, s): - """ - Parse *s* and return a _VersionInfo. - """ - v = s.split(".") - if len(v) == 3: - v.append("final") - - return cls( - year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3] - ) - - def _ensure_tuple(self, other): - """ - Ensure *other* is a tuple of a valid length. - - Returns a possibly transformed *other* and ourselves as a tuple of - the same length as *other*. - """ - - if self.__class__ is other.__class__: - other = astuple(other) - - if not isinstance(other, tuple): - raise NotImplementedError - - if not (1 <= len(other) <= 4): - raise NotImplementedError - - return astuple(self)[: len(other)], other - - def __eq__(self, other): - try: - us, them = self._ensure_tuple(other) - except NotImplementedError: - return NotImplemented - - return us == them - - def __lt__(self, other): - try: - us, them = self._ensure_tuple(other) - except NotImplementedError: - return NotImplemented - - # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't - # have to do anything special with releaselevel for now. - return us < them diff --git a/server/libs/attr/_version_info.pyi b/server/libs/attr/_version_info.pyi deleted file mode 100644 index 45ced08..0000000 --- a/server/libs/attr/_version_info.pyi +++ /dev/null @@ -1,9 +0,0 @@ -class VersionInfo: - @property - def year(self) -> int: ... - @property - def minor(self) -> int: ... - @property - def micro(self) -> int: ... - @property - def releaselevel(self) -> str: ... diff --git a/server/libs/attr/converters.py b/server/libs/attr/converters.py deleted file mode 100644 index 0a79dee..0000000 --- a/server/libs/attr/converters.py +++ /dev/null @@ -1,162 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful converters. -""" - -import typing - -from ._compat import _AnnotationExtractor -from ._make import NOTHING, Converter, Factory, pipe - - -__all__ = [ - "default_if_none", - "optional", - "pipe", - "to_bool", -] - - -def optional(converter): - """ - A converter that allows an attribute to be optional. An optional attribute - is one which can be set to `None`. - - Type annotations will be inferred from the wrapped converter's, if it has - any. - - Args: - converter (typing.Callable): - the converter that is used for non-`None` values. - - .. versionadded:: 17.1.0 - """ - - if isinstance(converter, Converter): - - def optional_converter(val, inst, field): - if val is None: - return None - return converter(val, inst, field) - - else: - - def optional_converter(val): - if val is None: - return None - return converter(val) - - xtr = _AnnotationExtractor(converter) - - t = xtr.get_first_param_type() - if t: - optional_converter.__annotations__["val"] = typing.Optional[t] - - rt = xtr.get_return_type() - if rt: - optional_converter.__annotations__["return"] = typing.Optional[rt] - - if isinstance(converter, Converter): - return Converter(optional_converter, takes_self=True, takes_field=True) - - return optional_converter - - -def default_if_none(default=NOTHING, factory=None): - """ - A converter that allows to replace `None` values by *default* or the result - of *factory*. - - Args: - default: - Value to be used if `None` is passed. Passing an instance of - `attrs.Factory` is supported, however the ``takes_self`` option is - *not*. - - factory (typing.Callable): - A callable that takes no parameters whose result is used if `None` - is passed. - - Raises: - TypeError: If **neither** *default* or *factory* is passed. - - TypeError: If **both** *default* and *factory* are passed. - - ValueError: - If an instance of `attrs.Factory` is passed with - ``takes_self=True``. - - .. versionadded:: 18.2.0 - """ - if default is NOTHING and factory is None: - msg = "Must pass either `default` or `factory`." - raise TypeError(msg) - - if default is not NOTHING and factory is not None: - msg = "Must pass either `default` or `factory` but not both." - raise TypeError(msg) - - if factory is not None: - default = Factory(factory) - - if isinstance(default, Factory): - if default.takes_self: - msg = "`takes_self` is not supported by default_if_none." - raise ValueError(msg) - - def default_if_none_converter(val): - if val is not None: - return val - - return default.factory() - - else: - - def default_if_none_converter(val): - if val is not None: - return val - - return default - - return default_if_none_converter - - -def to_bool(val): - """ - Convert "boolean" strings (for example, from environment variables) to real - booleans. - - Values mapping to `True`: - - - ``True`` - - ``"true"`` / ``"t"`` - - ``"yes"`` / ``"y"`` - - ``"on"`` - - ``"1"`` - - ``1`` - - Values mapping to `False`: - - - ``False`` - - ``"false"`` / ``"f"`` - - ``"no"`` / ``"n"`` - - ``"off"`` - - ``"0"`` - - ``0`` - - Raises: - ValueError: For any other value. - - .. versionadded:: 21.3.0 - """ - if isinstance(val, str): - val = val.lower() - - if val in (True, "true", "t", "yes", "y", "on", "1", 1): - return True - if val in (False, "false", "f", "no", "n", "off", "0", 0): - return False - - msg = f"Cannot convert value to bool: {val!r}" - raise ValueError(msg) diff --git a/server/libs/attr/converters.pyi b/server/libs/attr/converters.pyi deleted file mode 100644 index 12bd0c4..0000000 --- a/server/libs/attr/converters.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Callable, Any, overload - -from attrs import _ConverterType, _CallableConverterType - -@overload -def pipe(*validators: _CallableConverterType) -> _CallableConverterType: ... -@overload -def pipe(*validators: _ConverterType) -> _ConverterType: ... -@overload -def optional(converter: _CallableConverterType) -> _CallableConverterType: ... -@overload -def optional(converter: _ConverterType) -> _ConverterType: ... -@overload -def default_if_none(default: Any) -> _CallableConverterType: ... -@overload -def default_if_none( - *, factory: Callable[[], Any] -) -> _CallableConverterType: ... -def to_bool(val: str | int | bool) -> bool: ... diff --git a/server/libs/attr/exceptions.py b/server/libs/attr/exceptions.py deleted file mode 100644 index 3b7abb8..0000000 --- a/server/libs/attr/exceptions.py +++ /dev/null @@ -1,95 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - -from typing import ClassVar - - -class FrozenError(AttributeError): - """ - A frozen/immutable instance or attribute have been attempted to be - modified. - - It mirrors the behavior of ``namedtuples`` by using the same error message - and subclassing `AttributeError`. - - .. versionadded:: 20.1.0 - """ - - msg = "can't set attribute" - args: ClassVar[tuple[str]] = [msg] - - -class FrozenInstanceError(FrozenError): - """ - A frozen instance has been attempted to be modified. - - .. versionadded:: 16.1.0 - """ - - -class FrozenAttributeError(FrozenError): - """ - A frozen attribute has been attempted to be modified. - - .. versionadded:: 20.1.0 - """ - - -class AttrsAttributeNotFoundError(ValueError): - """ - An *attrs* function couldn't find an attribute that the user asked for. - - .. versionadded:: 16.2.0 - """ - - -class NotAnAttrsClassError(ValueError): - """ - A non-*attrs* class has been passed into an *attrs* function. - - .. versionadded:: 16.2.0 - """ - - -class DefaultAlreadySetError(RuntimeError): - """ - A default has been set when defining the field and is attempted to be reset - using the decorator. - - .. versionadded:: 17.1.0 - """ - - -class UnannotatedAttributeError(RuntimeError): - """ - A class with ``auto_attribs=True`` has a field without a type annotation. - - .. versionadded:: 17.3.0 - """ - - -class PythonTooOldError(RuntimeError): - """ - It was attempted to use an *attrs* feature that requires a newer Python - version. - - .. versionadded:: 18.2.0 - """ - - -class NotCallableError(TypeError): - """ - A field requiring a callable has been set with a value that is not - callable. - - .. versionadded:: 19.2.0 - """ - - def __init__(self, msg, value): - super(TypeError, self).__init__(msg, value) - self.msg = msg - self.value = value - - def __str__(self): - return str(self.msg) diff --git a/server/libs/attr/exceptions.pyi b/server/libs/attr/exceptions.pyi deleted file mode 100644 index f268011..0000000 --- a/server/libs/attr/exceptions.pyi +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Any - -class FrozenError(AttributeError): - msg: str = ... - -class FrozenInstanceError(FrozenError): ... -class FrozenAttributeError(FrozenError): ... -class AttrsAttributeNotFoundError(ValueError): ... -class NotAnAttrsClassError(ValueError): ... -class DefaultAlreadySetError(RuntimeError): ... -class UnannotatedAttributeError(RuntimeError): ... -class PythonTooOldError(RuntimeError): ... - -class NotCallableError(TypeError): - msg: str = ... - value: Any = ... - def __init__(self, msg: str, value: Any) -> None: ... diff --git a/server/libs/attr/filters.py b/server/libs/attr/filters.py deleted file mode 100644 index 689b170..0000000 --- a/server/libs/attr/filters.py +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful filters for `attrs.asdict` and `attrs.astuple`. -""" - -from ._make import Attribute - - -def _split_what(what): - """ - Returns a tuple of `frozenset`s of classes and attributes. - """ - return ( - frozenset(cls for cls in what if isinstance(cls, type)), - frozenset(cls for cls in what if isinstance(cls, str)), - frozenset(cls for cls in what if isinstance(cls, Attribute)), - ) - - -def include(*what): - """ - Create a filter that only allows *what*. - - Args: - what (list[type, str, attrs.Attribute]): - What to include. Can be a type, a name, or an attribute. - - Returns: - Callable: - A callable that can be passed to `attrs.asdict`'s and - `attrs.astuple`'s *filter* argument. - - .. versionchanged:: 23.1.0 Accept strings with field names. - """ - cls, names, attrs = _split_what(what) - - def include_(attribute, value): - return ( - value.__class__ in cls - or attribute.name in names - or attribute in attrs - ) - - return include_ - - -def exclude(*what): - """ - Create a filter that does **not** allow *what*. - - Args: - what (list[type, str, attrs.Attribute]): - What to exclude. Can be a type, a name, or an attribute. - - Returns: - Callable: - A callable that can be passed to `attrs.asdict`'s and - `attrs.astuple`'s *filter* argument. - - .. versionchanged:: 23.3.0 Accept field name string as input argument - """ - cls, names, attrs = _split_what(what) - - def exclude_(attribute, value): - return not ( - value.__class__ in cls - or attribute.name in names - or attribute in attrs - ) - - return exclude_ diff --git a/server/libs/attr/filters.pyi b/server/libs/attr/filters.pyi deleted file mode 100644 index 974abdc..0000000 --- a/server/libs/attr/filters.pyi +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Any - -from . import Attribute, _FilterType - -def include(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... -def exclude(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... diff --git a/server/libs/attr/setters.py b/server/libs/attr/setters.py deleted file mode 100644 index 78b0839..0000000 --- a/server/libs/attr/setters.py +++ /dev/null @@ -1,79 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly used hooks for on_setattr. -""" - -from . import _config -from .exceptions import FrozenAttributeError - - -def pipe(*setters): - """ - Run all *setters* and return the return value of the last one. - - .. versionadded:: 20.1.0 - """ - - def wrapped_pipe(instance, attrib, new_value): - rv = new_value - - for setter in setters: - rv = setter(instance, attrib, rv) - - return rv - - return wrapped_pipe - - -def frozen(_, __, ___): - """ - Prevent an attribute to be modified. - - .. versionadded:: 20.1.0 - """ - raise FrozenAttributeError - - -def validate(instance, attrib, new_value): - """ - Run *attrib*'s validator on *new_value* if it has one. - - .. versionadded:: 20.1.0 - """ - if _config._run_validators is False: - return new_value - - v = attrib.validator - if not v: - return new_value - - v(instance, attrib, new_value) - - return new_value - - -def convert(instance, attrib, new_value): - """ - Run *attrib*'s converter -- if it has one -- on *new_value* and return the - result. - - .. versionadded:: 20.1.0 - """ - c = attrib.converter - if c: - # This can be removed once we drop 3.8 and use attrs.Converter instead. - from ._make import Converter - - if not isinstance(c, Converter): - return c(new_value) - - return c(new_value, instance, attrib) - - return new_value - - -# Sentinel for disabling class-wide *on_setattr* hooks for certain attributes. -# Sphinx's autodata stopped working, so the docstring is inlined in the API -# docs. -NO_OP = object() diff --git a/server/libs/attr/setters.pyi b/server/libs/attr/setters.pyi deleted file mode 100644 index 73abf36..0000000 --- a/server/libs/attr/setters.pyi +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Any, NewType, NoReturn, TypeVar - -from . import Attribute -from attrs import _OnSetAttrType - -_T = TypeVar("_T") - -def frozen( - instance: Any, attribute: Attribute[Any], new_value: Any -) -> NoReturn: ... -def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ... -def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ... - -# convert is allowed to return Any, because they can be chained using pipe. -def convert( - instance: Any, attribute: Attribute[Any], new_value: Any -) -> Any: ... - -_NoOpType = NewType("_NoOpType", object) -NO_OP: _NoOpType diff --git a/server/libs/attr/validators.py b/server/libs/attr/validators.py deleted file mode 100644 index e7b7552..0000000 --- a/server/libs/attr/validators.py +++ /dev/null @@ -1,710 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful validators. -""" - -import operator -import re - -from contextlib import contextmanager -from re import Pattern - -from ._config import get_run_validators, set_run_validators -from ._make import _AndValidator, and_, attrib, attrs -from .converters import default_if_none -from .exceptions import NotCallableError - - -__all__ = [ - "and_", - "deep_iterable", - "deep_mapping", - "disabled", - "ge", - "get_disabled", - "gt", - "in_", - "instance_of", - "is_callable", - "le", - "lt", - "matches_re", - "max_len", - "min_len", - "not_", - "optional", - "or_", - "set_disabled", -] - - -def set_disabled(disabled): - """ - Globally disable or enable running validators. - - By default, they are run. - - Args: - disabled (bool): If `True`, disable running all validators. - - .. warning:: - - This function is not thread-safe! - - .. versionadded:: 21.3.0 - """ - set_run_validators(not disabled) - - -def get_disabled(): - """ - Return a bool indicating whether validators are currently disabled or not. - - Returns: - bool:`True` if validators are currently disabled. - - .. versionadded:: 21.3.0 - """ - return not get_run_validators() - - -@contextmanager -def disabled(): - """ - Context manager that disables running validators within its context. - - .. warning:: - - This context manager is not thread-safe! - - .. versionadded:: 21.3.0 - """ - set_run_validators(False) - try: - yield - finally: - set_run_validators(True) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _InstanceOfValidator: - type = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not isinstance(value, self.type): - msg = f"'{attr.name}' must be {self.type!r} (got {value!r} that is a {value.__class__!r})." - raise TypeError( - msg, - attr, - self.type, - value, - ) - - def __repr__(self): - return f"" - - -def instance_of(type): - """ - A validator that raises a `TypeError` if the initializer is called with a - wrong type for this particular attribute (checks are performed using - `isinstance` therefore it's also valid to pass a tuple of types). - - Args: - type (type | tuple[type]): The type to check for. - - Raises: - TypeError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected type, and the value it got. - """ - return _InstanceOfValidator(type) - - -@attrs(repr=False, frozen=True, slots=True) -class _MatchesReValidator: - pattern = attrib() - match_func = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not self.match_func(value): - msg = f"'{attr.name}' must match regex {self.pattern.pattern!r} ({value!r} doesn't)" - raise ValueError( - msg, - attr, - self.pattern, - value, - ) - - def __repr__(self): - return f"" - - -def matches_re(regex, flags=0, func=None): - r""" - A validator that raises `ValueError` if the initializer is called with a - string that doesn't match *regex*. - - Args: - regex (str, re.Pattern): - A regex string or precompiled pattern to match against - - flags (int): - Flags that will be passed to the underlying re function (default 0) - - func (typing.Callable): - Which underlying `re` function to call. Valid options are - `re.fullmatch`, `re.search`, and `re.match`; the default `None` - means `re.fullmatch`. For performance reasons, the pattern is - always precompiled using `re.compile`. - - .. versionadded:: 19.2.0 - .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern. - """ - valid_funcs = (re.fullmatch, None, re.search, re.match) - if func not in valid_funcs: - msg = "'func' must be one of {}.".format( - ", ".join( - sorted((e and e.__name__) or "None" for e in set(valid_funcs)) - ) - ) - raise ValueError(msg) - - if isinstance(regex, Pattern): - if flags: - msg = "'flags' can only be used with a string pattern; pass flags to re.compile() instead" - raise TypeError(msg) - pattern = regex - else: - pattern = re.compile(regex, flags) - - if func is re.match: - match_func = pattern.match - elif func is re.search: - match_func = pattern.search - else: - match_func = pattern.fullmatch - - return _MatchesReValidator(pattern, match_func) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _OptionalValidator: - validator = attrib() - - def __call__(self, inst, attr, value): - if value is None: - return - - self.validator(inst, attr, value) - - def __repr__(self): - return f"" - - -def optional(validator): - """ - A validator that makes an attribute optional. An optional attribute is one - which can be set to `None` in addition to satisfying the requirements of - the sub-validator. - - Args: - validator - (typing.Callable | tuple[typing.Callable] | list[typing.Callable]): - A validator (or validators) that is used for non-`None` values. - - .. versionadded:: 15.1.0 - .. versionchanged:: 17.1.0 *validator* can be a list of validators. - .. versionchanged:: 23.1.0 *validator* can also be a tuple of validators. - """ - if isinstance(validator, (list, tuple)): - return _OptionalValidator(_AndValidator(validator)) - - return _OptionalValidator(validator) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _InValidator: - options = attrib() - _original_options = attrib(hash=False) - - def __call__(self, inst, attr, value): - try: - in_options = value in self.options - except TypeError: # e.g. `1 in "abc"` - in_options = False - - if not in_options: - msg = f"'{attr.name}' must be in {self._original_options!r} (got {value!r})" - raise ValueError( - msg, - attr, - self._original_options, - value, - ) - - def __repr__(self): - return f"" - - -def in_(options): - """ - A validator that raises a `ValueError` if the initializer is called with a - value that does not belong in the *options* provided. - - The check is performed using ``value in options``, so *options* has to - support that operation. - - To keep the validator hashable, dicts, lists, and sets are transparently - transformed into a `tuple`. - - Args: - options: Allowed options. - - Raises: - ValueError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected options, and the value it got. - - .. versionadded:: 17.1.0 - .. versionchanged:: 22.1.0 - The ValueError was incomplete until now and only contained the human - readable error message. Now it contains all the information that has - been promised since 17.1.0. - .. versionchanged:: 24.1.0 - *options* that are a list, dict, or a set are now transformed into a - tuple to keep the validator hashable. - """ - repr_options = options - if isinstance(options, (list, dict, set)): - options = tuple(options) - - return _InValidator(options, repr_options) - - -@attrs(repr=False, slots=False, unsafe_hash=True) -class _IsCallableValidator: - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not callable(value): - message = ( - "'{name}' must be callable " - "(got {value!r} that is a {actual!r})." - ) - raise NotCallableError( - msg=message.format( - name=attr.name, value=value, actual=value.__class__ - ), - value=value, - ) - - def __repr__(self): - return "" - - -def is_callable(): - """ - A validator that raises a `attrs.exceptions.NotCallableError` if the - initializer is called with a value for this particular attribute that is - not callable. - - .. versionadded:: 19.1.0 - - Raises: - attrs.exceptions.NotCallableError: - With a human readable error message containing the attribute - (`attrs.Attribute`) name, and the value it got. - """ - return _IsCallableValidator() - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _DeepIterable: - member_validator = attrib(validator=is_callable()) - iterable_validator = attrib( - default=None, validator=optional(is_callable()) - ) - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if self.iterable_validator is not None: - self.iterable_validator(inst, attr, value) - - for member in value: - self.member_validator(inst, attr, member) - - def __repr__(self): - iterable_identifier = ( - "" - if self.iterable_validator is None - else f" {self.iterable_validator!r}" - ) - return ( - f"" - ) - - -def deep_iterable(member_validator, iterable_validator=None): - """ - A validator that performs deep validation of an iterable. - - Args: - member_validator: Validator to apply to iterable members. - - iterable_validator: - Validator to apply to iterable itself (optional). - - Raises - TypeError: if any sub-validators fail - - .. versionadded:: 19.1.0 - """ - if isinstance(member_validator, (list, tuple)): - member_validator = and_(*member_validator) - return _DeepIterable(member_validator, iterable_validator) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _DeepMapping: - key_validator = attrib(validator=is_callable()) - value_validator = attrib(validator=is_callable()) - mapping_validator = attrib(default=None, validator=optional(is_callable())) - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if self.mapping_validator is not None: - self.mapping_validator(inst, attr, value) - - for key in value: - self.key_validator(inst, attr, key) - self.value_validator(inst, attr, value[key]) - - def __repr__(self): - return f"" - - -def deep_mapping(key_validator, value_validator, mapping_validator=None): - """ - A validator that performs deep validation of a dictionary. - - Args: - key_validator: Validator to apply to dictionary keys. - - value_validator: Validator to apply to dictionary values. - - mapping_validator: - Validator to apply to top-level mapping attribute (optional). - - .. versionadded:: 19.1.0 - - Raises: - TypeError: if any sub-validators fail - """ - return _DeepMapping(key_validator, value_validator, mapping_validator) - - -@attrs(repr=False, frozen=True, slots=True) -class _NumberValidator: - bound = attrib() - compare_op = attrib() - compare_func = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not self.compare_func(value, self.bound): - msg = f"'{attr.name}' must be {self.compare_op} {self.bound}: {value}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def lt(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number larger or equal to *val*. - - The validator uses `operator.lt` to compare the values. - - Args: - val: Exclusive upper bound for values. - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, "<", operator.lt) - - -def le(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number greater than *val*. - - The validator uses `operator.le` to compare the values. - - Args: - val: Inclusive upper bound for values. - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, "<=", operator.le) - - -def ge(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number smaller than *val*. - - The validator uses `operator.ge` to compare the values. - - Args: - val: Inclusive lower bound for values - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, ">=", operator.ge) - - -def gt(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number smaller or equal to *val*. - - The validator uses `operator.ge` to compare the values. - - Args: - val: Exclusive lower bound for values - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, ">", operator.gt) - - -@attrs(repr=False, frozen=True, slots=True) -class _MaxLengthValidator: - max_length = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if len(value) > self.max_length: - msg = f"Length of '{attr.name}' must be <= {self.max_length}: {len(value)}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def max_len(length): - """ - A validator that raises `ValueError` if the initializer is called - with a string or iterable that is longer than *length*. - - Args: - length (int): Maximum length of the string or iterable - - .. versionadded:: 21.3.0 - """ - return _MaxLengthValidator(length) - - -@attrs(repr=False, frozen=True, slots=True) -class _MinLengthValidator: - min_length = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if len(value) < self.min_length: - msg = f"Length of '{attr.name}' must be >= {self.min_length}: {len(value)}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def min_len(length): - """ - A validator that raises `ValueError` if the initializer is called - with a string or iterable that is shorter than *length*. - - Args: - length (int): Minimum length of the string or iterable - - .. versionadded:: 22.1.0 - """ - return _MinLengthValidator(length) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _SubclassOfValidator: - type = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not issubclass(value, self.type): - msg = f"'{attr.name}' must be a subclass of {self.type!r} (got {value!r})." - raise TypeError( - msg, - attr, - self.type, - value, - ) - - def __repr__(self): - return f"" - - -def _subclass_of(type): - """ - A validator that raises a `TypeError` if the initializer is called with a - wrong type for this particular attribute (checks are performed using - `issubclass` therefore it's also valid to pass a tuple of types). - - Args: - type (type | tuple[type, ...]): The type(s) to check for. - - Raises: - TypeError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected type, and the value it got. - """ - return _SubclassOfValidator(type) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _NotValidator: - validator = attrib() - msg = attrib( - converter=default_if_none( - "not_ validator child '{validator!r}' " - "did not raise a captured error" - ) - ) - exc_types = attrib( - validator=deep_iterable( - member_validator=_subclass_of(Exception), - iterable_validator=instance_of(tuple), - ), - ) - - def __call__(self, inst, attr, value): - try: - self.validator(inst, attr, value) - except self.exc_types: - pass # suppress error to invert validity - else: - raise ValueError( - self.msg.format( - validator=self.validator, - exc_types=self.exc_types, - ), - attr, - self.validator, - value, - self.exc_types, - ) - - def __repr__(self): - return f"" - - -def not_(validator, *, msg=None, exc_types=(ValueError, TypeError)): - """ - A validator that wraps and logically 'inverts' the validator passed to it. - It will raise a `ValueError` if the provided validator *doesn't* raise a - `ValueError` or `TypeError` (by default), and will suppress the exception - if the provided validator *does*. - - Intended to be used with existing validators to compose logic without - needing to create inverted variants, for example, ``not_(in_(...))``. - - Args: - validator: A validator to be logically inverted. - - msg (str): - Message to raise if validator fails. Formatted with keys - ``exc_types`` and ``validator``. - - exc_types (tuple[type, ...]): - Exception type(s) to capture. Other types raised by child - validators will not be intercepted and pass through. - - Raises: - ValueError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the validator that failed to raise an - exception, the value it got, and the expected exception types. - - .. versionadded:: 22.2.0 - """ - try: - exc_types = tuple(exc_types) - except TypeError: - exc_types = (exc_types,) - return _NotValidator(validator, msg, exc_types) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _OrValidator: - validators = attrib() - - def __call__(self, inst, attr, value): - for v in self.validators: - try: - v(inst, attr, value) - except Exception: # noqa: BLE001, PERF203, S112 - continue - else: - return - - msg = f"None of {self.validators!r} satisfied for value {value!r}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def or_(*validators): - """ - A validator that composes multiple validators into one. - - When called on a value, it runs all wrapped validators until one of them is - satisfied. - - Args: - validators (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of validators. - - Raises: - ValueError: - If no validator is satisfied. Raised with a human-readable error - message listing all the wrapped validators and the value that - failed all of them. - - .. versionadded:: 24.1.0 - """ - vals = [] - for v in validators: - vals.extend(v.validators if isinstance(v, _OrValidator) else [v]) - - return _OrValidator(tuple(vals)) diff --git a/server/libs/attr/validators.pyi b/server/libs/attr/validators.pyi deleted file mode 100644 index a0fdda7..0000000 --- a/server/libs/attr/validators.pyi +++ /dev/null @@ -1,86 +0,0 @@ -from types import UnionType -from typing import ( - Any, - AnyStr, - Callable, - Container, - ContextManager, - Iterable, - Mapping, - Match, - Pattern, - TypeVar, - overload, -) - -from attrs import _ValidatorType -from attrs import _ValidatorArgType - -_T = TypeVar("_T") -_T1 = TypeVar("_T1") -_T2 = TypeVar("_T2") -_T3 = TypeVar("_T3") -_I = TypeVar("_I", bound=Iterable) -_K = TypeVar("_K") -_V = TypeVar("_V") -_M = TypeVar("_M", bound=Mapping) - -def set_disabled(run: bool) -> None: ... -def get_disabled() -> bool: ... -def disabled() -> ContextManager[None]: ... - -# To be more precise on instance_of use some overloads. -# If there are more than 3 items in the tuple then we fall back to Any -@overload -def instance_of(type: type[_T]) -> _ValidatorType[_T]: ... -@overload -def instance_of(type: tuple[type[_T]]) -> _ValidatorType[_T]: ... -@overload -def instance_of( - type: tuple[type[_T1], type[_T2]], -) -> _ValidatorType[_T1 | _T2]: ... -@overload -def instance_of( - type: tuple[type[_T1], type[_T2], type[_T3]], -) -> _ValidatorType[_T1 | _T2 | _T3]: ... -@overload -def instance_of(type: tuple[type, ...]) -> _ValidatorType[Any]: ... -@overload -def instance_of(type: UnionType) -> _ValidatorType[Any]: ... -def optional( - validator: ( - _ValidatorType[_T] - | list[_ValidatorType[_T]] - | tuple[_ValidatorType[_T]] - ), -) -> _ValidatorType[_T | None]: ... -def in_(options: Container[_T]) -> _ValidatorType[_T]: ... -def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... -def matches_re( - regex: Pattern[AnyStr] | AnyStr, - flags: int = ..., - func: Callable[[AnyStr, AnyStr, int], Match[AnyStr] | None] | None = ..., -) -> _ValidatorType[AnyStr]: ... -def deep_iterable( - member_validator: _ValidatorArgType[_T], - iterable_validator: _ValidatorType[_I] | None = ..., -) -> _ValidatorType[_I]: ... -def deep_mapping( - key_validator: _ValidatorType[_K], - value_validator: _ValidatorType[_V], - mapping_validator: _ValidatorType[_M] | None = ..., -) -> _ValidatorType[_M]: ... -def is_callable() -> _ValidatorType[_T]: ... -def lt(val: _T) -> _ValidatorType[_T]: ... -def le(val: _T) -> _ValidatorType[_T]: ... -def ge(val: _T) -> _ValidatorType[_T]: ... -def gt(val: _T) -> _ValidatorType[_T]: ... -def max_len(length: int) -> _ValidatorType[_T]: ... -def min_len(length: int) -> _ValidatorType[_T]: ... -def not_( - validator: _ValidatorType[_T], - *, - msg: str | None = None, - exc_types: type[Exception] | Iterable[type[Exception]] = ..., -) -> _ValidatorType[_T]: ... -def or_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... diff --git a/server/libs/attrs-25.3.0.dist-info/INSTALLER b/server/libs/attrs-25.3.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/server/libs/attrs-25.3.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/server/libs/attrs-25.3.0.dist-info/METADATA b/server/libs/attrs-25.3.0.dist-info/METADATA deleted file mode 100644 index 029afee..0000000 --- a/server/libs/attrs-25.3.0.dist-info/METADATA +++ /dev/null @@ -1,232 +0,0 @@ -Metadata-Version: 2.4 -Name: attrs -Version: 25.3.0 -Summary: Classes Without Boilerplate -Project-URL: Documentation, https://www.attrs.org/ -Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html -Project-URL: GitHub, https://github.com/python-attrs/attrs -Project-URL: Funding, https://github.com/sponsors/hynek -Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi -Author-email: Hynek Schlawack -License-Expression: MIT -License-File: LICENSE -Keywords: attribute,boilerplate,class -Classifier: Development Status :: 5 - Production/Stable -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Typing :: Typed -Requires-Python: >=3.8 -Provides-Extra: benchmark -Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'benchmark' -Requires-Dist: hypothesis; extra == 'benchmark' -Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'benchmark' -Requires-Dist: pympler; extra == 'benchmark' -Requires-Dist: pytest-codspeed; extra == 'benchmark' -Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'benchmark' -Requires-Dist: pytest-xdist[psutil]; extra == 'benchmark' -Requires-Dist: pytest>=4.3.0; extra == 'benchmark' -Provides-Extra: cov -Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'cov' -Requires-Dist: coverage[toml]>=5.3; extra == 'cov' -Requires-Dist: hypothesis; extra == 'cov' -Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'cov' -Requires-Dist: pympler; extra == 'cov' -Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'cov' -Requires-Dist: pytest-xdist[psutil]; extra == 'cov' -Requires-Dist: pytest>=4.3.0; extra == 'cov' -Provides-Extra: dev -Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'dev' -Requires-Dist: hypothesis; extra == 'dev' -Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'dev' -Requires-Dist: pre-commit-uv; extra == 'dev' -Requires-Dist: pympler; extra == 'dev' -Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'dev' -Requires-Dist: pytest-xdist[psutil]; extra == 'dev' -Requires-Dist: pytest>=4.3.0; extra == 'dev' -Provides-Extra: docs -Requires-Dist: cogapp; extra == 'docs' -Requires-Dist: furo; extra == 'docs' -Requires-Dist: myst-parser; extra == 'docs' -Requires-Dist: sphinx; extra == 'docs' -Requires-Dist: sphinx-notfound-page; extra == 'docs' -Requires-Dist: sphinxcontrib-towncrier; extra == 'docs' -Requires-Dist: towncrier; extra == 'docs' -Provides-Extra: tests -Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'tests' -Requires-Dist: hypothesis; extra == 'tests' -Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests' -Requires-Dist: pympler; extra == 'tests' -Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests' -Requires-Dist: pytest-xdist[psutil]; extra == 'tests' -Requires-Dist: pytest>=4.3.0; extra == 'tests' -Provides-Extra: tests-mypy -Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests-mypy' -Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests-mypy' -Description-Content-Type: text/markdown - -

- - attrs - -

- - -*attrs* is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka [dunder methods](https://www.attrs.org/en/latest/glossary.html#term-dunder-methods)). -[Trusted by NASA](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/personalizing-your-profile#list-of-qualifying-repositories-for-mars-2020-helicopter-contributor-achievement) for Mars missions since 2020! - -Its main goal is to help you to write **concise** and **correct** software without slowing down your code. - - -## Sponsors - -*attrs* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek). -Especially those generously supporting us at the *The Organization* tier and higher: - - - -

- - - - - - - - - - - -

- - - -

- Please consider joining them to help make attrs’s maintenance more sustainable! -

- - - -## Example - -*attrs* gives you a class decorator and a way to declaratively define the attributes on that class: - - - -```pycon ->>> from attrs import asdict, define, make_class, Factory - ->>> @define -... class SomeClass: -... a_number: int = 42 -... list_of_numbers: list[int] = Factory(list) -... -... def hard_math(self, another_number): -... return self.a_number + sum(self.list_of_numbers) * another_number - - ->>> sc = SomeClass(1, [1, 2, 3]) ->>> sc -SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) - ->>> sc.hard_math(3) -19 ->>> sc == SomeClass(1, [1, 2, 3]) -True ->>> sc != SomeClass(2, [3, 2, 1]) -True - ->>> asdict(sc) -{'a_number': 1, 'list_of_numbers': [1, 2, 3]} - ->>> SomeClass() -SomeClass(a_number=42, list_of_numbers=[]) - ->>> C = make_class("C", ["a", "b"]) ->>> C("foo", "bar") -C(a='foo', b='bar') -``` - -After *declaring* your attributes, *attrs* gives you: - -- a concise and explicit overview of the class's attributes, -- a nice human-readable `__repr__`, -- equality-checking methods, -- an initializer, -- and much more, - -*without* writing dull boilerplate code again and again and *without* runtime performance penalties. - ---- - -This example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0. -The classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**. - -Check out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for an in-depth explanation! - - -### Hate Type Annotations!? - -No problem! -Types are entirely **optional** with *attrs*. -Simply assign `attrs.field()` to the attributes instead of annotating them with types: - -```python -from attrs import define, field - -@define -class SomeClass: - a_number = field(default=42) - list_of_numbers = field(factory=list) -``` - - -## Data Classes - -On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*). -In practice it does a lot more and is more flexible. -For instance, it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), has a replacement for `__init_subclass__`, and allows for stepping through the generated methods using a debugger. - -For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes), but generally speaking, we are more likely to commit crimes against nature to make things work that one would expect to work, but that are quite complicated in practice. - - -## Project Information - -- [**Changelog**](https://www.attrs.org/en/stable/changelog.html) -- [**Documentation**](https://www.attrs.org/) -- [**PyPI**](https://pypi.org/project/attrs/) -- [**Source Code**](https://github.com/python-attrs/attrs) -- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md) -- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs) -- **Get Help**: use the `python-attrs` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/python-attrs) - - -### *attrs* for Enterprise - -Available as part of the [Tidelift Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek). - -The maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. -Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. - -## Release Information - -### Changes - -- Restore support for generator-based `field_transformer`s. - [#1417](https://github.com/python-attrs/attrs/issues/1417) - - - ---- - -[Full changelog →](https://www.attrs.org/en/stable/changelog.html) diff --git a/server/libs/attrs-25.3.0.dist-info/RECORD b/server/libs/attrs-25.3.0.dist-info/RECORD deleted file mode 100644 index 93d392c..0000000 --- a/server/libs/attrs-25.3.0.dist-info/RECORD +++ /dev/null @@ -1,56 +0,0 @@ -attr/__init__.py,sha256=fOYIvt1eGSqQre4uCS3sJWKZ0mwAuC8UD6qba5OS9_U,2057 -attr/__init__.pyi,sha256=QIXnnHPoucmDWkbpNsWTP-cgJ1bn8le7DjyRa_wYdew,11281 -attr/__pycache__/__init__.cpython-311.pyc,, -attr/__pycache__/_cmp.cpython-311.pyc,, -attr/__pycache__/_compat.cpython-311.pyc,, -attr/__pycache__/_config.cpython-311.pyc,, -attr/__pycache__/_funcs.cpython-311.pyc,, -attr/__pycache__/_make.cpython-311.pyc,, -attr/__pycache__/_next_gen.cpython-311.pyc,, -attr/__pycache__/_version_info.cpython-311.pyc,, -attr/__pycache__/converters.cpython-311.pyc,, -attr/__pycache__/exceptions.cpython-311.pyc,, -attr/__pycache__/filters.cpython-311.pyc,, -attr/__pycache__/setters.cpython-311.pyc,, -attr/__pycache__/validators.cpython-311.pyc,, -attr/_cmp.py,sha256=3Nn1TjxllUYiX_nJoVnEkXoDk0hM1DYKj5DE7GZe4i0,4117 -attr/_cmp.pyi,sha256=U-_RU_UZOyPUEQzXE6RMYQQcjkZRY25wTH99sN0s7MM,368 -attr/_compat.py,sha256=4hlXbWhdDjQCDK6FKF1EgnZ3POiHgtpp54qE0nxaGHg,2704 -attr/_config.py,sha256=dGq3xR6fgZEF6UBt_L0T-eUHIB4i43kRmH0P28sJVw8,843 -attr/_funcs.py,sha256=5-tUKJtp3h5El55EcDl6GWXFp68fT8D8U7uCRN6497I,15854 -attr/_make.py,sha256=lBUPPmxiA1BeHzB6OlHoCEh--tVvM1ozXO8eXOa6g4c,96664 -attr/_next_gen.py,sha256=7FRkbtl_N017SuBhf_Vw3mw2c2pGZhtCGOzadgz7tp4,24395 -attr/_typing_compat.pyi,sha256=XDP54TUn-ZKhD62TOQebmzrwFyomhUCoGRpclb6alRA,469 -attr/_version_info.py,sha256=exSqb3b5E-fMSsgZAlEw9XcLpEgobPORCZpcaEglAM4,2121 -attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209 -attr/converters.py,sha256=GlDeOzPeTFgeBBLbj9G57Ez5lAk68uhSALRYJ_exe84,3861 -attr/converters.pyi,sha256=orU2bff-VjQa2kMDyvnMQV73oJT2WRyQuw4ZR1ym1bE,643 -attr/exceptions.py,sha256=HRFq4iybmv7-DcZwyjl6M1euM2YeJVK_hFxuaBGAngI,1977 -attr/exceptions.pyi,sha256=zZq8bCUnKAy9mDtBEw42ZhPhAUIHoTKedDQInJD883M,539 -attr/filters.py,sha256=ZBiKWLp3R0LfCZsq7X11pn9WX8NslS2wXM4jsnLOGc8,1795 -attr/filters.pyi,sha256=3J5BG-dTxltBk1_-RuNRUHrv2qu1v8v4aDNAQ7_mifA,208 -attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -attr/setters.py,sha256=5-dcT63GQK35ONEzSgfXCkbB7pPkaR-qv15mm4PVSzQ,1617 -attr/setters.pyi,sha256=NnVkaFU1BB4JB8E4JuXyrzTUgvtMpj8p3wBdJY7uix4,584 -attr/validators.py,sha256=WaB1HLAHHqRHWsrv_K9H-sJ7ESil3H3Cmv2d8TtVZx4,20046 -attr/validators.pyi,sha256=s2WhKPqskxbsckJfKk8zOuuB088GfgpyxcCYSNFLqNU,2603 -attrs-25.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -attrs-25.3.0.dist-info/METADATA,sha256=W38cREj7s1wqNf1fg4hVwZmL1xh0AdSp4IhtTMROinw,10993 -attrs-25.3.0.dist-info/RECORD,, -attrs-25.3.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -attrs-25.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 -attrs-25.3.0.dist-info/licenses/LICENSE,sha256=iCEVyV38KvHutnFPjsbVy8q_Znyv-HKfQkINpj9xTp8,1109 -attrs/__init__.py,sha256=qeQJZ4O08yczSn840v9bYOaZyRE81WsVi-QCrY3krCU,1107 -attrs/__init__.pyi,sha256=nZmInocjM7tHV4AQw0vxO_fo6oJjL_PonlV9zKKW8DY,7931 -attrs/__pycache__/__init__.cpython-311.pyc,, -attrs/__pycache__/converters.cpython-311.pyc,, -attrs/__pycache__/exceptions.cpython-311.pyc,, -attrs/__pycache__/filters.cpython-311.pyc,, -attrs/__pycache__/setters.cpython-311.pyc,, -attrs/__pycache__/validators.cpython-311.pyc,, -attrs/converters.py,sha256=8kQljrVwfSTRu8INwEk8SI0eGrzmWftsT7rM0EqyohM,76 -attrs/exceptions.py,sha256=ACCCmg19-vDFaDPY9vFl199SPXCQMN_bENs4DALjzms,76 -attrs/filters.py,sha256=VOUMZug9uEU6dUuA0dF1jInUK0PL3fLgP0VBS5d-CDE,73 -attrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -attrs/setters.py,sha256=eL1YidYQV3T2h9_SYIZSZR1FAcHGb1TuCTy0E0Lv2SU,73 -attrs/validators.py,sha256=xcy6wD5TtTkdCG1f4XWbocPSO0faBjk5IfVJfP6SUj0,76 diff --git a/server/libs/attrs-25.3.0.dist-info/REQUESTED b/server/libs/attrs-25.3.0.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/server/libs/attrs-25.3.0.dist-info/WHEEL b/server/libs/attrs-25.3.0.dist-info/WHEEL deleted file mode 100644 index 12228d4..0000000 --- a/server/libs/attrs-25.3.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.27.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/server/libs/attrs-25.3.0.dist-info/licenses/LICENSE b/server/libs/attrs-25.3.0.dist-info/licenses/LICENSE deleted file mode 100644 index 2bd6453..0000000 --- a/server/libs/attrs-25.3.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Hynek Schlawack and the attrs contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/server/libs/attrs/__init__.py b/server/libs/attrs/__init__.py deleted file mode 100644 index e8023ff..0000000 --- a/server/libs/attrs/__init__.py +++ /dev/null @@ -1,69 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr import ( - NOTHING, - Attribute, - AttrsInstance, - Converter, - Factory, - NothingType, - _make_getattr, - assoc, - cmp_using, - define, - evolve, - field, - fields, - fields_dict, - frozen, - has, - make_class, - mutable, - resolve_types, - validate, -) -from attr._next_gen import asdict, astuple - -from . import converters, exceptions, filters, setters, validators - - -__all__ = [ - "NOTHING", - "Attribute", - "AttrsInstance", - "Converter", - "Factory", - "NothingType", - "__author__", - "__copyright__", - "__description__", - "__doc__", - "__email__", - "__license__", - "__title__", - "__url__", - "__version__", - "__version_info__", - "asdict", - "assoc", - "astuple", - "cmp_using", - "converters", - "define", - "evolve", - "exceptions", - "field", - "fields", - "fields_dict", - "filters", - "frozen", - "has", - "make_class", - "mutable", - "resolve_types", - "setters", - "validate", - "validators", -] - -__getattr__ = _make_getattr(__name__) diff --git a/server/libs/attrs/__init__.pyi b/server/libs/attrs/__init__.pyi deleted file mode 100644 index 648fa7a..0000000 --- a/server/libs/attrs/__init__.pyi +++ /dev/null @@ -1,263 +0,0 @@ -import sys - -from typing import ( - Any, - Callable, - Mapping, - Sequence, - overload, - TypeVar, -) - -# Because we need to type our own stuff, we have to make everything from -# attr explicitly public too. -from attr import __author__ as __author__ -from attr import __copyright__ as __copyright__ -from attr import __description__ as __description__ -from attr import __email__ as __email__ -from attr import __license__ as __license__ -from attr import __title__ as __title__ -from attr import __url__ as __url__ -from attr import __version__ as __version__ -from attr import __version_info__ as __version_info__ -from attr import assoc as assoc -from attr import Attribute as Attribute -from attr import AttrsInstance as AttrsInstance -from attr import cmp_using as cmp_using -from attr import converters as converters -from attr import Converter as Converter -from attr import evolve as evolve -from attr import exceptions as exceptions -from attr import Factory as Factory -from attr import fields as fields -from attr import fields_dict as fields_dict -from attr import filters as filters -from attr import has as has -from attr import make_class as make_class -from attr import NOTHING as NOTHING -from attr import resolve_types as resolve_types -from attr import setters as setters -from attr import validate as validate -from attr import validators as validators -from attr import attrib, asdict as asdict, astuple as astuple -from attr import NothingType as NothingType - -if sys.version_info >= (3, 11): - from typing import dataclass_transform -else: - from typing_extensions import dataclass_transform - -_T = TypeVar("_T") -_C = TypeVar("_C", bound=type) - -_EqOrderType = bool | Callable[[Any], Any] -_ValidatorType = Callable[[Any, "Attribute[_T]", _T], Any] -_CallableConverterType = Callable[[Any], Any] -_ConverterType = _CallableConverterType | Converter[Any, Any] -_ReprType = Callable[[Any], str] -_ReprArgType = bool | _ReprType -_OnSetAttrType = Callable[[Any, "Attribute[Any]", Any], Any] -_OnSetAttrArgType = _OnSetAttrType | list[_OnSetAttrType] | setters._NoOpType -_FieldTransformer = Callable[ - [type, list["Attribute[Any]"]], list["Attribute[Any]"] -] -# FIXME: in reality, if multiple validators are passed they must be in a list -# or tuple, but those are invariant and so would prevent subtypes of -# _ValidatorType from working when passed in a list or tuple. -_ValidatorArgType = _ValidatorType[_T] | Sequence[_ValidatorType[_T]] - -@overload -def field( - *, - default: None = ..., - validator: None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: None = ..., - factory: None = ..., - kw_only: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> Any: ... - -# This form catches an explicit None or no default and infers the type from the -# other arguments. -@overload -def field( - *, - default: None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> _T: ... - -# This form catches an explicit default argument. -@overload -def field( - *, - default: _T, - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> _T: ... - -# This form covers type=non-Type: e.g. forward references (str), Any -@overload -def field( - *, - default: _T | None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> Any: ... -@overload -@dataclass_transform(field_specifiers=(attrib, field)) -def define( - maybe_cls: _C, - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> _C: ... -@overload -@dataclass_transform(field_specifiers=(attrib, field)) -def define( - maybe_cls: None = ..., - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> Callable[[_C], _C]: ... - -mutable = define - -@overload -@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) -def frozen( - maybe_cls: _C, - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> _C: ... -@overload -@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) -def frozen( - maybe_cls: None = ..., - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> Callable[[_C], _C]: ... diff --git a/server/libs/attrs/converters.py b/server/libs/attrs/converters.py deleted file mode 100644 index 7821f6c..0000000 --- a/server/libs/attrs/converters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.converters import * # noqa: F403 diff --git a/server/libs/attrs/exceptions.py b/server/libs/attrs/exceptions.py deleted file mode 100644 index 3323f9d..0000000 --- a/server/libs/attrs/exceptions.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.exceptions import * # noqa: F403 diff --git a/server/libs/attrs/filters.py b/server/libs/attrs/filters.py deleted file mode 100644 index 3080f48..0000000 --- a/server/libs/attrs/filters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.filters import * # noqa: F403 diff --git a/server/libs/attrs/py.typed b/server/libs/attrs/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/server/libs/attrs/setters.py b/server/libs/attrs/setters.py deleted file mode 100644 index f3d73bb..0000000 --- a/server/libs/attrs/setters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.setters import * # noqa: F403 diff --git a/server/libs/attrs/validators.py b/server/libs/attrs/validators.py deleted file mode 100644 index 037e124..0000000 --- a/server/libs/attrs/validators.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.validators import * # noqa: F403 diff --git a/server/libs/bin/tclfmt.exe b/server/libs/bin/tclfmt.exe deleted file mode 100644 index 3173b08..0000000 Binary files a/server/libs/bin/tclfmt.exe and /dev/null differ diff --git a/server/libs/bin/tclint.exe b/server/libs/bin/tclint.exe deleted file mode 100644 index 6585f69..0000000 Binary files a/server/libs/bin/tclint.exe and /dev/null differ diff --git a/server/libs/bin/tclsp.exe b/server/libs/bin/tclsp.exe deleted file mode 100644 index 8fbb54d..0000000 Binary files a/server/libs/bin/tclsp.exe and /dev/null differ diff --git a/server/libs/cattr/__init__.py b/server/libs/cattr/__init__.py deleted file mode 100644 index 50f2a06..0000000 --- a/server/libs/cattr/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -from .converters import BaseConverter, Converter, GenConverter, UnstructureStrategy -from .gen import override - -__all__ = ( - "BaseConverter", - "Converter", - "GenConverter", - "UnstructureStrategy", - "global_converter", - "override", - "structure", - "structure_attrs_fromdict", - "structure_attrs_fromtuple", - "unstructure", -) -from cattrs import global_converter - -unstructure = global_converter.unstructure -structure = global_converter.structure -structure_attrs_fromtuple = global_converter.structure_attrs_fromtuple -structure_attrs_fromdict = global_converter.structure_attrs_fromdict -register_structure_hook = global_converter.register_structure_hook -register_structure_hook_func = global_converter.register_structure_hook_func -register_unstructure_hook = global_converter.register_unstructure_hook -register_unstructure_hook_func = global_converter.register_unstructure_hook_func diff --git a/server/libs/cattr/converters.py b/server/libs/cattr/converters.py deleted file mode 100644 index 4434fe5..0000000 --- a/server/libs/cattr/converters.py +++ /dev/null @@ -1,8 +0,0 @@ -from cattrs.converters import ( - BaseConverter, - Converter, - GenConverter, - UnstructureStrategy, -) - -__all__ = ["BaseConverter", "Converter", "GenConverter", "UnstructureStrategy"] diff --git a/server/libs/cattr/disambiguators.py b/server/libs/cattr/disambiguators.py deleted file mode 100644 index f10797a..0000000 --- a/server/libs/cattr/disambiguators.py +++ /dev/null @@ -1,3 +0,0 @@ -from cattrs.disambiguators import create_uniq_field_dis_func - -__all__ = ["create_uniq_field_dis_func"] diff --git a/server/libs/cattr/dispatch.py b/server/libs/cattr/dispatch.py deleted file mode 100644 index 2474247..0000000 --- a/server/libs/cattr/dispatch.py +++ /dev/null @@ -1,3 +0,0 @@ -from cattrs.dispatch import FunctionDispatch, MultiStrategyDispatch - -__all__ = ["FunctionDispatch", "MultiStrategyDispatch"] diff --git a/server/libs/cattr/errors.py b/server/libs/cattr/errors.py deleted file mode 100644 index af092e9..0000000 --- a/server/libs/cattr/errors.py +++ /dev/null @@ -1,15 +0,0 @@ -from cattrs.errors import ( - BaseValidationError, - ClassValidationError, - ForbiddenExtraKeysError, - IterableValidationError, - StructureHandlerNotFoundError, -) - -__all__ = [ - "BaseValidationError", - "ClassValidationError", - "ForbiddenExtraKeysError", - "IterableValidationError", - "StructureHandlerNotFoundError", -] diff --git a/server/libs/cattr/gen.py b/server/libs/cattr/gen.py deleted file mode 100644 index b1f63b5..0000000 --- a/server/libs/cattr/gen.py +++ /dev/null @@ -1,21 +0,0 @@ -from cattrs.cols import iterable_unstructure_factory as make_iterable_unstructure_fn -from cattrs.gen import ( - make_dict_structure_fn, - make_dict_unstructure_fn, - make_hetero_tuple_unstructure_fn, - make_mapping_structure_fn, - make_mapping_unstructure_fn, - override, -) -from cattrs.gen._consts import AttributeOverride - -__all__ = [ - "AttributeOverride", - "make_dict_structure_fn", - "make_dict_unstructure_fn", - "make_hetero_tuple_unstructure_fn", - "make_iterable_unstructure_fn", - "make_mapping_structure_fn", - "make_mapping_unstructure_fn", - "override", -] diff --git a/server/libs/cattr/preconf/__init__.py b/server/libs/cattr/preconf/__init__.py deleted file mode 100644 index fa6ad35..0000000 --- a/server/libs/cattr/preconf/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from cattrs.preconf import validate_datetime - -__all__ = ["validate_datetime"] diff --git a/server/libs/cattr/preconf/bson.py b/server/libs/cattr/preconf/bson.py deleted file mode 100644 index 4ac9743..0000000 --- a/server/libs/cattr/preconf/bson.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Preconfigured converters for bson.""" - -from cattrs.preconf.bson import BsonConverter, configure_converter, make_converter - -__all__ = ["BsonConverter", "configure_converter", "make_converter"] diff --git a/server/libs/cattr/preconf/json.py b/server/libs/cattr/preconf/json.py deleted file mode 100644 index ac77398..0000000 --- a/server/libs/cattr/preconf/json.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Preconfigured converters for the stdlib json.""" - -from cattrs.preconf.json import JsonConverter, configure_converter, make_converter - -__all__ = ["JsonConverter", "configure_converter", "make_converter"] diff --git a/server/libs/cattr/preconf/msgpack.py b/server/libs/cattr/preconf/msgpack.py deleted file mode 100644 index bb90250..0000000 --- a/server/libs/cattr/preconf/msgpack.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Preconfigured converters for msgpack.""" - -from cattrs.preconf.msgpack import MsgpackConverter, configure_converter, make_converter - -__all__ = ["MsgpackConverter", "configure_converter", "make_converter"] diff --git a/server/libs/cattr/preconf/orjson.py b/server/libs/cattr/preconf/orjson.py deleted file mode 100644 index 569ec18..0000000 --- a/server/libs/cattr/preconf/orjson.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Preconfigured converters for orjson.""" - -from cattrs.preconf.orjson import OrjsonConverter, configure_converter, make_converter - -__all__ = ["OrjsonConverter", "configure_converter", "make_converter"] diff --git a/server/libs/cattr/preconf/pyyaml.py b/server/libs/cattr/preconf/pyyaml.py deleted file mode 100644 index 6bf8b36..0000000 --- a/server/libs/cattr/preconf/pyyaml.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Preconfigured converters for pyyaml.""" - -from cattrs.preconf.pyyaml import PyyamlConverter, configure_converter, make_converter - -__all__ = ["PyyamlConverter", "configure_converter", "make_converter"] diff --git a/server/libs/cattr/preconf/tomlkit.py b/server/libs/cattr/preconf/tomlkit.py deleted file mode 100644 index 7c0e703..0000000 --- a/server/libs/cattr/preconf/tomlkit.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Preconfigured converters for tomlkit.""" - -from cattrs.preconf.tomlkit import TomlkitConverter, configure_converter, make_converter - -__all__ = ["TomlkitConverter", "configure_converter", "make_converter"] diff --git a/server/libs/cattr/preconf/ujson.py b/server/libs/cattr/preconf/ujson.py deleted file mode 100644 index 2efbbee..0000000 --- a/server/libs/cattr/preconf/ujson.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Preconfigured converters for ujson.""" - -from cattrs.preconf.ujson import UjsonConverter, configure_converter, make_converter - -__all__ = ["UjsonConverter", "configure_converter", "make_converter"] diff --git a/server/libs/cattr/py.typed b/server/libs/cattr/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/server/libs/cattrs-25.1.1.dist-info/INSTALLER b/server/libs/cattrs-25.1.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/server/libs/cattrs-25.1.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/server/libs/cattrs-25.1.1.dist-info/METADATA b/server/libs/cattrs-25.1.1.dist-info/METADATA deleted file mode 100644 index 302a49f..0000000 --- a/server/libs/cattrs-25.1.1.dist-info/METADATA +++ /dev/null @@ -1,161 +0,0 @@ -Metadata-Version: 2.4 -Name: cattrs -Version: 25.1.1 -Summary: Composable complex class support for attrs and dataclasses. -Project-URL: Homepage, https://catt.rs -Project-URL: Changelog, https://catt.rs/en/latest/history.html -Project-URL: Bug Tracker, https://github.com/python-attrs/cattrs/issues -Project-URL: Repository, https://github.com/python-attrs/cattrs -Project-URL: Documentation, https://catt.rs/en/stable/ -Author-email: Tin Tvrtkovic -License: MIT -License-File: LICENSE -Keywords: attrs,dataclasses,serialization -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Typing :: Typed -Requires-Python: >=3.9 -Requires-Dist: attrs>=24.3.0 -Requires-Dist: exceptiongroup>=1.1.1; python_version < '3.11' -Requires-Dist: typing-extensions>=4.12.2 -Provides-Extra: bson -Requires-Dist: pymongo>=4.4.0; extra == 'bson' -Provides-Extra: cbor2 -Requires-Dist: cbor2>=5.4.6; extra == 'cbor2' -Provides-Extra: msgpack -Requires-Dist: msgpack>=1.0.5; extra == 'msgpack' -Provides-Extra: msgspec -Requires-Dist: msgspec>=0.19.0; (implementation_name == 'cpython') and extra == 'msgspec' -Provides-Extra: orjson -Requires-Dist: orjson>=3.10.7; (implementation_name == 'cpython') and extra == 'orjson' -Provides-Extra: pyyaml -Requires-Dist: pyyaml>=6.0; extra == 'pyyaml' -Provides-Extra: tomlkit -Requires-Dist: tomlkit>=0.11.8; extra == 'tomlkit' -Provides-Extra: ujson -Requires-Dist: ujson>=5.10.0; extra == 'ujson' -Description-Content-Type: text/markdown - -# *cattrs*: Flexible Object Serialization and Validation - -*Because validation belongs to the edges.* - -[![Documentation](https://img.shields.io/badge/Docs-Read%20The%20Docs-black)](https://catt.rs/) -[![License: MIT](https://img.shields.io/badge/license-MIT-C06524)](https://github.com/hynek/stamina/blob/main/LICENSE) -[![PyPI](https://img.shields.io/pypi/v/cattrs.svg)](https://pypi.python.org/pypi/cattrs) -[![Supported Python Versions](https://img.shields.io/pypi/pyversions/cattrs.svg)](https://github.com/python-attrs/cattrs) -[![Downloads](https://static.pepy.tech/badge/cattrs/month)](https://pepy.tech/project/cattrs) -[![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/Tinche/22405310d6a663164d894a2beab4d44d/raw/covbadge.json)](https://github.com/python-attrs/cattrs/actions/workflows/main.yml) - ---- - - - -**cattrs** is a Swiss Army knife for (un)structuring and validating data in Python. -In practice, that means it converts **unstructured dictionaries** into **proper classes** and back, while **validating** their contents. - - - - -## Example - - - -_cattrs_ works best with [_attrs_](https://www.attrs.org/) classes, and [dataclasses](https://docs.python.org/3/library/dataclasses.html) where simple (un-)structuring works out of the box, even for nested data, without polluting your data model with serialization details: - -```python ->>> from attrs import define ->>> from cattrs import structure, unstructure ->>> @define -... class C: -... a: int -... b: list[str] ->>> instance = structure({'a': 1, 'b': ['x', 'y']}, C) ->>> instance -C(a=1, b=['x', 'y']) ->>> unstructure(instance) -{'a': 1, 'b': ['x', 'y']} -``` - - - - -Have a look at [*Why *cattrs*?*](https://catt.rs/en/latest/why.html) for more examples! - - - -## Features - -### Recursive Unstructuring - -- _attrs_ classes and dataclasses are converted into dictionaries in a way similar to `attrs.asdict()`, or into tuples in a way similar to `attrs.astuple()`. -- Enumeration instances are converted to their values. -- Other types are let through without conversion. This includes types such as integers, dictionaries, lists and instances of non-_attrs_ classes. -- Custom converters for any type can be registered using `register_unstructure_hook`. - - -### Recursive Structuring - -Converts unstructured data into structured data, recursively, according to your specification given as a type. -The following types are supported: - -- `typing.Optional[T]` and its 3.10+ form, `T | None`. -- `list[T]`, `typing.List[T]`, `typing.MutableSequence[T]`, `typing.Sequence[T]` convert to lists. -- `tuple` and `typing.Tuple` (both variants, `tuple[T, ...]` and `tuple[X, Y, Z]`). -- `set[T]`, `typing.MutableSet[T]`, and `typing.Set[T]` convert to sets. -- `frozenset[T]`, and `typing.FrozenSet[T]` convert to frozensets. -- `dict[K, V]`, `typing.Dict[K, V]`, `typing.MutableMapping[K, V]`, and `typing.Mapping[K, V]` convert to dictionaries. -- [`typing.TypedDict`](https://docs.python.org/3/library/typing.html#typing.TypedDict), both ordinary and generic. -- [`typing.NewType`](https://docs.python.org/3/library/typing.html#newtype) -- [PEP 695 type aliases](https://docs.python.org/3/library/typing.html#type-aliases) on 3.12+ -- _attrs_ classes with simple attributes and the usual `__init__`[^simple]. -- All _attrs_ classes and dataclasses with the usual `__init__`, if their complex attributes have type metadata. -- Unions of supported _attrs_ classes, given that all of the classes have a unique field. -- Unions of anything, if you provide a disambiguation function for it. -- Custom converters for any type can be registered using `register_structure_hook`. - -[^simple]: Simple attributes are attributes that can be assigned unstructured data, like numbers, strings, and collections of unstructured data. - - -### Batteries Included - -_cattrs_ comes with pre-configured converters for a number of serialization libraries, including JSON (standard library, [_orjson_](https://pypi.org/project/orjson/), [UltraJSON](https://pypi.org/project/ujson/)), [_msgpack_](https://pypi.org/project/msgpack/), [_cbor2_](https://pypi.org/project/cbor2/), [_bson_](https://pypi.org/project/bson/), [PyYAML](https://pypi.org/project/PyYAML/), [_tomlkit_](https://pypi.org/project/tomlkit/) and [_msgspec_](https://pypi.org/project/msgspec/) (supports only JSON at this time). - -For details, see the [cattrs.preconf package](https://catt.rs/en/stable/preconf.html). - - -## Design Decisions - -_cattrs_ is based on a few fundamental design decisions: - -- Un/structuring rules are separate from the models. - This allows models to have a one-to-many relationship with un/structuring rules, and to create un/structuring rules for models which you do not own and you cannot change. - (_cattrs_ can be configured to use un/structuring rules from models using the [`use_class_methods` strategy](https://catt.rs/en/latest/strategies.html#using-class-specific-structure-and-unstructure-methods).) -- Invent as little as possible; reuse existing ordinary Python instead. - For example, _cattrs_ did not have a custom exception type to group exceptions until the sanctioned Python [`exceptiongroups`](https://docs.python.org/3/library/exceptions.html#ExceptionGroup). - A side-effect of this design decision is that, in a lot of cases, when you're solving _cattrs_ problems you're actually learning Python instead of learning _cattrs_. -- Resist the temptation to guess. - If there are two ways of solving a problem, _cattrs_ should refuse to guess and let the user configure it themselves. - -A foolish consistency is the hobgoblin of little minds, so these decisions can and are sometimes broken, but they have proven to be a good foundation. - - - - -## Credits - -Major credits to Hynek Schlawack for creating [attrs](https://attrs.org) and its predecessor, [characteristic](https://github.com/hynek/characteristic). - -_cattrs_ is tested with [Hypothesis](http://hypothesis.readthedocs.io/en/latest/), by David R. MacIver. - -_cattrs_ is benchmarked using [perf](https://github.com/haypo/perf) and [pytest-benchmark](https://pytest-benchmark.readthedocs.io/en/latest/index.html). - -This package was created with [Cookiecutter](https://github.com/audreyr/cookiecutter) and the [`audreyr/cookiecutter-pypackage`](https://github.com/audreyr/cookiecutter-pypackage) project template. diff --git a/server/libs/cattrs-25.1.1.dist-info/RECORD b/server/libs/cattrs-25.1.1.dist-info/RECORD deleted file mode 100644 index 3b261d8..0000000 --- a/server/libs/cattrs-25.1.1.dist-info/RECORD +++ /dev/null @@ -1,102 +0,0 @@ -cattr/__init__.py,sha256=bYrmwTYSdYC_ut1xW31V7mxhXBlJQKs8EECgtUBgAuc,906 -cattr/__pycache__/__init__.cpython-311.pyc,, -cattr/__pycache__/converters.cpython-311.pyc,, -cattr/__pycache__/disambiguators.cpython-311.pyc,, -cattr/__pycache__/dispatch.cpython-311.pyc,, -cattr/__pycache__/errors.cpython-311.pyc,, -cattr/__pycache__/gen.cpython-311.pyc,, -cattr/converters.py,sha256=rQhY4J8r7QTZh5WICuFe4GWO1v0DS3DgQ9r569zd6jg,192 -cattr/disambiguators.py,sha256=ugD1fq1Z5x1pGu5P1lMzcT-IEi1q7IfQJIHEdmg62vM,103 -cattr/dispatch.py,sha256=uVEOgHWR9Hn5tm-wIw-bDccqrxJByVi8yRKaYyvL67k,125 -cattr/errors.py,sha256=V4RhoCObwGrlaM3oyn1H_FYxGR8iAB9dG5NxFDYM548,343 -cattr/gen.py,sha256=hWyKoZ_d2D36Jz_npspyGw8s9pWtUA69sXf0R3uOvgM,597 -cattr/preconf/__init__.py,sha256=NqPE7uhVfcP-PggkUpsbfAutMo8oHjcoB1cvjgLft-s,78 -cattr/preconf/__pycache__/__init__.cpython-311.pyc,, -cattr/preconf/__pycache__/bson.cpython-311.pyc,, -cattr/preconf/__pycache__/json.cpython-311.pyc,, -cattr/preconf/__pycache__/msgpack.cpython-311.pyc,, -cattr/preconf/__pycache__/orjson.cpython-311.pyc,, -cattr/preconf/__pycache__/pyyaml.cpython-311.pyc,, -cattr/preconf/__pycache__/tomlkit.cpython-311.pyc,, -cattr/preconf/__pycache__/ujson.cpython-311.pyc,, -cattr/preconf/bson.py,sha256=Bn4hJxac7OthGg_CR4LCPeBp_fz4kx3QniBVOZhguGs,195 -cattr/preconf/json.py,sha256=LpqYuO3oePDxbQtKFKB0SaoeAi3Z_agIgyNn1VQSIVo,206 -cattr/preconf/msgpack.py,sha256=pyJ9L9ekNlZ0IQHbJ9Ay_fi_NOqY5_rE_q-UnD94-RM,207 -cattr/preconf/orjson.py,sha256=Adh-7csx4eqCjx22zipMFgSlDXbR554wvgNHEb8Q5JM,203 -cattr/preconf/pyyaml.py,sha256=Fy40bejjp7uqgoLhTA_p4wZYF0uFaguHbUK9zs9LoC0,203 -cattr/preconf/tomlkit.py,sha256=_gADJ_UYpj3EiNXGYjAfSOkcoFIkLpYVOFfLEqBfIJQ,207 -cattr/preconf/ujson.py,sha256=IzEa7QUcYOaSUMiLQsFEWJnBihmmOLhehsM-5cPY9NI,199 -cattr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -cattrs-25.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -cattrs-25.1.1.dist-info/METADATA,sha256=ODqSak3dhIZZjmFa-SZT8Si32_3ey_oo2tUefYx0QtU,8388 -cattrs-25.1.1.dist-info/RECORD,, -cattrs-25.1.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -cattrs-25.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 -cattrs-25.1.1.dist-info/licenses/LICENSE,sha256=9fudHt43qIykf0IMSZ3KD0oFvJk-Esd9I1IKrSkcAb8,1074 -cattrs/__init__.py,sha256=UhiFdxf81gCuBBA6FutoE1oOzthzF_PkAdoE2AVslIo,1901 -cattrs/__pycache__/__init__.cpython-311.pyc,, -cattrs/__pycache__/_compat.cpython-311.pyc,, -cattrs/__pycache__/_generics.cpython-311.pyc,, -cattrs/__pycache__/cols.cpython-311.pyc,, -cattrs/__pycache__/converters.cpython-311.pyc,, -cattrs/__pycache__/disambiguators.cpython-311.pyc,, -cattrs/__pycache__/dispatch.cpython-311.pyc,, -cattrs/__pycache__/errors.cpython-311.pyc,, -cattrs/__pycache__/fns.cpython-311.pyc,, -cattrs/__pycache__/literals.cpython-311.pyc,, -cattrs/__pycache__/typealiases.cpython-311.pyc,, -cattrs/__pycache__/types.cpython-311.pyc,, -cattrs/__pycache__/v.cpython-311.pyc,, -cattrs/_compat.py,sha256=dMRB8a8RkxFdnQDKRpamresVF_SBkksM2_ZMAuL0s2w,11987 -cattrs/_generics.py,sha256=keExDE2CGIer8ci12SoJ_rXYTLva9P29uLlvyb_fxtM,966 -cattrs/cols.py,sha256=mWDchfvjMQ6uACKSfdZs05YiXrWdph2HOJfaqY3D_EI,8848 -cattrs/converters.py,sha256=ui4BSAxnV1J6Oh0pYN2oOHgp-mIybsXW-M8SXPDNzlo,54262 -cattrs/disambiguators.py,sha256=eUyWMtW6bQJcXGOWiraq1pFcMlUbo9BJHxFY--KF6Lk,6867 -cattrs/dispatch.py,sha256=9qA-pmsPvgrM6MGP8Ev2gVP6YL2rXvoBla_C0VgHxQ0,6780 -cattrs/errors.py,sha256=6IGfE-wVQbOaDNN4xAQJf7Hk_t2QNV0Zem64D6yMZrU,4168 -cattrs/fns.py,sha256=z5z1VZOZv8t5LwG8cBM_tIXg-_PlQUOyZb9wIrXNqlw,626 -cattrs/gen/__init__.py,sha256=bpRGHd3G0UTpWcHRcJTNAUcWmX-evoPHGvpH6u29FDU,38842 -cattrs/gen/__pycache__/__init__.cpython-311.pyc,, -cattrs/gen/__pycache__/_consts.cpython-311.pyc,, -cattrs/gen/__pycache__/_generics.cpython-311.pyc,, -cattrs/gen/__pycache__/_lc.cpython-311.pyc,, -cattrs/gen/__pycache__/_shared.cpython-311.pyc,, -cattrs/gen/__pycache__/typeddicts.cpython-311.pyc,, -cattrs/gen/_consts.py,sha256=ZwT_m2J3S7p-UjltpbA1WtfQZLNj9KhmFYCAv6Zl-g0,511 -cattrs/gen/_generics.py,sha256=_DyXCGql2QIxGhAv3_B1hsi80uPK8PhK2hhZa95YOlo,3011 -cattrs/gen/_lc.py,sha256=4fjeUsmgQcCAIjnNndBic0gf5qKmxVS3CZHqUQ9Rw5g,882 -cattrs/gen/_shared.py,sha256=xKsfcVtpyYIir9AW8VuOVoiSbaEI7tsSL0JpUCIUX-g,2296 -cattrs/gen/typeddicts.py,sha256=Ck3QMr_B1T7vwxyRjfZPHafKphN2hndL181dpQNxzPs,21254 -cattrs/literals.py,sha256=0kzAewmWk9ikJGoKq4ysnAR22DMawG3iNqLl8NLgpk0,331 -cattrs/preconf/__init__.py,sha256=P7czFRcjeN6zBcdwUyeBloniltlJptCa8Yd2uFGlz9w,1527 -cattrs/preconf/__pycache__/__init__.cpython-311.pyc,, -cattrs/preconf/__pycache__/bson.cpython-311.pyc,, -cattrs/preconf/__pycache__/cbor2.cpython-311.pyc,, -cattrs/preconf/__pycache__/json.cpython-311.pyc,, -cattrs/preconf/__pycache__/msgpack.cpython-311.pyc,, -cattrs/preconf/__pycache__/msgspec.cpython-311.pyc,, -cattrs/preconf/__pycache__/orjson.cpython-311.pyc,, -cattrs/preconf/__pycache__/pyyaml.cpython-311.pyc,, -cattrs/preconf/__pycache__/tomlkit.cpython-311.pyc,, -cattrs/preconf/__pycache__/ujson.cpython-311.pyc,, -cattrs/preconf/bson.py,sha256=6p1kmOFMjswSXFCb1hKJeNvr3kNsAm1gfX_DA6igq8E,4201 -cattrs/preconf/cbor2.py,sha256=LnREcjpOp_402poUGRVIhDWI4f_R1wvJkdKvs5MrTGU,2022 -cattrs/preconf/json.py,sha256=zTrkfjOxXZFwwabNESeafy-C7MEpn7Cw5AdhkkeOjU4,2631 -cattrs/preconf/msgpack.py,sha256=dZE9tsAA5qX3pSc3MZmlGuvJ5q_wI6mANDyugKXKj-E,2325 -cattrs/preconf/msgspec.py,sha256=Ds0rPW4900zsBLqfupF-smkg9_Kwyx7D_Vh9a0yJB8M,7250 -cattrs/preconf/orjson.py,sha256=5MBcUsyp3eGsHgLfLtt8-q90L2mxjD0ttnrWBUIwouo,3870 -cattrs/preconf/pyyaml.py,sha256=w0aM_gJ6VhZf-Zpu_UlJki7rdgv4mfaSXElPofB3nlE,2378 -cattrs/preconf/tomlkit.py,sha256=gJWGJjMONCViTMZuphOg2xXzjQt3SCEVFVdoKgDjqc8,3148 -cattrs/preconf/ujson.py,sha256=wRLidBM8aWucFkCQ9haiktY8xYoCdanDhQuKJLQJgGM,2425 -cattrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -cattrs/strategies/__init__.py,sha256=nkZWCzSRYcS-75FMfk52mioZSuWykaN8hB39Vig5Xkg,339 -cattrs/strategies/__pycache__/__init__.cpython-311.pyc,, -cattrs/strategies/__pycache__/_class_methods.cpython-311.pyc,, -cattrs/strategies/__pycache__/_subclasses.cpython-311.pyc,, -cattrs/strategies/__pycache__/_unions.cpython-311.pyc,, -cattrs/strategies/_class_methods.py,sha256=O5xhQCzNpuFiDNDMlbcyeOVqyrV65NhMZNRsG3jnoBU,2591 -cattrs/strategies/_subclasses.py,sha256=aCE2UQjevZQHMnPOPyl2qR_hgRpgRUt1j9lE4qZ3hNc,9365 -cattrs/strategies/_unions.py,sha256=YBBklVSWJ-7DSkLDLpumwAJJ39ALuSGyB6W0Ptz5Rz4,9355 -cattrs/typealiases.py,sha256=toHavC2kJsIcxThwvATPO5JShzKeC8kIl9KqteFohbw,1619 -cattrs/types.py,sha256=cqvfmzliYfrvPswxlW_tN4DmhQ2xpAKQvVbNBJaxiWs,278 -cattrs/v.py,sha256=IqUajgJFCKJYf-4S9TCKRtJcmmK4c3En69TGuf2FKOs,4126 diff --git a/server/libs/cattrs-25.1.1.dist-info/REQUESTED b/server/libs/cattrs-25.1.1.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/server/libs/cattrs-25.1.1.dist-info/WHEEL b/server/libs/cattrs-25.1.1.dist-info/WHEEL deleted file mode 100644 index 12228d4..0000000 --- a/server/libs/cattrs-25.1.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.27.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/server/libs/cattrs-25.1.1.dist-info/licenses/LICENSE b/server/libs/cattrs-25.1.1.dist-info/licenses/LICENSE deleted file mode 100644 index 340022c..0000000 --- a/server/libs/cattrs-25.1.1.dist-info/licenses/LICENSE +++ /dev/null @@ -1,11 +0,0 @@ - -MIT License - -Copyright (c) 2016, Tin Tvrtković - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/server/libs/cattrs/__init__.py b/server/libs/cattrs/__init__.py deleted file mode 100644 index 2252272..0000000 --- a/server/libs/cattrs/__init__.py +++ /dev/null @@ -1,57 +0,0 @@ -from typing import Final - -from .converters import BaseConverter, Converter, GenConverter, UnstructureStrategy -from .errors import ( - AttributeValidationNote, - BaseValidationError, - ClassValidationError, - ForbiddenExtraKeysError, - IterableValidationError, - IterableValidationNote, - StructureHandlerNotFoundError, -) -from .gen import override -from .types import SimpleStructureHook -from .v import transform_error - -__all__ = [ - "AttributeValidationNote", - "BaseConverter", - "BaseValidationError", - "ClassValidationError", - "Converter", - "ForbiddenExtraKeysError", - "GenConverter", - "IterableValidationError", - "IterableValidationNote", - "SimpleStructureHook", - "StructureHandlerNotFoundError", - "UnstructureStrategy", - "get_structure_hook", - "get_unstructure_hook", - "global_converter", - "override", - "register_structure_hook", - "register_structure_hook_func", - "register_unstructure_hook", - "register_unstructure_hook_func", - "structure", - "structure_attrs_fromdict", - "structure_attrs_fromtuple", - "transform_error", - "unstructure", -] - -#: The global converter. Prefer creating your own if customizations are required. -global_converter: Final = Converter() - -unstructure = global_converter.unstructure -structure = global_converter.structure -structure_attrs_fromtuple = global_converter.structure_attrs_fromtuple -structure_attrs_fromdict = global_converter.structure_attrs_fromdict -register_structure_hook = global_converter.register_structure_hook -register_structure_hook_func = global_converter.register_structure_hook_func -register_unstructure_hook = global_converter.register_unstructure_hook -register_unstructure_hook_func = global_converter.register_unstructure_hook_func -get_structure_hook: Final = global_converter.get_structure_hook -get_unstructure_hook: Final = global_converter.get_unstructure_hook diff --git a/server/libs/cattrs/_compat.py b/server/libs/cattrs/_compat.py deleted file mode 100644 index da50c22..0000000 --- a/server/libs/cattrs/_compat.py +++ /dev/null @@ -1,428 +0,0 @@ -import sys -from collections import Counter, deque -from collections.abc import Mapping as AbcMapping -from collections.abc import MutableMapping as AbcMutableMapping -from collections.abc import MutableSequence as AbcMutableSequence -from collections.abc import MutableSet as AbcMutableSet -from collections.abc import Sequence as AbcSequence -from collections.abc import Set as AbcSet -from dataclasses import MISSING, Field, is_dataclass -from dataclasses import fields as dataclass_fields -from functools import partial -from inspect import signature as _signature -from types import GenericAlias -from typing import ( - Annotated, - Any, - Deque, - Dict, - Final, - FrozenSet, - Generic, - List, - Literal, - NewType, - Optional, - Protocol, - Tuple, - Union, - _AnnotatedAlias, - _GenericAlias, - _SpecialGenericAlias, - _UnionGenericAlias, - get_args, - get_origin, - get_type_hints, -) -from typing import Counter as TypingCounter -from typing import Mapping as TypingMapping -from typing import MutableMapping as TypingMutableMapping -from typing import MutableSequence as TypingMutableSequence -from typing import MutableSet as TypingMutableSet -from typing import Sequence as TypingSequence -from typing import Set as TypingSet - -from attrs import NOTHING, Attribute, Factory, NothingType, resolve_types -from attrs import fields as attrs_fields -from attrs import fields_dict as attrs_fields_dict - -__all__ = [ - "ANIES", - "ExceptionGroup", - "ExtensionsTypedDict", - "TypeAlias", - "adapted_fields", - "fields_dict", - "has", - "is_typeddict", -] - -try: - from typing_extensions import TypedDict as ExtensionsTypedDict -except ImportError: # pragma: no cover - ExtensionsTypedDict = None - -if sys.version_info >= (3, 11): - from builtins import ExceptionGroup -else: - from exceptiongroup import ExceptionGroup - -try: - from typing_extensions import is_typeddict as _is_typeddict -except ImportError: # pragma: no cover - assert sys.version_info >= (3, 10) - from typing import is_typeddict as _is_typeddict - -try: - from typing_extensions import TypeAlias -except ImportError: # pragma: no cover - assert sys.version_info >= (3, 11) - from typing import TypeAlias - -LITERALS = {Literal} -try: - from typing_extensions import Literal as teLiteral - - LITERALS.add(teLiteral) -except ImportError: # pragma: no cover - pass - -# On some Python versions, `typing_extensions.Any` is different than -# `typing.Any`. -try: - from typing_extensions import Any as teAny - - ANIES = frozenset([Any, teAny]) -except ImportError: # pragma: no cover - ANIES = frozenset([Any]) - -NoneType = type(None) - - -def is_optional(typ: Any) -> bool: - return is_union_type(typ) and NoneType in typ.__args__ and len(typ.__args__) == 2 - - -def is_typeddict(cls: Any): - """Thin wrapper around typing(_extensions).is_typeddict""" - return _is_typeddict(getattr(cls, "__origin__", cls)) - - -def has(cls): - return hasattr(cls, "__attrs_attrs__") or hasattr(cls, "__dataclass_fields__") - - -def has_with_generic(cls): - """Test whether the class if a normal or generic attrs or dataclass.""" - return has(cls) or has(get_origin(cls)) - - -def fields(type): - try: - return type.__attrs_attrs__ - except AttributeError: - return dataclass_fields(type) - - -def fields_dict(type) -> dict[str, Union[Attribute, Field]]: - """Return the fields_dict for attrs and dataclasses.""" - if is_dataclass(type): - return {f.name: f for f in dataclass_fields(type)} - return attrs_fields_dict(type) - - -def adapted_fields(cl: type) -> list[Attribute]: - """Return the attrs format of `fields()` for attrs and dataclasses. - - Resolves `attrs` stringified annotations, if present. - """ - if is_dataclass(cl): - attrs = dataclass_fields(cl) - if any(isinstance(a.type, str) for a in attrs): - # Do this conditionally in case `get_type_hints` fails, so - # users can resolve on their own first. - type_hints = get_type_hints(cl) - else: - type_hints = {} - return [ - Attribute( - attr.name, - ( - attr.default - if attr.default is not MISSING - else ( - Factory(attr.default_factory) - if attr.default_factory is not MISSING - else NOTHING - ) - ), - None, - True, - None, - True, - attr.init, - True, - type=type_hints.get(attr.name, attr.type), - alias=attr.name, - kw_only=getattr(attr, "kw_only", False), - ) - for attr in attrs - ] - attribs = attrs_fields(cl) - if any(isinstance(a.type, str) for a in attribs): - # PEP 563 annotations - need to be resolved. - resolve_types(cl) - attribs = attrs_fields(cl) - return attribs - - -def is_subclass(obj: type, bases) -> bool: - """A safe version of issubclass (won't raise).""" - try: - return issubclass(obj, bases) - except TypeError: - return False - - -def is_hetero_tuple(type: Any) -> bool: - origin = getattr(type, "__origin__", None) - return origin is tuple and ... not in type.__args__ - - -def is_protocol(type: Any) -> bool: - return is_subclass(type, Protocol) and getattr(type, "_is_protocol", False) - - -def is_bare_final(type) -> bool: - return type is Final - - -def get_final_base(type) -> Optional[type]: - """Return the base of the Final annotation, if it is Final.""" - if type is Final: - return Any - if type.__class__ is _GenericAlias and type.__origin__ is Final: - return type.__args__[0] - return None - - -OriginAbstractSet = AbcSet -OriginMutableSet = AbcMutableSet - -signature = _signature - -if sys.version_info >= (3, 10): - signature = partial(_signature, eval_str=True) - - -try: - # Not present on 3.9.0, so we try carefully. - from typing import _LiteralGenericAlias - - def is_literal(type: Any) -> bool: - """Is this a literal?""" - return type in LITERALS or ( - isinstance( - type, (_GenericAlias, _LiteralGenericAlias, _SpecialGenericAlias) - ) - and type.__origin__ in LITERALS - ) - -except ImportError: # pragma: no cover - - def is_literal(_) -> bool: - return False - - -Set = AbcSet -MutableSet = AbcMutableSet -Sequence = AbcSequence -MutableSequence = AbcMutableSequence -MutableMapping = AbcMutableMapping -Mapping = AbcMapping -FrozenSetSubscriptable = frozenset -TupleSubscriptable = tuple - - -def is_annotated(type) -> bool: - return getattr(type, "__class__", None) is _AnnotatedAlias - - -def is_tuple(type): - return ( - type in (Tuple, tuple) - or (type.__class__ is _GenericAlias and is_subclass(type.__origin__, Tuple)) - or (getattr(type, "__origin__", None) is tuple) - ) - - -if sys.version_info >= (3, 10): - - def is_union_type(obj): - from types import UnionType - - return ( - obj is Union - or (isinstance(obj, _UnionGenericAlias) and obj.__origin__ is Union) - or isinstance(obj, UnionType) - ) - - def get_newtype_base(typ: Any) -> Optional[type]: - if typ is NewType or isinstance(typ, NewType): - return typ.__supertype__ - return None - - if sys.version_info >= (3, 11): - from typing import NotRequired, Required - else: - from typing_extensions import NotRequired, Required - -else: - # 3.9 - from typing_extensions import NotRequired, Required - - def is_union_type(obj): - return obj is Union or ( - isinstance(obj, _UnionGenericAlias) and obj.__origin__ is Union - ) - - def get_newtype_base(typ: Any) -> Optional[type]: - supertype = getattr(typ, "__supertype__", None) - if ( - supertype is not None - and getattr(typ, "__qualname__", "") == "NewType..new_type" - and typ.__module__ in ("typing", "typing_extensions") - ): - return supertype - return None - - -def get_notrequired_base(type) -> Union[Any, NothingType]: - if is_annotated(type): - # Handle `Annotated[NotRequired[int]]` - type = get_args(type)[0] - if get_origin(type) in (NotRequired, Required): - return get_args(type)[0] - return NOTHING - - -def is_sequence(type: Any) -> bool: - """A predicate function for sequences. - - Matches lists, sequences, mutable sequences, deques and homogenous - tuples. - """ - origin = getattr(type, "__origin__", None) - return ( - type - in ( - List, - list, - TypingSequence, - TypingMutableSequence, - AbcMutableSequence, - tuple, - Tuple, - deque, - Deque, - ) - or ( - type.__class__ is _GenericAlias - and ( - ((origin is not tuple) and is_subclass(origin, TypingSequence)) - or (origin is tuple and type.__args__[1] is ...) - ) - ) - or (origin in (list, deque, AbcMutableSequence, AbcSequence)) - or (origin is tuple and type.__args__[1] is ...) - ) - - -def is_deque(type): - return ( - type in (deque, Deque) - or (type.__class__ is _GenericAlias and is_subclass(type.__origin__, deque)) - or (getattr(type, "__origin__", None) is deque) - ) - - -def is_mutable_set(type: Any) -> bool: - """A predicate function for (mutable) sets. - - Matches built-in sets and sets from the typing module. - """ - return ( - type in (TypingSet, TypingMutableSet, set) - or ( - type.__class__ is _GenericAlias - and is_subclass(type.__origin__, TypingMutableSet) - ) - or (getattr(type, "__origin__", None) in (set, AbcMutableSet, AbcSet)) - ) - - -def is_frozenset(type: Any) -> bool: - """A predicate function for frozensets. - - Matches built-in frozensets and frozensets from the typing module. - """ - return ( - type in (FrozenSet, frozenset) - or (type.__class__ is _GenericAlias and is_subclass(type.__origin__, FrozenSet)) - or (getattr(type, "__origin__", None) is frozenset) - ) - - -def is_bare(type): - return isinstance(type, _SpecialGenericAlias) or ( - not hasattr(type, "__origin__") and not hasattr(type, "__args__") - ) - - -def is_mapping(type: Any) -> bool: - """A predicate function for mappings.""" - return ( - type in (dict, Dict, TypingMapping, TypingMutableMapping, AbcMutableMapping) - or ( - type.__class__ is _GenericAlias - and is_subclass(type.__origin__, TypingMapping) - ) - or is_subclass( - getattr(type, "__origin__", type), (dict, AbcMutableMapping, AbcMapping) - ) - ) - - -def is_counter(type): - return ( - type in (Counter, TypingCounter) or getattr(type, "__origin__", None) is Counter - ) - - -def is_generic(type) -> bool: - """Whether `type` is a generic type.""" - # Inheriting from protocol will inject `Generic` into the MRO - # without `__orig_bases__`. - return isinstance(type, (_GenericAlias, GenericAlias)) or ( - is_subclass(type, Generic) and hasattr(type, "__orig_bases__") - ) - - -def copy_with(type, args): - """Replace a generic type's arguments.""" - if is_annotated(type): - # typing.Annotated requires a special case. - return Annotated[args] - if isinstance(args, tuple) and len(args) == 1: - # Some annotations can't handle 1-tuples. - args = args[0] - return type.__origin__[args] - - -def get_full_type_hints(obj, globalns=None, localns=None): - return get_type_hints(obj, globalns, localns, include_extras=True) - - -def is_generic_attrs(type) -> bool: - """Return True for both specialized (A[int]) and unspecialized (A) generics.""" - return is_generic(type) and has(type.__origin__) diff --git a/server/libs/cattrs/_generics.py b/server/libs/cattrs/_generics.py deleted file mode 100644 index 6f36e94..0000000 --- a/server/libs/cattrs/_generics.py +++ /dev/null @@ -1,32 +0,0 @@ -from collections.abc import Mapping -from typing import Any - -from attrs import NOTHING -from typing_extensions import Self - -from ._compat import copy_with, get_args, is_annotated, is_generic - - -def deep_copy_with(t, mapping: Mapping[str, Any], self_is=NOTHING): - args = get_args(t) - rest = () - if is_annotated(t) and args: - # If we're dealing with `Annotated`, we only map the first type parameter - rest = tuple(args[1:]) - args = (args[0],) - new_args = ( - tuple( - ( - self_is - if a is Self and self_is is not NOTHING - else ( - mapping[a.__name__] - if hasattr(a, "__name__") and a.__name__ in mapping - else (deep_copy_with(a, mapping, self_is) if is_generic(a) else a) - ) - ) - for a in args - ) - + rest - ) - return copy_with(t, new_args) if new_args != args else t diff --git a/server/libs/cattrs/cols.py b/server/libs/cattrs/cols.py deleted file mode 100644 index 0b578eb..0000000 --- a/server/libs/cattrs/cols.py +++ /dev/null @@ -1,309 +0,0 @@ -"""Utility functions for collections.""" - -from __future__ import annotations - -from collections import defaultdict -from collections.abc import Callable, Iterable -from functools import partial -from typing import ( - TYPE_CHECKING, - Any, - DefaultDict, - Literal, - NamedTuple, - TypeVar, - get_type_hints, -) - -from attrs import NOTHING, Attribute, NothingType - -from ._compat import ( - ANIES, - get_args, - get_origin, - is_bare, - is_frozenset, - is_mapping, - is_sequence, - is_subclass, -) -from ._compat import is_mutable_set as is_set -from .dispatch import StructureHook, UnstructureHook -from .errors import IterableValidationError, IterableValidationNote -from .fns import identity -from .gen import ( - AttributeOverride, - already_generating, - make_dict_structure_fn_from_attrs, - make_dict_unstructure_fn_from_attrs, - make_hetero_tuple_unstructure_fn, - mapping_structure_factory, - mapping_unstructure_factory, -) -from .gen import make_iterable_unstructure_fn as iterable_unstructure_factory - -if TYPE_CHECKING: - from .converters import BaseConverter - -__all__ = [ - "defaultdict_structure_factory", - "is_any_set", - "is_defaultdict", - "is_frozenset", - "is_mapping", - "is_namedtuple", - "is_sequence", - "is_set", - "iterable_unstructure_factory", - "list_structure_factory", - "mapping_structure_factory", - "mapping_unstructure_factory", - "namedtuple_dict_structure_factory", - "namedtuple_dict_unstructure_factory", - "namedtuple_structure_factory", - "namedtuple_unstructure_factory", -] - - -def is_any_set(type) -> bool: - """A predicate function for both mutable and frozensets.""" - return is_set(type) or is_frozenset(type) - - -def is_namedtuple(type: Any) -> bool: - """A predicate function for named tuples.""" - - if is_subclass(type, tuple): - for cl in type.mro(): - orig_bases = cl.__dict__.get("__orig_bases__", ()) - if NamedTuple in orig_bases: - return True - return False - - -def _is_passthrough(type: type[tuple], converter: BaseConverter) -> bool: - """If all fields would be passed through, this class should not be processed - either. - """ - return all( - converter.get_unstructure_hook(t) == identity - for t in type.__annotations__.values() - ) - - -T = TypeVar("T") - - -def list_structure_factory(type: type, converter: BaseConverter) -> StructureHook: - """A hook factory for structuring lists. - - Converts any given iterable into a list. - """ - - if is_bare(type) or type.__args__[0] in ANIES: - - def structure_list(obj: Iterable[T], _: type = type) -> list[T]: - return list(obj) - - return structure_list - - elem_type = type.__args__[0] - - try: - handler = converter.get_structure_hook(elem_type) - except RecursionError: - # Break the cycle by using late binding. - handler = converter.structure - - if converter.detailed_validation: - - def structure_list( - obj: Iterable[T], _: type = type, _handler=handler, _elem_type=elem_type - ) -> list[T]: - errors = [] - res = [] - ix = 0 # Avoid `enumerate` for performance. - for e in obj: - try: - res.append(handler(e, _elem_type)) - except Exception as e: - msg = IterableValidationNote( - f"Structuring {type} @ index {ix}", ix, elem_type - ) - e.__notes__ = [*getattr(e, "__notes__", []), msg] - errors.append(e) - finally: - ix += 1 - if errors: - raise IterableValidationError( - f"While structuring {type!r}", errors, type - ) - - return res - - else: - - def structure_list( - obj: Iterable[T], _: type = type, _handler=handler, _elem_type=elem_type - ) -> list[T]: - return [_handler(e, _elem_type) for e in obj] - - return structure_list - - -def namedtuple_unstructure_factory( - cl: type[tuple], converter: BaseConverter, unstructure_to: Any = None -) -> UnstructureHook: - """A hook factory for unstructuring namedtuples. - - :param unstructure_to: Force unstructuring to this type, if provided. - """ - - if unstructure_to is None and _is_passthrough(cl, converter): - return identity - - return make_hetero_tuple_unstructure_fn( - cl, - converter, - unstructure_to=tuple if unstructure_to is None else unstructure_to, - type_args=tuple(cl.__annotations__.values()), - ) - - -def namedtuple_structure_factory( - cl: type[tuple], converter: BaseConverter -) -> StructureHook: - """A hook factory for structuring namedtuples from iterables.""" - # We delegate to the existing infrastructure for heterogenous tuples. - hetero_tuple_type = tuple[tuple(cl.__annotations__.values())] - base_hook = converter.get_structure_hook(hetero_tuple_type) - return lambda v, _: cl(*base_hook(v, hetero_tuple_type)) - - -def _namedtuple_to_attrs(cl: type[tuple]) -> list[Attribute]: - """Generate pseudo attributes for a namedtuple.""" - return [ - Attribute( - name, - cl._field_defaults.get(name, NOTHING), - None, - False, - False, - False, - True, - False, - type=a, - alias=name, - ) - for name, a in get_type_hints(cl).items() - ] - - -def namedtuple_dict_structure_factory( - cl: type[tuple], - converter: BaseConverter, - detailed_validation: bool | Literal["from_converter"] = "from_converter", - forbid_extra_keys: bool = False, - use_linecache: bool = True, - /, - **kwargs: AttributeOverride, -) -> StructureHook: - """A hook factory for hooks structuring namedtuples from dictionaries. - - :param forbid_extra_keys: Whether the hook should raise a `ForbiddenExtraKeysError` - if unknown keys are encountered. - :param use_linecache: Whether to store the source code in the Python linecache. - - .. versionadded:: 24.1.0 - """ - try: - working_set = already_generating.working_set - except AttributeError: - working_set = set() - already_generating.working_set = working_set - else: - if cl in working_set: - raise RecursionError() - - working_set.add(cl) - - try: - return make_dict_structure_fn_from_attrs( - _namedtuple_to_attrs(cl), - cl, - converter, - _cattrs_forbid_extra_keys=forbid_extra_keys, - _cattrs_use_detailed_validation=detailed_validation, - _cattrs_use_linecache=use_linecache, - **kwargs, - ) - finally: - working_set.remove(cl) - if not working_set: - del already_generating.working_set - - -def namedtuple_dict_unstructure_factory( - cl: type[tuple], - converter: BaseConverter, - omit_if_default: bool = False, - use_linecache: bool = True, - /, - **kwargs: AttributeOverride, -) -> UnstructureHook: - """A hook factory for hooks unstructuring namedtuples to dictionaries. - - :param omit_if_default: When true, attributes equal to their default values - will be omitted in the result dictionary. - :param use_linecache: Whether to store the source code in the Python linecache. - - .. versionadded:: 24.1.0 - """ - try: - working_set = already_generating.working_set - except AttributeError: - working_set = set() - already_generating.working_set = working_set - if cl in working_set: - raise RecursionError() - - working_set.add(cl) - - try: - return make_dict_unstructure_fn_from_attrs( - _namedtuple_to_attrs(cl), - cl, - converter, - _cattrs_omit_if_default=omit_if_default, - _cattrs_use_linecache=use_linecache, - **kwargs, - ) - finally: - working_set.remove(cl) - if not working_set: - del already_generating.working_set - - -def is_defaultdict(type: Any) -> bool: - """Is this type a defaultdict? - - Bare defaultdicts (defaultdicts with no type arguments) are not supported - since there's no way to discover their _default_factory_. - """ - return is_subclass(get_origin(type), (defaultdict, DefaultDict)) - - -def defaultdict_structure_factory( - type: type[defaultdict], - converter: BaseConverter, - default_factory: Callable[[], Any] | NothingType = NOTHING, -) -> StructureHook: - """A structure hook factory for defaultdicts. - - The value type parameter will be used as the _default factory_. - """ - if default_factory is NOTHING: - default_factory = get_args(type)[1] - return mapping_structure_factory( - type, converter, partial(defaultdict, default_factory) - ) diff --git a/server/libs/cattrs/converters.py b/server/libs/cattrs/converters.py deleted file mode 100644 index 9a54476..0000000 --- a/server/libs/cattrs/converters.py +++ /dev/null @@ -1,1429 +0,0 @@ -from __future__ import annotations - -from collections import Counter, deque -from collections.abc import Callable, Iterable -from collections.abc import Mapping as AbcMapping -from collections.abc import MutableMapping as AbcMutableMapping -from dataclasses import Field -from enum import Enum -from inspect import Signature -from inspect import signature as inspect_signature -from pathlib import Path -from typing import Any, Optional, Tuple, TypeVar, overload - -from attrs import Attribute, resolve_types -from attrs import has as attrs_has -from typing_extensions import Self - -from ._compat import ( - ANIES, - FrozenSetSubscriptable, - Mapping, - MutableMapping, - MutableSequence, - NoneType, - OriginAbstractSet, - OriginMutableSet, - Sequence, - Set, - TypeAlias, - fields, - get_final_base, - get_newtype_base, - get_origin, - has, - has_with_generic, - is_annotated, - is_bare, - is_counter, - is_deque, - is_frozenset, - is_generic, - is_generic_attrs, - is_hetero_tuple, - is_literal, - is_mapping, - is_mutable_set, - is_optional, - is_protocol, - is_sequence, - is_tuple, - is_typeddict, - is_union_type, - signature, -) -from .cols import ( - defaultdict_structure_factory, - is_defaultdict, - is_namedtuple, - iterable_unstructure_factory, - list_structure_factory, - mapping_structure_factory, - mapping_unstructure_factory, - namedtuple_structure_factory, - namedtuple_unstructure_factory, -) -from .disambiguators import create_default_dis_func, is_supported_union -from .dispatch import ( - HookFactory, - MultiStrategyDispatch, - StructuredValue, - StructureHook, - TargetType, - UnstructuredValue, - UnstructureHook, -) -from .errors import ( - IterableValidationError, - IterableValidationNote, - StructureHandlerNotFoundError, -) -from .fns import Predicate, identity, raise_error -from .gen import ( - AttributeOverride, - HeteroTupleUnstructureFn, - IterableUnstructureFn, - MappingUnstructureFn, - make_dict_structure_fn, - make_dict_unstructure_fn, - make_hetero_tuple_unstructure_fn, -) -from .gen.typeddicts import make_dict_structure_fn as make_typeddict_dict_struct_fn -from .gen.typeddicts import make_dict_unstructure_fn as make_typeddict_dict_unstruct_fn -from .literals import is_literal_containing_enums -from .typealiases import ( - get_type_alias_base, - is_type_alias, - type_alias_structure_factory, -) -from .types import SimpleStructureHook - -__all__ = ["BaseConverter", "Converter", "GenConverter", "UnstructureStrategy"] - -T = TypeVar("T") -V = TypeVar("V") - -UnstructureHookFactory = TypeVar( - "UnstructureHookFactory", bound=HookFactory[UnstructureHook] -) - -# The Extended factory also takes a converter. -ExtendedUnstructureHookFactory: TypeAlias = Callable[[TargetType, T], UnstructureHook] - -# This typevar for the BaseConverter. -AnyUnstructureHookFactoryBase = TypeVar( - "AnyUnstructureHookFactoryBase", - bound="HookFactory[UnstructureHook] | ExtendedUnstructureHookFactory[BaseConverter]", -) - -# This typevar for the Converter. -AnyUnstructureHookFactory = TypeVar( - "AnyUnstructureHookFactory", - bound="HookFactory[UnstructureHook] | ExtendedUnstructureHookFactory[Converter]", -) - -StructureHookFactory = TypeVar("StructureHookFactory", bound=HookFactory[StructureHook]) - -# The Extended factory also takes a converter. -ExtendedStructureHookFactory: TypeAlias = Callable[[TargetType, T], StructureHook] - -# This typevar for the BaseConverter. -AnyStructureHookFactoryBase = TypeVar( - "AnyStructureHookFactoryBase", - bound="HookFactory[StructureHook] | ExtendedStructureHookFactory[BaseConverter]", -) - -# This typevar for the Converter. -AnyStructureHookFactory = TypeVar( - "AnyStructureHookFactory", - bound="HookFactory[StructureHook] | ExtendedStructureHookFactory[Converter]", -) - -UnstructureHookT = TypeVar("UnstructureHookT", bound=UnstructureHook) -StructureHookT = TypeVar("StructureHookT", bound=StructureHook) -CounterT = TypeVar("CounterT", bound=Counter) - - -class UnstructureStrategy(Enum): - """`attrs` classes unstructuring strategies.""" - - AS_DICT = "asdict" - AS_TUPLE = "astuple" - - -def _is_extended_factory(factory: Callable) -> bool: - """Does this factory also accept a converter arg?""" - # We use the original `inspect.signature` to not evaluate string - # annotations. - sig = inspect_signature(factory) - return ( - len(sig.parameters) >= 2 - and (list(sig.parameters.values())[1]).default is Signature.empty - ) - - -class BaseConverter: - """Converts between structured and unstructured data.""" - - __slots__ = ( - "_dict_factory", - "_prefer_attrib_converters", - "_struct_copy_skip", - "_structure_attrs", - "_structure_func", - "_union_struct_registry", - "_unstruct_copy_skip", - "_unstructure_attrs", - "_unstructure_func", - "detailed_validation", - ) - - def __init__( - self, - dict_factory: Callable[[], Any] = dict, - unstruct_strat: UnstructureStrategy = UnstructureStrategy.AS_DICT, - prefer_attrib_converters: bool = False, - detailed_validation: bool = True, - unstructure_fallback_factory: HookFactory[UnstructureHook] = lambda _: identity, - structure_fallback_factory: HookFactory[StructureHook] = lambda t: raise_error( - None, t - ), - ) -> None: - """ - :param detailed_validation: Whether to use a slightly slower mode for detailed - validation errors. - :param unstructure_fallback_factory: A hook factory to be called when no - registered unstructuring hooks match. - :param structure_fallback_factory: A hook factory to be called when no - registered structuring hooks match. - - .. versionadded:: 23.2.0 *unstructure_fallback_factory* - .. versionadded:: 23.2.0 *structure_fallback_factory* - .. versionchanged:: 24.2.0 - The default `structure_fallback_factory` now raises errors for missing handlers - more eagerly, surfacing problems earlier. - """ - unstruct_strat = UnstructureStrategy(unstruct_strat) - self._prefer_attrib_converters = prefer_attrib_converters - - self.detailed_validation = detailed_validation - self._union_struct_registry: dict[Any, Callable[[Any, type[T]], T]] = {} - - # Create a per-instance cache. - if unstruct_strat is UnstructureStrategy.AS_DICT: - self._unstructure_attrs = self.unstructure_attrs_asdict - self._structure_attrs = self.structure_attrs_fromdict - else: - self._unstructure_attrs = self.unstructure_attrs_astuple - self._structure_attrs = self.structure_attrs_fromtuple - - self._unstructure_func = MultiStrategyDispatch( - unstructure_fallback_factory, self - ) - self._unstructure_func.register_cls_list( - [(bytes, identity), (str, identity), (Path, str)] - ) - self._unstructure_func.register_func_list( - [ - ( - is_protocol, - lambda o: self.unstructure(o, unstructure_as=o.__class__), - ), - ( - lambda t: get_final_base(t) is not None, - lambda t: self.get_unstructure_hook(get_final_base(t)), - True, - ), - ( - is_type_alias, - lambda t: self.get_unstructure_hook(get_type_alias_base(t)), - True, - ), - (is_literal_containing_enums, self.unstructure), - (is_mapping, self._unstructure_mapping), - (is_sequence, self._unstructure_seq), - (is_mutable_set, self._unstructure_seq), - (is_frozenset, self._unstructure_seq), - (lambda t: issubclass(t, Enum), self._unstructure_enum), - (has, self._unstructure_attrs), - (is_union_type, self._unstructure_union), - (lambda t: t in ANIES, self.unstructure), - ] - ) - - # Per-instance register of to-attrs converters. - # Singledispatch dispatches based on the first argument, so we - # store the function and switch the arguments in self.loads. - self._structure_func = MultiStrategyDispatch(structure_fallback_factory, self) - self._structure_func.register_func_list( - [ - ( - lambda cl: cl in ANIES or cl is Optional or cl is None, - lambda v, _: v, - ), - (is_generic_attrs, self._gen_structure_generic, True), - (lambda t: get_newtype_base(t) is not None, self._structure_newtype), - (is_type_alias, type_alias_structure_factory, "extended"), - ( - lambda t: get_final_base(t) is not None, - self._structure_final_factory, - True, - ), - (is_literal, self._structure_simple_literal), - (is_literal_containing_enums, self._structure_enum_literal), - (is_sequence, list_structure_factory, "extended"), - (is_deque, self._structure_deque), - (is_mutable_set, self._structure_set), - (is_frozenset, self._structure_frozenset), - (is_tuple, self._structure_tuple), - (is_namedtuple, namedtuple_structure_factory, "extended"), - (is_mapping, self._structure_dict), - (is_supported_union, self._gen_attrs_union_structure, True), - (is_optional, self._structure_optional), - ( - lambda t: is_union_type(t) and t in self._union_struct_registry, - self._union_struct_registry.__getitem__, - True, - ), - (has, self._structure_attrs), - ] - ) - # Strings are sequences. - self._structure_func.register_cls_list( - [ - (str, self._structure_call), - (bytes, self._structure_call), - (int, self._structure_call), - (float, self._structure_call), - (Enum, self._structure_call), - (Path, self._structure_call), - ] - ) - - self._dict_factory = dict_factory - - self._unstruct_copy_skip = self._unstructure_func.get_num_fns() - self._struct_copy_skip = self._structure_func.get_num_fns() - - def unstructure(self, obj: Any, unstructure_as: Any = None) -> Any: - return self._unstructure_func.dispatch( - obj.__class__ if unstructure_as is None else unstructure_as - )(obj) - - @property - def unstruct_strat(self) -> UnstructureStrategy: - """The default way of unstructuring ``attrs`` classes.""" - return ( - UnstructureStrategy.AS_DICT - if self._unstructure_attrs == self.unstructure_attrs_asdict - else UnstructureStrategy.AS_TUPLE - ) - - @overload - def register_unstructure_hook(self, cls: UnstructureHookT) -> UnstructureHookT: ... - - @overload - def register_unstructure_hook(self, cls: Any, func: UnstructureHook) -> None: ... - - def register_unstructure_hook( - self, cls: Any = None, func: UnstructureHook | None = None - ) -> Callable[[UnstructureHook]] | None: - """Register a class-to-primitive converter function for a class. - - The converter function should take an instance of the class and return - its Python equivalent. - - May also be used as a decorator. When used as a decorator, the first - argument annotation from the decorated function will be used as the - type to register the hook for. - - .. versionchanged:: 24.1.0 - This method may now be used as a decorator. - .. versionchanged:: 25.1.0 - Modern type aliases are now supported. - """ - if func is None: - # Autodetecting decorator. - func = cls - sig = signature(func) - cls = next(iter(sig.parameters.values())).annotation - self.register_unstructure_hook(cls, func) - - return func - - if attrs_has(cls): - resolve_types(cls) - if is_union_type(cls): - self._unstructure_func.register_func_list([(lambda t: t == cls, func)]) - elif is_type_alias(cls): - self._unstructure_func.register_func_list([(lambda t: t is cls, func)]) - elif get_newtype_base(cls) is not None: - # This is a newtype, so we handle it specially. - self._unstructure_func.register_func_list([(lambda t: t is cls, func)]) - else: - self._unstructure_func.register_cls_list([(cls, func)]) - return None - - def register_unstructure_hook_func( - self, check_func: Predicate, func: UnstructureHook - ) -> None: - """Register a class-to-primitive converter function for a class, using - a function to check if it's a match. - """ - self._unstructure_func.register_func_list([(check_func, func)]) - - @overload - def register_unstructure_hook_factory( - self, predicate: Predicate - ) -> Callable[[AnyUnstructureHookFactoryBase], AnyUnstructureHookFactoryBase]: ... - - @overload - def register_unstructure_hook_factory( - self, predicate: Predicate, factory: UnstructureHookFactory - ) -> UnstructureHookFactory: ... - - @overload - def register_unstructure_hook_factory( - self, - predicate: Predicate, - factory: ExtendedUnstructureHookFactory[BaseConverter], - ) -> ExtendedUnstructureHookFactory[BaseConverter]: ... - - def register_unstructure_hook_factory(self, predicate, factory=None): - """ - Register a hook factory for a given predicate. - - The hook factory may expose an additional required parameter. In this case, - the current converter will be provided to the hook factory as that - parameter. - - May also be used as a decorator. - - :param predicate: A function that, given a type, returns whether the factory - can produce a hook for that type. - :param factory: A callable that, given a type, produces an unstructuring - hook for that type. This unstructuring hook will be cached. - - .. versionchanged:: 24.1.0 - This method may now be used as a decorator. - The factory may also receive the converter as a second, required argument. - """ - if factory is None: - - def decorator(factory): - # Is this an extended factory (takes a converter too)? - if _is_extended_factory(factory): - self._unstructure_func.register_func_list( - [(predicate, factory, "extended")] - ) - else: - self._unstructure_func.register_func_list( - [(predicate, factory, True)] - ) - - return decorator - - self._unstructure_func.register_func_list( - [ - ( - predicate, - factory, - "extended" if _is_extended_factory(factory) else True, - ) - ] - ) - return factory - - def get_unstructure_hook( - self, type: Any, cache_result: bool = True - ) -> UnstructureHook: - """Get the unstructure hook for the given type. - - This hook can be manually called, or composed with other functions - and re-registered. - - If no hook is registered, the converter unstructure fallback factory - will be used to produce one. - - :param cache: Whether to cache the returned hook. - - .. versionadded:: 24.1.0 - """ - return ( - self._unstructure_func.dispatch(type) - if cache_result - else self._unstructure_func.dispatch_without_caching(type) - ) - - @overload - def register_structure_hook(self, cl: StructureHookT) -> StructureHookT: ... - - @overload - def register_structure_hook(self, cl: Any, func: StructureHook) -> None: ... - - def register_structure_hook( - self, cl: Any, func: StructureHook | None = None - ) -> None: - """Register a primitive-to-class converter function for a type. - - The converter function should take two arguments: - * a Python object to be converted, - * the type to convert to - - and return the instance of the class. The type may seem redundant, but - is sometimes needed (for example, when dealing with generic classes). - - This method may be used as a decorator. In this case, the decorated - hook must have a return type annotation, and this annotation will be used - as the type for the hook. - - .. versionchanged:: 24.1.0 - This method may now be used as a decorator. - .. versionchanged:: 25.1.0 - Modern type aliases are now supported. - """ - if func is None: - # The autodetecting decorator. - func = cl - sig = signature(func) - self.register_structure_hook(sig.return_annotation, func) - return func - - if attrs_has(cl): - resolve_types(cl) - if is_union_type(cl): - self._union_struct_registry[cl] = func - self._structure_func.clear_cache() - elif is_type_alias(cl): - # Type aliases are special-cased. - self._structure_func.register_func_list([(lambda t: t is cl, func)]) - elif get_newtype_base(cl) is not None: - # This is a newtype, so we handle it specially. - self._structure_func.register_func_list([(lambda t: t is cl, func)]) - else: - self._structure_func.register_cls_list([(cl, func)]) - return None - - def register_structure_hook_func( - self, check_func: Predicate, func: StructureHook - ) -> None: - """Register a class-to-primitive converter function for a class, using - a function to check if it's a match. - """ - self._structure_func.register_func_list([(check_func, func)]) - - @overload - def register_structure_hook_factory( - self, predicate: Predicate - ) -> Callable[[AnyStructureHookFactoryBase], AnyStructureHookFactoryBase]: ... - - @overload - def register_structure_hook_factory( - self, predicate: Predicate, factory: StructureHookFactory - ) -> StructureHookFactory: ... - - @overload - def register_structure_hook_factory( - self, predicate: Predicate, factory: ExtendedStructureHookFactory[BaseConverter] - ) -> ExtendedStructureHookFactory[BaseConverter]: ... - - def register_structure_hook_factory(self, predicate, factory=None): - """ - Register a hook factory for a given predicate. - - The hook factory may expose an additional required parameter. In this case, - the current converter will be provided to the hook factory as that - parameter. - - May also be used as a decorator. - - :param predicate: A function that, given a type, returns whether the factory - can produce a hook for that type. - :param factory: A callable that, given a type, produces a structuring - hook for that type. This structuring hook will be cached. - - .. versionchanged:: 24.1.0 - This method may now be used as a decorator. - The factory may also receive the converter as a second, required argument. - """ - if factory is None: - # Decorator use. - def decorator(factory): - # Is this an extended factory (takes a converter too)? - if _is_extended_factory(factory): - self._structure_func.register_func_list( - [(predicate, factory, "extended")] - ) - else: - self._structure_func.register_func_list( - [(predicate, factory, True)] - ) - - return decorator - self._structure_func.register_func_list( - [ - ( - predicate, - factory, - "extended" if _is_extended_factory(factory) else True, - ) - ] - ) - return factory - - def structure(self, obj: UnstructuredValue, cl: type[T]) -> T: - """Convert unstructured Python data structures to structured data.""" - return self._structure_func.dispatch(cl)(obj, cl) - - def get_structure_hook(self, type: Any, cache_result: bool = True) -> StructureHook: - """Get the structure hook for the given type. - - This hook can be manually called, or composed with other functions - and re-registered. - - If no hook is registered, the converter structure fallback factory - will be used to produce one. - - :param cache: Whether to cache the returned hook. - - .. versionadded:: 24.1.0 - """ - return ( - self._structure_func.dispatch(type) - if cache_result - else self._structure_func.dispatch_without_caching(type) - ) - - # Classes to Python primitives. - def unstructure_attrs_asdict(self, obj: Any) -> dict[str, Any]: - """Our version of `attrs.asdict`, so we can call back to us.""" - attrs = fields(obj.__class__) - dispatch = self._unstructure_func.dispatch - rv = self._dict_factory() - for a in attrs: - name = a.name - v = getattr(obj, name) - rv[name] = dispatch(a.type or v.__class__)(v) - return rv - - def unstructure_attrs_astuple(self, obj: Any) -> tuple[Any, ...]: - """Our version of `attrs.astuple`, so we can call back to us.""" - attrs = fields(obj.__class__) - dispatch = self._unstructure_func.dispatch - res = [] - for a in attrs: - name = a.name - v = getattr(obj, name) - res.append(dispatch(a.type or v.__class__)(v)) - return tuple(res) - - def _unstructure_enum(self, obj: Enum) -> Any: - """Convert an enum to its value.""" - return obj.value - - def _unstructure_seq(self, seq: Sequence[T]) -> Sequence[T]: - """Convert a sequence to primitive equivalents.""" - # We can reuse the sequence class, so tuples stay tuples. - dispatch = self._unstructure_func.dispatch - return seq.__class__(dispatch(e.__class__)(e) for e in seq) - - def _unstructure_mapping(self, mapping: Mapping[T, V]) -> Mapping[T, V]: - """Convert a mapping of attr classes to primitive equivalents.""" - - # We can reuse the mapping class, so dicts stay dicts and OrderedDicts - # stay OrderedDicts. - dispatch = self._unstructure_func.dispatch - return mapping.__class__( - (dispatch(k.__class__)(k), dispatch(v.__class__)(v)) - for k, v in mapping.items() - ) - - # note: Use UnionType when 3.11 is released as - # the behaviour of @final is changed. This would - # affect how we can support UnionType in ._compat.py - def _unstructure_union(self, obj: Any) -> Any: - """ - Unstructure an object as a union. - - By default, just unstructures the instance. - """ - return self._unstructure_func.dispatch(obj.__class__)(obj) - - # Python primitives to classes. - - def _gen_structure_generic( - self, cl: type[T] - ) -> SimpleStructureHook[Mapping[str, Any], T]: - """Create and return a hook for structuring generics.""" - return make_dict_structure_fn( - cl, self, _cattrs_prefer_attrib_converters=self._prefer_attrib_converters - ) - - def _gen_attrs_union_structure( - self, cl: Any, use_literals: bool = True - ) -> Callable[[Any, type[T]], type[T] | None]: - """ - Generate a structuring function for a union of attrs classes (and maybe None). - - :param use_literals: Whether to consider literal fields. - """ - dis_fn = self._get_dis_func(cl, use_literals=use_literals) - has_none = NoneType in cl.__args__ - - if has_none: - - def structure_attrs_union(obj, _) -> cl: - if obj is None: - return None - return self.structure(obj, dis_fn(obj)) - - else: - - def structure_attrs_union(obj, _): - return self.structure(obj, dis_fn(obj)) - - return structure_attrs_union - - @staticmethod - def _structure_call(obj: Any, cl: type[T]) -> Any: - """Just call ``cl`` with the given ``obj``. - - This is just an optimization on the ``_structure_default`` case, when - we know we can skip the ``if`` s. Use for ``str``, ``bytes``, ``enum``, - etc. - """ - return cl(obj) - - @staticmethod - def _structure_simple_literal(val, type): - if val not in type.__args__: - raise Exception(f"{val} not in literal {type}") - return val - - @staticmethod - def _structure_enum_literal(val, type): - vals = {(x.value if isinstance(x, Enum) else x): x for x in type.__args__} - try: - return vals[val] - except KeyError: - raise Exception(f"{val} not in literal {type}") from None - - def _structure_newtype(self, val: UnstructuredValue, type) -> StructuredValue: - base = get_newtype_base(type) - return self.get_structure_hook(base)(val, base) - - def _structure_final_factory(self, type): - base = get_final_base(type) - res = self.get_structure_hook(base) - return lambda v, _, __base=base: res(v, __base) - - # Attrs classes. - - def structure_attrs_fromtuple(self, obj: tuple[Any, ...], cl: type[T]) -> T: - """Load an attrs class from a sequence (tuple).""" - conv_obj = [] # A list of converter parameters. - for a, value in zip(fields(cl), obj): - # We detect the type by the metadata. - converted = self._structure_attribute(a, value) - conv_obj.append(converted) - - return cl(*conv_obj) - - def _structure_attribute(self, a: Attribute | Field, value: Any) -> Any: - """Handle an individual attrs attribute.""" - type_ = a.type - attrib_converter = getattr(a, "converter", None) - if self._prefer_attrib_converters and attrib_converter: - # A attrib converter is defined on this attribute, and - # prefer_attrib_converters is set to give these priority over registered - # structure hooks. So, pass through the raw value, which attrs will flow - # into the converter - return value - if type_ is None: - # No type metadata. - return value - - try: - return self._structure_func.dispatch(type_)(value, type_) - except StructureHandlerNotFoundError: - if attrib_converter: - # Return the original value and fallback to using an attrib converter. - return value - raise - - def structure_attrs_fromdict(self, obj: Mapping[str, Any], cl: type[T]) -> T: - """Instantiate an attrs class from a mapping (dict).""" - # For public use. - - conv_obj = {} # Start with a fresh dict, to ignore extra keys. - for a in fields(cl): - try: - val = obj[a.name] - except KeyError: - continue - - # try .alias and .name because this code also supports dataclasses! - conv_obj[getattr(a, "alias", a.name)] = self._structure_attribute(a, val) - - return cl(**conv_obj) - - def _structure_deque(self, obj: Iterable[T], cl: Any) -> deque[T]: - """Convert an iterable to a potentially generic deque.""" - if is_bare(cl) or cl.__args__[0] in ANIES: - res = deque(obj) - else: - elem_type = cl.__args__[0] - handler = self._structure_func.dispatch(elem_type) - if self.detailed_validation: - errors = [] - res = deque() - ix = 0 # Avoid `enumerate` for performance. - for e in obj: - try: - res.append(handler(e, elem_type)) - except Exception as e: - msg = IterableValidationNote( - f"Structuring {cl} @ index {ix}", ix, elem_type - ) - e.__notes__ = [*getattr(e, "__notes__", []), msg] - errors.append(e) - finally: - ix += 1 - if errors: - raise IterableValidationError( - f"While structuring {cl!r}", errors, cl - ) - else: - res = deque(handler(e, elem_type) for e in obj) - return res - - def _structure_set( - self, obj: Iterable[T], cl: Any, structure_to: type = set - ) -> Set[T]: - """Convert an iterable into a potentially generic set.""" - if is_bare(cl) or cl.__args__[0] in ANIES: - return structure_to(obj) - elem_type = cl.__args__[0] - handler = self._structure_func.dispatch(elem_type) - if self.detailed_validation: - errors = [] - res = set() - ix = 0 - for e in obj: - try: - res.add(handler(e, elem_type)) - except Exception as exc: - msg = IterableValidationNote( - f"Structuring {structure_to.__name__} @ element {e!r}", - ix, - elem_type, - ) - exc.__notes__ = [*getattr(exc, "__notes__", []), msg] - errors.append(exc) - finally: - ix += 1 - if errors: - raise IterableValidationError(f"While structuring {cl!r}", errors, cl) - return res if structure_to is set else structure_to(res) - if structure_to is set: - return {handler(e, elem_type) for e in obj} - return structure_to([handler(e, elem_type) for e in obj]) - - def _structure_frozenset( - self, obj: Iterable[T], cl: Any - ) -> FrozenSetSubscriptable[T]: - """Convert an iterable into a potentially generic frozenset.""" - return self._structure_set(obj, cl, structure_to=frozenset) - - def _structure_dict(self, obj: Mapping[T, V], cl: Any) -> dict[T, V]: - """Convert a mapping into a potentially generic dict.""" - if is_bare(cl) or cl.__args__ == (Any, Any): - return dict(obj) - key_type, val_type = cl.__args__ - - if self.detailed_validation: - key_handler = self._structure_func.dispatch(key_type) - val_handler = self._structure_func.dispatch(val_type) - errors = [] - res = {} - - for k, v in obj.items(): - try: - value = val_handler(v, val_type) - except Exception as exc: - msg = IterableValidationNote( - f"Structuring mapping value @ key {k!r}", k, val_type - ) - exc.__notes__ = [*getattr(exc, "__notes__", []), msg] - errors.append(exc) - continue - - try: - key = key_handler(k, key_type) - res[key] = value - except Exception as exc: - msg = IterableValidationNote( - f"Structuring mapping key @ key {k!r}", k, key_type - ) - exc.__notes__ = [*getattr(exc, "__notes__", []), msg] - errors.append(exc) - - if errors: - raise IterableValidationError(f"While structuring {cl!r}", errors, cl) - return res - - if key_type in ANIES: - val_conv = self._structure_func.dispatch(val_type) - return {k: val_conv(v, val_type) for k, v in obj.items()} - if val_type in ANIES: - key_conv = self._structure_func.dispatch(key_type) - return {key_conv(k, key_type): v for k, v in obj.items()} - key_conv = self._structure_func.dispatch(key_type) - val_conv = self._structure_func.dispatch(val_type) - return {key_conv(k, key_type): val_conv(v, val_type) for k, v in obj.items()} - - def _structure_optional(self, obj, union): - if obj is None: - return None - union_params = union.__args__ - other = union_params[0] if union_params[1] is NoneType else union_params[1] - # We can't actually have a Union of a Union, so this is safe. - return self._structure_func.dispatch(other)(obj, other) - - def _structure_tuple(self, obj: Iterable, tup: type[T]) -> T: - """Deal with structuring into a tuple.""" - tup_params = None if tup in (Tuple, tuple) else tup.__args__ - has_ellipsis = tup_params and tup_params[-1] is Ellipsis - if tup_params is None or (has_ellipsis and tup_params[0] in ANIES): - # Just a Tuple. (No generic information.) - return tuple(obj) - if has_ellipsis: - # We're dealing with a homogenous tuple, tuple[int, ...] - tup_type = tup_params[0] - conv = self._structure_func.dispatch(tup_type) - if self.detailed_validation: - errors = [] - res = [] - ix = 0 - for e in obj: - try: - res.append(conv(e, tup_type)) - except Exception as exc: - msg = IterableValidationNote( - f"Structuring {tup} @ index {ix}", ix, tup_type - ) - exc.__notes__ = [*getattr(exc, "__notes__", []), msg] - errors.append(exc) - finally: - ix += 1 - if errors: - raise IterableValidationError( - f"While structuring {tup!r}", errors, tup - ) - return tuple(res) - return tuple(conv(e, tup_type) for e in obj) - - # We're dealing with a heterogenous tuple. - exp_len = len(tup_params) - if self.detailed_validation: - errors = [] - res = [] - for ix, (t, e) in enumerate(zip(tup_params, obj)): - try: - conv = self._structure_func.dispatch(t) - res.append(conv(e, t)) - except Exception as exc: - msg = IterableValidationNote( - f"Structuring {tup} @ index {ix}", ix, t - ) - exc.__notes__ = [*getattr(exc, "__notes__", []), msg] - errors.append(exc) - if len(obj) != exp_len: - problem = "Not enough" if len(res) < exp_len else "Too many" - exc = ValueError(f"{problem} values in {obj!r} to structure as {tup!r}") - msg = f"Structuring {tup}" - exc.__notes__ = [*getattr(exc, "__notes__", []), msg] - errors.append(exc) - if errors: - raise IterableValidationError(f"While structuring {tup!r}", errors, tup) - return tuple(res) - - if len(obj) != exp_len: - problem = "Not enough" if len(obj) < len(tup_params) else "Too many" - raise ValueError(f"{problem} values in {obj!r} to structure as {tup!r}") - return tuple( - [self._structure_func.dispatch(t)(e, t) for t, e in zip(tup_params, obj)] - ) - - def _get_dis_func( - self, - union: Any, - use_literals: bool = True, - overrides: dict[str, AttributeOverride] | None = None, - ) -> Callable[[Any], type]: - """Fetch or try creating a disambiguation function for a union.""" - union_types = union.__args__ - if NoneType in union_types: - # We support unions of attrs classes and NoneType higher in the - # logic. - union_types = tuple(e for e in union_types if e is not NoneType) - - if not all(has(get_origin(e) or e) for e in union_types): - raise StructureHandlerNotFoundError( - "Only unions of attrs classes and dataclasses supported " - "currently. Register a structure hook manually.", - type_=union, - ) - - return create_default_dis_func( - self, - *union_types, - use_literals=use_literals, - overrides=overrides if overrides is not None else "from_converter", - ) - - def __deepcopy__(self, _) -> BaseConverter: - return self.copy() - - def copy( - self, - dict_factory: Callable[[], Any] | None = None, - unstruct_strat: UnstructureStrategy | None = None, - prefer_attrib_converters: bool | None = None, - detailed_validation: bool | None = None, - ) -> Self: - """Create a copy of the converter, keeping all existing custom hooks. - - :param detailed_validation: Whether to use a slightly slower mode for detailed - validation errors. - """ - res = self.__class__( - dict_factory if dict_factory is not None else self._dict_factory, - ( - unstruct_strat - if unstruct_strat is not None - else ( - UnstructureStrategy.AS_DICT - if self._unstructure_attrs == self.unstructure_attrs_asdict - else UnstructureStrategy.AS_TUPLE - ) - ), - ( - prefer_attrib_converters - if prefer_attrib_converters is not None - else self._prefer_attrib_converters - ), - ( - detailed_validation - if detailed_validation is not None - else self.detailed_validation - ), - ) - - self._unstructure_func.copy_to(res._unstructure_func, self._unstruct_copy_skip) - self._structure_func.copy_to(res._structure_func, self._struct_copy_skip) - - return res - - -class Converter(BaseConverter): - """A converter which generates specialized un/structuring functions.""" - - __slots__ = ( - "_unstruct_collection_overrides", - "forbid_extra_keys", - "omit_if_default", - "type_overrides", - ) - - def __init__( - self, - dict_factory: Callable[[], Any] = dict, - unstruct_strat: UnstructureStrategy = UnstructureStrategy.AS_DICT, - omit_if_default: bool = False, - forbid_extra_keys: bool = False, - type_overrides: Mapping[type, AttributeOverride] = {}, - unstruct_collection_overrides: Mapping[type, UnstructureHook] = {}, - prefer_attrib_converters: bool = False, - detailed_validation: bool = True, - unstructure_fallback_factory: HookFactory[UnstructureHook] = lambda _: identity, - structure_fallback_factory: HookFactory[StructureHook] = lambda t: raise_error( - None, t - ), - ): - """ - :param detailed_validation: Whether to use a slightly slower mode for detailed - validation errors. - :param unstructure_fallback_factory: A hook factory to be called when no - registered unstructuring hooks match. - :param structure_fallback_factory: A hook factory to be called when no - registered structuring hooks match. - - .. versionadded:: 23.2.0 *unstructure_fallback_factory* - .. versionadded:: 23.2.0 *structure_fallback_factory* - .. versionchanged:: 24.2.0 - The default `structure_fallback_factory` now raises errors for missing handlers - more eagerly, surfacing problems earlier. - """ - super().__init__( - dict_factory=dict_factory, - unstruct_strat=unstruct_strat, - prefer_attrib_converters=prefer_attrib_converters, - detailed_validation=detailed_validation, - unstructure_fallback_factory=unstructure_fallback_factory, - structure_fallback_factory=structure_fallback_factory, - ) - self.omit_if_default = omit_if_default - self.forbid_extra_keys = forbid_extra_keys - self.type_overrides = dict(type_overrides) - - unstruct_collection_overrides = { - get_origin(k) or k: v for k, v in unstruct_collection_overrides.items() - } - - self._unstruct_collection_overrides = unstruct_collection_overrides - - # Do a little post-processing magic to make things easier for users. - co = unstruct_collection_overrides - - # abc.Set overrides, if defined, apply to abc.MutableSets and sets - if OriginAbstractSet in co: - if OriginMutableSet not in co: - co[OriginMutableSet] = co[OriginAbstractSet] - if FrozenSetSubscriptable not in co: - co[FrozenSetSubscriptable] = co[OriginAbstractSet] - - # abc.MutableSet overrrides, if defined, apply to sets - if OriginMutableSet in co and set not in co: - co[set] = co[OriginMutableSet] - - # abc.Sequence overrides, if defined, can apply to MutableSequences, lists and - # tuples - if Sequence in co: - if MutableSequence not in co: - co[MutableSequence] = co[Sequence] - if tuple not in co: - co[tuple] = co[Sequence] - - # abc.MutableSequence overrides, if defined, can apply to lists - if MutableSequence in co: - if list not in co: - co[list] = co[MutableSequence] - if deque not in co: - co[deque] = co[MutableSequence] - - # abc.Mapping overrides, if defined, can apply to MutableMappings - if Mapping in co and MutableMapping not in co: - co[MutableMapping] = co[Mapping] - - # abc.MutableMapping overrides, if defined, can apply to dicts - if MutableMapping in co and dict not in co: - co[dict] = co[MutableMapping] - - # builtins.dict overrides, if defined, can apply to counters - if dict in co and Counter not in co: - co[Counter] = co[dict] - - if unstruct_strat is UnstructureStrategy.AS_DICT: - # Override the attrs handler. - self.register_unstructure_hook_factory( - has_with_generic, self.gen_unstructure_attrs_fromdict - ) - self.register_structure_hook_factory( - has_with_generic, self.gen_structure_attrs_fromdict - ) - self.register_unstructure_hook_factory( - is_annotated, self.gen_unstructure_annotated - ) - self.register_unstructure_hook_factory( - is_hetero_tuple, self.gen_unstructure_hetero_tuple - ) - self.register_unstructure_hook_factory(is_namedtuple)( - namedtuple_unstructure_factory - ) - self.register_unstructure_hook_factory( - is_sequence, self.gen_unstructure_iterable - ) - self.register_unstructure_hook_factory(is_mapping, self.gen_unstructure_mapping) - self.register_unstructure_hook_factory( - is_mutable_set, - lambda cl: self.gen_unstructure_iterable(cl, unstructure_to=set), - ) - self.register_unstructure_hook_factory( - is_frozenset, - lambda cl: self.gen_unstructure_iterable(cl, unstructure_to=frozenset), - ) - self.register_unstructure_hook_factory( - is_optional, self.gen_unstructure_optional - ) - self.register_unstructure_hook_factory( - is_typeddict, self.gen_unstructure_typeddict - ) - self.register_unstructure_hook_factory( - lambda t: get_newtype_base(t) is not None, - lambda t: self.get_unstructure_hook(get_newtype_base(t)), - ) - - self.register_structure_hook_factory(is_annotated, self.gen_structure_annotated) - self.register_structure_hook_factory(is_mapping, self.gen_structure_mapping) - self.register_structure_hook_factory(is_counter, self.gen_structure_counter) - self.register_structure_hook_factory( - is_defaultdict, defaultdict_structure_factory - ) - self.register_structure_hook_factory(is_typeddict, self.gen_structure_typeddict) - self.register_structure_hook_factory( - lambda t: get_newtype_base(t) is not None, self.get_structure_newtype - ) - - # We keep these so we can more correctly copy the hooks. - self._struct_copy_skip = self._structure_func.get_num_fns() - self._unstruct_copy_skip = self._unstructure_func.get_num_fns() - - @overload - def register_unstructure_hook_factory( - self, predicate: Predicate - ) -> Callable[[AnyUnstructureHookFactory], AnyUnstructureHookFactory]: ... - - @overload - def register_unstructure_hook_factory( - self, predicate: Predicate, factory: UnstructureHookFactory - ) -> UnstructureHookFactory: ... - - @overload - def register_unstructure_hook_factory( - self, predicate: Predicate, factory: ExtendedUnstructureHookFactory[Converter] - ) -> ExtendedUnstructureHookFactory[Converter]: ... - - def register_unstructure_hook_factory(self, predicate, factory=None): - # This dummy wrapper is required due to how `@overload` works. - return super().register_unstructure_hook_factory(predicate, factory) - - @overload - def register_structure_hook_factory( - self, predicate: Predicate - ) -> Callable[[AnyStructureHookFactory], AnyStructureHookFactory]: ... - - @overload - def register_structure_hook_factory( - self, predicate: Predicate, factory: StructureHookFactory - ) -> StructureHookFactory: ... - - @overload - def register_structure_hook_factory( - self, predicate: Predicate, factory: ExtendedStructureHookFactory[Converter] - ) -> ExtendedStructureHookFactory[Converter]: ... - - def register_structure_hook_factory(self, predicate, factory=None): - # This dummy wrapper is required due to how `@overload` works. - return super().register_structure_hook_factory(predicate, factory) - - def get_structure_newtype(self, type: type[T]) -> Callable[[Any, Any], T]: - base = get_newtype_base(type) - handler = self.get_structure_hook(base) - return lambda v, _: handler(v, base) - - def gen_unstructure_annotated(self, type): - origin = type.__origin__ - return self.get_unstructure_hook(origin) - - def gen_structure_annotated(self, type) -> Callable: - """A hook factory for annotated types.""" - origin = type.__origin__ - hook = self.get_structure_hook(origin) - return lambda v, _: hook(v, origin) - - def gen_unstructure_typeddict(self, cl: Any) -> Callable[[dict], dict]: - """Generate a TypedDict unstructure function. - - Also apply converter-scored modifications. - """ - return make_typeddict_dict_unstruct_fn(cl, self) - - def gen_unstructure_attrs_fromdict( - self, cl: type[T] - ) -> Callable[[T], dict[str, Any]]: - origin = get_origin(cl) - attribs = fields(origin or cl) - if attrs_has(cl) and any(isinstance(a.type, str) for a in attribs): - # PEP 563 annotations - need to be resolved. - resolve_types(cl) - attrib_overrides = { - a.name: self.type_overrides[a.type] - for a in attribs - if a.type in self.type_overrides - } - - return make_dict_unstructure_fn( - cl, self, _cattrs_omit_if_default=self.omit_if_default, **attrib_overrides - ) - - def gen_unstructure_optional(self, cl: type[T]) -> Callable[[T], Any]: - """Generate an unstructuring hook for optional types.""" - union_params = cl.__args__ - other = union_params[0] if union_params[1] is NoneType else union_params[1] - - if isinstance(other, TypeVar): - handler = self.unstructure - else: - handler = self.get_unstructure_hook(other) - - def unstructure_optional(val, _handler=handler): - return None if val is None else _handler(val) - - return unstructure_optional - - def gen_structure_typeddict(self, cl: Any) -> Callable[[dict, Any], dict]: - """Generate a TypedDict structure function. - - Also apply converter-scored modifications. - """ - return make_typeddict_dict_struct_fn( - cl, self, _cattrs_detailed_validation=self.detailed_validation - ) - - def gen_structure_attrs_fromdict( - self, cl: type[T] - ) -> Callable[[Mapping[str, Any], Any], T]: - attribs = fields(get_origin(cl) or cl if is_generic(cl) else cl) - if attrs_has(cl) and any(isinstance(a.type, str) for a in attribs): - # PEP 563 annotations - need to be resolved. - resolve_types(cl) - attrib_overrides = { - a.name: self.type_overrides[a.type] - for a in attribs - if a.type in self.type_overrides - } - return make_dict_structure_fn( - cl, - self, - _cattrs_forbid_extra_keys=self.forbid_extra_keys, - _cattrs_prefer_attrib_converters=self._prefer_attrib_converters, - _cattrs_detailed_validation=self.detailed_validation, - **attrib_overrides, - ) - - def gen_unstructure_iterable( - self, cl: Any, unstructure_to: Any = None - ) -> IterableUnstructureFn: - unstructure_to = self._unstruct_collection_overrides.get( - get_origin(cl) or cl, unstructure_to or list - ) - h = iterable_unstructure_factory(cl, self, unstructure_to=unstructure_to) - self._unstructure_func.register_cls_list([(cl, h)], direct=True) - return h - - def gen_unstructure_hetero_tuple( - self, cl: Any, unstructure_to: Any = None - ) -> HeteroTupleUnstructureFn: - unstructure_to = self._unstruct_collection_overrides.get( - get_origin(cl) or cl, unstructure_to or tuple - ) - h = make_hetero_tuple_unstructure_fn(cl, self, unstructure_to=unstructure_to) - self._unstructure_func.register_cls_list([(cl, h)], direct=True) - return h - - def gen_unstructure_mapping( - self, - cl: Any, - unstructure_to: Any = None, - key_handler: Callable[[Any, Any | None], Any] | None = None, - ) -> MappingUnstructureFn: - unstructure_to = self._unstruct_collection_overrides.get( - get_origin(cl) or cl, unstructure_to or dict - ) - h = mapping_unstructure_factory( - cl, self, unstructure_to=unstructure_to, key_handler=key_handler - ) - self._unstructure_func.register_cls_list([(cl, h)], direct=True) - return h - - def gen_structure_counter( - self, cl: type[CounterT] - ) -> SimpleStructureHook[Mapping[Any, Any], CounterT]: - h = mapping_structure_factory( - cl, - self, - structure_to=Counter, - val_type=int, - detailed_validation=self.detailed_validation, - ) - self._structure_func.register_cls_list([(cl, h)], direct=True) - return h - - def gen_structure_mapping( - self, cl: Any - ) -> SimpleStructureHook[Mapping[Any, Any], Any]: - structure_to = get_origin(cl) or cl - if structure_to in ( - MutableMapping, - AbcMutableMapping, - Mapping, - AbcMapping, - ): # These default to dicts - structure_to = dict - h = mapping_structure_factory( - cl, self, structure_to, detailed_validation=self.detailed_validation - ) - self._structure_func.register_cls_list([(cl, h)], direct=True) - return h - - def copy( - self, - dict_factory: Callable[[], Any] | None = None, - unstruct_strat: UnstructureStrategy | None = None, - omit_if_default: bool | None = None, - forbid_extra_keys: bool | None = None, - type_overrides: Mapping[type, AttributeOverride] | None = None, - unstruct_collection_overrides: Mapping[type, UnstructureHook] | None = None, - prefer_attrib_converters: bool | None = None, - detailed_validation: bool | None = None, - ) -> Self: - """Create a copy of the converter, keeping all existing custom hooks. - - :param detailed_validation: Whether to use a slightly slower mode for detailed - validation errors. - """ - res = self.__class__( - dict_factory if dict_factory is not None else self._dict_factory, - ( - unstruct_strat - if unstruct_strat is not None - else ( - UnstructureStrategy.AS_DICT - if self._unstructure_attrs == self.unstructure_attrs_asdict - else UnstructureStrategy.AS_TUPLE - ) - ), - omit_if_default if omit_if_default is not None else self.omit_if_default, - ( - forbid_extra_keys - if forbid_extra_keys is not None - else self.forbid_extra_keys - ), - type_overrides if type_overrides is not None else self.type_overrides, - ( - unstruct_collection_overrides - if unstruct_collection_overrides is not None - else self._unstruct_collection_overrides - ), - ( - prefer_attrib_converters - if prefer_attrib_converters is not None - else self._prefer_attrib_converters - ), - ( - detailed_validation - if detailed_validation is not None - else self.detailed_validation - ), - ) - - self._unstructure_func.copy_to( - res._unstructure_func, skip=self._unstruct_copy_skip - ) - self._structure_func.copy_to(res._structure_func, skip=self._struct_copy_skip) - - return res - - -GenConverter: TypeAlias = Converter diff --git a/server/libs/cattrs/disambiguators.py b/server/libs/cattrs/disambiguators.py deleted file mode 100644 index 6fc5d9d..0000000 --- a/server/libs/cattrs/disambiguators.py +++ /dev/null @@ -1,206 +0,0 @@ -"""Utilities for union (sum type) disambiguation.""" - -from __future__ import annotations - -from collections import defaultdict -from collections.abc import Mapping -from dataclasses import MISSING -from functools import reduce -from operator import or_ -from typing import TYPE_CHECKING, Any, Callable, Literal, Union - -from attrs import NOTHING, Attribute, AttrsInstance - -from ._compat import ( - NoneType, - adapted_fields, - fields_dict, - get_args, - get_origin, - has, - is_literal, - is_union_type, -) -from .gen import AttributeOverride - -if TYPE_CHECKING: - from .converters import BaseConverter - -__all__ = ["create_default_dis_func", "is_supported_union"] - - -def is_supported_union(typ: Any) -> bool: - """Whether the type is a union of attrs classes or dataclasses.""" - return is_union_type(typ) and all( - e is NoneType or has(get_origin(e) or e) for e in typ.__args__ - ) - - -def create_default_dis_func( - converter: BaseConverter, - *classes: type[AttrsInstance], - use_literals: bool = True, - overrides: ( - dict[str, AttributeOverride] | Literal["from_converter"] - ) = "from_converter", -) -> Callable[[Mapping[Any, Any]], type[Any] | None]: - """Given attrs classes or dataclasses, generate a disambiguation function. - - The function is based on unique fields without defaults or unique values. - - :param use_literals: Whether to try using fields annotated as literals for - disambiguation. - :param overrides: Attribute overrides to apply. - - .. versionchanged:: 24.1.0 - Dataclasses are now supported. - """ - if len(classes) < 2: - raise ValueError("At least two classes required.") - - if overrides == "from_converter": - overrides = [ - getattr(converter.get_structure_hook(c), "overrides", {}) for c in classes - ] - else: - overrides = [overrides for _ in classes] - - # first, attempt for unique values - if use_literals: - # requirements for a discriminator field: - # (... TODO: a single fallback is OK) - # - it must always be enumerated - cls_candidates = [ - { - at.name - for at in adapted_fields(get_origin(cl) or cl) - if is_literal(at.type) - } - for cl in classes - ] - - # literal field names common to all members - discriminators: set[str] = cls_candidates[0] - for possible_discriminators in cls_candidates: - discriminators &= possible_discriminators - - best_result = None - best_discriminator = None - for discriminator in discriminators: - # maps Literal values (strings, ints...) to classes - mapping = defaultdict(list) - - for cl in classes: - for key in get_args( - fields_dict(get_origin(cl) or cl)[discriminator].type - ): - mapping[key].append(cl) - - if best_result is None or max(len(v) for v in mapping.values()) <= max( - len(v) for v in best_result.values() - ): - best_result = mapping - best_discriminator = discriminator - - if ( - best_result - and best_discriminator - and max(len(v) for v in best_result.values()) != len(classes) - ): - final_mapping = { - k: v[0] if len(v) == 1 else Union[tuple(v)] - for k, v in best_result.items() - } - - def dis_func(data: Mapping[Any, Any]) -> type | None: - if not isinstance(data, Mapping): - raise ValueError("Only input mappings are supported.") - return final_mapping[data[best_discriminator]] - - return dis_func - - # next, attempt for unique keys - - # NOTE: This could just as well work with just field availability and not - # uniqueness, returning Unions ... it doesn't do that right now. - cls_and_attrs = [ - (cl, *_usable_attribute_names(cl, override)) - for cl, override in zip(classes, overrides) - ] - # For each class, attempt to generate a single unique required field. - uniq_attrs_dict: dict[str, type] = {} - - # We start from classes with the largest number of unique fields - # so we can do easy picks first, making later picks easier. - cls_and_attrs.sort(key=lambda c_a: len(c_a[1]), reverse=True) - - fallback = None # If none match, try this. - - for cl, cl_reqs, back_map in cls_and_attrs: - # We do not have to consider classes we've already processed, since - # they will have been eliminated by the match dictionary already. - other_classes = [ - c_and_a - for c_and_a in cls_and_attrs - if c_and_a[0] is not cl and c_and_a[0] not in uniq_attrs_dict.values() - ] - other_reqs = reduce(or_, (c_a[1] for c_a in other_classes), set()) - uniq = cl_reqs - other_reqs - - # We want a unique attribute with no default. - cl_fields = fields_dict(get_origin(cl) or cl) - for maybe_renamed_attr_name in uniq: - orig_name = back_map[maybe_renamed_attr_name] - if cl_fields[orig_name].default in (NOTHING, MISSING): - break - else: - if fallback is None: - fallback = cl - continue - raise TypeError(f"{cl} has no usable non-default attributes") - uniq_attrs_dict[maybe_renamed_attr_name] = cl - - if fallback is None: - - def dis_func(data: Mapping[Any, Any]) -> type[AttrsInstance] | None: - if not isinstance(data, Mapping): - raise ValueError("Only input mappings are supported") - for k, v in uniq_attrs_dict.items(): - if k in data: - return v - raise ValueError("Couldn't disambiguate") - - else: - - def dis_func(data: Mapping[Any, Any]) -> type[AttrsInstance] | None: - if not isinstance(data, Mapping): - raise ValueError("Only input mappings are supported") - for k, v in uniq_attrs_dict.items(): - if k in data: - return v - return fallback - - return dis_func - - -create_uniq_field_dis_func = create_default_dis_func - - -def _overriden_name(at: Attribute, override: AttributeOverride | None) -> str: - if override is None or override.rename is None: - return at.name - return override.rename - - -def _usable_attribute_names( - cl: type[Any], overrides: dict[str, AttributeOverride] -) -> tuple[set[str], dict[str, str]]: - """Return renamed fields and a mapping to original field names.""" - res = set() - mapping = {} - - for at in adapted_fields(get_origin(cl) or cl): - res.add(n := _overriden_name(at, overrides.get(at.name))) - mapping[n] = at.name - - return res, mapping diff --git a/server/libs/cattrs/dispatch.py b/server/libs/cattrs/dispatch.py deleted file mode 100644 index f98dc51..0000000 --- a/server/libs/cattrs/dispatch.py +++ /dev/null @@ -1,193 +0,0 @@ -from __future__ import annotations - -from functools import lru_cache, singledispatch -from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, TypeVar - -from attrs import Factory, define - -from ._compat import TypeAlias -from .fns import Predicate - -if TYPE_CHECKING: - from .converters import BaseConverter - -TargetType: TypeAlias = Any -UnstructuredValue: TypeAlias = Any -StructuredValue: TypeAlias = Any - -StructureHook: TypeAlias = Callable[[UnstructuredValue, TargetType], StructuredValue] -UnstructureHook: TypeAlias = Callable[[StructuredValue], UnstructuredValue] - -Hook = TypeVar("Hook", StructureHook, UnstructureHook) -HookFactory: TypeAlias = Callable[[TargetType], Hook] - - -@define -class _DispatchNotFound: - """A dummy object to help signify a dispatch not found.""" - - -@define -class FunctionDispatch: - """ - FunctionDispatch is similar to functools.singledispatch, but - instead dispatches based on functions that take the type of the - first argument in the method, and return True or False. - - objects that help determine dispatch should be instantiated objects. - - :param converter: A converter to be used for factories that require converters. - - .. versionchanged:: 24.1.0 - Support for factories that require converters, hence this requires a - converter when creating. - """ - - _converter: BaseConverter - _handler_pairs: list[tuple[Predicate, Callable[[Any, Any], Any], bool, bool]] = ( - Factory(list) - ) - - def register( - self, - predicate: Predicate, - func: Callable[..., Any], - is_generator=False, - takes_converter=False, - ) -> None: - self._handler_pairs.insert(0, (predicate, func, is_generator, takes_converter)) - - def dispatch(self, typ: Any) -> Callable[..., Any] | None: - """ - Return the appropriate handler for the object passed. - """ - for can_handle, handler, is_generator, takes_converter in self._handler_pairs: - # can handle could raise an exception here - # such as issubclass being called on an instance. - # it's easier to just ignore that case. - try: - ch = can_handle(typ) - except Exception: # noqa: S112 - continue - if ch: - if is_generator: - if takes_converter: - return handler(typ, self._converter) - return handler(typ) - - return handler - return None - - def get_num_fns(self) -> int: - return len(self._handler_pairs) - - def copy_to(self, other: FunctionDispatch, skip: int = 0) -> None: - other._handler_pairs = self._handler_pairs[:-skip] + other._handler_pairs - - -@define(init=False) -class MultiStrategyDispatch(Generic[Hook]): - """ - MultiStrategyDispatch uses a combination of exact-match dispatch, - singledispatch, and FunctionDispatch. - - :param fallback_factory: A hook factory to be called when a hook cannot be - produced. - :param converter: A converter to be used for factories that require converters. - - .. versionchanged:: 23.2.0 - Fallbacks are now factories. - .. versionchanged:: 24.1.0 - Support for factories that require converters, hence this requires a - converter when creating. - """ - - _fallback_factory: HookFactory[Hook] - _direct_dispatch: dict[TargetType, Hook] - _function_dispatch: FunctionDispatch - _single_dispatch: Any - dispatch: Callable[[TargetType, BaseConverter], Hook] - - def __init__( - self, fallback_factory: HookFactory[Hook], converter: BaseConverter - ) -> None: - self._fallback_factory = fallback_factory - self._direct_dispatch = {} - self._function_dispatch = FunctionDispatch(converter) - self._single_dispatch = singledispatch(_DispatchNotFound) - self.dispatch = lru_cache(maxsize=None)(self.dispatch_without_caching) - - def dispatch_without_caching(self, typ: TargetType) -> Hook: - """Dispatch on the type but without caching the result.""" - try: - dispatch = self._single_dispatch.dispatch(typ) - if dispatch is not _DispatchNotFound: - return dispatch - except Exception: # noqa: S110 - pass - - direct_dispatch = self._direct_dispatch.get(typ) - if direct_dispatch is not None: - return direct_dispatch - - res = self._function_dispatch.dispatch(typ) - return res if res is not None else self._fallback_factory(typ) - - def register_cls_list(self, cls_and_handler, direct: bool = False) -> None: - """Register a class to direct or singledispatch.""" - for cls, handler in cls_and_handler: - if direct: - self._direct_dispatch[cls] = handler - else: - self._single_dispatch.register(cls, handler) - self.clear_direct() - self.dispatch.cache_clear() - - def register_func_list( - self, - pred_and_handler: list[ - tuple[Predicate, Any] - | tuple[Predicate, Any, bool] - | tuple[Predicate, Callable[[Any, BaseConverter], Any], Literal["extended"]] - ], - ): - """ - Register a predicate function to determine if the handler - should be used for the type. - - :param pred_and_handler: The list of predicates and their associated - handlers. If a handler is registered in `extended` mode, it's a - factory that requires a converter. - """ - for tup in pred_and_handler: - if len(tup) == 2: - func, handler = tup - self._function_dispatch.register(func, handler) - else: - func, handler, is_gen = tup - if is_gen == "extended": - self._function_dispatch.register( - func, handler, is_generator=is_gen, takes_converter=True - ) - else: - self._function_dispatch.register(func, handler, is_generator=is_gen) - self.clear_direct() - self.dispatch.cache_clear() - - def clear_direct(self) -> None: - """Clear the direct dispatch.""" - self._direct_dispatch.clear() - - def clear_cache(self) -> None: - """Clear all caches.""" - self._direct_dispatch.clear() - self.dispatch.cache_clear() - - def get_num_fns(self) -> int: - return self._function_dispatch.get_num_fns() - - def copy_to(self, other: MultiStrategyDispatch, skip: int = 0) -> None: - self._function_dispatch.copy_to(other._function_dispatch, skip=skip) - for cls, fn in self._single_dispatch.registry.items(): - other._single_dispatch.register(cls, fn) - other.clear_cache() diff --git a/server/libs/cattrs/errors.py b/server/libs/cattrs/errors.py deleted file mode 100644 index 4f9a737..0000000 --- a/server/libs/cattrs/errors.py +++ /dev/null @@ -1,132 +0,0 @@ -from collections.abc import Sequence -from typing import Any, Optional, Union - -from typing_extensions import Self - -from cattrs._compat import ExceptionGroup - - -class StructureHandlerNotFoundError(Exception): - """ - Error raised when structuring cannot find a handler for converting inputs into - :attr:`type_`. - """ - - def __init__(self, message: str, type_: type) -> None: - super().__init__(message) - self.type_ = type_ - - -class BaseValidationError(ExceptionGroup): - cl: type - - def __new__(cls, message: str, excs: Sequence[Exception], cl: type): - obj = super().__new__(cls, message, excs) - obj.cl = cl - return obj - - def derive(self, excs: Sequence[Exception]) -> Self: - return self.__class__(self.message, excs, self.cl) - - -class IterableValidationNote(str): - """Attached as a note to an exception when an iterable element fails structuring.""" - - index: Union[int, str] # Ints for list indices, strs for dict keys - type: Any - - def __new__( - cls, string: str, index: Union[int, str], type: Any - ) -> "IterableValidationNote": - instance = str.__new__(cls, string) - instance.index = index - instance.type = type - return instance - - def __getnewargs__(self) -> tuple[str, Union[int, str], Any]: - return (str(self), self.index, self.type) - - -class IterableValidationError(BaseValidationError): - """Raised when structuring an iterable.""" - - def group_exceptions( - self, - ) -> tuple[list[tuple[Exception, IterableValidationNote]], list[Exception]]: - """Split the exceptions into two groups: with and without validation notes.""" - excs_with_notes = [] - other_excs = [] - for subexc in self.exceptions: - if hasattr(subexc, "__notes__"): - for note in subexc.__notes__: - if note.__class__ is IterableValidationNote: - excs_with_notes.append((subexc, note)) - break - else: - other_excs.append(subexc) - else: - other_excs.append(subexc) - - return excs_with_notes, other_excs - - -class AttributeValidationNote(str): - """Attached as a note to an exception when an attribute fails structuring.""" - - name: str - type: Any - - def __new__(cls, string: str, name: str, type: Any) -> "AttributeValidationNote": - instance = str.__new__(cls, string) - instance.name = name - instance.type = type - return instance - - def __getnewargs__(self) -> tuple[str, str, Any]: - return (str(self), self.name, self.type) - - -class ClassValidationError(BaseValidationError): - """Raised when validating a class if any attributes are invalid.""" - - def group_exceptions( - self, - ) -> tuple[list[tuple[Exception, AttributeValidationNote]], list[Exception]]: - """Split the exceptions into two groups: with and without validation notes.""" - excs_with_notes = [] - other_excs = [] - for subexc in self.exceptions: - if hasattr(subexc, "__notes__"): - for note in subexc.__notes__: - if note.__class__ is AttributeValidationNote: - excs_with_notes.append((subexc, note)) - break - else: - other_excs.append(subexc) - else: - other_excs.append(subexc) - - return excs_with_notes, other_excs - - -class ForbiddenExtraKeysError(Exception): - """ - Raised when `forbid_extra_keys` is activated and such extra keys are detected - during structuring. - - The attribute `extra_fields` is a sequence of those extra keys, which were the - cause of this error, and `cl` is the class which was structured with those extra - keys. - """ - - def __init__( - self, message: Optional[str], cl: type, extra_fields: set[str] - ) -> None: - self.cl = cl - self.extra_fields = extra_fields - cln = cl.__name__ - - super().__init__( - message - or f"Extra fields in constructor for {cln}: {', '.join(extra_fields)}" - ) diff --git a/server/libs/cattrs/fns.py b/server/libs/cattrs/fns.py deleted file mode 100644 index 984c05e..0000000 --- a/server/libs/cattrs/fns.py +++ /dev/null @@ -1,22 +0,0 @@ -"""Useful internal functions.""" - -from typing import Any, Callable, NoReturn, TypeVar - -from ._compat import TypeAlias -from .errors import StructureHandlerNotFoundError - -T = TypeVar("T") - -Predicate: TypeAlias = Callable[[Any], bool] -"""A predicate function determines if a type can be handled.""" - - -def identity(obj: T) -> T: - """The identity function.""" - return obj - - -def raise_error(_, cl: Any) -> NoReturn: - """At the bottom of the condition stack, we explode if we can't handle it.""" - msg = f"Unsupported type: {cl!r}. Register a structure hook for it." - raise StructureHandlerNotFoundError(msg, type_=cl) diff --git a/server/libs/cattrs/gen/__init__.py b/server/libs/cattrs/gen/__init__.py deleted file mode 100644 index 3afa3b9..0000000 --- a/server/libs/cattrs/gen/__init__.py +++ /dev/null @@ -1,1048 +0,0 @@ -from __future__ import annotations - -import re -from collections.abc import Callable, Iterable, Mapping -from typing import TYPE_CHECKING, Any, Final, Literal, TypeVar - -from attrs import NOTHING, Attribute, Factory -from typing_extensions import NoDefault - -from .._compat import ( - ANIES, - TypeAlias, - adapted_fields, - get_args, - get_origin, - is_annotated, - is_bare, - is_bare_final, - is_generic, -) -from .._generics import deep_copy_with -from ..dispatch import UnstructureHook -from ..errors import ( - AttributeValidationNote, - ClassValidationError, - ForbiddenExtraKeysError, - IterableValidationError, - IterableValidationNote, - StructureHandlerNotFoundError, -) -from ..fns import identity -from ..types import SimpleStructureHook -from ._consts import AttributeOverride, already_generating, neutral -from ._generics import generate_mapping -from ._lc import generate_unique_filename -from ._shared import find_structure_handler - -if TYPE_CHECKING: - from ..converters import BaseConverter - -__all__ = [ - "make_dict_structure_fn", - "make_dict_structure_fn_from_attrs", - "make_dict_unstructure_fn", - "make_dict_unstructure_fn_from_attrs", - "make_hetero_tuple_unstructure_fn", - "make_iterable_unstructure_fn", - "make_mapping_structure_fn", - "make_mapping_unstructure_fn", -] - - -def override( - omit_if_default: bool | None = None, - rename: str | None = None, - omit: bool | None = None, - struct_hook: Callable[[Any, Any], Any] | None = None, - unstruct_hook: Callable[[Any], Any] | None = None, -) -> AttributeOverride: - """Override how a particular field is handled. - - :param omit: Whether to skip the field or not. `None` means apply default handling. - """ - return AttributeOverride(omit_if_default, rename, omit, struct_hook, unstruct_hook) - - -T = TypeVar("T") - - -def make_dict_unstructure_fn_from_attrs( - attrs: list[Attribute], - cl: type[T], - converter: BaseConverter, - typevar_map: dict[str, Any] = {}, - _cattrs_omit_if_default: bool = False, - _cattrs_use_linecache: bool = True, - _cattrs_use_alias: bool = False, - _cattrs_include_init_false: bool = False, - **kwargs: AttributeOverride, -) -> Callable[[T], dict[str, Any]]: - """ - Generate a specialized dict unstructuring function for a list of attributes. - - Usually used as a building block by more specialized hook factories. - - Any provided overrides are attached to the generated function under the - `overrides` attribute. - - :param cl: The class for which the function is generated; used mostly for its name, - module name and qualname. - :param _cattrs_omit_if_default: if true, attributes equal to their default values - will be omitted in the result dictionary. - :param _cattrs_use_alias: If true, the attribute alias will be used as the - dictionary key by default. - :param _cattrs_include_init_false: If true, _attrs_ fields marked as `init=False` - will be included. - - .. versionadded:: 24.1.0 - """ - - fn_name = "unstructure_" + cl.__name__ - globs = {} - lines = [] - invocation_lines = [] - internal_arg_parts = {} - - for a in attrs: - attr_name = a.name - override = kwargs.get(attr_name, neutral) - if override.omit: - continue - if override.omit is None and not a.init and not _cattrs_include_init_false: - continue - if override.rename is None: - kn = attr_name if not _cattrs_use_alias else a.alias - else: - kn = override.rename - d = a.default - - # For each attribute, we try resolving the type here and now. - # If a type is manually overwritten, this function should be - # regenerated. - handler = None - if override.unstruct_hook is not None: - handler = override.unstruct_hook - else: - if a.type is not None: - t = a.type - if isinstance(t, TypeVar): - if t.__name__ in typevar_map: - t = typevar_map[t.__name__] - else: - handler = converter.unstructure - elif is_generic(t) and not is_bare(t) and not is_annotated(t): - t = deep_copy_with(t, typevar_map, cl) - - if handler is None: - if ( - is_bare_final(t) - and a.default is not NOTHING - and not isinstance(a.default, Factory) - ): - # This is a special case where we can use the - # type of the default to dispatch on. - t = a.default.__class__ - try: - handler = converter.get_unstructure_hook(t, cache_result=False) - except RecursionError: - # There's a circular reference somewhere down the line - handler = converter.unstructure - else: - handler = converter.unstructure - - is_identity = handler == identity - - if not is_identity: - unstruct_handler_name = f"__c_unstr_{attr_name}" - globs[unstruct_handler_name] = handler - internal_arg_parts[unstruct_handler_name] = handler - invoke = f"{unstruct_handler_name}(instance.{attr_name})" - else: - invoke = f"instance.{attr_name}" - - if d is not NOTHING and ( - (_cattrs_omit_if_default and override.omit_if_default is not False) - or override.omit_if_default - ): - def_name = f"__c_def_{attr_name}" - - if isinstance(d, Factory): - globs[def_name] = d.factory - internal_arg_parts[def_name] = d.factory - if d.takes_self: - lines.append(f" if instance.{attr_name} != {def_name}(instance):") - else: - lines.append(f" if instance.{attr_name} != {def_name}():") - lines.append(f" res['{kn}'] = {invoke}") - else: - globs[def_name] = d - internal_arg_parts[def_name] = d - lines.append(f" if instance.{attr_name} != {def_name}:") - lines.append(f" res['{kn}'] = {invoke}") - - else: - # No default or no override. - invocation_lines.append(f"'{kn}': {invoke},") - - internal_arg_line = ", ".join([f"{i}={i}" for i in internal_arg_parts]) - if internal_arg_line: - internal_arg_line = f", {internal_arg_line}" - for k, v in internal_arg_parts.items(): - globs[k] = v - - total_lines = ( - [f"def {fn_name}(instance{internal_arg_line}):"] - + [" res = {"] - + [f" {line}" for line in invocation_lines] - + [" }"] - + lines - + [" return res"] - ) - script = "\n".join(total_lines) - fname = generate_unique_filename( - cl, "unstructure", lines=total_lines if _cattrs_use_linecache else [] - ) - - eval(compile(script, fname, "exec"), globs) - - res = globs[fn_name] - res.overrides = kwargs - - return res - - -def make_dict_unstructure_fn( - cl: type[T], - converter: BaseConverter, - _cattrs_omit_if_default: bool = False, - _cattrs_use_linecache: bool = True, - _cattrs_use_alias: bool = False, - _cattrs_include_init_false: bool = False, - **kwargs: AttributeOverride, -) -> Callable[[T], dict[str, Any]]: - """ - Generate a specialized dict unstructuring function for an attrs class or a - dataclass. - - Any provided overrides are attached to the generated function under the - `overrides` attribute. - - :param _cattrs_omit_if_default: if true, attributes equal to their default values - will be omitted in the result dictionary. - :param _cattrs_use_alias: If true, the attribute alias will be used as the - dictionary key by default. - :param _cattrs_include_init_false: If true, _attrs_ fields marked as `init=False` - will be included. - - .. versionadded:: 23.2.0 *_cattrs_use_alias* - .. versionadded:: 23.2.0 *_cattrs_include_init_false* - """ - origin = get_origin(cl) - attrs = adapted_fields(origin or cl) # type: ignore - - mapping = {} - if is_generic(cl): - mapping = generate_mapping(cl, mapping) - - if origin is not None: - cl = origin - - # We keep track of what we're generating to help with recursive - # class graphs. - try: - working_set = already_generating.working_set - except AttributeError: - working_set = set() - already_generating.working_set = working_set - if cl in working_set: - raise RecursionError() - - working_set.add(cl) - - try: - return make_dict_unstructure_fn_from_attrs( - attrs, - cl, - converter, - mapping, - _cattrs_omit_if_default=_cattrs_omit_if_default, - _cattrs_use_linecache=_cattrs_use_linecache, - _cattrs_use_alias=_cattrs_use_alias, - _cattrs_include_init_false=_cattrs_include_init_false, - **kwargs, - ) - finally: - working_set.remove(cl) - if not working_set: - del already_generating.working_set - - -def make_dict_structure_fn_from_attrs( - attrs: list[Attribute], - cl: type[T], - converter: BaseConverter, - typevar_map: dict[str, Any] = {}, - _cattrs_forbid_extra_keys: bool | Literal["from_converter"] = "from_converter", - _cattrs_use_linecache: bool = True, - _cattrs_prefer_attrib_converters: ( - bool | Literal["from_converter"] - ) = "from_converter", - _cattrs_detailed_validation: bool | Literal["from_converter"] = "from_converter", - _cattrs_use_alias: bool = False, - _cattrs_include_init_false: bool = False, - **kwargs: AttributeOverride, -) -> SimpleStructureHook[Mapping[str, Any], T]: - """ - Generate a specialized dict structuring function for a list of attributes. - - Usually used as a building block by more specialized hook factories. - - Any provided overrides are attached to the generated function under the - `overrides` attribute. - - :param _cattrs_forbid_extra_keys: Whether the structuring function should raise a - `ForbiddenExtraKeysError` if unknown keys are encountered. - :param _cattrs_use_linecache: Whether to store the source code in the Python - linecache. - :param _cattrs_prefer_attrib_converters: If an _attrs_ converter is present on a - field, use it instead of processing the field normally. - :param _cattrs_detailed_validation: Whether to use a slower mode that produces - more detailed errors. - :param _cattrs_use_alias: If true, the attribute alias will be used as the - dictionary key by default. - :param _cattrs_include_init_false: If true, _attrs_ fields marked as `init=False` - will be included. - - .. versionadded:: 24.1.0 - """ - - cl_name = cl.__name__ - fn_name = "structure_" + cl_name - - # We have generic parameters and need to generate a unique name for the function - for p in getattr(cl, "__parameters__", ()): - # This is nasty, I am not sure how best to handle `typing.List[str]` or - # `TClass[int, int]` as a parameter type here - try: - name_base = typevar_map[p.__name__] - except KeyError: - pn = p.__name__ - raise StructureHandlerNotFoundError( - f"Missing type for generic argument {pn}, specify it when structuring.", - p, - ) from None - name = getattr(name_base, "__name__", None) or str(name_base) - # `<>` can be present in lambdas - # `|` can be present in unions - name = re.sub(r"[\[\.\] ,<>]", "_", name) - name = re.sub(r"\|", "u", name) - fn_name += f"_{name}" - - internal_arg_parts = {"__cl": cl} - globs = {} - lines = [] - post_lines = [] - pi_lines = [] # post instantiation lines - invocation_lines = [] - - allowed_fields = set() - if _cattrs_forbid_extra_keys == "from_converter": - # BaseConverter doesn't have it so we're careful. - _cattrs_forbid_extra_keys = getattr(converter, "forbid_extra_keys", False) - if _cattrs_detailed_validation == "from_converter": - _cattrs_detailed_validation = converter.detailed_validation - if _cattrs_prefer_attrib_converters == "from_converter": - _cattrs_prefer_attrib_converters = converter._prefer_attrib_converters - - if _cattrs_forbid_extra_keys: - globs["__c_a"] = allowed_fields - globs["__c_feke"] = ForbiddenExtraKeysError - - if _cattrs_detailed_validation: - lines.append(" res = {}") - lines.append(" errors = []") - invocation_lines.append("**res,") - internal_arg_parts["__c_cve"] = ClassValidationError - internal_arg_parts["__c_avn"] = AttributeValidationNote - for a in attrs: - an = a.name - override = kwargs.get(an, neutral) - if override.omit: - continue - if override.omit is None and not a.init and not _cattrs_include_init_false: - continue - t = a.type - if isinstance(t, TypeVar): - t = typevar_map.get(t.__name__, t) - elif is_generic(t) and not is_bare(t) and not is_annotated(t): - t = deep_copy_with(t, typevar_map, cl) - - # For each attribute, we try resolving the type here and now. - # If a type is manually overwritten, this function should be - # regenerated. - if override.struct_hook is not None: - # If the user has requested an override, just use that. - handler = override.struct_hook - else: - handler = find_structure_handler( - a, t, converter, _cattrs_prefer_attrib_converters - ) - - struct_handler_name = f"__c_structure_{an}" - if handler is not None: - internal_arg_parts[struct_handler_name] = handler - - ian = a.alias - if override.rename is None: - kn = an if not _cattrs_use_alias else a.alias - else: - kn = override.rename - - allowed_fields.add(kn) - i = " " - - if not a.init: - if a.default is not NOTHING: - pi_lines.append(f"{i}if '{kn}' in o:") - i = f"{i} " - pi_lines.append(f"{i}try:") - i = f"{i} " - type_name = f"__c_type_{an}" - internal_arg_parts[type_name] = t - if handler is not None: - if handler == converter._structure_call: - internal_arg_parts[struct_handler_name] = t - pi_lines.append( - f"{i}instance.{an} = {struct_handler_name}(o['{kn}'])" - ) - else: - tn = f"__c_type_{an}" - internal_arg_parts[tn] = t - pi_lines.append( - f"{i}instance.{an} = {struct_handler_name}(o['{kn}'], {tn})" - ) - else: - pi_lines.append(f"{i}instance.{an} = o['{kn}']") - i = i[:-2] - pi_lines.append(f"{i}except Exception as e:") - i = f"{i} " - pi_lines.append( - f'{i}e.__notes__ = getattr(e, \'__notes__\', []) + [__c_avn("Structuring class {cl.__qualname__} @ attribute {an}", "{an}", __c_type_{an})]' - ) - pi_lines.append(f"{i}errors.append(e)") - - else: - if a.default is not NOTHING: - lines.append(f"{i}if '{kn}' in o:") - i = f"{i} " - lines.append(f"{i}try:") - i = f"{i} " - type_name = f"__c_type_{an}" - internal_arg_parts[type_name] = t - if handler: - if handler == converter._structure_call: - internal_arg_parts[struct_handler_name] = t - lines.append( - f"{i}res['{ian}'] = {struct_handler_name}(o['{kn}'])" - ) - else: - lines.append( - f"{i}res['{ian}'] = {struct_handler_name}(o['{kn}'], {type_name})" - ) - else: - lines.append(f"{i}res['{ian}'] = o['{kn}']") - i = i[:-2] - lines.append(f"{i}except Exception as e:") - i = f"{i} " - lines.append( - f'{i}e.__notes__ = getattr(e, \'__notes__\', []) + [__c_avn("Structuring class {cl.__qualname__} @ attribute {an}", "{an}", __c_type_{an})]' - ) - lines.append(f"{i}errors.append(e)") - - if _cattrs_forbid_extra_keys: - post_lines += [ - " unknown_fields = set(o.keys()) - __c_a", - " if unknown_fields:", - " errors.append(__c_feke('', __cl, unknown_fields))", - ] - - post_lines.append( - f" if errors: raise __c_cve('While structuring ' + {cl_name!r}, errors, __cl)" - ) - if not pi_lines: - instantiation_lines = ( - [" try:"] - + [" return __cl("] - + [f" {line}" for line in invocation_lines] - + [" )"] - + [ - f" except Exception as exc: raise __c_cve('While structuring ' + {cl_name!r}, [exc], __cl)" - ] - ) - else: - instantiation_lines = ( - [" try:"] - + [" instance = __cl("] - + [f" {line}" for line in invocation_lines] - + [" )"] - + [ - f" except Exception as exc: raise __c_cve('While structuring ' + {cl_name!r}, [exc], __cl)" - ] - ) - pi_lines.append(" return instance") - else: - non_required = [] - # The first loop deals with required args. - for a in attrs: - an = a.name - override = kwargs.get(an, neutral) - if override.omit: - continue - if override.omit is None and not a.init and not _cattrs_include_init_false: - continue - if a.default is not NOTHING: - non_required.append(a) - continue - t = a.type - if isinstance(t, TypeVar): - t = typevar_map.get(t.__name__, t) - elif is_generic(t) and not is_bare(t) and not is_annotated(t): - t = deep_copy_with(t, typevar_map, cl) - - # For each attribute, we try resolving the type here and now. - # If a type is manually overwritten, this function should be - # regenerated. - if override.struct_hook is not None: - # If the user has requested an override, just use that. - handler = override.struct_hook - else: - handler = find_structure_handler( - a, t, converter, _cattrs_prefer_attrib_converters - ) - - if override.rename is None: - kn = an if not _cattrs_use_alias else a.alias - else: - kn = override.rename - allowed_fields.add(kn) - - if not a.init: - if handler is not None: - struct_handler_name = f"__c_structure_{an}" - internal_arg_parts[struct_handler_name] = handler - if handler == converter._structure_call: - internal_arg_parts[struct_handler_name] = t - pi_line = f" instance.{an} = {struct_handler_name}(o['{kn}'])" - else: - tn = f"__c_type_{an}" - internal_arg_parts[tn] = t - pi_line = ( - f" instance.{an} = {struct_handler_name}(o['{kn}'], {tn})" - ) - else: - pi_line = f" instance.{an} = o['{kn}']" - - pi_lines.append(pi_line) - else: - if handler: - struct_handler_name = f"__c_structure_{an}" - internal_arg_parts[struct_handler_name] = handler - if handler == converter._structure_call: - internal_arg_parts[struct_handler_name] = t - invocation_line = f"{struct_handler_name}(o['{kn}'])," - else: - tn = f"__c_type_{an}" - internal_arg_parts[tn] = t - invocation_line = f"{struct_handler_name}(o['{kn}'], {tn})," - else: - invocation_line = f"o['{kn}']," - - if a.kw_only: - invocation_line = f"{a.alias}={invocation_line}" - invocation_lines.append(invocation_line) - - # The second loop is for optional args. - if non_required: - invocation_lines.append("**res,") - lines.append(" res = {}") - - for a in non_required: - an = a.name - override = kwargs.get(an, neutral) - t = a.type - if isinstance(t, TypeVar): - t = typevar_map.get(t.__name__, t) - elif is_generic(t) and not is_bare(t) and not is_annotated(t): - t = deep_copy_with(t, typevar_map, cl) - - # For each attribute, we try resolving the type here and now. - # If a type is manually overwritten, this function should be - # regenerated. - if override.struct_hook is not None: - # If the user has requested an override, just use that. - handler = override.struct_hook - else: - handler = find_structure_handler( - a, t, converter, _cattrs_prefer_attrib_converters - ) - - struct_handler_name = f"__c_structure_{an}" - internal_arg_parts[struct_handler_name] = handler - - if override.rename is None: - kn = an if not _cattrs_use_alias else a.alias - else: - kn = override.rename - allowed_fields.add(kn) - if not a.init: - pi_lines.append(f" if '{kn}' in o:") - if handler: - if handler == converter._structure_call: - internal_arg_parts[struct_handler_name] = t - pi_lines.append( - f" instance.{an} = {struct_handler_name}(o['{kn}'])" - ) - else: - tn = f"__c_type_{an}" - internal_arg_parts[tn] = t - pi_lines.append( - f" instance.{an} = {struct_handler_name}(o['{kn}'], {tn})" - ) - else: - pi_lines.append(f" instance.{an} = o['{kn}']") - else: - post_lines.append(f" if '{kn}' in o:") - if handler: - if handler == converter._structure_call: - internal_arg_parts[struct_handler_name] = t - post_lines.append( - f" res['{a.alias}'] = {struct_handler_name}(o['{kn}'])" - ) - else: - tn = f"__c_type_{an}" - internal_arg_parts[tn] = t - post_lines.append( - f" res['{a.alias}'] = {struct_handler_name}(o['{kn}'], {tn})" - ) - else: - post_lines.append(f" res['{a.alias}'] = o['{kn}']") - if not pi_lines: - instantiation_lines = ( - [" return __cl("] - + [f" {line}" for line in invocation_lines] - + [" )"] - ) - else: - instantiation_lines = ( - [" instance = __cl("] - + [f" {line}" for line in invocation_lines] - + [" )"] - ) - pi_lines.append(" return instance") - - if _cattrs_forbid_extra_keys: - post_lines += [ - " unknown_fields = set(o.keys()) - __c_a", - " if unknown_fields:", - " raise __c_feke('', __cl, unknown_fields)", - ] - - # At the end, we create the function header. - internal_arg_line = ", ".join([f"{i}={i}" for i in internal_arg_parts]) - globs.update(internal_arg_parts) - - total_lines = [ - f"def {fn_name}(o, _=__cl, {internal_arg_line}):", - *lines, - *post_lines, - *instantiation_lines, - *pi_lines, - ] - - script = "\n".join(total_lines) - fname = generate_unique_filename( - cl, "structure", lines=total_lines if _cattrs_use_linecache else [] - ) - - eval(compile(script, fname, "exec"), globs) - - res = globs[fn_name] - res.overrides = kwargs - - return res - - -def make_dict_structure_fn( - cl: type[T], - converter: BaseConverter, - _cattrs_forbid_extra_keys: bool | Literal["from_converter"] = "from_converter", - _cattrs_use_linecache: bool = True, - _cattrs_prefer_attrib_converters: ( - bool | Literal["from_converter"] - ) = "from_converter", - _cattrs_detailed_validation: bool | Literal["from_converter"] = "from_converter", - _cattrs_use_alias: bool = False, - _cattrs_include_init_false: bool = False, - **kwargs: AttributeOverride, -) -> SimpleStructureHook[Mapping[str, Any], T]: - """ - Generate a specialized dict structuring function for an attrs class or - dataclass. - - Any provided overrides are attached to the generated function under the - `overrides` attribute. - - :param _cattrs_forbid_extra_keys: Whether the structuring function should raise a - `ForbiddenExtraKeysError` if unknown keys are encountered. - :param _cattrs_use_linecache: Whether to store the source code in the Python - linecache. - :param _cattrs_prefer_attrib_converters: If an _attrs_ converter is present on a - field, use it instead of processing the field normally. - :param _cattrs_detailed_validation: Whether to use a slower mode that produces - more detailed errors. - :param _cattrs_use_alias: If true, the attribute alias will be used as the - dictionary key by default. - :param _cattrs_include_init_false: If true, _attrs_ fields marked as `init=False` - will be included. - - .. versionadded:: 23.2.0 *_cattrs_use_alias* - .. versionadded:: 23.2.0 *_cattrs_include_init_false* - .. versionchanged:: 23.2.0 - The `_cattrs_forbid_extra_keys` and `_cattrs_detailed_validation` parameters - take their values from the given converter by default. - .. versionchanged:: 24.1.0 - The `_cattrs_prefer_attrib_converters` parameter takes its value from the given - converter by default. - """ - - mapping = {} - if is_generic(cl): - base = get_origin(cl) - mapping = generate_mapping(cl, mapping) - if base is not None: - cl = base - - for base in getattr(cl, "__orig_bases__", ()): - if is_generic(base) and not str(base).startswith("typing.Generic"): - mapping = generate_mapping(base, mapping) - break - - attrs = adapted_fields(cl) - - # We keep track of what we're generating to help with recursive - # class graphs. - try: - working_set = already_generating.working_set - except AttributeError: - working_set = set() - already_generating.working_set = working_set - else: - if cl in working_set: - raise RecursionError() - - working_set.add(cl) - - try: - return make_dict_structure_fn_from_attrs( - attrs, - cl, - converter, - mapping, - _cattrs_forbid_extra_keys=_cattrs_forbid_extra_keys, - _cattrs_use_linecache=_cattrs_use_linecache, - _cattrs_prefer_attrib_converters=_cattrs_prefer_attrib_converters, - _cattrs_detailed_validation=_cattrs_detailed_validation, - _cattrs_use_alias=_cattrs_use_alias, - _cattrs_include_init_false=_cattrs_include_init_false, - **kwargs, - ) - finally: - working_set.remove(cl) - if not working_set: - del already_generating.working_set - - -IterableUnstructureFn = Callable[[Iterable[Any]], Any] - - -#: A type alias for heterogeneous tuple unstructure hooks. -HeteroTupleUnstructureFn: TypeAlias = Callable[[tuple[Any, ...]], Any] - - -def make_hetero_tuple_unstructure_fn( - cl: Any, - converter: BaseConverter, - unstructure_to: Any = None, - type_args: tuple | None = None, -) -> HeteroTupleUnstructureFn: - """Generate a specialized unstructure function for a heterogenous tuple. - - :param type_args: If provided, override the type arguments. - """ - fn_name = "unstructure_tuple" - - type_args = get_args(cl) if type_args is None else type_args - - # We can do the dispatch here and now. - handlers = [converter.get_unstructure_hook(type_arg) for type_arg in type_args] - - globs = {f"__cattr_u_{i}": h for i, h in enumerate(handlers)} - if unstructure_to is not tuple: - globs["__cattr_seq_cl"] = unstructure_to or cl - lines = [] - - lines.append(f"def {fn_name}(tup):") - if unstructure_to is not tuple: - lines.append(" res = __cattr_seq_cl((") - else: - lines.append(" res = (") - for i in range(len(handlers)): - if handlers[i] == identity: - lines.append(f" tup[{i}],") - else: - lines.append(f" __cattr_u_{i}(tup[{i}]),") - - if unstructure_to is not tuple: - lines.append(" ))") - else: - lines.append(" )") - - total_lines = [*lines, " return res"] - - eval(compile("\n".join(total_lines), "", "exec"), globs) - - return globs[fn_name] - - -MappingUnstructureFn = Callable[[Mapping[Any, Any]], Any] - - -# This factory is here for backwards compatibility and circular imports. -def mapping_unstructure_factory( - cl: Any, - converter: BaseConverter, - unstructure_to: Any = None, - key_handler: Callable[[Any, Any | None], Any] | None = None, -) -> MappingUnstructureFn: - """Generate a specialized unstructure function for a mapping. - - :param unstructure_to: The class to unstructure to; defaults to the - same class as the mapping being unstructured. - """ - kh = key_handler or converter.unstructure - val_handler = converter.unstructure - - fn_name = "unstructure_mapping" - origin = cl - - # Let's try fishing out the type args. - if getattr(cl, "__args__", None) is not None: - args = get_args(cl) - if len(args) == 2: - key_arg, val_arg = args - else: - # Probably a Counter - key_arg, val_arg = args, Any - # We can do the dispatch here and now. - kh = key_handler or converter.get_unstructure_hook(key_arg, cache_result=False) - if kh == identity: - kh = None - - val_handler = converter.get_unstructure_hook(val_arg, cache_result=False) - if val_handler == identity: - val_handler = None - - origin = get_origin(cl) - - globs = {"__cattr_k_u": kh, "__cattr_v_u": val_handler} - - k_u = "__cattr_k_u(k)" if kh is not None else "k" - v_u = "__cattr_v_u(v)" if val_handler is not None else "v" - - lines = [f"def {fn_name}(mapping):"] - - if unstructure_to is dict or (unstructure_to is None and origin is dict): - if kh is None and val_handler is None: - # Simplest path. - return dict - - lines.append(f" return {{{k_u}: {v_u} for k, v in mapping.items()}}") - else: - globs["__cattr_mapping_cl"] = unstructure_to or cl - lines.append( - f" res = __cattr_mapping_cl(({k_u}, {v_u}) for k, v in mapping.items())" - ) - - lines = [*lines, " return res"] - - eval(compile("\n".join(lines), "", "exec"), globs) - - return globs[fn_name] - - -make_mapping_unstructure_fn: Final = mapping_unstructure_factory - - -# This factory is here for backwards compatibility and circular imports. -def mapping_structure_factory( - cl: type[T], - converter: BaseConverter, - structure_to: type = dict, - key_type=NOTHING, - val_type=NOTHING, - detailed_validation: bool | Literal["from_converter"] = "from_converter", -) -> SimpleStructureHook[Mapping[Any, Any], T]: - """Generate a specialized structure function for a mapping.""" - fn_name = "structure_mapping" - - if detailed_validation == "from_converter": - detailed_validation = converter.detailed_validation - - globs: dict[str, type] = {"__cattr_mapping_cl": structure_to} - - lines = [] - internal_arg_parts = {} - - # Let's try fishing out the type args. - if not is_bare(cl): - args = get_args(cl) - if len(args) == 2: - key_arg_cand, val_arg_cand = args - if key_type is NOTHING: - key_type = key_arg_cand - if val_type is NOTHING: - val_type = val_arg_cand - else: - if key_type is not NOTHING and val_type is NOTHING: - (val_type,) = args - elif key_type is NOTHING and val_type is not NOTHING: - (key_type,) = args - else: - # Probably a Counter - (key_type,) = args - val_type = Any - - is_bare_dict = val_type in ANIES and key_type in ANIES - if not is_bare_dict: - # We can do the dispatch here and now. - key_handler = converter.get_structure_hook(key_type, cache_result=False) - if key_handler == converter._structure_call: - key_handler = key_type - - val_handler = converter.get_structure_hook(val_type, cache_result=False) - if val_handler == converter._structure_call: - val_handler = val_type - - globs["__cattr_k_t"] = key_type - globs["__cattr_v_t"] = val_type - globs["__cattr_k_s"] = key_handler - globs["__cattr_v_s"] = val_handler - k_s = ( - "__cattr_k_s(k, __cattr_k_t)" - if key_handler != key_type - else "__cattr_k_s(k)" - ) - v_s = ( - "__cattr_v_s(v, __cattr_v_t)" - if val_handler != val_type - else "__cattr_v_s(v)" - ) - else: - is_bare_dict = True - - if is_bare_dict: - # No args, it's a bare dict. - lines.append(" res = dict(mapping)") - else: - if detailed_validation: - internal_arg_parts["IterableValidationError"] = IterableValidationError - internal_arg_parts["IterableValidationNote"] = IterableValidationNote - internal_arg_parts["val_type"] = ( - val_type if val_type is not NOTHING else Any - ) - internal_arg_parts["key_type"] = ( - key_type if key_type is not NOTHING else Any - ) - globs["enumerate"] = enumerate - - lines.append(" res = {}; errors = []") - lines.append(" for k, v in mapping.items():") - lines.append(" try:") - lines.append(f" value = {v_s}") - lines.append(" except Exception as e:") - lines.append( - " e.__notes__ = getattr(e, '__notes__', []) + [IterableValidationNote(f'Structuring mapping value @ key {k!r}', k, val_type)]" - ) - lines.append(" errors.append(e)") - lines.append(" continue") - lines.append(" try:") - lines.append(f" key = {k_s}") - lines.append(" res[key] = value") - lines.append(" except Exception as e:") - lines.append( - " e.__notes__ = getattr(e, '__notes__', []) + [IterableValidationNote(f'Structuring mapping key @ key {k!r}', k, key_type)]" - ) - lines.append(" errors.append(e)") - lines.append(" if errors:") - lines.append( - f" raise IterableValidationError('While structuring ' + {repr(cl)!r}, errors, __cattr_mapping_cl)" - ) - else: - lines.append(f" res = {{{k_s}: {v_s} for k, v in mapping.items()}}") - if structure_to is not dict: - lines.append(" res = __cattr_mapping_cl(res)") - - internal_arg_line = ", ".join([f"{i}={i}" for i in internal_arg_parts]) - if internal_arg_line: - internal_arg_line = f", {internal_arg_line}" - for k, v in internal_arg_parts.items(): - globs[k] = v - - globs["cl"] = cl - def_line = f"def {fn_name}(mapping, cl=cl{internal_arg_line}):" - total_lines = [def_line, *lines, " return res"] - script = "\n".join(total_lines) - - eval(compile(script, "", "exec"), globs) - - return globs[fn_name] - - -make_mapping_structure_fn: Final = mapping_structure_factory - - -# This factory is here for backwards compatibility and circular imports. -def iterable_unstructure_factory( - cl: Any, converter: BaseConverter, unstructure_to: Any = None -) -> UnstructureHook: - """A hook factory for unstructuring iterables. - - :param unstructure_to: Force unstructuring to this type, if provided. - - .. versionchanged:: 24.2.0 - `typing.NoDefault` is now correctly handled as `Any`. - """ - handler = converter.unstructure - - # Let's try fishing out the type args - # Unspecified tuples have `__args__` as empty tuples, so guard - # against IndexError. - if getattr(cl, "__args__", None) not in (None, ()): - type_arg = cl.__args__[0] - if isinstance(type_arg, TypeVar): - type_arg = getattr(type_arg, "__default__", Any) - if type_arg is NoDefault: - type_arg = Any - handler = converter.get_unstructure_hook(type_arg, cache_result=False) - if handler == identity: - # Save ourselves the trouble of iterating over it all. - return unstructure_to or cl - - def unstructure_iterable(iterable, _seq_cl=unstructure_to or cl, _hook=handler): - return _seq_cl(_hook(i) for i in iterable) - - return unstructure_iterable - - -make_iterable_unstructure_fn: Final = iterable_unstructure_factory diff --git a/server/libs/cattrs/gen/_consts.py b/server/libs/cattrs/gen/_consts.py deleted file mode 100644 index a6dcd03..0000000 --- a/server/libs/cattrs/gen/_consts.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import annotations - -from threading import local -from typing import Any, Callable - -from attrs import frozen - - -@frozen -class AttributeOverride: - omit_if_default: bool | None = None - rename: str | None = None - omit: bool | None = None # Omit the field completely. - struct_hook: Callable[[Any, Any], Any] | None = None # Structure hook to use. - unstruct_hook: Callable[[Any], Any] | None = None # Structure hook to use. - - -neutral = AttributeOverride() -already_generating = local() diff --git a/server/libs/cattrs/gen/_generics.py b/server/libs/cattrs/gen/_generics.py deleted file mode 100644 index 069c48c..0000000 --- a/server/libs/cattrs/gen/_generics.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -from typing import TypeVar - -from .._compat import get_args, get_origin, is_generic - - -def _tvar_has_default(tvar) -> bool: - """Does `tvar` have a default? - - In CPython 3.13+ and typing_extensions>=4.12.0: - - TypeVars have a `no_default()` method for detecting - if a TypeVar has a default - - TypeVars with `default=None` have `__default__` set to `None` - - TypeVars with no `default` parameter passed - have `__default__` set to `typing(_extensions).NoDefault - - On typing_exensions<4.12.0: - - TypeVars do not have a `no_default()` method for detecting - if a TypeVar has a default - - TypeVars with `default=None` have `__default__` set to `NoneType` - - TypeVars with no `default` parameter passed - have `__default__` set to `typing(_extensions).NoDefault - """ - try: - return tvar.has_default() - except AttributeError: - # compatibility for typing_extensions<4.12.0 - return getattr(tvar, "__default__", None) is not None - - -def generate_mapping(cl: type, old_mapping: dict[str, type] = {}) -> dict[str, type]: - """Generate a mapping of typevars to actual types for a generic class.""" - mapping = dict(old_mapping) - - origin = get_origin(cl) - - if origin is not None: - # To handle the cases where classes in the typing module are using - # the GenericAlias structure but aren't a Generic and hence - # end up in this function but do not have an `__parameters__` - # attribute. These classes are interface types, for example - # `typing.Hashable`. - parameters = getattr(get_origin(cl), "__parameters__", None) - if parameters is None: - return dict(old_mapping) - - for p, t in zip(parameters, get_args(cl)): - if isinstance(t, TypeVar): - continue - mapping[p.__name__] = t - - elif is_generic(cl): - # Origin is None, so this may be a subclass of a generic class. - orig_bases = cl.__orig_bases__ - for base in orig_bases: - if not hasattr(base, "__args__"): - continue - base_args = base.__args__ - if hasattr(base.__origin__, "__parameters__"): - base_params = base.__origin__.__parameters__ - elif any(_tvar_has_default(base_arg) for base_arg in base_args): - # TypeVar with a default e.g. PEP 696 - # https://www.python.org/dev/peps/pep-0696/ - # Extract the defaults for the TypeVars and insert - # them into the mapping - mapping_params = [ - (base_arg, base_arg.__default__) - for base_arg in base_args - if _tvar_has_default(base_arg) - ] - base_params, base_args = zip(*mapping_params) - else: - continue - - for param, arg in zip(base_params, base_args): - mapping[param.__name__] = arg - - return mapping diff --git a/server/libs/cattrs/gen/_lc.py b/server/libs/cattrs/gen/_lc.py deleted file mode 100644 index 71e8b61..0000000 --- a/server/libs/cattrs/gen/_lc.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Line-cache functionality.""" - -import linecache - - -def generate_unique_filename(cls: type, func_name: str, lines: list[str] = []) -> str: - """ - Create a "filename" suitable for a function being generated. - - If *lines* are provided, insert them in the first free spot or stop - if a duplicate is found. - """ - extra = "" - count = 1 - - while True: - unique_filename = "".format( - func_name, cls.__module__, getattr(cls, "__qualname__", cls.__name__), extra - ) - if not lines: - return unique_filename - cache_line = (len("\n".join(lines)), None, lines, unique_filename) - if linecache.cache.setdefault(unique_filename, cache_line) == cache_line: - return unique_filename - - # Looks like this spot is taken. Try again. - count += 1 - extra = f"-{count}" diff --git a/server/libs/cattrs/gen/_shared.py b/server/libs/cattrs/gen/_shared.py deleted file mode 100644 index 904c774..0000000 --- a/server/libs/cattrs/gen/_shared.py +++ /dev/null @@ -1,64 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any - -from attrs import NOTHING, Attribute, Factory - -from .._compat import is_bare_final -from ..dispatch import StructureHook -from ..errors import StructureHandlerNotFoundError -from ..fns import raise_error - -if TYPE_CHECKING: - from ..converters import BaseConverter - - -def find_structure_handler( - a: Attribute, type: Any, c: BaseConverter, prefer_attrs_converters: bool = False -) -> StructureHook | None: - """Find the appropriate structure handler to use. - - Return `None` if no handler should be used. - """ - try: - if a.converter is not None and prefer_attrs_converters: - # If the user as requested to use attrib converters, use nothing - # so it falls back to that. - handler = None - elif ( - a.converter is not None and not prefer_attrs_converters and type is not None - ): - try: - handler = c.get_structure_hook(type, cache_result=False) - except StructureHandlerNotFoundError: - handler = None - else: - # The legacy way, should still work. - if handler == raise_error: - handler = None - elif type is not None: - if ( - is_bare_final(type) - and a.default is not NOTHING - and not isinstance(a.default, Factory) - ): - # This is a special case where we can use the - # type of the default to dispatch on. - type = a.default.__class__ - handler = c.get_structure_hook(type, cache_result=False) - if handler == c._structure_call: - # Finals can't really be used with _structure_call, so - # we wrap it so the rest of the toolchain doesn't get - # confused. - - def handler(v, _, _h=handler): - return _h(v, type) - - else: - handler = c.get_structure_hook(type, cache_result=False) - else: - handler = c.structure - return handler - except RecursionError: - # This means we're dealing with a reference cycle, so use late binding. - return c.structure diff --git a/server/libs/cattrs/gen/typeddicts.py b/server/libs/cattrs/gen/typeddicts.py deleted file mode 100644 index bca38a5..0000000 --- a/server/libs/cattrs/gen/typeddicts.py +++ /dev/null @@ -1,582 +0,0 @@ -from __future__ import annotations - -import re -import sys -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, Callable, Literal, TypeVar - -from attrs import NOTHING, Attribute -from typing_extensions import _TypedDictMeta - -try: - from inspect import get_annotations - - def get_annots(cl) -> dict[str, Any]: - return get_annotations(cl, eval_str=True) - -except ImportError: - # https://docs.python.org/3/howto/annotations.html#accessing-the-annotations-dict-of-an-object-in-python-3-9-and-older - def get_annots(cl) -> dict[str, Any]: - return cl.__dict__.get("__annotations__", {}) - - -from .._compat import ( - get_full_type_hints, - get_notrequired_base, - get_origin, - is_annotated, - is_bare, - is_generic, -) -from .._generics import deep_copy_with -from ..errors import ( - AttributeValidationNote, - ClassValidationError, - ForbiddenExtraKeysError, - StructureHandlerNotFoundError, -) -from ..fns import identity -from . import AttributeOverride -from ._consts import already_generating, neutral -from ._generics import generate_mapping -from ._lc import generate_unique_filename -from ._shared import find_structure_handler - -if TYPE_CHECKING: - from ..converters import BaseConverter - -__all__ = ["make_dict_structure_fn", "make_dict_unstructure_fn"] - -T = TypeVar("T") - - -def make_dict_unstructure_fn( - cl: type[T], - converter: BaseConverter, - _cattrs_use_linecache: bool = True, - **kwargs: AttributeOverride, -) -> Callable[[T], dict[str, Any]]: - """ - Generate a specialized dict unstructuring function for a TypedDict. - - :param cl: A `TypedDict` class. - :param converter: A Converter instance to use for unstructuring nested fields. - :param kwargs: A mapping of field names to an `AttributeOverride`, for - customization. - :param _cattrs_detailed_validation: Whether to store the generated code in the - _linecache_, for easier debugging and better stack traces. - """ - origin = get_origin(cl) - attrs = _adapted_fields(origin or cl) # type: ignore - req_keys = _required_keys(origin or cl) - - mapping = {} - if is_generic(cl): - mapping = generate_mapping(cl, mapping) - - for base in getattr(origin, "__orig_bases__", ()): - if is_generic(base) and not str(base).startswith("typing.Generic"): - mapping = generate_mapping(base, mapping) - break - - # It's possible for origin to be None if this is a subclass - # of a generic class. - if origin is not None: - cl = origin - - cl_name = cl.__name__ - fn_name = "unstructure_typeddict_" + cl_name - globs = {} - lines = [] - internal_arg_parts = {} - - # We keep track of what we're generating to help with recursive - # class graphs. - try: - working_set = already_generating.working_set - except AttributeError: - working_set = set() - already_generating.working_set = working_set - if cl in working_set: - raise RecursionError() - working_set.add(cl) - - try: - # We want to short-circuit in certain cases and return the identity - # function. - # We short-circuit if all of these are true: - # * no attributes have been overridden - # * all attributes resolve to `converter._unstructure_identity` - for a in attrs: - attr_name = a.name - override = kwargs.get(attr_name, neutral) - if override != neutral: - break - handler = None - t = a.type - - if isinstance(t, TypeVar): - if t.__name__ in mapping: - t = mapping[t.__name__] - else: - # Unbound typevars use late binding. - handler = converter.unstructure - elif is_generic(t) and not is_bare(t) and not is_annotated(t): - t = deep_copy_with(t, mapping, cl) - - if handler is None: - nrb = get_notrequired_base(t) - if nrb is not NOTHING: - t = nrb - try: - handler = converter.get_unstructure_hook(t) - except RecursionError: - # There's a circular reference somewhere down the line - handler = converter.unstructure - is_identity = handler == identity - if not is_identity: - break - else: - # We've not broken the loop. - return identity - - for ix, a in enumerate(attrs): - attr_name = a.name - override = kwargs.get(attr_name, neutral) - if override.omit: - lines.append(f" res.pop('{attr_name}', None)") - continue - if override.rename is not None: - # We also need to pop when renaming, since we're copying - # the original. - lines.append(f" res.pop('{attr_name}', None)") - kn = attr_name if override.rename is None else override.rename - attr_required = attr_name in req_keys - - # For each attribute, we try resolving the type here and now. - # If a type is manually overwritten, this function should be - # regenerated. - handler = None - if override.unstruct_hook is not None: - handler = override.unstruct_hook - else: - t = a.type - - if isinstance(t, TypeVar): - if t.__name__ in mapping: - t = mapping[t.__name__] - else: - handler = converter.unstructure - elif is_generic(t) and not is_bare(t) and not is_annotated(t): - t = deep_copy_with(t, mapping, cl) - - if handler is None: - nrb = get_notrequired_base(t) - if nrb is not NOTHING: - t = nrb - try: - handler = converter.get_unstructure_hook(t) - except RecursionError: - # There's a circular reference somewhere down the line - handler = converter.unstructure - - is_identity = handler == identity - - if not is_identity: - unstruct_handler_name = f"__c_unstr_{ix}" - globs[unstruct_handler_name] = handler - internal_arg_parts[unstruct_handler_name] = handler - invoke = f"{unstruct_handler_name}(instance['{attr_name}'])" - elif override.rename is None: - # We're not doing anything to this attribute, so - # it'll already be present in the input dict. - continue - else: - # Probably renamed, we just fetch it. - invoke = f"instance['{attr_name}']" - - if attr_required: - # No default or no override. - lines.append(f" res['{kn}'] = {invoke}") - else: - lines.append(f" if '{attr_name}' in instance: res['{kn}'] = {invoke}") - - internal_arg_line = ", ".join([f"{i}={i}" for i in internal_arg_parts]) - if internal_arg_line: - internal_arg_line = f", {internal_arg_line}" - for k, v in internal_arg_parts.items(): - globs[k] = v - - total_lines = [ - f"def {fn_name}(instance{internal_arg_line}):", - " res = instance.copy()", - *lines, - " return res", - ] - script = "\n".join(total_lines) - - fname = generate_unique_filename( - cl, "unstructure", lines=total_lines if _cattrs_use_linecache else [] - ) - - eval(compile(script, fname, "exec"), globs) - finally: - working_set.remove(cl) - if not working_set: - del already_generating.working_set - - return globs[fn_name] - - -def make_dict_structure_fn( - cl: Any, - converter: BaseConverter, - _cattrs_forbid_extra_keys: bool | Literal["from_converter"] = "from_converter", - _cattrs_use_linecache: bool = True, - _cattrs_detailed_validation: bool | Literal["from_converter"] = "from_converter", - **kwargs: AttributeOverride, -) -> Callable[[dict, Any], Any]: - """Generate a specialized dict structuring function for typed dicts. - - :param cl: A `TypedDict` class. - :param converter: A Converter instance to use for structuring nested fields. - :param kwargs: A mapping of field names to an `AttributeOverride`, for - customization. - :param _cattrs_detailed_validation: Whether to use a slower mode that produces - more detailed errors. - :param _cattrs_forbid_extra_keys: Whether the structuring function should raise a - `ForbiddenExtraKeysError` if unknown keys are encountered. - :param _cattrs_detailed_validation: Whether to store the generated code in the - _linecache_, for easier debugging and better stack traces. - - .. versionchanged:: 23.2.0 - The `_cattrs_forbid_extra_keys` and `_cattrs_detailed_validation` parameters - take their values from the given converter by default. - """ - - mapping = {} - if is_generic(cl): - base = get_origin(cl) - mapping = generate_mapping(cl, mapping) - if base is not None: - # It's possible for this to be a subclass of a generic, - # so no origin. - cl = base - - for base in getattr(cl, "__orig_bases__", ()): - if is_generic(base) and not str(base).startswith("typing.Generic"): - mapping = generate_mapping(base, mapping) - break - - cl_name = cl.__name__ - fn_name = "structure_" + cl_name - - # We have generic parameters and need to generate a unique name for the function - for p in getattr(cl, "__parameters__", ()): - try: - name_base = mapping[p.__name__] - except KeyError: - pn = p.__name__ - raise StructureHandlerNotFoundError( - f"Missing type for generic argument {pn}, specify it when structuring.", - p, - ) from None - name = getattr(name_base, "__name__", None) or str(name_base) - # `<>` can be present in lambdas - # `|` can be present in unions - name = re.sub(r"[\[\.\] ,<>]", "_", name) - name = re.sub(r"\|", "u", name) - fn_name += f"_{name}" - - internal_arg_parts = {"__cl": cl} - globs = {} - lines = [] - post_lines = [] - - attrs = _adapted_fields(cl) - req_keys = _required_keys(cl) - - allowed_fields = set() - if _cattrs_forbid_extra_keys == "from_converter": - # BaseConverter doesn't have it so we're careful. - _cattrs_forbid_extra_keys = getattr(converter, "forbid_extra_keys", False) - if _cattrs_detailed_validation == "from_converter": - _cattrs_detailed_validation = converter.detailed_validation - - if _cattrs_forbid_extra_keys: - globs["__c_a"] = allowed_fields - globs["__c_feke"] = ForbiddenExtraKeysError - - if _cattrs_detailed_validation: - # When running under detailed validation, be extra careful about the - # input type so that the correct error is raised if the input isn't a dict. - internal_arg_parts["__c_mapping"] = Mapping - lines.append(" if not isinstance(o, __c_mapping):") - te = "TypeError(f'expected a mapping, not {o.__class__.__name__}')" - lines.append( - f" raise __c_cve('While structuring ' + {cl.__name__!r}, [{te}], __cl)" - ) - - lines.append(" res = o.copy()") - - if _cattrs_detailed_validation: - lines.append(" errors = []") - internal_arg_parts["__c_cve"] = ClassValidationError - internal_arg_parts["__c_avn"] = AttributeValidationNote - for ix, a in enumerate(attrs): - an = a.name - attr_required = an in req_keys - override = kwargs.get(an, neutral) - if override.omit: - continue - t = a.type - - if isinstance(t, TypeVar): - t = mapping.get(t.__name__, t) - elif is_generic(t) and not is_bare(t) and not is_annotated(t): - t = deep_copy_with(t, mapping, cl) - - nrb = get_notrequired_base(t) - if nrb is not NOTHING: - t = nrb - - if is_generic(t) and not is_bare(t) and not is_annotated(t): - t = deep_copy_with(t, mapping, cl) - - # For each attribute, we try resolving the type here and now. - # If a type is manually overwritten, this function should be - # regenerated. - if override.struct_hook is not None: - # If the user has requested an override, just use that. - handler = override.struct_hook - else: - handler = find_structure_handler(a, t, converter) - - struct_handler_name = f"__c_structure_{ix}" - internal_arg_parts[struct_handler_name] = handler - - kn = an if override.rename is None else override.rename - allowed_fields.add(kn) - i = " " - if not attr_required: - lines.append(f"{i}if '{kn}' in o:") - i = f"{i} " - lines.append(f"{i}try:") - i = f"{i} " - - tn = f"__c_type_{ix}" - internal_arg_parts[tn] = t - - if handler == converter._structure_call: - internal_arg_parts[struct_handler_name] = t - lines.append(f"{i}res['{an}'] = {struct_handler_name}(o['{kn}'])") - else: - lines.append(f"{i}res['{an}'] = {struct_handler_name}(o['{kn}'], {tn})") - if override.rename is not None: - lines.append(f"{i}del res['{kn}']") - i = i[:-2] - lines.append(f"{i}except Exception as e:") - i = f"{i} " - lines.append( - f'{i}e.__notes__ = [*getattr(e, \'__notes__\', []), __c_avn("Structuring typeddict {cl.__qualname__} @ attribute {an}", "{an}", {tn})]' - ) - lines.append(f"{i}errors.append(e)") - - if _cattrs_forbid_extra_keys: - post_lines += [ - " unknown_fields = o.keys() - __c_a", - " if unknown_fields:", - " errors.append(__c_feke('', __cl, unknown_fields))", - ] - - post_lines.append( - f" if errors: raise __c_cve('While structuring ' + {cl.__name__!r}, errors, __cl)" - ) - else: - non_required = [] - - # The first loop deals with required args. - for ix, a in enumerate(attrs): - an = a.name - attr_required = an in req_keys - override = kwargs.get(an, neutral) - if override.omit: - continue - if not attr_required: - non_required.append((ix, a)) - continue - - t = a.type - - if isinstance(t, TypeVar): - t = mapping.get(t.__name__, t) - elif is_generic(t) and not is_bare(t) and not is_annotated(t): - t = deep_copy_with(t, mapping, cl) - - nrb = get_notrequired_base(t) - if nrb is not NOTHING: - t = nrb - - if override.struct_hook is not None: - handler = override.struct_hook - else: - # For each attribute, we try resolving the type here and now. - # If a type is manually overwritten, this function should be - # regenerated. - handler = converter.get_structure_hook(t) - - kn = an if override.rename is None else override.rename - allowed_fields.add(kn) - - struct_handler_name = f"__c_structure_{ix}" - internal_arg_parts[struct_handler_name] = handler - if handler == converter._structure_call: - internal_arg_parts[struct_handler_name] = t - invocation_line = f" res['{an}'] = {struct_handler_name}(o['{kn}'])" - else: - tn = f"__c_type_{ix}" - internal_arg_parts[tn] = t - invocation_line = ( - f" res['{an}'] = {struct_handler_name}(o['{kn}'], {tn})" - ) - - lines.append(invocation_line) - if override.rename is not None: - lines.append(f" del res['{override.rename}']") - - # The second loop is for optional args. - if non_required: - for ix, a in non_required: - an = a.name - override = kwargs.get(an, neutral) - t = a.type - - nrb = get_notrequired_base(t) - if nrb is not NOTHING: - t = nrb - - if isinstance(t, TypeVar): - t = mapping.get(t.__name__, t) - elif is_generic(t) and not is_bare(t) and not is_annotated(t): - t = deep_copy_with(t, mapping, cl) - - if override.struct_hook is not None: - handler = override.struct_hook - else: - # For each attribute, we try resolving the type here and now. - # If a type is manually overwritten, this function should be - # regenerated. - handler = converter.get_structure_hook(t) - - struct_handler_name = f"__c_structure_{ix}" - internal_arg_parts[struct_handler_name] = handler - - ian = an - kn = an if override.rename is None else override.rename - allowed_fields.add(kn) - post_lines.append(f" if '{kn}' in o:") - if handler == converter._structure_call: - internal_arg_parts[struct_handler_name] = t - post_lines.append( - f" res['{ian}'] = {struct_handler_name}(o['{kn}'])" - ) - else: - tn = f"__c_type_{ix}" - internal_arg_parts[tn] = t - post_lines.append( - f" res['{ian}'] = {struct_handler_name}(o['{kn}'], {tn})" - ) - if override.rename is not None: - lines.append(f" res.pop('{override.rename}', None)") - - if _cattrs_forbid_extra_keys: - post_lines += [ - " unknown_fields = o.keys() - __c_a", - " if unknown_fields:", - " raise __c_feke('', __cl, unknown_fields)", - ] - - # At the end, we create the function header. - internal_arg_line = ", ".join([f"{i}={i}" for i in internal_arg_parts]) - for k, v in internal_arg_parts.items(): - globs[k] = v - - total_lines = [ - f"def {fn_name}(o, _, {internal_arg_line}):", - *lines, - *post_lines, - " return res", - ] - - script = "\n".join(total_lines) - fname = generate_unique_filename( - cl, "structure", lines=total_lines if _cattrs_use_linecache else [] - ) - - eval(compile(script, fname, "exec"), globs) - return globs[fn_name] - - -def _adapted_fields(cls: Any) -> list[Attribute]: - annotations = get_annots(cls) - hints = get_full_type_hints(cls) - return [ - Attribute( - n, - NOTHING, - None, - False, - False, - False, - False, - False, - type=hints[n] if n in hints else annotations[n], - ) - for n, a in annotations.items() - ] - - -def _is_extensions_typeddict(cls) -> bool: - return cls.__class__ is _TypedDictMeta or ( - is_generic(cls) and (cls.__origin__.__class__ is _TypedDictMeta) - ) - - -if sys.version_info >= (3, 11): - - def _required_keys(cls: type) -> set[str]: - return cls.__required_keys__ - -else: - from typing_extensions import Annotated, NotRequired, get_args - - # Note that there is no `typing.Required` on 3.9 and 3.10, only in - # `typing_extensions`. Therefore, `typing.TypedDict` will not honor this - # annotation, only `typing_extensions.TypedDict`. - - def _required_keys(cls: type) -> set[str]: - """Our own processor for required keys.""" - if _is_extensions_typeddict(cls): - return cls.__required_keys__ - - # We vendor a part of the typing_extensions logic for - # gathering required keys. *sigh* - own_annotations = cls.__dict__.get("__annotations__", {}) - required_keys = set() - # On 3.9 - 3.10, typing.TypedDict doesn't put typeddict superclasses - # in the MRO, therefore we cannot handle non-required keys properly - # in some situations. Oh well. - for key in getattr(cls, "__required_keys__", []): - annotation_type = own_annotations[key] - annotation_origin = get_origin(annotation_type) - if annotation_origin is Annotated: - annotation_args = get_args(annotation_type) - if annotation_args: - annotation_type = annotation_args[0] - annotation_origin = get_origin(annotation_type) - - if annotation_origin is NotRequired: - pass - elif cls.__total__: - required_keys.add(key) - return required_keys diff --git a/server/libs/cattrs/literals.py b/server/libs/cattrs/literals.py deleted file mode 100644 index badedda..0000000 --- a/server/libs/cattrs/literals.py +++ /dev/null @@ -1,11 +0,0 @@ -from enum import Enum -from typing import Any - -from ._compat import is_literal - -__all__ = ["is_literal", "is_literal_containing_enums"] - - -def is_literal_containing_enums(type: Any) -> bool: - """Is this a literal containing at least one Enum?""" - return is_literal(type) and any(isinstance(val, Enum) for val in type.__args__) diff --git a/server/libs/cattrs/preconf/__init__.py b/server/libs/cattrs/preconf/__init__.py deleted file mode 100644 index 1b12ef9..0000000 --- a/server/libs/cattrs/preconf/__init__.py +++ /dev/null @@ -1,55 +0,0 @@ -import sys -from datetime import datetime -from enum import Enum -from typing import Any, Callable, TypeVar, get_args - -from .._compat import is_subclass -from ..converters import Converter, UnstructureHook -from ..fns import identity - -if sys.version_info[:2] < (3, 10): - from typing_extensions import ParamSpec -else: - from typing import ParamSpec - - -def validate_datetime(v, _): - if not isinstance(v, datetime): - raise Exception(f"Expected datetime, got {v}") - return v - - -T = TypeVar("T") -P = ParamSpec("P") - - -def wrap(_: Callable[P, Any]) -> Callable[[Callable[..., T]], Callable[P, T]]: - """Wrap a `Converter` `__init__` in a type-safe way.""" - - def impl(x: Callable[..., T]) -> Callable[P, T]: - return x - - return impl - - -def is_primitive_enum(type: Any, include_bare_enums: bool = False) -> bool: - """Is this a string or int enum that can be passed through?""" - return is_subclass(type, Enum) and ( - is_subclass(type, (str, int)) - or (include_bare_enums and type.mro()[1:] == Enum.mro()) - ) - - -def literals_with_enums_unstructure_factory( - typ: Any, converter: Converter -) -> UnstructureHook: - """An unstructure hook factory for literals containing enums. - - If all contained enums can be passed through (their unstructure hook is `identity`), - the entire literal can also be passed through. - """ - if all( - converter.get_unstructure_hook(type(arg)) == identity for arg in get_args(typ) - ): - return identity - return converter.unstructure diff --git a/server/libs/cattrs/preconf/bson.py b/server/libs/cattrs/preconf/bson.py deleted file mode 100644 index 4957489..0000000 --- a/server/libs/cattrs/preconf/bson.py +++ /dev/null @@ -1,121 +0,0 @@ -"""Preconfigured converters for bson.""" - -from base64 import b85decode, b85encode -from collections.abc import Set -from datetime import date, datetime -from typing import Any, TypeVar, Union - -from bson import DEFAULT_CODEC_OPTIONS, CodecOptions, Int64, ObjectId, decode, encode - -from .._compat import is_mapping, is_subclass -from ..cols import mapping_structure_factory -from ..converters import BaseConverter, Converter -from ..dispatch import StructureHook -from ..fns import identity -from ..literals import is_literal_containing_enums -from ..strategies import configure_union_passthrough -from . import ( - is_primitive_enum, - literals_with_enums_unstructure_factory, - validate_datetime, - wrap, -) - -T = TypeVar("T") - - -class Base85Bytes(bytes): - """A subclass to help with binary key encoding/decoding.""" - - -class BsonConverter(Converter): - def dumps( - self, - obj: Any, - unstructure_as: Any = None, - check_keys: bool = False, - codec_options: CodecOptions = DEFAULT_CODEC_OPTIONS, - ) -> bytes: - return encode( - self.unstructure(obj, unstructure_as=unstructure_as), - check_keys=check_keys, - codec_options=codec_options, - ) - - def loads( - self, - data: bytes, - cl: type[T], - codec_options: CodecOptions = DEFAULT_CODEC_OPTIONS, - ) -> T: - return self.structure(decode(data, codec_options=codec_options), cl) - - -def configure_converter(converter: BaseConverter): - """ - Configure the converter for use with the bson library. - - * sets are serialized as lists - * byte mapping keys are base85-encoded into strings when unstructuring, and reverse - * non-string, non-byte mapping keys are coerced into strings when unstructuring - * a deserialization hook is registered for bson.ObjectId by default - * string and int enums are passed through when unstructuring - - .. versionchanged:: 24.2.0 - Enums are left to the library to unstructure, speeding them up. - """ - - def gen_unstructure_mapping(cl: Any, unstructure_to=None): - key_handler = str - args = getattr(cl, "__args__", None) - if args: - if is_subclass(args[0], str): - key_handler = None - elif is_subclass(args[0], bytes): - - def key_handler(k): - return b85encode(k).decode("utf8") - - return converter.gen_unstructure_mapping( - cl, unstructure_to=unstructure_to, key_handler=key_handler - ) - - def gen_structure_mapping(cl: Any) -> StructureHook: - args = getattr(cl, "__args__", None) - if args and is_subclass(args[0], bytes): - h = mapping_structure_factory(cl, converter, key_type=Base85Bytes) - else: - h = mapping_structure_factory(cl, converter) - return h - - converter.register_structure_hook(Base85Bytes, lambda v, _: b85decode(v)) - converter.register_unstructure_hook_factory(is_mapping, gen_unstructure_mapping) - converter.register_structure_hook_factory(is_mapping, gen_structure_mapping) - - converter.register_structure_hook(ObjectId, lambda v, _: ObjectId(v)) - configure_union_passthrough( - Union[str, bool, int, float, None, bytes, datetime, ObjectId, Int64], converter - ) - - # datetime inherits from date, so identity unstructure hook used - # here to prevent the date unstructure hook running. - converter.register_unstructure_hook(datetime, lambda v: v) - converter.register_structure_hook(datetime, validate_datetime) - converter.register_unstructure_hook(date, lambda v: v.isoformat()) - converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v)) - converter.register_unstructure_hook_func(is_primitive_enum, identity) - converter.register_unstructure_hook_factory( - is_literal_containing_enums, literals_with_enums_unstructure_factory - ) - - -@wrap(BsonConverter) -def make_converter(*args: Any, **kwargs: Any) -> BsonConverter: - kwargs["unstruct_collection_overrides"] = { - Set: list, - **kwargs.get("unstruct_collection_overrides", {}), - } - res = BsonConverter(*args, **kwargs) - configure_converter(res) - - return res diff --git a/server/libs/cattrs/preconf/cbor2.py b/server/libs/cattrs/preconf/cbor2.py deleted file mode 100644 index 6341d89..0000000 --- a/server/libs/cattrs/preconf/cbor2.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Preconfigured converters for cbor2.""" - -from collections.abc import Set -from datetime import date, datetime, timezone -from typing import Any, TypeVar, Union - -from cbor2 import dumps, loads - -from ..converters import BaseConverter, Converter -from ..fns import identity -from ..literals import is_literal_containing_enums -from ..strategies import configure_union_passthrough -from . import is_primitive_enum, literals_with_enums_unstructure_factory, wrap - -T = TypeVar("T") - - -class Cbor2Converter(Converter): - def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes: - return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs) - - def loads(self, data: bytes, cl: type[T], **kwargs: Any) -> T: - return self.structure(loads(data, **kwargs), cl) - - -def configure_converter(converter: BaseConverter): - """ - Configure the converter for use with the cbor2 library. - - * datetimes are serialized as timestamp floats - * sets are serialized as lists - * string and int enums are passed through when unstructuring - """ - converter.register_unstructure_hook(datetime, lambda v: v.timestamp()) - converter.register_structure_hook( - datetime, lambda v, _: datetime.fromtimestamp(v, timezone.utc) - ) - converter.register_unstructure_hook(date, lambda v: v.isoformat()) - converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v)) - converter.register_unstructure_hook_func(is_primitive_enum, identity) - converter.register_unstructure_hook_factory( - is_literal_containing_enums, literals_with_enums_unstructure_factory - ) - configure_union_passthrough(Union[str, bool, int, float, None, bytes], converter) - - -@wrap(Cbor2Converter) -def make_converter(*args: Any, **kwargs: Any) -> Cbor2Converter: - kwargs["unstruct_collection_overrides"] = { - Set: list, - **kwargs.get("unstruct_collection_overrides", {}), - } - res = Cbor2Converter(*args, **kwargs) - configure_converter(res) - - return res diff --git a/server/libs/cattrs/preconf/json.py b/server/libs/cattrs/preconf/json.py deleted file mode 100644 index 199c574..0000000 --- a/server/libs/cattrs/preconf/json.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Preconfigured converters for the stdlib json.""" - -from base64 import b85decode, b85encode -from collections.abc import Set -from datetime import date, datetime -from json import dumps, loads -from typing import Any, TypeVar, Union - -from .._compat import Counter -from ..converters import BaseConverter, Converter -from ..fns import identity -from ..literals import is_literal_containing_enums -from ..strategies import configure_union_passthrough -from . import is_primitive_enum, literals_with_enums_unstructure_factory, wrap - -__all__ = ["JsonConverter", "configure_converter", "make_converter"] - -T = TypeVar("T") - - -class JsonConverter(Converter): - def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str: - return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs) - - def loads(self, data: Union[bytes, str], cl: type[T], **kwargs: Any) -> T: - return self.structure(loads(data, **kwargs), cl) - - -def configure_converter(converter: BaseConverter) -> None: - """ - Configure the converter for use with the stdlib json module. - - * bytes are serialized as base85 strings - * datetimes are serialized as ISO 8601 - * counters are serialized as dicts - * sets are serialized as lists - * string and int enums are passed through when unstructuring - * union passthrough is configured for unions of strings, bools, ints, - floats and None - - .. versionchanged:: 24.2.0 - Enums are left to the library to unstructure, speeding them up. - """ - converter.register_unstructure_hook( - bytes, lambda v: (b85encode(v) if v else b"").decode("utf8") - ) - converter.register_structure_hook(bytes, lambda v, _: b85decode(v)) - converter.register_unstructure_hook(datetime, lambda v: v.isoformat()) - converter.register_structure_hook(datetime, lambda v, _: datetime.fromisoformat(v)) - converter.register_unstructure_hook(date, lambda v: v.isoformat()) - converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v)) - converter.register_unstructure_hook_factory( - is_literal_containing_enums, literals_with_enums_unstructure_factory - ) - converter.register_unstructure_hook_func(is_primitive_enum, identity) - configure_union_passthrough(Union[str, bool, int, float, None], converter) - - -@wrap(JsonConverter) -def make_converter(*args: Any, **kwargs: Any) -> JsonConverter: - kwargs["unstruct_collection_overrides"] = { - Set: list, - Counter: dict, - **kwargs.get("unstruct_collection_overrides", {}), - } - res = JsonConverter(*args, **kwargs) - configure_converter(res) - - return res diff --git a/server/libs/cattrs/preconf/msgpack.py b/server/libs/cattrs/preconf/msgpack.py deleted file mode 100644 index 9287641..0000000 --- a/server/libs/cattrs/preconf/msgpack.py +++ /dev/null @@ -1,65 +0,0 @@ -"""Preconfigured converters for msgpack.""" - -from collections.abc import Set -from datetime import date, datetime, time, timezone -from typing import Any, TypeVar, Union - -from msgpack import dumps, loads - -from ..converters import BaseConverter, Converter -from ..fns import identity -from ..literals import is_literal_containing_enums -from ..strategies import configure_union_passthrough -from . import is_primitive_enum, literals_with_enums_unstructure_factory, wrap - -__all__ = ["MsgpackConverter", "configure_converter", "make_converter"] - -T = TypeVar("T") - - -class MsgpackConverter(Converter): - def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes: - return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs) - - def loads(self, data: bytes, cl: type[T], **kwargs: Any) -> T: - return self.structure(loads(data, **kwargs), cl) - - -def configure_converter(converter: BaseConverter) -> None: - """ - Configure the converter for use with the msgpack library. - - * datetimes are serialized as timestamp floats - * sets are serialized as lists - * string and int enums are passed through when unstructuring - - .. versionchanged:: 24.2.0 - Enums are left to the library to unstructure, speeding them up. - """ - converter.register_unstructure_hook(datetime, lambda v: v.timestamp()) - converter.register_structure_hook( - datetime, lambda v, _: datetime.fromtimestamp(v, timezone.utc) - ) - converter.register_unstructure_hook( - date, lambda v: datetime.combine(v, time(tzinfo=timezone.utc)).timestamp() - ) - converter.register_structure_hook( - date, lambda v, _: datetime.fromtimestamp(v, timezone.utc).date() - ) - converter.register_unstructure_hook_func(is_primitive_enum, identity) - converter.register_unstructure_hook_factory( - is_literal_containing_enums, literals_with_enums_unstructure_factory - ) - configure_union_passthrough(Union[str, bool, int, float, None, bytes], converter) - - -@wrap(MsgpackConverter) -def make_converter(*args: Any, **kwargs: Any) -> MsgpackConverter: - kwargs["unstruct_collection_overrides"] = { - Set: list, - **kwargs.get("unstruct_collection_overrides", {}), - } - res = MsgpackConverter(*args, **kwargs) - configure_converter(res) - - return res diff --git a/server/libs/cattrs/preconf/msgspec.py b/server/libs/cattrs/preconf/msgspec.py deleted file mode 100644 index 6274a32..0000000 --- a/server/libs/cattrs/preconf/msgspec.py +++ /dev/null @@ -1,202 +0,0 @@ -"""Preconfigured converters for msgspec.""" - -from __future__ import annotations - -from base64 import b64decode -from dataclasses import is_dataclass -from datetime import date, datetime -from enum import Enum -from functools import partial -from typing import Any, Callable, TypeVar, Union, get_type_hints - -from attrs import has as attrs_has -from attrs import resolve_types -from msgspec import Struct, convert, to_builtins -from msgspec.json import Encoder, decode - -from .._compat import fields, get_args, get_origin, is_bare, is_mapping, is_sequence -from ..cols import is_namedtuple -from ..converters import BaseConverter, Converter -from ..dispatch import UnstructureHook -from ..fns import identity -from ..gen import make_hetero_tuple_unstructure_fn -from ..literals import is_literal_containing_enums -from ..strategies import configure_union_passthrough -from . import literals_with_enums_unstructure_factory, wrap - -T = TypeVar("T") - -__all__ = ["MsgspecJsonConverter", "configure_converter", "make_converter"] - - -class MsgspecJsonConverter(Converter): - """A converter specialized for the _msgspec_ library.""" - - #: The msgspec encoder for dumping. - encoder: Encoder = Encoder() - - def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes: - """Unstructure and encode `obj` into JSON bytes.""" - return self.encoder.encode( - self.unstructure(obj, unstructure_as=unstructure_as), **kwargs - ) - - def get_dumps_hook( - self, unstructure_as: Any, **kwargs: Any - ) -> Callable[[Any], bytes]: - """Produce a `dumps` hook for the given type.""" - unstruct_hook = self.get_unstructure_hook(unstructure_as) - if unstruct_hook in (identity, to_builtins): - return self.encoder.encode - return self.dumps - - def loads(self, data: bytes, cl: type[T], **kwargs: Any) -> T: - """Decode and structure `cl` from the provided JSON bytes.""" - return self.structure(decode(data, **kwargs), cl) - - def get_loads_hook(self, cl: type[T]) -> Callable[[bytes], T]: - """Produce a `loads` hook for the given type.""" - return partial(self.loads, cl=cl) - - -def configure_converter(converter: Converter) -> None: - """Configure the converter for the msgspec library. - - * bytes are serialized as base64 strings, directly by msgspec - * datetimes and dates are passed through to be serialized as RFC 3339 directly - * enums are passed through to msgspec directly - * union passthrough configured for str, bool, int, float and None - * bare, string and int enums are passed through when unstructuring - - .. versionchanged:: 24.2.0 - Enums are left to the library to unstructure, speeding them up. - """ - configure_passthroughs(converter) - - converter.register_unstructure_hook(Struct, to_builtins) - converter.register_unstructure_hook(Enum, identity) - - converter.register_structure_hook(Struct, convert) - converter.register_structure_hook(bytes, lambda v, _: b64decode(v)) - converter.register_structure_hook(datetime, lambda v, _: convert(v, datetime)) - converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v)) - converter.register_unstructure_hook_factory( - is_literal_containing_enums, literals_with_enums_unstructure_factory - ) - configure_union_passthrough(Union[str, bool, int, float, None], converter) - - -@wrap(MsgspecJsonConverter) -def make_converter(*args: Any, **kwargs: Any) -> MsgspecJsonConverter: - res = MsgspecJsonConverter(*args, **kwargs) - configure_converter(res) - return res - - -def configure_passthroughs(converter: Converter) -> None: - """Configure optimizing passthroughs. - - A passthrough is when we let msgspec handle something automatically. - - .. versionchanged:: 25.1.0 - Dataclasses with private attributes are now passed through. - """ - converter.register_unstructure_hook(bytes, to_builtins) - converter.register_unstructure_hook_factory(is_mapping, mapping_unstructure_factory) - converter.register_unstructure_hook_factory(is_sequence, seq_unstructure_factory) - converter.register_unstructure_hook_factory( - attrs_has, msgspec_attrs_unstructure_factory - ) - converter.register_unstructure_hook_factory( - is_dataclass, - partial(msgspec_attrs_unstructure_factory, msgspec_skips_private=False), - ) - converter.register_unstructure_hook_factory( - is_namedtuple, namedtuple_unstructure_factory - ) - - -def seq_unstructure_factory(type, converter: Converter) -> UnstructureHook: - """The msgspec unstructure hook factory for sequences.""" - if is_bare(type): - type_arg = Any - else: - args = get_args(type) - type_arg = args[0] - handler = converter.get_unstructure_hook(type_arg, cache_result=False) - - if handler in (identity, to_builtins): - return handler - return converter.gen_unstructure_iterable(type) - - -def mapping_unstructure_factory(type, converter: BaseConverter) -> UnstructureHook: - """The msgspec unstructure hook factory for mappings.""" - if is_bare(type): - key_arg = Any - val_arg = Any - key_handler = converter.get_unstructure_hook(key_arg, cache_result=False) - value_handler = converter.get_unstructure_hook(val_arg, cache_result=False) - else: - args = get_args(type) - if len(args) == 2: - key_arg, val_arg = args - else: - # Probably a Counter - key_arg, val_arg = args, Any - key_handler = converter.get_unstructure_hook(key_arg, cache_result=False) - value_handler = converter.get_unstructure_hook(val_arg, cache_result=False) - - if key_handler in (identity, to_builtins) and value_handler in ( - identity, - to_builtins, - ): - return to_builtins - return converter.gen_unstructure_mapping(type) - - -def msgspec_attrs_unstructure_factory( - type: Any, converter: Converter, msgspec_skips_private: bool = True -) -> UnstructureHook: - """Choose whether to use msgspec handling or our own. - - Args: - msgspec_skips_private: Whether the msgspec library skips unstructuring - private attributes, making us do the work. - """ - origin = get_origin(type) - attribs = fields(origin or type) - if attrs_has(type) and any(isinstance(a.type, str) for a in attribs): - resolve_types(type) - attribs = fields(origin or type) - - if msgspec_skips_private and any( - attr.name.startswith("_") - or ( - converter.get_unstructure_hook(attr.type, cache_result=False) - not in (identity, to_builtins) - ) - for attr in attribs - ): - return converter.gen_unstructure_attrs_fromdict(type) - - return to_builtins - - -def namedtuple_unstructure_factory( - type: type[tuple], converter: BaseConverter -) -> UnstructureHook: - """A hook factory for unstructuring namedtuples, modified for msgspec.""" - - if all( - converter.get_unstructure_hook(t) in (identity, to_builtins) - for t in get_type_hints(type).values() - ): - return identity - - return make_hetero_tuple_unstructure_fn( - type, - converter, - unstructure_to=tuple, - type_args=tuple(get_type_hints(type).values()), - ) diff --git a/server/libs/cattrs/preconf/orjson.py b/server/libs/cattrs/preconf/orjson.py deleted file mode 100644 index 0726ef0..0000000 --- a/server/libs/cattrs/preconf/orjson.py +++ /dev/null @@ -1,108 +0,0 @@ -"""Preconfigured converters for orjson.""" - -from base64 import b85decode, b85encode -from collections.abc import Set -from datetime import date, datetime -from enum import Enum -from functools import partial -from typing import Any, TypeVar, Union - -from orjson import dumps, loads - -from .._compat import is_subclass -from ..cols import is_mapping, is_namedtuple, namedtuple_unstructure_factory -from ..converters import Converter -from ..fns import identity -from ..literals import is_literal_containing_enums -from ..strategies import configure_union_passthrough -from . import is_primitive_enum, literals_with_enums_unstructure_factory, wrap - -__all__ = ["OrjsonConverter", "configure_converter", "make_converter"] - -T = TypeVar("T") - - -class OrjsonConverter(Converter): - def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes: - return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs) - - def loads(self, data: Union[bytes, bytearray, memoryview, str], cl: type[T]) -> T: - return self.structure(loads(data), cl) - - -def configure_converter(converter: Converter) -> None: - """ - Configure the converter for use with the orjson library. - - * bytes are serialized as base85 strings - * datetimes and dates are passed through to be serialized as RFC 3339 by orjson - * typed namedtuples are serialized as lists - * sets are serialized as lists - * string enum mapping keys have special handling - * mapping keys are coerced into strings when unstructuring - * bare, string and int enums are passed through when unstructuring - - .. versionchanged:: 24.1.0 - Add support for typed namedtuples. - .. versionchanged:: 24.2.0 - Enums are left to the library to unstructure, speeding them up. - """ - converter.register_unstructure_hook( - bytes, lambda v: (b85encode(v) if v else b"").decode("utf8") - ) - converter.register_structure_hook(bytes, lambda v, _: b85decode(v)) - - converter.register_structure_hook(datetime, lambda v, _: datetime.fromisoformat(v)) - converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v)) - - def unstructure_mapping_factory(cl: Any, unstructure_to=None): - key_handler = str - args = getattr(cl, "__args__", None) - if args: - if is_subclass(args[0], str) and is_subclass(args[0], Enum): - - def key_handler(v): - return v.value - - else: - # It's possible the handler for the key type has been overridden. - # (For example base85 encoding for bytes.) - # In that case, we want to use the override. - - kh = converter.get_unstructure_hook(args[0]) - if kh != identity: - key_handler = kh - - return converter.gen_unstructure_mapping( - cl, unstructure_to=unstructure_to, key_handler=key_handler - ) - - converter._unstructure_func.register_func_list( - [ - (is_mapping, unstructure_mapping_factory, True), - ( - is_namedtuple, - partial(namedtuple_unstructure_factory, unstructure_to=tuple), - "extended", - ), - ] - ) - converter.register_unstructure_hook_func( - partial(is_primitive_enum, include_bare_enums=True), identity - ) - converter.register_unstructure_hook_factory( - is_literal_containing_enums, literals_with_enums_unstructure_factory - ) - configure_union_passthrough(Union[str, bool, int, float, None], converter) - - -@wrap(OrjsonConverter) -def make_converter(*args: Any, **kwargs: Any) -> OrjsonConverter: - kwargs["unstruct_collection_overrides"] = { - Set: list, - **kwargs.get("unstruct_collection_overrides", {}), - } - res = OrjsonConverter(*args, **kwargs) - configure_converter(res) - - return res diff --git a/server/libs/cattrs/preconf/pyyaml.py b/server/libs/cattrs/preconf/pyyaml.py deleted file mode 100644 index b1b8854..0000000 --- a/server/libs/cattrs/preconf/pyyaml.py +++ /dev/null @@ -1,74 +0,0 @@ -"""Preconfigured converters for pyyaml.""" - -from datetime import date, datetime -from functools import partial -from typing import Any, TypeVar, Union - -from yaml import safe_dump, safe_load - -from .._compat import FrozenSetSubscriptable -from ..cols import is_namedtuple, namedtuple_unstructure_factory -from ..converters import BaseConverter, Converter -from ..strategies import configure_union_passthrough -from . import validate_datetime, wrap - -__all__ = ["PyyamlConverter", "configure_converter", "make_converter"] - -T = TypeVar("T") - - -def validate_date(v: Any, _): - if not isinstance(v, date): - raise ValueError(f"Expected date, got {v}") - return v - - -class PyyamlConverter(Converter): - def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str: - return safe_dump(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs) - - def loads(self, data: str, cl: type[T]) -> T: - return self.structure(safe_load(data), cl) - - -def configure_converter(converter: BaseConverter) -> None: - """ - Configure the converter for use with the pyyaml library. - - * frozensets are serialized as lists - * string enums are converted into strings explicitly - * datetimes and dates are validated - * typed namedtuples are serialized as lists - - .. versionchanged:: 24.1.0 - Add support for typed namedtuples. - """ - converter.register_unstructure_hook( - str, lambda v: v if v.__class__ is str else v.value - ) - - # datetime inherits from date, so identity unstructure hook used - # here to prevent the date unstructure hook running. - converter.register_unstructure_hook(datetime, lambda v: v) - converter.register_structure_hook(datetime, validate_datetime) - converter.register_structure_hook(date, validate_date) - - converter.register_unstructure_hook_factory(is_namedtuple)( - partial(namedtuple_unstructure_factory, unstructure_to=tuple) - ) - - configure_union_passthrough( - Union[str, bool, int, float, None, bytes, datetime, date], converter - ) - - -@wrap(PyyamlConverter) -def make_converter(*args: Any, **kwargs: Any) -> PyyamlConverter: - kwargs["unstruct_collection_overrides"] = { - FrozenSetSubscriptable: list, - **kwargs.get("unstruct_collection_overrides", {}), - } - res = PyyamlConverter(*args, **kwargs) - configure_converter(res) - - return res diff --git a/server/libs/cattrs/preconf/tomlkit.py b/server/libs/cattrs/preconf/tomlkit.py deleted file mode 100644 index 802df9b..0000000 --- a/server/libs/cattrs/preconf/tomlkit.py +++ /dev/null @@ -1,89 +0,0 @@ -"""Preconfigured converters for tomlkit.""" - -from base64 import b85decode, b85encode -from collections.abc import Set -from datetime import date, datetime -from enum import Enum -from operator import attrgetter -from typing import Any, TypeVar, Union - -from tomlkit import dumps, loads -from tomlkit.items import Float, Integer, String - -from .._compat import is_mapping, is_subclass -from ..converters import BaseConverter, Converter -from ..strategies import configure_union_passthrough -from . import validate_datetime, wrap - -__all__ = ["TomlkitConverter", "configure_converter", "make_converter"] - -T = TypeVar("T") -_enum_value_getter = attrgetter("_value_") - - -class TomlkitConverter(Converter): - def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str: - return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs) - - def loads(self, data: str, cl: type[T]) -> T: - return self.structure(loads(data), cl) - - -def configure_converter(converter: BaseConverter): - """ - Configure the converter for use with the tomlkit library. - - * bytes are serialized as base85 strings - * sets are serialized as lists - * tuples are serializas as lists - * mapping keys are coerced into strings when unstructuring - """ - converter.register_structure_hook(bytes, lambda v, _: b85decode(v)) - converter.register_unstructure_hook( - bytes, lambda v: (b85encode(v) if v else b"").decode("utf8") - ) - - def gen_unstructure_mapping(cl: Any, unstructure_to=None): - key_handler = str - args = getattr(cl, "__args__", None) - if args: - # Currently, tomlkit has inconsistent behavior on 3.11 - # so we paper over it here. - # https://github.com/sdispater/tomlkit/issues/237 - if is_subclass(args[0], str): - key_handler = _enum_value_getter if is_subclass(args[0], Enum) else None - elif is_subclass(args[0], bytes): - - def key_handler(k: bytes): - return b85encode(k).decode("utf8") - - return converter.gen_unstructure_mapping( - cl, unstructure_to=unstructure_to, key_handler=key_handler - ) - - converter._unstructure_func.register_func_list( - [(is_mapping, gen_unstructure_mapping, True)] - ) - - # datetime inherits from date, so identity unstructure hook used - # here to prevent the date unstructure hook running. - converter.register_unstructure_hook(datetime, lambda v: v) - converter.register_structure_hook(datetime, validate_datetime) - converter.register_unstructure_hook(date, lambda v: v.isoformat()) - converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v)) - configure_union_passthrough( - Union[str, String, bool, int, Integer, float, Float], converter - ) - - -@wrap(TomlkitConverter) -def make_converter(*args: Any, **kwargs: Any) -> TomlkitConverter: - kwargs["unstruct_collection_overrides"] = { - Set: list, - tuple: list, - **kwargs.get("unstruct_collection_overrides", {}), - } - res = TomlkitConverter(*args, **kwargs) - configure_converter(res) - - return res diff --git a/server/libs/cattrs/preconf/ujson.py b/server/libs/cattrs/preconf/ujson.py deleted file mode 100644 index 8f33061..0000000 --- a/server/libs/cattrs/preconf/ujson.py +++ /dev/null @@ -1,66 +0,0 @@ -"""Preconfigured converters for ujson.""" - -from base64 import b85decode, b85encode -from collections.abc import Set -from datetime import date, datetime -from typing import Any, AnyStr, TypeVar, Union - -from ujson import dumps, loads - -from ..converters import BaseConverter, Converter -from ..fns import identity -from ..literals import is_literal_containing_enums -from ..strategies import configure_union_passthrough -from . import is_primitive_enum, literals_with_enums_unstructure_factory, wrap - -__all__ = ["UjsonConverter", "configure_converter", "make_converter"] - -T = TypeVar("T") - - -class UjsonConverter(Converter): - def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str: - return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs) - - def loads(self, data: AnyStr, cl: type[T], **kwargs: Any) -> T: - return self.structure(loads(data, **kwargs), cl) - - -def configure_converter(converter: BaseConverter): - """ - Configure the converter for use with the ujson library. - - * bytes are serialized as base64 strings - * datetimes are serialized as ISO 8601 - * sets are serialized as lists - * string and int enums are passed through when unstructuring - - .. versionchanged:: 24.2.0 - Enums are left to the library to unstructure, speeding them up. - """ - converter.register_unstructure_hook( - bytes, lambda v: (b85encode(v) if v else b"").decode("utf8") - ) - converter.register_structure_hook(bytes, lambda v, _: b85decode(v)) - - converter.register_unstructure_hook(datetime, lambda v: v.isoformat()) - converter.register_structure_hook(datetime, lambda v, _: datetime.fromisoformat(v)) - converter.register_unstructure_hook(date, lambda v: v.isoformat()) - converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v)) - converter.register_unstructure_hook_func(is_primitive_enum, identity) - converter.register_unstructure_hook_factory( - is_literal_containing_enums, literals_with_enums_unstructure_factory - ) - configure_union_passthrough(Union[str, bool, int, float, None], converter) - - -@wrap(UjsonConverter) -def make_converter(*args: Any, **kwargs: Any) -> UjsonConverter: - kwargs["unstruct_collection_overrides"] = { - Set: list, - **kwargs.get("unstruct_collection_overrides", {}), - } - res = UjsonConverter(*args, **kwargs) - configure_converter(res) - - return res diff --git a/server/libs/cattrs/py.typed b/server/libs/cattrs/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/server/libs/cattrs/strategies/__init__.py b/server/libs/cattrs/strategies/__init__.py deleted file mode 100644 index 9caf073..0000000 --- a/server/libs/cattrs/strategies/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -"""High level strategies for converters.""" - -from ._class_methods import use_class_methods -from ._subclasses import include_subclasses -from ._unions import configure_tagged_union, configure_union_passthrough - -__all__ = [ - "configure_tagged_union", - "configure_union_passthrough", - "include_subclasses", - "use_class_methods", -] diff --git a/server/libs/cattrs/strategies/_class_methods.py b/server/libs/cattrs/strategies/_class_methods.py deleted file mode 100644 index 80a3c90..0000000 --- a/server/libs/cattrs/strategies/_class_methods.py +++ /dev/null @@ -1,64 +0,0 @@ -"""Strategy for using class-specific (un)structuring methods.""" - -from inspect import signature -from typing import Any, Callable, Optional, TypeVar - -from .. import BaseConverter - -T = TypeVar("T") - - -def use_class_methods( - converter: BaseConverter, - structure_method_name: Optional[str] = None, - unstructure_method_name: Optional[str] = None, -) -> None: - """ - Configure the converter such that dedicated methods are used for (un)structuring - the instance of a class if such methods are available. The default (un)structuring - will be applied if such an (un)structuring methods cannot be found. - - :param converter: The `Converter` on which this strategy is applied. You can use - :class:`cattrs.BaseConverter` or any other derived class. - :param structure_method_name: Optional string with the name of the class method - which should be used for structuring. If not provided, no class method will be - used for structuring. - :param unstructure_method_name: Optional string with the name of the class method - which should be used for unstructuring. If not provided, no class method will - be used for unstructuring. - - If you want to (un)structured nested objects, just append a converter parameter - to your (un)structuring methods and you will receive the converter there. - - .. versionadded:: 23.2.0 - """ - - if structure_method_name: - - def make_class_method_structure(cl: type[T]) -> Callable[[Any, type[T]], T]: - fn = getattr(cl, structure_method_name) - n_parameters = len(signature(fn).parameters) - if n_parameters == 1: - return lambda v, _: fn(v) - if n_parameters == 2: - return lambda v, _: fn(v, converter) - raise TypeError("Provide a class method with one or two arguments.") - - converter.register_structure_hook_factory( - lambda t: hasattr(t, structure_method_name), make_class_method_structure - ) - - if unstructure_method_name: - - def make_class_method_unstructure(cl: type[T]) -> Callable[[T], T]: - fn = getattr(cl, unstructure_method_name) - n_parameters = len(signature(fn).parameters) - if n_parameters == 1: - return fn - if n_parameters == 2: - return lambda self_: fn(self_, converter) - raise TypeError("Provide a method with no or one argument.") - - converter.register_unstructure_hook_factory( - lambda t: hasattr(t, unstructure_method_name), make_class_method_unstructure - ) diff --git a/server/libs/cattrs/strategies/_subclasses.py b/server/libs/cattrs/strategies/_subclasses.py deleted file mode 100644 index 483a226..0000000 --- a/server/libs/cattrs/strategies/_subclasses.py +++ /dev/null @@ -1,243 +0,0 @@ -"""Strategies for customizing subclass behaviors.""" - -from __future__ import annotations - -import typing -from gc import collect -from typing import Any, Callable, TypeVar, Union - -from ..converters import BaseConverter -from ..gen import AttributeOverride, make_dict_structure_fn, make_dict_unstructure_fn -from ..gen._consts import already_generating - - -def _make_subclasses_tree(cl: type) -> list[type]: - # get class origin for accessing subclasses (see #648 for more info) - cls_origin = typing.get_origin(cl) or cl - return [cl] + [ - sscl - for scl in cls_origin.__subclasses__() - for sscl in _make_subclasses_tree(scl) - ] - - -def _has_subclasses(cl: type, given_subclasses: tuple[type, ...]) -> bool: - """Whether the given class has subclasses from `given_subclasses`.""" - actual = set(cl.__subclasses__()) - given = set(given_subclasses) - return bool(actual & given) - - -def _get_union_type(cl: type, given_subclasses_tree: tuple[type]) -> type | None: - actual_subclass_tree = tuple(_make_subclasses_tree(cl)) - class_tree = tuple(set(actual_subclass_tree) & set(given_subclasses_tree)) - return Union[class_tree] if len(class_tree) >= 2 else None - - -C = TypeVar("C", bound=BaseConverter) - - -def include_subclasses( - cl: type, - converter: C, - subclasses: tuple[type, ...] | None = None, - union_strategy: Callable[[Any, C], Any] | None = None, - overrides: dict[str, AttributeOverride] | None = None, -) -> None: - """ - Configure the converter so that the attrs/dataclass `cl` is un/structured as if it - was a union of itself and all its subclasses that are defined at the time when this - strategy is applied. - - :param cl: A base `attrs` or `dataclass` class. - :param converter: The `Converter` on which this strategy is applied. Do note that - the strategy does not work for a :class:`cattrs.BaseConverter`. - :param subclasses: A tuple of sublcasses whose ancestor is `cl`. If left as `None`, - subclasses are detected using recursively the `__subclasses__` method of `cl` - and its descendents. - :param union_strategy: A callable of two arguments passed by position - (`subclass_union`, `converter`) that defines the union strategy to use to - disambiguate the subclasses union. If `None` (the default), the automatic unique - field disambiguation is used which means that every single subclass - participating in the union must have an attribute name that does not exist in - any other sibling class. - :param overrides: a mapping of `cl` attribute names to overrides (instantiated with - :func:`cattrs.gen.override`) to customize un/structuring. - - .. versionadded:: 23.1.0 - .. versionchanged:: 24.1.0 - When overrides are not provided, hooks for individual classes are retrieved from - the converter instead of generated with no overrides, using converter defaults. - """ - # Due to https://github.com/python-attrs/attrs/issues/1047 - collect() - if subclasses is not None: - parent_subclass_tree = (cl, *subclasses) - else: - parent_subclass_tree = tuple(_make_subclasses_tree(cl)) - - if union_strategy is None: - _include_subclasses_without_union_strategy( - cl, converter, parent_subclass_tree, overrides - ) - else: - _include_subclasses_with_union_strategy( - converter, parent_subclass_tree, union_strategy, overrides - ) - - -def _include_subclasses_without_union_strategy( - cl, - converter: BaseConverter, - parent_subclass_tree: tuple[type, ...], - overrides: dict[str, AttributeOverride] | None, -): - # The iteration approach is required if subclasses are more than one level deep: - for cl in parent_subclass_tree: - # We re-create a reduced union type to handle the following case: - # - # converter.structure(d, as=Child) - # - # In the above, the `as=Child` argument will be transformed to a union type of - # itself and its subtypes, that way we guarantee that the returned object will - # not be the parent. - subclass_union = _get_union_type(cl, parent_subclass_tree) - - def cls_is_cl(cls, _cl=cl): - return cls is _cl - - if overrides is not None: - base_struct_hook = make_dict_structure_fn(cl, converter, **overrides) - base_unstruct_hook = make_dict_unstructure_fn(cl, converter, **overrides) - else: - base_struct_hook = converter.get_structure_hook(cl) - base_unstruct_hook = converter.get_unstructure_hook(cl) - - if subclass_union is None: - - def struct_hook(val: dict, _, _cl=cl, _base_hook=base_struct_hook) -> cl: - return _base_hook(val, _cl) - - else: - dis_fn = converter._get_dis_func(subclass_union, overrides=overrides) - - def struct_hook( - val: dict, - _, - _c=converter, - _cl=cl, - _base_hook=base_struct_hook, - _dis_fn=dis_fn, - ) -> cl: - """ - If val is disambiguated to the class `cl`, use its base hook. - - If val is disambiguated to a subclass, dispatch on its exact runtime - type. - """ - dis_cl = _dis_fn(val) - if dis_cl is _cl: - return _base_hook(val, _cl) - return _c.structure(val, dis_cl) - - def unstruct_hook( - val: parent_subclass_tree[0], - _c=converter, - _cl=cl, - _base_hook=base_unstruct_hook, - ) -> dict: - """ - If val is an instance of the class `cl`, use the hook. - - If val is an instance of a subclass, dispatch on its exact runtime type. - """ - if val.__class__ is _cl: - return _base_hook(val) - return _c.unstructure(val, unstructure_as=val.__class__) - - # This needs to use function dispatch, using singledispatch will again - # match A and all subclasses, which is not what we want. - converter.register_structure_hook_func(cls_is_cl, struct_hook) - converter.register_unstructure_hook_func(cls_is_cl, unstruct_hook) - - -def _include_subclasses_with_union_strategy( - converter: C, - union_classes: tuple[type, ...], - union_strategy: Callable[[Any, C], Any], - overrides: dict[str, AttributeOverride] | None, -): - """ - This function is tricky because we're dealing with what is essentially a circular - reference. - - We need to generate a structure hook for a class that is both: - * specific for that particular class and its own fields - * but should handle specific functions for all its descendants too - - Hence the dance with registering below. - """ - - parent_classes = [cl for cl in union_classes if _has_subclasses(cl, union_classes)] - if not parent_classes: - return - - original_unstruct_hooks = {} - original_struct_hooks = {} - for cl in union_classes: - # In the first pass, every class gets its own unstructure function according to - # the overrides. - # We just generate the hooks, and do not register them. This allows us to - # manipulate the _already_generating set to force runtime dispatch. - already_generating.working_set = set(union_classes) - {cl} - try: - if overrides is not None: - unstruct_hook = make_dict_unstructure_fn(cl, converter, **overrides) - struct_hook = make_dict_structure_fn(cl, converter, **overrides) - else: - unstruct_hook = converter.get_unstructure_hook(cl, cache_result=False) - struct_hook = converter.get_structure_hook(cl, cache_result=False) - finally: - already_generating.working_set = set() - original_unstruct_hooks[cl] = unstruct_hook - original_struct_hooks[cl] = struct_hook - - # Now that's done, we can register all the hooks and generate the - # union handler. The union handler needs them. - final_union = Union[union_classes] # type: ignore - - for cl, hook in original_unstruct_hooks.items(): - - def cls_is_cl(cls, _cl=cl): - return cls is _cl - - converter.register_unstructure_hook_func(cls_is_cl, hook) - - for cl, hook in original_struct_hooks.items(): - - def cls_is_cl(cls, _cl=cl): - return cls is _cl - - converter.register_structure_hook_func(cls_is_cl, hook) - - union_strategy(final_union, converter) - unstruct_hook = converter.get_unstructure_hook(final_union) - struct_hook = converter.get_structure_hook(final_union) - - for cl in union_classes: - # In the second pass, we overwrite the hooks with the union hook. - - def cls_is_cl(cls, _cl=cl): - return cls is _cl - - converter.register_unstructure_hook_func(cls_is_cl, unstruct_hook) - subclasses = tuple([c for c in union_classes if issubclass(c, cl)]) - if len(subclasses) > 1: - u = Union[subclasses] # type: ignore - union_strategy(u, converter) - struct_hook = converter.get_structure_hook(u) - - def sh(payload: dict, _, _u=u, _s=struct_hook) -> cl: - return _s(payload, _u) - - converter.register_structure_hook_func(cls_is_cl, sh) diff --git a/server/libs/cattrs/strategies/_unions.py b/server/libs/cattrs/strategies/_unions.py deleted file mode 100644 index 57e132d..0000000 --- a/server/libs/cattrs/strategies/_unions.py +++ /dev/null @@ -1,264 +0,0 @@ -from collections import defaultdict -from typing import Any, Callable, Union - -from attrs import NOTHING, NothingType - -from .. import BaseConverter -from .._compat import get_newtype_base, is_literal, is_subclass, is_union_type -from ..typealiases import is_type_alias - -__all__ = [ - "configure_tagged_union", - "configure_union_passthrough", - "default_tag_generator", -] - - -def default_tag_generator(typ: type) -> str: - """Return the class name.""" - return typ.__name__ - - -def configure_tagged_union( - union: Any, - converter: BaseConverter, - tag_generator: Callable[[type], str] = default_tag_generator, - tag_name: str = "_type", - default: Union[type, NothingType] = NOTHING, -) -> None: - """ - Configure the converter so that `union` (which should be a union, or a type alias - of one) is un/structured with the help of an additional piece of data in the - unstructured payload, the tag. - - :param converter: The converter to apply the strategy to. - :param tag_generator: A `tag_generator` function is used to map each - member of the union to a tag, which is then included in the - unstructured payload. The default tag generator returns the name of - the class. - :param tag_name: The key under which the tag will be set in the - unstructured payload. By default, `'_type'`. - :param default: An optional class to be used if the tag information - is not present when structuring. - - The tagged union strategy currently only works with the dict - un/structuring base strategy. - - .. versionadded:: 23.1.0 - - .. versionchanged:: 25.1 - Type aliases of unions are now also supported. - """ - if is_type_alias(union): - union = union.__value__ - args = union.__args__ - tag_to_hook = {} - exact_cl_unstruct_hooks = {} - for cl in args: - tag = tag_generator(cl) - struct_handler = converter.get_structure_hook(cl) - unstruct_handler = converter.get_unstructure_hook(cl) - - def structure_union_member(val: dict, _cl=cl, _h=struct_handler) -> cl: - return _h(val, _cl) - - def unstructure_union_member(val: union, _h=unstruct_handler) -> dict: - return _h(val) - - tag_to_hook[tag] = structure_union_member - exact_cl_unstruct_hooks[cl] = unstructure_union_member - - cl_to_tag = {cl: tag_generator(cl) for cl in args} - - if default is not NOTHING: - default_handler = converter.get_structure_hook(default) - - def structure_default(val: dict, _cl=default, _h=default_handler): - return _h(val, _cl) - - tag_to_hook = defaultdict(lambda: structure_default, tag_to_hook) - cl_to_tag = defaultdict(lambda: default, cl_to_tag) - - def unstructure_tagged_union( - val: union, - _exact_cl_unstruct_hooks=exact_cl_unstruct_hooks, - _cl_to_tag=cl_to_tag, - _tag_name=tag_name, - ) -> dict: - res = _exact_cl_unstruct_hooks[val.__class__](val) - res[_tag_name] = _cl_to_tag[val.__class__] - return res - - if default is NOTHING: - if getattr(converter, "forbid_extra_keys", False): - - def structure_tagged_union( - val: dict, _, _tag_to_cl=tag_to_hook, _tag_name=tag_name - ) -> union: - val = val.copy() - return _tag_to_cl[val.pop(_tag_name)](val) - - else: - - def structure_tagged_union( - val: dict, _, _tag_to_cl=tag_to_hook, _tag_name=tag_name - ) -> union: - return _tag_to_cl[val[_tag_name]](val) - - else: - if getattr(converter, "forbid_extra_keys", False): - - def structure_tagged_union( - val: dict, - _, - _tag_to_hook=tag_to_hook, - _tag_name=tag_name, - _dh=default_handler, - _default=default, - ) -> union: - if _tag_name in val: - val = val.copy() - return _tag_to_hook[val.pop(_tag_name)](val) - return _dh(val, _default) - - else: - - def structure_tagged_union( - val: dict, - _, - _tag_to_hook=tag_to_hook, - _tag_name=tag_name, - _dh=default_handler, - _default=default, - ) -> union: - if _tag_name in val: - return _tag_to_hook[val[_tag_name]](val) - return _dh(val, _default) - - converter.register_unstructure_hook(union, unstructure_tagged_union) - converter.register_structure_hook(union, structure_tagged_union) - - -def configure_union_passthrough(union: Any, converter: BaseConverter) -> None: - """ - Configure the converter to support validating and passing through unions of the - provided types and their subsets. - - For example, all mature JSON libraries natively support producing unions of ints, - floats, Nones, and strings. Using this strategy, a converter can be configured - to efficiently validate and pass through unions containing these types. - - The most important point is that another library (in this example the JSON - library) handles producing the union, and the converter is configured to just - validate it. - - Literals of provided types are also supported, and are checked by value. - - NewTypes of provided types are also supported. - - The strategy is designed to be O(1) in execution time, and independent of the - ordering of types in the union. - - If the union contains a class and one or more of its subclasses, the subclasses - will also be included when validating the superclass. - - .. versionadded:: 23.2.0 - """ - args = set(union.__args__) - - def make_structure_native_union(exact_type: Any) -> Callable: - # `exact_type` is likely to be a subset of the entire configured union (`args`). - literal_values = { - v for t in exact_type.__args__ if is_literal(t) for v in t.__args__ - } - - # We have no idea what the actual type of `val` will be, so we can't - # use it blindly with an `in` check since it might not be hashable. - # So we do an additional check when handling literals. - # Note: do no use `literal_values` here, since {0, False} gets reduced to {0} - literal_classes = { - v.__class__ - for t in exact_type.__args__ - if is_literal(t) - for v in t.__args__ - } - - non_literal_classes = { - get_newtype_base(t) or t - for t in exact_type.__args__ - if not is_literal(t) and ((get_newtype_base(t) or t) in args) - } - - # We augment the set of allowed classes with any configured subclasses of - # the exact subclasses. - non_literal_classes |= { - a for a in args if any(is_subclass(a, c) for c in non_literal_classes) - } - - # We check for spillover - union types not handled by the strategy. - # If spillover exists and we fail to validate our types, we call - # further into the converter with the rest. - spillover = { - a - for a in exact_type.__args__ - if (get_newtype_base(a) or a) not in non_literal_classes - and not is_literal(a) - } - - if spillover: - spillover_type = ( - Union[tuple(spillover)] if len(spillover) > 1 else next(iter(spillover)) - ) - - def structure_native_union( - val: Any, - _: Any, - classes=non_literal_classes, - vals=literal_values, - converter=converter, - spillover=spillover_type, - ) -> exact_type: - if val.__class__ in literal_classes and val in vals: - return val - if val.__class__ in classes: - return val - return converter.structure(val, spillover) - - else: - - def structure_native_union( - val: Any, _: Any, classes=non_literal_classes, vals=literal_values - ) -> exact_type: - if val.__class__ in literal_classes and val in vals: - return val - if val.__class__ in classes: - return val - raise TypeError(f"{val} ({val.__class__}) not part of {_}") - - return structure_native_union - - def contains_native_union(exact_type: Any) -> bool: - """Can we handle this type?""" - if is_union_type(exact_type): - type_args = set(exact_type.__args__) - # We special case optionals, since they are very common - # and are handled a little more efficiently by default. - if len(type_args) == 2 and type(None) in type_args: - return False - - literal_classes = { - lit_arg.__class__ - for t in type_args - if is_literal(t) - for lit_arg in t.__args__ - } - non_literal_types = { - get_newtype_base(t) or t for t in type_args if not is_literal(t) - } - - return (literal_classes | non_literal_types) & args - return False - - converter.register_structure_hook_factory( - contains_native_union, make_structure_native_union - ) diff --git a/server/libs/cattrs/typealiases.py b/server/libs/cattrs/typealiases.py deleted file mode 100644 index d3a20c4..0000000 --- a/server/libs/cattrs/typealiases.py +++ /dev/null @@ -1,57 +0,0 @@ -"""Utilities for type aliases.""" - -from __future__ import annotations - -import sys -from typing import TYPE_CHECKING, Any - -from ._compat import is_generic -from ._generics import deep_copy_with -from .dispatch import StructureHook -from .gen._generics import generate_mapping - -if TYPE_CHECKING: - from .converters import BaseConverter - -__all__ = ["get_type_alias_base", "is_type_alias", "type_alias_structure_factory"] - -if sys.version_info >= (3, 12): - from types import GenericAlias - from typing import TypeAliasType - - def is_type_alias(type: Any) -> bool: - """Is this a PEP 695 type alias?""" - return isinstance( - type.__origin__ if type.__class__ is GenericAlias else type, TypeAliasType - ) - -else: - - def is_type_alias(type: Any) -> bool: - """Is this a PEP 695 type alias?""" - return False - - -def get_type_alias_base(type: Any) -> Any: - """ - What is this a type alias of? - - Works only on 3.12+. - """ - return type.__value__ - - -def type_alias_structure_factory(type: Any, converter: BaseConverter) -> StructureHook: - base = get_type_alias_base(type) - if is_generic(type): - mapping = generate_mapping(type) - if base.__name__ in mapping: - # Probably just type T = T - base = mapping[base.__name__] - else: - base = deep_copy_with(base, mapping) - res = converter.get_structure_hook(base) - if res == converter._structure_call: - # we need to replace the type arg of `structure_call` - return lambda v, _, __base=base: __base(v) - return lambda v, _, __base=base: res(v, __base) diff --git a/server/libs/cattrs/types.py b/server/libs/cattrs/types.py deleted file mode 100644 index a864cb9..0000000 --- a/server/libs/cattrs/types.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import Protocol, TypeVar - -__all__ = ["SimpleStructureHook"] - -In = TypeVar("In") -T = TypeVar("T") - - -class SimpleStructureHook(Protocol[In, T]): - """A structure hook with an optional (ignored) second argument.""" - - def __call__(self, _: In, /, cl=...) -> T: ... diff --git a/server/libs/cattrs/v.py b/server/libs/cattrs/v.py deleted file mode 100644 index 134c990..0000000 --- a/server/libs/cattrs/v.py +++ /dev/null @@ -1,106 +0,0 @@ -"""Cattrs validation.""" - -from typing import Callable, Union - -from .errors import ( - ClassValidationError, - ForbiddenExtraKeysError, - IterableValidationError, -) - -__all__ = ["format_exception", "transform_error"] - - -def format_exception(exc: BaseException, type: Union[type, None]) -> str: - """The default exception formatter, handling the most common exceptions. - - The following exceptions are handled specially: - - * `KeyErrors` (`required field missing`) - * `ValueErrors` (`invalid value for type, expected ` or just `invalid value`) - * `TypeErrors` (`invalid value for type, expected ` and a couple special - cases for iterables) - * `cattrs.ForbiddenExtraKeysError` - * some `AttributeErrors` (special cased for structing mappings) - """ - if isinstance(exc, KeyError): - res = "required field missing" - elif isinstance(exc, ValueError): - if type is not None: - tn = type.__name__ if hasattr(type, "__name__") else repr(type) - res = f"invalid value for type, expected {tn}" - else: - res = "invalid value" - elif isinstance(exc, TypeError): - if type is None: - if exc.args[0].endswith("object is not iterable"): - res = "invalid value for type, expected an iterable" - else: - res = f"invalid type ({exc})" - else: - tn = type.__name__ if hasattr(type, "__name__") else repr(type) - res = f"invalid value for type, expected {tn}" - elif isinstance(exc, ForbiddenExtraKeysError): - res = f"extra fields found ({', '.join(exc.extra_fields)})" - elif isinstance(exc, AttributeError) and exc.args[0].endswith( - "object has no attribute 'items'" - ): - # This was supposed to be a mapping (and have .items()) but it something else. - res = "expected a mapping" - else: - res = f"unknown error ({exc})" - - return res - - -def transform_error( - exc: Union[ClassValidationError, IterableValidationError, BaseException], - path: str = "$", - format_exception: Callable[ - [BaseException, Union[type, None]], str - ] = format_exception, -) -> list[str]: - """Transform an exception into a list of error messages. - - To get detailed error messages, the exception should be produced by a converter - with `detailed_validation` set. - - By default, the error messages are in the form of `{description} @ {path}`. - - While traversing the exception and subexceptions, the path is formed: - - * by appending `.{field_name}` for fields in classes - * by appending `[{int}]` for indices in iterables, like lists - * by appending `[{str}]` for keys in mappings, like dictionaries - - :param exc: The exception to transform into error messages. - :param path: The root path to use. - :param format_exception: A callable to use to transform `Exceptions` into - string descriptions of errors. - - .. versionadded:: 23.1.0 - """ - errors = [] - if isinstance(exc, IterableValidationError): - with_notes, without = exc.group_exceptions() - for exc, note in with_notes: - p = f"{path}[{note.index!r}]" - if isinstance(exc, (ClassValidationError, IterableValidationError)): - errors.extend(transform_error(exc, p, format_exception)) - else: - errors.append(f"{format_exception(exc, note.type)} @ {p}") - for exc in without: - errors.append(f"{format_exception(exc, None)} @ {path}") - elif isinstance(exc, ClassValidationError): - with_notes, without = exc.group_exceptions() - for exc, note in with_notes: - p = f"{path}.{note.name}" - if isinstance(exc, (ClassValidationError, IterableValidationError)): - errors.extend(transform_error(exc, p, format_exception)) - else: - errors.append(f"{format_exception(exc, note.type)} @ {p}") - for exc in without: - errors.append(f"{format_exception(exc, None)} @ {path}") - else: - errors.append(f"{format_exception(exc, None)} @ {path}") - return errors diff --git a/server/libs/importlib_metadata-6.8.0.dist-info/INSTALLER b/server/libs/importlib_metadata-6.8.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/server/libs/importlib_metadata-6.8.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/server/libs/importlib_metadata-6.8.0.dist-info/LICENSE b/server/libs/importlib_metadata-6.8.0.dist-info/LICENSE deleted file mode 100644 index d645695..0000000 --- a/server/libs/importlib_metadata-6.8.0.dist-info/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/server/libs/importlib_metadata-6.8.0.dist-info/METADATA b/server/libs/importlib_metadata-6.8.0.dist-info/METADATA deleted file mode 100644 index 639bbea..0000000 --- a/server/libs/importlib_metadata-6.8.0.dist-info/METADATA +++ /dev/null @@ -1,138 +0,0 @@ -Metadata-Version: 2.1 -Name: importlib-metadata -Version: 6.8.0 -Summary: Read metadata from Python packages -Home-page: https://github.com/python/importlib_metadata -Author: Jason R. Coombs -Author-email: jaraco@jaraco.com -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Requires-Python: >=3.8 -License-File: LICENSE -Requires-Dist: zipp (>=0.5) -Requires-Dist: typing-extensions (>=3.6.4) ; python_version < "3.8" -Provides-Extra: docs -Requires-Dist: sphinx (>=3.5) ; extra == 'docs' -Requires-Dist: jaraco.packaging (>=9) ; extra == 'docs' -Requires-Dist: rst.linker (>=1.9) ; extra == 'docs' -Requires-Dist: furo ; extra == 'docs' -Requires-Dist: sphinx-lint ; extra == 'docs' -Requires-Dist: jaraco.tidelift (>=1.4) ; extra == 'docs' -Provides-Extra: perf -Requires-Dist: ipython ; extra == 'perf' -Provides-Extra: testing -Requires-Dist: pytest (>=6) ; extra == 'testing' -Requires-Dist: pytest-checkdocs (>=2.4) ; extra == 'testing' -Requires-Dist: pytest-cov ; extra == 'testing' -Requires-Dist: pytest-enabler (>=2.2) ; extra == 'testing' -Requires-Dist: pytest-ruff ; extra == 'testing' -Requires-Dist: packaging ; extra == 'testing' -Requires-Dist: pyfakefs ; extra == 'testing' -Requires-Dist: flufl.flake8 ; extra == 'testing' -Requires-Dist: pytest-perf (>=0.9.2) ; extra == 'testing' -Requires-Dist: pytest-black (>=0.3.7) ; (platform_python_implementation != "PyPy") and extra == 'testing' -Requires-Dist: pytest-mypy (>=0.9.1) ; (platform_python_implementation != "PyPy") and extra == 'testing' -Requires-Dist: importlib-resources (>=1.3) ; (python_version < "3.9") and extra == 'testing' - -.. image:: https://img.shields.io/pypi/v/importlib_metadata.svg - :target: https://pypi.org/project/importlib_metadata - -.. image:: https://img.shields.io/pypi/pyversions/importlib_metadata.svg - -.. image:: https://github.com/python/importlib_metadata/workflows/tests/badge.svg - :target: https://github.com/python/importlib_metadata/actions?query=workflow%3A%22tests%22 - :alt: tests - -.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json - :target: https://github.com/astral-sh/ruff - :alt: Ruff - -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code style: Black - -.. image:: https://readthedocs.org/projects/importlib-metadata/badge/?version=latest - :target: https://importlib-metadata.readthedocs.io/en/latest/?badge=latest - -.. image:: https://img.shields.io/badge/skeleton-2023-informational - :target: https://blog.jaraco.com/skeleton - -.. image:: https://tidelift.com/badges/package/pypi/importlib-metadata - :target: https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=readme - -Library to access the metadata for a Python package. - -This package supplies third-party access to the functionality of -`importlib.metadata `_ -including improvements added to subsequent Python versions. - - -Compatibility -============= - -New features are introduced in this third-party library and later merged -into CPython. The following table indicates which versions of this library -were contributed to different versions in the standard library: - -.. list-table:: - :header-rows: 1 - - * - importlib_metadata - - stdlib - * - 6.5 - - 3.12 - * - 4.13 - - 3.11 - * - 4.6 - - 3.10 - * - 1.4 - - 3.8 - - -Usage -===== - -See the `online documentation `_ -for usage details. - -`Finder authors -`_ can -also add support for custom package installers. See the above documentation -for details. - - -Caveats -======= - -This project primarily supports third-party packages installed by PyPA -tools (or other conforming packages). It does not support: - -- Packages in the stdlib. -- Packages installed without metadata. - -Project details -=============== - - * Project home: https://github.com/python/importlib_metadata - * Report bugs at: https://github.com/python/importlib_metadata/issues - * Code hosting: https://github.com/python/importlib_metadata - * Documentation: https://importlib-metadata.readthedocs.io/ - -For Enterprise -============== - -Available as part of the Tidelift Subscription. - -This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. - -`Learn more `_. - -Security Contact -================ - -To report a security vulnerability, please use the -`Tidelift security contact `_. -Tidelift will coordinate the fix and disclosure. diff --git a/server/libs/importlib_metadata-6.8.0.dist-info/RECORD b/server/libs/importlib_metadata-6.8.0.dist-info/RECORD deleted file mode 100644 index 9e6c0a6..0000000 --- a/server/libs/importlib_metadata-6.8.0.dist-info/RECORD +++ /dev/null @@ -1,26 +0,0 @@ -importlib_metadata-6.8.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -importlib_metadata-6.8.0.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358 -importlib_metadata-6.8.0.dist-info/METADATA,sha256=X79qGRh7gqvuaL_utK5X-MnwHJuIWke0e3eAx0IiLhc,5067 -importlib_metadata-6.8.0.dist-info/RECORD,, -importlib_metadata-6.8.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -importlib_metadata-6.8.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92 -importlib_metadata-6.8.0.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19 -importlib_metadata/__init__.py,sha256=EiH0qTKP_6oa6pRGJgPrq0kvjnL3hJ18BJH8VaAYSBA,30749 -importlib_metadata/__pycache__/__init__.cpython-311.pyc,, -importlib_metadata/__pycache__/_adapters.cpython-311.pyc,, -importlib_metadata/__pycache__/_collections.cpython-311.pyc,, -importlib_metadata/__pycache__/_compat.cpython-311.pyc,, -importlib_metadata/__pycache__/_functools.cpython-311.pyc,, -importlib_metadata/__pycache__/_itertools.cpython-311.pyc,, -importlib_metadata/__pycache__/_meta.cpython-311.pyc,, -importlib_metadata/__pycache__/_py39compat.cpython-311.pyc,, -importlib_metadata/__pycache__/_text.cpython-311.pyc,, -importlib_metadata/_adapters.py,sha256=i8S6Ib1OQjcILA-l4gkzktMZe18TaeUNI49PLRp6OBU,2454 -importlib_metadata/_collections.py,sha256=CJ0OTCHIjWA0ZIVS4voORAsn2R4R2cQBEtPsZEJpASY,743 -importlib_metadata/_compat.py,sha256=zhjcWMfA9SNExFVVVBozOYbuiok0A4tdMsNk9ZDZi-A,1554 -importlib_metadata/_functools.py,sha256=PsY2-4rrKX4RVeRC1oGp1lB1pmC9eKN88_f-bD9uOoA,2895 -importlib_metadata/_itertools.py,sha256=cvr_2v8BRbxcIl5x5ldfqdHjhI8Yi8s8yk50G_nm6jQ,2068 -importlib_metadata/_meta.py,sha256=kypMW_-xSStooSm0WpJc6eupjT-Ipc2ZBIl23PyC3No,1613 -importlib_metadata/_py39compat.py,sha256=2Tk5twb_VgLCY-1NEAQjdZp_S9OFMC-pUzP2isuaPsQ,1098 -importlib_metadata/_text.py,sha256=HCsFksZpJLeTP3NEk_ngrAeXVRRtTrtyh9eOABoRP4A,2166 -importlib_metadata/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/server/libs/importlib_metadata-6.8.0.dist-info/REQUESTED b/server/libs/importlib_metadata-6.8.0.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/server/libs/importlib_metadata-6.8.0.dist-info/WHEEL b/server/libs/importlib_metadata-6.8.0.dist-info/WHEEL deleted file mode 100644 index 1f37c02..0000000 --- a/server/libs/importlib_metadata-6.8.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.40.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/server/libs/importlib_metadata-6.8.0.dist-info/top_level.txt b/server/libs/importlib_metadata-6.8.0.dist-info/top_level.txt deleted file mode 100644 index bbb0754..0000000 --- a/server/libs/importlib_metadata-6.8.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -importlib_metadata diff --git a/server/libs/importlib_metadata/__init__.py b/server/libs/importlib_metadata/__init__.py deleted file mode 100644 index 6ba414e..0000000 --- a/server/libs/importlib_metadata/__init__.py +++ /dev/null @@ -1,1015 +0,0 @@ -import os -import re -import abc -import csv -import sys -import zipp -import email -import inspect -import pathlib -import operator -import textwrap -import warnings -import functools -import itertools -import posixpath -import collections - -from . import _adapters, _meta, _py39compat -from ._collections import FreezableDefaultDict, Pair -from ._compat import ( - NullFinder, - StrPath, - install, - pypy_partial, -) -from ._functools import method_cache, pass_none -from ._itertools import always_iterable, unique_everseen -from ._meta import PackageMetadata, SimplePath - -from contextlib import suppress -from importlib import import_module -from importlib.abc import MetaPathFinder -from itertools import starmap -from typing import Iterable, List, Mapping, Optional, Set, cast - -__all__ = [ - 'Distribution', - 'DistributionFinder', - 'PackageMetadata', - 'PackageNotFoundError', - 'distribution', - 'distributions', - 'entry_points', - 'files', - 'metadata', - 'packages_distributions', - 'requires', - 'version', -] - - -class PackageNotFoundError(ModuleNotFoundError): - """The package was not found.""" - - def __str__(self) -> str: - return f"No package metadata was found for {self.name}" - - @property - def name(self) -> str: # type: ignore[override] - (name,) = self.args - return name - - -class Sectioned: - """ - A simple entry point config parser for performance - - >>> for item in Sectioned.read(Sectioned._sample): - ... print(item) - Pair(name='sec1', value='# comments ignored') - Pair(name='sec1', value='a = 1') - Pair(name='sec1', value='b = 2') - Pair(name='sec2', value='a = 2') - - >>> res = Sectioned.section_pairs(Sectioned._sample) - >>> item = next(res) - >>> item.name - 'sec1' - >>> item.value - Pair(name='a', value='1') - >>> item = next(res) - >>> item.value - Pair(name='b', value='2') - >>> item = next(res) - >>> item.name - 'sec2' - >>> item.value - Pair(name='a', value='2') - >>> list(res) - [] - """ - - _sample = textwrap.dedent( - """ - [sec1] - # comments ignored - a = 1 - b = 2 - - [sec2] - a = 2 - """ - ).lstrip() - - @classmethod - def section_pairs(cls, text): - return ( - section._replace(value=Pair.parse(section.value)) - for section in cls.read(text, filter_=cls.valid) - if section.name is not None - ) - - @staticmethod - def read(text, filter_=None): - lines = filter(filter_, map(str.strip, text.splitlines())) - name = None - for value in lines: - section_match = value.startswith('[') and value.endswith(']') - if section_match: - name = value.strip('[]') - continue - yield Pair(name, value) - - @staticmethod - def valid(line: str): - return line and not line.startswith('#') - - -class DeprecatedTuple: - """ - Provide subscript item access for backward compatibility. - - >>> recwarn = getfixture('recwarn') - >>> ep = EntryPoint(name='name', value='value', group='group') - >>> ep[:] - ('name', 'value', 'group') - >>> ep[0] - 'name' - >>> len(recwarn) - 1 - """ - - # Do not remove prior to 2023-05-01 or Python 3.13 - _warn = functools.partial( - warnings.warn, - "EntryPoint tuple interface is deprecated. Access members by name.", - DeprecationWarning, - stacklevel=pypy_partial(2), - ) - - def __getitem__(self, item): - self._warn() - return self._key()[item] - - -class EntryPoint(DeprecatedTuple): - """An entry point as defined by Python packaging conventions. - - See `the packaging docs on entry points - `_ - for more information. - - >>> ep = EntryPoint( - ... name=None, group=None, value='package.module:attr [extra1, extra2]') - >>> ep.module - 'package.module' - >>> ep.attr - 'attr' - >>> ep.extras - ['extra1', 'extra2'] - """ - - pattern = re.compile( - r'(?P[\w.]+)\s*' - r'(:\s*(?P[\w.]+)\s*)?' - r'((?P\[.*\])\s*)?$' - ) - """ - A regular expression describing the syntax for an entry point, - which might look like: - - - module - - package.module - - package.module:attribute - - package.module:object.attribute - - package.module:attr [extra1, extra2] - - Other combinations are possible as well. - - The expression is lenient about whitespace around the ':', - following the attr, and following any extras. - """ - - name: str - value: str - group: str - - dist: Optional['Distribution'] = None - - def __init__(self, name: str, value: str, group: str) -> None: - vars(self).update(name=name, value=value, group=group) - - def load(self): - """Load the entry point from its definition. If only a module - is indicated by the value, return that module. Otherwise, - return the named object. - """ - match = self.pattern.match(self.value) - module = import_module(match.group('module')) - attrs = filter(None, (match.group('attr') or '').split('.')) - return functools.reduce(getattr, attrs, module) - - @property - def module(self) -> str: - match = self.pattern.match(self.value) - assert match is not None - return match.group('module') - - @property - def attr(self) -> str: - match = self.pattern.match(self.value) - assert match is not None - return match.group('attr') - - @property - def extras(self) -> List[str]: - match = self.pattern.match(self.value) - assert match is not None - return re.findall(r'\w+', match.group('extras') or '') - - def _for(self, dist): - vars(self).update(dist=dist) - return self - - def matches(self, **params): - """ - EntryPoint matches the given parameters. - - >>> ep = EntryPoint(group='foo', name='bar', value='bing:bong [extra1, extra2]') - >>> ep.matches(group='foo') - True - >>> ep.matches(name='bar', value='bing:bong [extra1, extra2]') - True - >>> ep.matches(group='foo', name='other') - False - >>> ep.matches() - True - >>> ep.matches(extras=['extra1', 'extra2']) - True - >>> ep.matches(module='bing') - True - >>> ep.matches(attr='bong') - True - """ - attrs = (getattr(self, param) for param in params) - return all(map(operator.eq, params.values(), attrs)) - - def _key(self): - return self.name, self.value, self.group - - def __lt__(self, other): - return self._key() < other._key() - - def __eq__(self, other): - return self._key() == other._key() - - def __setattr__(self, name, value): - raise AttributeError("EntryPoint objects are immutable.") - - def __repr__(self): - return ( - f'EntryPoint(name={self.name!r}, value={self.value!r}, ' - f'group={self.group!r})' - ) - - def __hash__(self) -> int: - return hash(self._key()) - - -class EntryPoints(tuple): - """ - An immutable collection of selectable EntryPoint objects. - """ - - __slots__ = () - - def __getitem__(self, name: str) -> EntryPoint: # type: ignore[override] - """ - Get the EntryPoint in self matching name. - """ - try: - return next(iter(self.select(name=name))) - except StopIteration: - raise KeyError(name) - - def select(self, **params): - """ - Select entry points from self that match the - given parameters (typically group and/or name). - """ - return EntryPoints(ep for ep in self if _py39compat.ep_matches(ep, **params)) - - @property - def names(self) -> Set[str]: - """ - Return the set of all names of all entry points. - """ - return {ep.name for ep in self} - - @property - def groups(self) -> Set[str]: - """ - Return the set of all groups of all entry points. - """ - return {ep.group for ep in self} - - @classmethod - def _from_text_for(cls, text, dist): - return cls(ep._for(dist) for ep in cls._from_text(text)) - - @staticmethod - def _from_text(text): - return ( - EntryPoint(name=item.value.name, value=item.value.value, group=item.name) - for item in Sectioned.section_pairs(text or '') - ) - - -class PackagePath(pathlib.PurePosixPath): - """A reference to a path in a package""" - - hash: Optional["FileHash"] - size: int - dist: "Distribution" - - def read_text(self, encoding: str = 'utf-8') -> str: # type: ignore[override] - with self.locate().open(encoding=encoding) as stream: - return stream.read() - - def read_binary(self) -> bytes: - with self.locate().open('rb') as stream: - return stream.read() - - def locate(self) -> pathlib.Path: - """Return a path-like object for this path""" - return self.dist.locate_file(self) - - -class FileHash: - def __init__(self, spec: str) -> None: - self.mode, _, self.value = spec.partition('=') - - def __repr__(self) -> str: - return f'' - - -class DeprecatedNonAbstract: - def __new__(cls, *args, **kwargs): - all_names = { - name for subclass in inspect.getmro(cls) for name in vars(subclass) - } - abstract = { - name - for name in all_names - if getattr(getattr(cls, name), '__isabstractmethod__', False) - } - if abstract: - warnings.warn( - f"Unimplemented abstract methods {abstract}", - DeprecationWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class Distribution(DeprecatedNonAbstract): - """A Python distribution package.""" - - @abc.abstractmethod - def read_text(self, filename) -> Optional[str]: - """Attempt to load metadata file given by the name. - - :param filename: The name of the file in the distribution info. - :return: The text if found, otherwise None. - """ - - @abc.abstractmethod - def locate_file(self, path: StrPath) -> pathlib.Path: - """ - Given a path to a file in this distribution, return a path - to it. - """ - - @classmethod - def from_name(cls, name: str) -> "Distribution": - """Return the Distribution for the given package name. - - :param name: The name of the distribution package to search for. - :return: The Distribution instance (or subclass thereof) for the named - package, if found. - :raises PackageNotFoundError: When the named package's distribution - metadata cannot be found. - :raises ValueError: When an invalid value is supplied for name. - """ - if not name: - raise ValueError("A distribution name is required.") - try: - return next(iter(cls.discover(name=name))) - except StopIteration: - raise PackageNotFoundError(name) - - @classmethod - def discover(cls, **kwargs) -> Iterable["Distribution"]: - """Return an iterable of Distribution objects for all packages. - - Pass a ``context`` or pass keyword arguments for constructing - a context. - - :context: A ``DistributionFinder.Context`` object. - :return: Iterable of Distribution objects for all packages. - """ - context = kwargs.pop('context', None) - if context and kwargs: - raise ValueError("cannot accept context and kwargs") - context = context or DistributionFinder.Context(**kwargs) - return itertools.chain.from_iterable( - resolver(context) for resolver in cls._discover_resolvers() - ) - - @staticmethod - def at(path: StrPath) -> "Distribution": - """Return a Distribution for the indicated metadata path - - :param path: a string or path-like object - :return: a concrete Distribution instance for the path - """ - return PathDistribution(pathlib.Path(path)) - - @staticmethod - def _discover_resolvers(): - """Search the meta_path for resolvers.""" - declared = ( - getattr(finder, 'find_distributions', None) for finder in sys.meta_path - ) - return filter(None, declared) - - @property - def metadata(self) -> _meta.PackageMetadata: - """Return the parsed metadata for this Distribution. - - The returned object will have keys that name the various bits of - metadata. See PEP 566 for details. - """ - opt_text = ( - self.read_text('METADATA') - or self.read_text('PKG-INFO') - # This last clause is here to support old egg-info files. Its - # effect is to just end up using the PathDistribution's self._path - # (which points to the egg-info file) attribute unchanged. - or self.read_text('') - ) - text = cast(str, opt_text) - return _adapters.Message(email.message_from_string(text)) - - @property - def name(self) -> str: - """Return the 'Name' metadata for the distribution package.""" - return self.metadata['Name'] - - @property - def _normalized_name(self): - """Return a normalized version of the name.""" - return Prepared.normalize(self.name) - - @property - def version(self) -> str: - """Return the 'Version' metadata for the distribution package.""" - return self.metadata['Version'] - - @property - def entry_points(self) -> EntryPoints: - return EntryPoints._from_text_for(self.read_text('entry_points.txt'), self) - - @property - def files(self) -> Optional[List[PackagePath]]: - """Files in this distribution. - - :return: List of PackagePath for this distribution or None - - Result is `None` if the metadata file that enumerates files - (i.e. RECORD for dist-info, or installed-files.txt or - SOURCES.txt for egg-info) is missing. - Result may be empty if the metadata exists but is empty. - """ - - def make_file(name, hash=None, size_str=None): - result = PackagePath(name) - result.hash = FileHash(hash) if hash else None - result.size = int(size_str) if size_str else None - result.dist = self - return result - - @pass_none - def make_files(lines): - return starmap(make_file, csv.reader(lines)) - - @pass_none - def skip_missing_files(package_paths): - return list(filter(lambda path: path.locate().exists(), package_paths)) - - return skip_missing_files( - make_files( - self._read_files_distinfo() - or self._read_files_egginfo_installed() - or self._read_files_egginfo_sources() - ) - ) - - def _read_files_distinfo(self): - """ - Read the lines of RECORD - """ - text = self.read_text('RECORD') - return text and text.splitlines() - - def _read_files_egginfo_installed(self): - """ - Read installed-files.txt and return lines in a similar - CSV-parsable format as RECORD: each file must be placed - relative to the site-packages directory and must also be - quoted (since file names can contain literal commas). - - This file is written when the package is installed by pip, - but it might not be written for other installation methods. - Assume the file is accurate if it exists. - """ - text = self.read_text('installed-files.txt') - # Prepend the .egg-info/ subdir to the lines in this file. - # But this subdir is only available from PathDistribution's - # self._path. - subdir = getattr(self, '_path', None) - if not text or not subdir: - return - - paths = ( - (subdir / name) - .resolve() - .relative_to(self.locate_file('').resolve()) - .as_posix() - for name in text.splitlines() - ) - return map('"{}"'.format, paths) - - def _read_files_egginfo_sources(self): - """ - Read SOURCES.txt and return lines in a similar CSV-parsable - format as RECORD: each file name must be quoted (since it - might contain literal commas). - - Note that SOURCES.txt is not a reliable source for what - files are installed by a package. This file is generated - for a source archive, and the files that are present - there (e.g. setup.py) may not correctly reflect the files - that are present after the package has been installed. - """ - text = self.read_text('SOURCES.txt') - return text and map('"{}"'.format, text.splitlines()) - - @property - def requires(self) -> Optional[List[str]]: - """Generated requirements specified for this Distribution""" - reqs = self._read_dist_info_reqs() or self._read_egg_info_reqs() - return reqs and list(reqs) - - def _read_dist_info_reqs(self): - return self.metadata.get_all('Requires-Dist') - - def _read_egg_info_reqs(self): - source = self.read_text('requires.txt') - return pass_none(self._deps_from_requires_text)(source) - - @classmethod - def _deps_from_requires_text(cls, source): - return cls._convert_egg_info_reqs_to_simple_reqs(Sectioned.read(source)) - - @staticmethod - def _convert_egg_info_reqs_to_simple_reqs(sections): - """ - Historically, setuptools would solicit and store 'extra' - requirements, including those with environment markers, - in separate sections. More modern tools expect each - dependency to be defined separately, with any relevant - extras and environment markers attached directly to that - requirement. This method converts the former to the - latter. See _test_deps_from_requires_text for an example. - """ - - def make_condition(name): - return name and f'extra == "{name}"' - - def quoted_marker(section): - section = section or '' - extra, sep, markers = section.partition(':') - if extra and markers: - markers = f'({markers})' - conditions = list(filter(None, [markers, make_condition(extra)])) - return '; ' + ' and '.join(conditions) if conditions else '' - - def url_req_space(req): - """ - PEP 508 requires a space between the url_spec and the quoted_marker. - Ref python/importlib_metadata#357. - """ - # '@' is uniquely indicative of a url_req. - return ' ' * ('@' in req) - - for section in sections: - space = url_req_space(section.value) - yield section.value + space + quoted_marker(section.name) - - -class DistributionFinder(MetaPathFinder): - """ - A MetaPathFinder capable of discovering installed distributions. - """ - - class Context: - """ - Keyword arguments presented by the caller to - ``distributions()`` or ``Distribution.discover()`` - to narrow the scope of a search for distributions - in all DistributionFinders. - - Each DistributionFinder may expect any parameters - and should attempt to honor the canonical - parameters defined below when appropriate. - """ - - name = None - """ - Specific name for which a distribution finder should match. - A name of ``None`` matches all distributions. - """ - - def __init__(self, **kwargs): - vars(self).update(kwargs) - - @property - def path(self) -> List[str]: - """ - The sequence of directory path that a distribution finder - should search. - - Typically refers to Python installed package paths such as - "site-packages" directories and defaults to ``sys.path``. - """ - return vars(self).get('path', sys.path) - - @abc.abstractmethod - def find_distributions(self, context=Context()) -> Iterable[Distribution]: - """ - Find distributions. - - Return an iterable of all Distribution instances capable of - loading the metadata for packages matching the ``context``, - a DistributionFinder.Context instance. - """ - - -class FastPath: - """ - Micro-optimized class for searching a path for - children. - - >>> FastPath('').children() - ['...'] - """ - - @functools.lru_cache() # type: ignore - def __new__(cls, root): - return super().__new__(cls) - - def __init__(self, root): - self.root = root - - def joinpath(self, child): - return pathlib.Path(self.root, child) - - def children(self): - with suppress(Exception): - return os.listdir(self.root or '.') - with suppress(Exception): - return self.zip_children() - return [] - - def zip_children(self): - zip_path = zipp.Path(self.root) - names = zip_path.root.namelist() - self.joinpath = zip_path.joinpath - - return dict.fromkeys(child.split(posixpath.sep, 1)[0] for child in names) - - def search(self, name): - return self.lookup(self.mtime).search(name) - - @property - def mtime(self): - with suppress(OSError): - return os.stat(self.root).st_mtime - self.lookup.cache_clear() - - @method_cache - def lookup(self, mtime): - return Lookup(self) - - -class Lookup: - def __init__(self, path: FastPath): - base = os.path.basename(path.root).lower() - base_is_egg = base.endswith(".egg") - self.infos = FreezableDefaultDict(list) - self.eggs = FreezableDefaultDict(list) - - for child in path.children(): - low = child.lower() - if low.endswith((".dist-info", ".egg-info")): - # rpartition is faster than splitext and suitable for this purpose. - name = low.rpartition(".")[0].partition("-")[0] - normalized = Prepared.normalize(name) - self.infos[normalized].append(path.joinpath(child)) - elif base_is_egg and low == "egg-info": - name = base.rpartition(".")[0].partition("-")[0] - legacy_normalized = Prepared.legacy_normalize(name) - self.eggs[legacy_normalized].append(path.joinpath(child)) - - self.infos.freeze() - self.eggs.freeze() - - def search(self, prepared): - infos = ( - self.infos[prepared.normalized] - if prepared - else itertools.chain.from_iterable(self.infos.values()) - ) - eggs = ( - self.eggs[prepared.legacy_normalized] - if prepared - else itertools.chain.from_iterable(self.eggs.values()) - ) - return itertools.chain(infos, eggs) - - -class Prepared: - """ - A prepared search for metadata on a possibly-named package. - """ - - normalized = None - legacy_normalized = None - - def __init__(self, name): - self.name = name - if name is None: - return - self.normalized = self.normalize(name) - self.legacy_normalized = self.legacy_normalize(name) - - @staticmethod - def normalize(name): - """ - PEP 503 normalization plus dashes as underscores. - """ - return re.sub(r"[-_.]+", "-", name).lower().replace('-', '_') - - @staticmethod - def legacy_normalize(name): - """ - Normalize the package name as found in the convention in - older packaging tools versions and specs. - """ - return name.lower().replace('-', '_') - - def __bool__(self): - return bool(self.name) - - -@install -class MetadataPathFinder(NullFinder, DistributionFinder): - """A degenerate finder for distribution packages on the file system. - - This finder supplies only a find_distributions() method for versions - of Python that do not have a PathFinder find_distributions(). - """ - - def find_distributions( - self, context=DistributionFinder.Context() - ) -> Iterable["PathDistribution"]: - """ - Find distributions. - - Return an iterable of all Distribution instances capable of - loading the metadata for packages matching ``context.name`` - (or all names if ``None`` indicated) along the paths in the list - of directories ``context.path``. - """ - found = self._search_paths(context.name, context.path) - return map(PathDistribution, found) - - @classmethod - def _search_paths(cls, name, paths): - """Find metadata directories in paths heuristically.""" - prepared = Prepared(name) - return itertools.chain.from_iterable( - path.search(prepared) for path in map(FastPath, paths) - ) - - def invalidate_caches(cls) -> None: - FastPath.__new__.cache_clear() - - -class PathDistribution(Distribution): - def __init__(self, path: SimplePath) -> None: - """Construct a distribution. - - :param path: SimplePath indicating the metadata directory. - """ - self._path = path - - def read_text(self, filename: StrPath) -> Optional[str]: - with suppress( - FileNotFoundError, - IsADirectoryError, - KeyError, - NotADirectoryError, - PermissionError, - ): - return self._path.joinpath(filename).read_text(encoding='utf-8') - - return None - - read_text.__doc__ = Distribution.read_text.__doc__ - - def locate_file(self, path: StrPath) -> pathlib.Path: - return self._path.parent / path - - @property - def _normalized_name(self): - """ - Performance optimization: where possible, resolve the - normalized name from the file system path. - """ - stem = os.path.basename(str(self._path)) - return ( - pass_none(Prepared.normalize)(self._name_from_stem(stem)) - or super()._normalized_name - ) - - @staticmethod - def _name_from_stem(stem): - """ - >>> PathDistribution._name_from_stem('foo-3.0.egg-info') - 'foo' - >>> PathDistribution._name_from_stem('CherryPy-3.0.dist-info') - 'CherryPy' - >>> PathDistribution._name_from_stem('face.egg-info') - 'face' - >>> PathDistribution._name_from_stem('foo.bar') - """ - filename, ext = os.path.splitext(stem) - if ext not in ('.dist-info', '.egg-info'): - return - name, sep, rest = filename.partition('-') - return name - - -def distribution(distribution_name: str) -> Distribution: - """Get the ``Distribution`` instance for the named package. - - :param distribution_name: The name of the distribution package as a string. - :return: A ``Distribution`` instance (or subclass thereof). - """ - return Distribution.from_name(distribution_name) - - -def distributions(**kwargs) -> Iterable[Distribution]: - """Get all ``Distribution`` instances in the current environment. - - :return: An iterable of ``Distribution`` instances. - """ - return Distribution.discover(**kwargs) - - -def metadata(distribution_name: str) -> _meta.PackageMetadata: - """Get the metadata for the named package. - - :param distribution_name: The name of the distribution package to query. - :return: A PackageMetadata containing the parsed metadata. - """ - return Distribution.from_name(distribution_name).metadata - - -def version(distribution_name: str) -> str: - """Get the version string for the named package. - - :param distribution_name: The name of the distribution package to query. - :return: The version string for the package as defined in the package's - "Version" metadata key. - """ - return distribution(distribution_name).version - - -_unique = functools.partial( - unique_everseen, - key=_py39compat.normalized_name, -) -""" -Wrapper for ``distributions`` to return unique distributions by name. -""" - - -def entry_points(**params) -> EntryPoints: - """Return EntryPoint objects for all installed packages. - - Pass selection parameters (group or name) to filter the - result to entry points matching those properties (see - EntryPoints.select()). - - :return: EntryPoints for all installed packages. - """ - eps = itertools.chain.from_iterable( - dist.entry_points for dist in _unique(distributions()) - ) - return EntryPoints(eps).select(**params) - - -def files(distribution_name: str) -> Optional[List[PackagePath]]: - """Return a list of files for the named package. - - :param distribution_name: The name of the distribution package to query. - :return: List of files composing the distribution. - """ - return distribution(distribution_name).files - - -def requires(distribution_name: str) -> Optional[List[str]]: - """ - Return a list of requirements for the named package. - - :return: An iterable of requirements, suitable for - packaging.requirement.Requirement. - """ - return distribution(distribution_name).requires - - -def packages_distributions() -> Mapping[str, List[str]]: - """ - Return a mapping of top-level packages to their - distributions. - - >>> import collections.abc - >>> pkgs = packages_distributions() - >>> all(isinstance(dist, collections.abc.Sequence) for dist in pkgs.values()) - True - """ - pkg_to_dist = collections.defaultdict(list) - for dist in distributions(): - for pkg in _top_level_declared(dist) or _top_level_inferred(dist): - pkg_to_dist[pkg].append(dist.metadata['Name']) - return dict(pkg_to_dist) - - -def _top_level_declared(dist): - return (dist.read_text('top_level.txt') or '').split() - - -def _topmost(name: PackagePath) -> Optional[str]: - """ - Return the top-most parent as long as there is a parent. - """ - top, *rest = name.parts - return top if rest else None - - -def _get_toplevel_name(name: PackagePath) -> str: - """ - Infer a possibly importable module name from a name presumed on - sys.path. - - >>> _get_toplevel_name(PackagePath('foo.py')) - 'foo' - >>> _get_toplevel_name(PackagePath('foo')) - 'foo' - >>> _get_toplevel_name(PackagePath('foo.pyc')) - 'foo' - >>> _get_toplevel_name(PackagePath('foo/__init__.py')) - 'foo' - >>> _get_toplevel_name(PackagePath('foo.pth')) - 'foo.pth' - >>> _get_toplevel_name(PackagePath('foo.dist-info')) - 'foo.dist-info' - """ - return _topmost(name) or ( - # python/typeshed#10328 - inspect.getmodulename(name) # type: ignore - or str(name) - ) - - -def _top_level_inferred(dist): - opt_names = set(map(_get_toplevel_name, always_iterable(dist.files))) - - def importable_name(name): - return '.' not in name - - return filter(importable_name, opt_names) diff --git a/server/libs/importlib_metadata/_adapters.py b/server/libs/importlib_metadata/_adapters.py deleted file mode 100644 index e33cba5..0000000 --- a/server/libs/importlib_metadata/_adapters.py +++ /dev/null @@ -1,90 +0,0 @@ -import functools -import warnings -import re -import textwrap -import email.message - -from ._text import FoldedCase -from ._compat import pypy_partial - - -# Do not remove prior to 2024-01-01 or Python 3.14 -_warn = functools.partial( - warnings.warn, - "Implicit None on return values is deprecated and will raise KeyErrors.", - DeprecationWarning, - stacklevel=pypy_partial(2), -) - - -class Message(email.message.Message): - multiple_use_keys = set( - map( - FoldedCase, - [ - 'Classifier', - 'Obsoletes-Dist', - 'Platform', - 'Project-URL', - 'Provides-Dist', - 'Provides-Extra', - 'Requires-Dist', - 'Requires-External', - 'Supported-Platform', - 'Dynamic', - ], - ) - ) - """ - Keys that may be indicated multiple times per PEP 566. - """ - - def __new__(cls, orig: email.message.Message): - res = super().__new__(cls) - vars(res).update(vars(orig)) - return res - - def __init__(self, *args, **kwargs): - self._headers = self._repair_headers() - - # suppress spurious error from mypy - def __iter__(self): - return super().__iter__() - - def __getitem__(self, item): - """ - Warn users that a ``KeyError`` can be expected when a - mising key is supplied. Ref python/importlib_metadata#371. - """ - res = super().__getitem__(item) - if res is None: - _warn() - return res - - def _repair_headers(self): - def redent(value): - "Correct for RFC822 indentation" - if not value or '\n' not in value: - return value - return textwrap.dedent(' ' * 8 + value) - - headers = [(key, redent(value)) for key, value in vars(self)['_headers']] - if self._payload: - headers.append(('Description', self.get_payload())) - return headers - - @property - def json(self): - """ - Convert PackageMetadata to a JSON-compatible format - per PEP 0566. - """ - - def transform(key): - value = self.get_all(key) if key in self.multiple_use_keys else self[key] - if key == 'Keywords': - value = re.split(r'\s+', value) - tk = key.lower().replace('-', '_') - return tk, value - - return dict(map(transform, map(FoldedCase, self))) diff --git a/server/libs/importlib_metadata/_collections.py b/server/libs/importlib_metadata/_collections.py deleted file mode 100644 index cf0954e..0000000 --- a/server/libs/importlib_metadata/_collections.py +++ /dev/null @@ -1,30 +0,0 @@ -import collections - - -# from jaraco.collections 3.3 -class FreezableDefaultDict(collections.defaultdict): - """ - Often it is desirable to prevent the mutation of - a default dict after its initial construction, such - as to prevent mutation during iteration. - - >>> dd = FreezableDefaultDict(list) - >>> dd[0].append('1') - >>> dd.freeze() - >>> dd[1] - [] - >>> len(dd) - 1 - """ - - def __missing__(self, key): - return getattr(self, '_frozen', super().__missing__)(key) - - def freeze(self): - self._frozen = lambda key: self.default_factory() - - -class Pair(collections.namedtuple('Pair', 'name value')): - @classmethod - def parse(cls, text): - return cls(*map(str.strip, text.split("=", 1))) diff --git a/server/libs/importlib_metadata/_compat.py b/server/libs/importlib_metadata/_compat.py deleted file mode 100644 index c0f15c7..0000000 --- a/server/libs/importlib_metadata/_compat.py +++ /dev/null @@ -1,67 +0,0 @@ -import os -import sys -import platform - -from typing import Union - - -__all__ = ['install', 'NullFinder'] - - -def install(cls): - """ - Class decorator for installation on sys.meta_path. - - Adds the backport DistributionFinder to sys.meta_path and - attempts to disable the finder functionality of the stdlib - DistributionFinder. - """ - sys.meta_path.append(cls()) - disable_stdlib_finder() - return cls - - -def disable_stdlib_finder(): - """ - Give the backport primacy for discovering path-based distributions - by monkey-patching the stdlib O_O. - - See #91 for more background for rationale on this sketchy - behavior. - """ - - def matches(finder): - return getattr( - finder, '__module__', None - ) == '_frozen_importlib_external' and hasattr(finder, 'find_distributions') - - for finder in filter(matches, sys.meta_path): # pragma: nocover - del finder.find_distributions - - -class NullFinder: - """ - A "Finder" (aka "MetaClassFinder") that never finds any modules, - but may find distributions. - """ - - @staticmethod - def find_spec(*args, **kwargs): - return None - - -def pypy_partial(val): - """ - Adjust for variable stacklevel on partial under PyPy. - - Workaround for #327. - """ - is_pypy = platform.python_implementation() == 'PyPy' - return val + is_pypy - - -if sys.version_info >= (3, 9): - StrPath = Union[str, os.PathLike[str]] -else: - # PathLike is only subscriptable at runtime in 3.9+ - StrPath = Union[str, "os.PathLike[str]"] # pragma: no cover diff --git a/server/libs/importlib_metadata/_functools.py b/server/libs/importlib_metadata/_functools.py deleted file mode 100644 index 71f66bd..0000000 --- a/server/libs/importlib_metadata/_functools.py +++ /dev/null @@ -1,104 +0,0 @@ -import types -import functools - - -# from jaraco.functools 3.3 -def method_cache(method, cache_wrapper=None): - """ - Wrap lru_cache to support storing the cache data in the object instances. - - Abstracts the common paradigm where the method explicitly saves an - underscore-prefixed protected property on first call and returns that - subsequently. - - >>> class MyClass: - ... calls = 0 - ... - ... @method_cache - ... def method(self, value): - ... self.calls += 1 - ... return value - - >>> a = MyClass() - >>> a.method(3) - 3 - >>> for x in range(75): - ... res = a.method(x) - >>> a.calls - 75 - - Note that the apparent behavior will be exactly like that of lru_cache - except that the cache is stored on each instance, so values in one - instance will not flush values from another, and when an instance is - deleted, so are the cached values for that instance. - - >>> b = MyClass() - >>> for x in range(35): - ... res = b.method(x) - >>> b.calls - 35 - >>> a.method(0) - 0 - >>> a.calls - 75 - - Note that if method had been decorated with ``functools.lru_cache()``, - a.calls would have been 76 (due to the cached value of 0 having been - flushed by the 'b' instance). - - Clear the cache with ``.cache_clear()`` - - >>> a.method.cache_clear() - - Same for a method that hasn't yet been called. - - >>> c = MyClass() - >>> c.method.cache_clear() - - Another cache wrapper may be supplied: - - >>> cache = functools.lru_cache(maxsize=2) - >>> MyClass.method2 = method_cache(lambda self: 3, cache_wrapper=cache) - >>> a = MyClass() - >>> a.method2() - 3 - - Caution - do not subsequently wrap the method with another decorator, such - as ``@property``, which changes the semantics of the function. - - See also - http://code.activestate.com/recipes/577452-a-memoize-decorator-for-instance-methods/ - for another implementation and additional justification. - """ - cache_wrapper = cache_wrapper or functools.lru_cache() - - def wrapper(self, *args, **kwargs): - # it's the first call, replace the method with a cached, bound method - bound_method = types.MethodType(method, self) - cached_method = cache_wrapper(bound_method) - setattr(self, method.__name__, cached_method) - return cached_method(*args, **kwargs) - - # Support cache clear even before cache has been created. - wrapper.cache_clear = lambda: None - - return wrapper - - -# From jaraco.functools 3.3 -def pass_none(func): - """ - Wrap func so it's not called if its first param is None - - >>> print_text = pass_none(print) - >>> print_text('text') - text - >>> print_text(None) - """ - - @functools.wraps(func) - def wrapper(param, *args, **kwargs): - if param is not None: - return func(param, *args, **kwargs) - - return wrapper diff --git a/server/libs/importlib_metadata/_itertools.py b/server/libs/importlib_metadata/_itertools.py deleted file mode 100644 index d4ca9b9..0000000 --- a/server/libs/importlib_metadata/_itertools.py +++ /dev/null @@ -1,73 +0,0 @@ -from itertools import filterfalse - - -def unique_everseen(iterable, key=None): - "List unique elements, preserving order. Remember all elements ever seen." - # unique_everseen('AAAABBBCCDAABBB') --> A B C D - # unique_everseen('ABBCcAD', str.lower) --> A B C D - seen = set() - seen_add = seen.add - if key is None: - for element in filterfalse(seen.__contains__, iterable): - seen_add(element) - yield element - else: - for element in iterable: - k = key(element) - if k not in seen: - seen_add(k) - yield element - - -# copied from more_itertools 8.8 -def always_iterable(obj, base_type=(str, bytes)): - """If *obj* is iterable, return an iterator over its items:: - - >>> obj = (1, 2, 3) - >>> list(always_iterable(obj)) - [1, 2, 3] - - If *obj* is not iterable, return a one-item iterable containing *obj*:: - - >>> obj = 1 - >>> list(always_iterable(obj)) - [1] - - If *obj* is ``None``, return an empty iterable: - - >>> obj = None - >>> list(always_iterable(None)) - [] - - By default, binary and text strings are not considered iterable:: - - >>> obj = 'foo' - >>> list(always_iterable(obj)) - ['foo'] - - If *base_type* is set, objects for which ``isinstance(obj, base_type)`` - returns ``True`` won't be considered iterable. - - >>> obj = {'a': 1} - >>> list(always_iterable(obj)) # Iterate over the dict's keys - ['a'] - >>> list(always_iterable(obj, base_type=dict)) # Treat dicts as a unit - [{'a': 1}] - - Set *base_type* to ``None`` to avoid any special handling and treat objects - Python considers iterable as iterable: - - >>> obj = 'foo' - >>> list(always_iterable(obj, base_type=None)) - ['f', 'o', 'o'] - """ - if obj is None: - return iter(()) - - if (base_type is not None) and isinstance(obj, base_type): - return iter((obj,)) - - try: - return iter(obj) - except TypeError: - return iter((obj,)) diff --git a/server/libs/importlib_metadata/_meta.py b/server/libs/importlib_metadata/_meta.py deleted file mode 100644 index f670016..0000000 --- a/server/libs/importlib_metadata/_meta.py +++ /dev/null @@ -1,63 +0,0 @@ -from typing import Protocol -from typing import Any, Dict, Iterator, List, Optional, TypeVar, Union, overload - - -_T = TypeVar("_T") - - -class PackageMetadata(Protocol): - def __len__(self) -> int: - ... # pragma: no cover - - def __contains__(self, item: str) -> bool: - ... # pragma: no cover - - def __getitem__(self, key: str) -> str: - ... # pragma: no cover - - def __iter__(self) -> Iterator[str]: - ... # pragma: no cover - - @overload - def get(self, name: str, failobj: None = None) -> Optional[str]: - ... # pragma: no cover - - @overload - def get(self, name: str, failobj: _T) -> Union[str, _T]: - ... # pragma: no cover - - # overload per python/importlib_metadata#435 - @overload - def get_all(self, name: str, failobj: None = None) -> Optional[List[Any]]: - ... # pragma: no cover - - @overload - def get_all(self, name: str, failobj: _T) -> Union[List[Any], _T]: - """ - Return all values associated with a possibly multi-valued key. - """ - - @property - def json(self) -> Dict[str, Union[str, List[str]]]: - """ - A JSON-compatible form of the metadata. - """ - - -class SimplePath(Protocol[_T]): - """ - A minimal subset of pathlib.Path required by PathDistribution. - """ - - def joinpath(self, other: Union[str, _T]) -> _T: - ... # pragma: no cover - - def __truediv__(self, other: Union[str, _T]) -> _T: - ... # pragma: no cover - - @property - def parent(self) -> _T: - ... # pragma: no cover - - def read_text(self) -> str: - ... # pragma: no cover diff --git a/server/libs/importlib_metadata/_py39compat.py b/server/libs/importlib_metadata/_py39compat.py deleted file mode 100644 index cde4558..0000000 --- a/server/libs/importlib_metadata/_py39compat.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Compatibility layer with Python 3.8/3.9 -""" -from typing import TYPE_CHECKING, Any, Optional - -if TYPE_CHECKING: # pragma: no cover - # Prevent circular imports on runtime. - from . import Distribution, EntryPoint -else: - Distribution = EntryPoint = Any - - -def normalized_name(dist: Distribution) -> Optional[str]: - """ - Honor name normalization for distributions that don't provide ``_normalized_name``. - """ - try: - return dist._normalized_name - except AttributeError: - from . import Prepared # -> delay to prevent circular imports. - - return Prepared.normalize(getattr(dist, "name", None) or dist.metadata['Name']) - - -def ep_matches(ep: EntryPoint, **params) -> bool: - """ - Workaround for ``EntryPoint`` objects without the ``matches`` method. - """ - try: - return ep.matches(**params) - except AttributeError: - from . import EntryPoint # -> delay to prevent circular imports. - - # Reconstruct the EntryPoint object to make sure it is compatible. - return EntryPoint(ep.name, ep.value, ep.group).matches(**params) diff --git a/server/libs/importlib_metadata/_text.py b/server/libs/importlib_metadata/_text.py deleted file mode 100644 index c88cfbb..0000000 --- a/server/libs/importlib_metadata/_text.py +++ /dev/null @@ -1,99 +0,0 @@ -import re - -from ._functools import method_cache - - -# from jaraco.text 3.5 -class FoldedCase(str): - """ - A case insensitive string class; behaves just like str - except compares equal when the only variation is case. - - >>> s = FoldedCase('hello world') - - >>> s == 'Hello World' - True - - >>> 'Hello World' == s - True - - >>> s != 'Hello World' - False - - >>> s.index('O') - 4 - - >>> s.split('O') - ['hell', ' w', 'rld'] - - >>> sorted(map(FoldedCase, ['GAMMA', 'alpha', 'Beta'])) - ['alpha', 'Beta', 'GAMMA'] - - Sequence membership is straightforward. - - >>> "Hello World" in [s] - True - >>> s in ["Hello World"] - True - - You may test for set inclusion, but candidate and elements - must both be folded. - - >>> FoldedCase("Hello World") in {s} - True - >>> s in {FoldedCase("Hello World")} - True - - String inclusion works as long as the FoldedCase object - is on the right. - - >>> "hello" in FoldedCase("Hello World") - True - - But not if the FoldedCase object is on the left: - - >>> FoldedCase('hello') in 'Hello World' - False - - In that case, use in_: - - >>> FoldedCase('hello').in_('Hello World') - True - - >>> FoldedCase('hello') > FoldedCase('Hello') - False - """ - - def __lt__(self, other): - return self.lower() < other.lower() - - def __gt__(self, other): - return self.lower() > other.lower() - - def __eq__(self, other): - return self.lower() == other.lower() - - def __ne__(self, other): - return self.lower() != other.lower() - - def __hash__(self): - return hash(self.lower()) - - def __contains__(self, other): - return super().lower().__contains__(other.lower()) - - def in_(self, other): - "Does self appear in other?" - return self in FoldedCase(other) - - # cache lower since it's likely to be called frequently. - @method_cache - def lower(self): - return super().lower() - - def index(self, sub): - return self.lower().index(sub.lower()) - - def split(self, splitter=' ', maxsplit=0): - pattern = re.compile(re.escape(splitter), re.I) - return pattern.split(self, maxsplit) diff --git a/server/libs/importlib_metadata/py.typed b/server/libs/importlib_metadata/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/server/libs/lsprotocol-2023.0.1.dist-info/INSTALLER b/server/libs/lsprotocol-2023.0.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/server/libs/lsprotocol-2023.0.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/server/libs/lsprotocol-2023.0.1.dist-info/LICENSE b/server/libs/lsprotocol-2023.0.1.dist-info/LICENSE deleted file mode 100644 index 9e841e7..0000000 --- a/server/libs/lsprotocol-2023.0.1.dist-info/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ - MIT License - - Copyright (c) Microsoft Corporation. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE diff --git a/server/libs/lsprotocol-2023.0.1.dist-info/METADATA b/server/libs/lsprotocol-2023.0.1.dist-info/METADATA deleted file mode 100644 index eb5f7d6..0000000 --- a/server/libs/lsprotocol-2023.0.1.dist-info/METADATA +++ /dev/null @@ -1,65 +0,0 @@ -Metadata-Version: 2.1 -Name: lsprotocol -Version: 2023.0.1 -Summary: Python implementation of the Language Server Protocol. -Author-email: Microsoft Corporation -Maintainer-email: Brett Cannon , Karthik Nadig -Requires-Python: >=3.7 -Description-Content-Type: text/markdown -Classifier: Development Status :: 5 - Production/Stable -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Requires-Dist: attrs>=21.3.0 -Requires-Dist: cattrs!=23.2.1 -Project-URL: Issues, https://github.com/microsoft/lsprotocol/issues -Project-URL: Source, https://github.com/microsoft/lsprotocol - -# Language Server Protocol Types implementation for Python - -`lsprotocol` is a python implementation of object types used in the Language Server Protocol (LSP). This repository contains the code generator and the generated types for LSP. - -## Overview - -LSP is used by editors to communicate with various tools to enables services like code completion, documentation on hover, formatting, code analysis, etc. The intent of this library is to allow you to build on top of the types used by LSP. This repository will be kept up to date with the latest version of LSP as it is updated. - -## Installation - -`python -m pip install lsprotocol` - -## Usage - -### Using LSP types - -```python -from lsprotocol import types - -position = types.Position(line=10, character=3) -``` - -### Using built-in type converters - -```python -# test.py -import json -from lsprotocol import converters, types - -position = types.Position(line=10, character=3) -converter = converters.get_converter() -print(json.dumps(converter.unstructure(position, unstructure_as=types.Position))) -``` - -Output: - -```console -> python test.py -{"line": 10, "character": 3} -``` - diff --git a/server/libs/lsprotocol-2023.0.1.dist-info/RECORD b/server/libs/lsprotocol-2023.0.1.dist-info/RECORD deleted file mode 100644 index 7edecce..0000000 --- a/server/libs/lsprotocol-2023.0.1.dist-info/RECORD +++ /dev/null @@ -1,17 +0,0 @@ -lsprotocol-2023.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -lsprotocol-2023.0.1.dist-info/LICENSE,sha256=ws_MuBL-SCEBqPBFl9_FqZkaaydIJmxHrJG2parhU4M,1141 -lsprotocol-2023.0.1.dist-info/METADATA,sha256=oh7M_V0nCX-lx8MCik5z0_J8Wyd7ApJtdl30wWs4Tb8,2237 -lsprotocol-2023.0.1.dist-info/RECORD,, -lsprotocol-2023.0.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -lsprotocol-2023.0.1.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 -lsprotocol/__init__.py,sha256=zoT6Do2JtGHGb7pOeKpahg4ocXIsSpyowjhOrhUhx8g,94 -lsprotocol/__pycache__/__init__.cpython-311.pyc,, -lsprotocol/__pycache__/_hooks.cpython-311.pyc,, -lsprotocol/__pycache__/converters.cpython-311.pyc,, -lsprotocol/__pycache__/types.cpython-311.pyc,, -lsprotocol/__pycache__/validators.cpython-311.pyc,, -lsprotocol/_hooks.py,sha256=PCTq4Ve_dDd02DMcWQ8afu9gj_oyX0B4nDOomPghqYs,41570 -lsprotocol/converters.py,sha256=404tQOVoZL31R9CBrDe6Gx9Nok5cRph3glKlnSx00fo,433 -lsprotocol/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -lsprotocol/types.py,sha256=nZYiI5ZvHEBkRYjtPd8tpqe0n2NpmdaCZ2RLwHxoMLs,454735 -lsprotocol/validators.py,sha256=5UMUmWhk52_Ps66_KFydjNkMfLNUsPH3wmV0Buv645s,1420 diff --git a/server/libs/lsprotocol-2023.0.1.dist-info/REQUESTED b/server/libs/lsprotocol-2023.0.1.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/server/libs/lsprotocol-2023.0.1.dist-info/WHEEL b/server/libs/lsprotocol-2023.0.1.dist-info/WHEEL deleted file mode 100644 index 3b5e64b..0000000 --- a/server/libs/lsprotocol-2023.0.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.9.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/server/libs/lsprotocol/__init__.py b/server/libs/lsprotocol/__init__.py deleted file mode 100644 index 5b7f7a9..0000000 --- a/server/libs/lsprotocol/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. diff --git a/server/libs/lsprotocol/_hooks.py b/server/libs/lsprotocol/_hooks.py deleted file mode 100644 index 3f51ce2..0000000 --- a/server/libs/lsprotocol/_hooks.py +++ /dev/null @@ -1,1237 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. -import sys -from typing import Any, List, Optional, Tuple, Union - -import attrs -import cattrs - -from . import types as lsp_types - -LSPAny = lsp_types.LSPAny -OptionalPrimitive = Optional[Union[bool, int, str, float]] - -# Flag to ensure we only resolve forward references once. -_resolved_forward_references = False - - -def _resolve_forward_references() -> None: - """Resolve forward references for faster processing with cattrs.""" - global _resolved_forward_references - if not _resolved_forward_references: - - def _filter(p: Tuple[str, object]) -> bool: - return isinstance(p[1], type) and attrs.has(p[1]) - - # Creating a concrete list here because `resolve_types` mutates the provided map. - items = list(filter(_filter, lsp_types.ALL_TYPES_MAP.items())) - for _, value in items: - if isinstance(value, type): - attrs.resolve_types(value, lsp_types.ALL_TYPES_MAP, {}) # type: ignore - _resolved_forward_references = True - - -def register_hooks(converter: cattrs.Converter) -> cattrs.Converter: - _resolve_forward_references() - converter = _register_capabilities_hooks(converter) - converter = _register_required_structure_hooks(converter) - return _register_custom_property_hooks(converter) - - -def _register_capabilities_hooks(converter: cattrs.Converter) -> cattrs.Converter: - def _text_document_sync_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.TextDocumentSyncOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.TextDocumentSyncOptions) - - def _notebook_document_sync_hook( - object_: Any, _: type - ) -> Optional[ - Union[ - lsp_types.NotebookDocumentSyncRegistrationOptions, - lsp_types.NotebookDocumentSyncOptions, - ] - ]: - if object_ is None: - return None - if "id" in object_: - return converter.structure( - object_, lsp_types.NotebookDocumentSyncRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.NotebookDocumentSyncOptions) - - def _hover_provider_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.HoverOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.HoverOptions) - - def _declaration_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.DeclarationRegistrationOptions, - lsp_types.DeclarationOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure( - object_, lsp_types.DeclarationRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.DeclarationOptions) - - def _definition_provider_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.DefinitionOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.DefinitionOptions) - - def _type_definition_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.TypeDefinitionRegistrationOptions, - lsp_types.TypeDefinitionOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure( - object_, lsp_types.TypeDefinitionRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.TypeDefinitionOptions) - - def _implementation_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.ImplementationRegistrationOptions, - lsp_types.ImplementationOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure( - object_, lsp_types.ImplementationRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.ImplementationOptions) - - def _references_provider_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.ReferenceOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.ReferenceOptions) - - def _position_encoding_hook( - object_: Union[lsp_types.PositionEncodingKind, OptionalPrimitive], _: type - ) -> Union[lsp_types.PositionEncodingKind, OptionalPrimitive]: - return object_ - - def _document_highlight_provider_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.DocumentHighlightOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.DocumentHighlightOptions) - - def _document_symbol_provider_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.DocumentSymbolOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.DocumentSymbolOptions) - - def _code_action_provider_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.CodeActionOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.CodeActionOptions) - - def _color_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.DocumentColorRegistrationOptions, - lsp_types.DocumentColorOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure( - object_, lsp_types.DocumentColorRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.DocumentColorOptions) - - def _workspace_symbol_provider_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.WorkspaceSymbolOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.WorkspaceSymbolOptions) - - def _document_formatting_provider_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.DocumentFormattingOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.DocumentFormattingOptions) - - def _document_range_formatting_provider_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.DocumentRangeFormattingOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.DocumentRangeFormattingOptions) - - def _rename_provider_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.RenameOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.RenameOptions) - - def _folding_range_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.FoldingRangeRegistrationOptions, - lsp_types.FoldingRangeOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure( - object_, lsp_types.FoldingRangeRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.FoldingRangeOptions) - - def _selection_range_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.SelectionRangeRegistrationOptions, - lsp_types.SelectionRangeOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure( - object_, lsp_types.SelectionRangeRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.SelectionRangeOptions) - - def _call_hierarchy_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.CallHierarchyRegistrationOptions, - lsp_types.CallHierarchyOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure( - object_, lsp_types.CallHierarchyRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.CallHierarchyOptions) - - def _linked_editing_range_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.LinkedEditingRangeRegistrationOptions, - lsp_types.LinkedEditingRangeOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure( - object_, lsp_types.LinkedEditingRangeRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.LinkedEditingRangeOptions) - - def _semantic_tokens_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.SemanticTokensRegistrationOptions, - lsp_types.SemanticTokensOptions, - ]: - if object_ is None: - return None - if "id" in object_: - return converter.structure( - object_, lsp_types.SemanticTokensRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.SemanticTokensOptions) - - def _moniker_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.MonikerRegistrationOptions, - lsp_types.MonikerOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure(object_, lsp_types.MonikerRegistrationOptions) - else: - return converter.structure(object_, lsp_types.MonikerOptions) - - def _type_hierarchy_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.TypeHierarchyRegistrationOptions, - lsp_types.TypeHierarchyOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure( - object_, lsp_types.TypeHierarchyRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.TypeHierarchyOptions) - - def _inline_value_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.InlineValueRegistrationOptions, - lsp_types.InlineValueOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure( - object_, lsp_types.InlineValueRegistrationOptions - ) - else: - return converter.structure(object_, lsp_types.InlineValueOptions) - - def _inlay_hint_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.InlayHintRegistrationOptions, - lsp_types.InlayHintOptions, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if "id" in object_: - return converter.structure(object_, lsp_types.InlayHintRegistrationOptions) - else: - return converter.structure(object_, lsp_types.InlayHintOptions) - - def _inlay_hint_label_part_hook( - object_: Any, _: type - ) -> Union[str, List[lsp_types.InlayHintLabelPart]]: - if isinstance(object_, str): - return object_ - - return [ - converter.structure(item, lsp_types.InlayHintLabelPart) for item in object_ - ] - - def _diagnostic_provider_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.DiagnosticRegistrationOptions, - lsp_types.DiagnosticOptions, - ]: - if object_ is None: - return None - if "id" in object_: - return converter.structure(object_, lsp_types.DiagnosticRegistrationOptions) - else: - return converter.structure(object_, lsp_types.DiagnosticOptions) - - def _save_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.SaveOptions]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.SaveOptions) - - def _code_action_hook( - object_: Any, _: type - ) -> Union[lsp_types.Command, lsp_types.CodeAction]: - if "command" in object_: - return converter.structure(object_, lsp_types.Command) - else: - return converter.structure(object_, lsp_types.CodeAction) - - def _completion_list_hook( - object_: Any, _: type - ) -> Optional[Union[lsp_types.CompletionList, List[lsp_types.CompletionItem]]]: - if object_ is None: - return None - if isinstance(object_, list): - return [ - converter.structure(item, lsp_types.CompletionItem) for item in object_ - ] - else: - return converter.structure(object_, lsp_types.CompletionList) - - def _location_hook( - object_: Any, _: type - ) -> Optional[ - Union[ - lsp_types.Location, - List[lsp_types.Location], - List[lsp_types.LocationLink], - ] - ]: - if object_ is None: - return None - if isinstance(object_, list): - if len(object_) == 0: - return [] - if "targetUri" in object_[0]: - return [ - converter.structure(item, lsp_types.LocationLink) - for item in object_ - ] - else: - return [ - converter.structure(item, lsp_types.Location) for item in object_ - ] - else: - return converter.structure(object_, lsp_types.Location) - - def _symbol_hook( - object_: Any, _: type - ) -> Optional[ - Union[List[lsp_types.DocumentSymbol], List[lsp_types.SymbolInformation]] - ]: - if object_ is None: - return None - if isinstance(object_, list): - if len(object_) == 0: - return [] - if "location" in object_[0]: - return [ - converter.structure(item, lsp_types.SymbolInformation) - for item in object_ - ] - else: - return [ - converter.structure(item, lsp_types.DocumentSymbol) - for item in object_ - ] - else: - return None - - def _markup_content_hook( - object_: Any, _: type - ) -> Optional[ - Union[ - OptionalPrimitive, - lsp_types.MarkupContent, - lsp_types.MarkedString_Type1, - List[Union[OptionalPrimitive, lsp_types.MarkedString_Type1]], - ] - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - if isinstance(object_, list): - return [ - ( - item - if isinstance(item, (bool, int, str, float)) - else converter.structure(item, lsp_types.MarkedString_Type1) - ) - for item in object_ - ] - if "kind" in object_: - return converter.structure(object_, lsp_types.MarkupContent) - else: - return converter.structure(object_, lsp_types.MarkedString_Type1) - - def _document_edit_hook( - object_: Any, _: type - ) -> Optional[ - Union[ - lsp_types.TextDocumentEdit, - lsp_types.CreateFile, - lsp_types.RenameFile, - lsp_types.DeleteFile, - ] - ]: - if object_ is None: - return None - if "kind" in object_: - if object_["kind"] == "create": - return converter.structure(object_, lsp_types.CreateFile) - elif object_["kind"] == "rename": - return converter.structure(object_, lsp_types.RenameFile) - elif object_["kind"] == "delete": - return converter.structure(object_, lsp_types.DeleteFile) - else: - raise ValueError("Unknown edit kind: ", object_) - else: - return converter.structure(object_, lsp_types.TextDocumentEdit) - - def _semantic_tokens_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.SemanticTokensOptionsFullType1]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.SemanticTokensOptionsFullType1) - - def _semantic_tokens_capabilities_hook( - object_: Any, _: type - ) -> Union[ - OptionalPrimitive, - lsp_types.SemanticTokensClientCapabilitiesRequestsTypeFullType1, - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure( - object_, lsp_types.SemanticTokensClientCapabilitiesRequestsTypeFullType1 - ) - - def _code_action_kind_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.CodeActionKind]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.CodeActionKind) - - def _position_encoding_kind_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.PositionEncodingKind]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.PositionEncodingKind) - - def _folding_range_kind_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.FoldingRangeKind]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.FoldingRangeKind) - - def _semantic_token_types_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.SemanticTokenTypes]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.SemanticTokenTypes) - - def _semantic_token_modifiers_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.SemanticTokenModifiers]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.SemanticTokenModifiers) - - def _watch_kind_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.WatchKind]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.WatchKind) - - def _notebook_sync_option_selector_hook( - object_: Any, _: type - ) -> Union[ - lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType1, - lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType2, - ]: - if "notebook" in object_: - return converter.structure( - object_, lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType1 - ) - else: - return converter.structure( - object_, lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType2 - ) - - def _semantic_token_registration_options_hook( - object_: Any, _: type - ) -> Optional[ - Union[OptionalPrimitive, lsp_types.SemanticTokensRegistrationOptionsFullType1] - ]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure( - object_, lsp_types.SemanticTokensRegistrationOptionsFullType1 - ) - - def _inline_completion_provider_hook( - object_: Any, _: type - ) -> Optional[Union[OptionalPrimitive, lsp_types.InlineCompletionOptions]]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.InlineCompletionOptions) - - def _inline_completion_list_hook( - object_: Any, _: type - ) -> Optional[ - Union[lsp_types.InlineCompletionList, List[lsp_types.InlineCompletionItem]] - ]: - if object_ is None: - return None - if isinstance(object_, list): - return [ - converter.structure(item, lsp_types.InlineCompletionItem) - for item in object_ - ] - return converter.structure(object_, lsp_types.InlineCompletionList) - - def _string_value_hook( - object_: Any, _: type - ) -> Union[OptionalPrimitive, lsp_types.StringValue]: - if object_ is None: - return None - if isinstance(object_, (bool, int, str, float)): - return object_ - return converter.structure(object_, lsp_types.StringValue) - - def _symbol_list_hook( - object_: Any, _: type - ) -> Optional[ - Union[List[lsp_types.SymbolInformation], List[lsp_types.WorkspaceSymbol]] - ]: - if object_ is None: - return None - assert isinstance(object_, list) - if len(object_) == 0: - return [] - if "deprecated" in object_[0]: - return [ - converter.structure(item, lsp_types.SymbolInformation) - for item in object_ - ] - elif ("data" in object_[0]) or ("range" not in object_[0]["location"]): - return [ - converter.structure(item, lsp_types.WorkspaceSymbol) for item in object_ - ] - - return [ - converter.structure(item, lsp_types.SymbolInformation) for item in object_ - ] - - def _notebook_sync_registration_option_selector_hook( - object_: Any, _: type - ) -> Union[ - lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1, - lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2, - ]: - if "notebook" in object_: - return converter.structure( - object_, - lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1, - ) - else: - return converter.structure( - object_, - lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2, - ) - - structure_hooks = [ - ( - Optional[ - Union[lsp_types.TextDocumentSyncOptions, lsp_types.TextDocumentSyncKind] - ], - _text_document_sync_hook, - ), - ( - Optional[ - Union[ - lsp_types.NotebookDocumentSyncOptions, - lsp_types.NotebookDocumentSyncRegistrationOptions, - ] - ], - _notebook_document_sync_hook, - ), - (Optional[Union[bool, lsp_types.HoverOptions]], _hover_provider_hook), - ( - Optional[ - Union[ - bool, - lsp_types.DeclarationOptions, - lsp_types.DeclarationRegistrationOptions, - ] - ], - _declaration_provider_hook, - ), - (Optional[Union[bool, lsp_types.DefinitionOptions]], _definition_provider_hook), - ( - Optional[ - Union[ - bool, - lsp_types.TypeDefinitionOptions, - lsp_types.TypeDefinitionRegistrationOptions, - ] - ], - _type_definition_provider_hook, - ), - ( - Optional[ - Union[ - bool, - lsp_types.ImplementationOptions, - lsp_types.ImplementationRegistrationOptions, - ] - ], - _implementation_provider_hook, - ), - (Optional[Union[bool, lsp_types.ReferenceOptions]], _references_provider_hook), - ( - Optional[Union[bool, lsp_types.DocumentHighlightOptions]], - _document_highlight_provider_hook, - ), - ( - Optional[Union[bool, lsp_types.DocumentSymbolOptions]], - _document_symbol_provider_hook, - ), - ( - Optional[Union[bool, lsp_types.CodeActionOptions]], - _code_action_provider_hook, - ), - ( - Optional[ - Union[ - bool, - lsp_types.DocumentColorOptions, - lsp_types.DocumentColorRegistrationOptions, - ] - ], - _color_provider_hook, - ), - ( - Optional[Union[bool, lsp_types.WorkspaceSymbolOptions]], - _workspace_symbol_provider_hook, - ), - ( - Optional[Union[bool, lsp_types.DocumentFormattingOptions]], - _document_formatting_provider_hook, - ), - ( - Optional[Union[bool, lsp_types.DocumentRangeFormattingOptions]], - _document_range_formatting_provider_hook, - ), - (Optional[Union[bool, lsp_types.RenameOptions]], _rename_provider_hook), - ( - Optional[ - Union[ - bool, - lsp_types.FoldingRangeOptions, - lsp_types.FoldingRangeRegistrationOptions, - ] - ], - _folding_range_provider_hook, - ), - ( - Optional[ - Union[ - bool, - lsp_types.SelectionRangeOptions, - lsp_types.SelectionRangeRegistrationOptions, - ] - ], - _selection_range_provider_hook, - ), - ( - Optional[ - Union[ - bool, - lsp_types.CallHierarchyOptions, - lsp_types.CallHierarchyRegistrationOptions, - ] - ], - _call_hierarchy_provider_hook, - ), - ( - Optional[ - Union[ - bool, - lsp_types.LinkedEditingRangeOptions, - lsp_types.LinkedEditingRangeRegistrationOptions, - ] - ], - _linked_editing_range_provider_hook, - ), - ( - Optional[ - Union[ - lsp_types.SemanticTokensOptions, - lsp_types.SemanticTokensRegistrationOptions, - ] - ], - _semantic_tokens_provider_hook, - ), - ( - Optional[ - Union[ - bool, lsp_types.MonikerOptions, lsp_types.MonikerRegistrationOptions - ] - ], - _moniker_provider_hook, - ), - ( - Optional[ - Union[ - bool, - lsp_types.TypeHierarchyOptions, - lsp_types.TypeHierarchyRegistrationOptions, - ] - ], - _type_hierarchy_provider_hook, - ), - ( - Optional[ - Union[ - bool, - lsp_types.InlineValueOptions, - lsp_types.InlineValueRegistrationOptions, - ] - ], - _inline_value_provider_hook, - ), - ( - Optional[ - Union[ - bool, - lsp_types.InlayHintOptions, - lsp_types.InlayHintRegistrationOptions, - ] - ], - _inlay_hint_provider_hook, - ), - ( - Union[str, List[lsp_types.InlayHintLabelPart]], - _inlay_hint_label_part_hook, - ), - ( - Optional[ - Union[ - lsp_types.DiagnosticOptions, lsp_types.DiagnosticRegistrationOptions - ] - ], - _diagnostic_provider_hook, - ), - ( - Optional[Union[lsp_types.SaveOptions, bool]], - _save_hook, - ), - ( - Union[lsp_types.Command, lsp_types.CodeAction], - _code_action_hook, - ), - ( - Optional[Union[List[lsp_types.CompletionItem], lsp_types.CompletionList]], - _completion_list_hook, - ), - ( - Optional[ - Union[ - lsp_types.Location, - List[lsp_types.Location], - List[lsp_types.LocationLink], - ] - ], - _location_hook, - ), - ( - Optional[ - Union[List[lsp_types.SymbolInformation], List[lsp_types.DocumentSymbol]] - ], - _symbol_hook, - ), - ( - Union[ - lsp_types.MarkupContent, - str, - lsp_types.MarkedString_Type1, - List[Union[str, lsp_types.MarkedString_Type1]], - ], - _markup_content_hook, - ), - ( - Union[ - lsp_types.TextDocumentEdit, - lsp_types.CreateFile, - lsp_types.RenameFile, - lsp_types.DeleteFile, - ], - _document_edit_hook, - ), - ( - Optional[Union[bool, lsp_types.SemanticTokensOptionsFullType1]], - _semantic_tokens_hook, - ), - ( - Optional[ - Union[ - bool, - lsp_types.SemanticTokensClientCapabilitiesRequestsTypeFullType1, - ] - ], - _semantic_tokens_capabilities_hook, - ), - ( - Optional[Union[str, lsp_types.MarkupContent]], - _markup_content_hook, - ), - ( - Optional[Union[lsp_types.CodeActionKind, str]], - _code_action_kind_hook, - ), - ( - Union[lsp_types.CodeActionKind, str], - _code_action_kind_hook, - ), - ( - Union[lsp_types.PositionEncodingKind, str], - _position_encoding_kind_hook, - ), - ( - Optional[Union[lsp_types.FoldingRangeKind, str]], - _folding_range_kind_hook, - ), - ( - Union[lsp_types.FoldingRangeKind, str], - _folding_range_kind_hook, - ), - ( - Union[lsp_types.SemanticTokenTypes, str], - _semantic_token_types_hook, - ), - ( - Optional[Union[lsp_types.SemanticTokenTypes, str]], - _semantic_token_types_hook, - ), - ( - Union[lsp_types.SemanticTokenModifiers, str], - _semantic_token_modifiers_hook, - ), - ( - Optional[Union[lsp_types.SemanticTokenModifiers, str]], - _semantic_token_modifiers_hook, - ), - ( - Union[lsp_types.WatchKind, int], - _watch_kind_hook, - ), - ( - Optional[Union[lsp_types.WatchKind, int]], - _watch_kind_hook, - ), - ( - Union[ - lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType1, - lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType2, - ], - _notebook_sync_option_selector_hook, - ), - ( - Optional[ - Union[ - lsp_types.PositionEncodingKind, - str, - ] - ], - _position_encoding_hook, - ), - ( - Optional[Union[bool, lsp_types.SemanticTokensRegistrationOptionsFullType1]], - _semantic_token_registration_options_hook, - ), - ( - Optional[Union[bool, lsp_types.InlineCompletionOptions]], - _inline_completion_provider_hook, - ), - ( - Optional[ - Union[ - lsp_types.InlineCompletionList, List[lsp_types.InlineCompletionItem] - ] - ], - _inline_completion_list_hook, - ), - ( - Union[str, lsp_types.StringValue], - _string_value_hook, - ), - ( - Optional[ - Union[ - List[lsp_types.SymbolInformation], List[lsp_types.WorkspaceSymbol] - ] - ], - _symbol_list_hook, - ), - ( - Union[ - lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1, - lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2, - ], - _notebook_sync_registration_option_selector_hook, - ), - ] - for type_, hook in structure_hooks: - converter.register_structure_hook(type_, hook) - return converter - - -def _register_required_structure_hooks( - converter: cattrs.Converter, -) -> cattrs.Converter: - def _lsp_object_hook(object_: Any, type_: type) -> Any: - return object_ - - def _parameter_information_label_hook( - object_: Any, type: type - ) -> Union[str, Tuple[int, int]]: - if isinstance(object_, str): - return object_ - else: - return (int(object_[0]), int(object_[1])) - - def _text_document_filter_hook( - object_: Any, _: type - ) -> Union[ - str, - lsp_types.TextDocumentFilter_Type1, - lsp_types.TextDocumentFilter_Type2, - lsp_types.TextDocumentFilter_Type3, - lsp_types.NotebookCellTextDocumentFilter, - ]: - if isinstance(object_, str): - return str(object_) - elif "notebook" in object_: - return converter.structure( - object_, lsp_types.NotebookCellTextDocumentFilter - ) - elif "language" in object_: - return converter.structure(object_, lsp_types.TextDocumentFilter_Type1) - elif "scheme" in object_: - return converter.structure(object_, lsp_types.TextDocumentFilter_Type2) - else: - return converter.structure(object_, lsp_types.TextDocumentFilter_Type3) - - def _notebook_filter_hook( - object_: Any, _: type - ) -> Union[ - str, - lsp_types.NotebookDocumentFilter_Type1, - lsp_types.NotebookDocumentFilter_Type2, - lsp_types.NotebookDocumentFilter_Type3, - ]: - if isinstance(object_, str): - return str(object_) - elif "notebookType" in object_: - return converter.structure(object_, lsp_types.NotebookDocumentFilter_Type1) - elif "scheme" in object_: - return converter.structure(object_, lsp_types.NotebookDocumentFilter_Type2) - else: - return converter.structure(object_, lsp_types.NotebookDocumentFilter_Type3) - - # TODO: Remove the ignore after this issue with attrs is addressed in either attrs or mypy - NotebookSelectorItem = attrs.fields( - lsp_types.NotebookCellTextDocumentFilter - ).notebook.type - STRUCTURE_HOOKS = [ - (type(None), lambda object_, _type: object_), - (Optional[Union[int, str]], lambda object_, _type: object_), - (Union[int, str], lambda object_, _type: object_), - (lsp_types.LSPAny, _lsp_object_hook), - (Optional[Union[str, bool]], lambda object_, _type: object_), - (Optional[Union[bool, Any]], lambda object_, _type: object_), - ( - Union[ - lsp_types.TextDocumentFilter_Type1, - lsp_types.TextDocumentFilter_Type2, - lsp_types.TextDocumentFilter_Type3, - lsp_types.NotebookCellTextDocumentFilter, - ], - _text_document_filter_hook, - ), - (lsp_types.DocumentFilter, _text_document_filter_hook), - ( - Union[ - str, - lsp_types.NotebookDocumentFilter_Type1, - lsp_types.NotebookDocumentFilter_Type2, - lsp_types.NotebookDocumentFilter_Type3, - ], - _notebook_filter_hook, - ), - (NotebookSelectorItem, _notebook_filter_hook), - ( - Union[lsp_types.LSPObject, List["LSPAny"], str, int, float, bool, None], - _lsp_object_hook, - ), - ( - Union[ - lsp_types.LSPObject, List[lsp_types.LSPAny], str, int, float, bool, None - ], - _lsp_object_hook, - ), - ( - Union[str, Tuple[int, int]], - _parameter_information_label_hook, - ), - (lsp_types.LSPObject, _lsp_object_hook), - ] - - if sys.version_info > (3, 8): - STRUCTURE_HOOKS += [ - ( - Union[ - lsp_types.LSPObject, - List[ - Union[ - lsp_types.LSPObject, - List["LSPAny"], - str, - int, - float, - bool, - None, - ] - ], - str, - int, - float, - bool, - None, - ], - _lsp_object_hook, - ) - ] - - for type_, hook in STRUCTURE_HOOKS: - converter.register_structure_hook(type_, hook) - - return converter - - -def _register_custom_property_hooks(converter: cattrs.Converter) -> cattrs.Converter: - def _to_camel_case(name: str) -> str: - # TODO: when min Python becomes >= 3.9, then update this to: - # `return name.removesuffix("_")`. - new_name = name[:-1] if name.endswith("_") else name - parts = new_name.split("_") - return parts[0] + "".join(p.title() for p in parts[1:]) - - def _omit(cls: type, prop: str) -> bool: - special = lsp_types.is_special_property(cls, prop) - return not special - - def _with_custom_unstructure(cls: type) -> Any: - attributes = { - a.name: cattrs.gen.override( - rename=_to_camel_case(a.name), - omit_if_default=_omit(cls, a.name), - ) - for a in attrs.fields(cls) - } - return cattrs.gen.make_dict_unstructure_fn(cls, converter, **attributes) - - def _with_custom_structure(cls: type) -> Any: - attributes = { - a.name: cattrs.gen.override( - rename=_to_camel_case(a.name), - omit_if_default=_omit(cls, a.name), - ) - for a in attrs.fields(cls) - } - return cattrs.gen.make_dict_structure_fn(cls, converter, **attributes) - - converter.register_unstructure_hook_factory(attrs.has, _with_custom_unstructure) - converter.register_structure_hook_factory(attrs.has, _with_custom_structure) - return converter diff --git a/server/libs/lsprotocol/converters.py b/server/libs/lsprotocol/converters.py deleted file mode 100644 index db12c65..0000000 --- a/server/libs/lsprotocol/converters.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -from typing import Optional - -import cattrs - -from . import _hooks - - -def get_converter( - converter: Optional[cattrs.Converter] = None, -) -> cattrs.Converter: - """Adds cattrs hooks for LSP lsp_types to the given converter.""" - if converter is None: - converter = cattrs.Converter() - return _hooks.register_hooks(converter) diff --git a/server/libs/lsprotocol/py.typed b/server/libs/lsprotocol/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/server/libs/lsprotocol/types.py b/server/libs/lsprotocol/types.py deleted file mode 100644 index 98b2d4b..0000000 --- a/server/libs/lsprotocol/types.py +++ /dev/null @@ -1,12898 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -# ****** THIS IS A GENERATED FILE, DO NOT EDIT. ****** -# Steps to generate: -# 1. Checkout https://github.com/microsoft/lsprotocol -# 2. Install nox: `python -m pip install nox` -# 3. Run command: `python -m nox --session build_lsp` - -import enum -import functools -from typing import Any, Dict, List, Optional, Tuple, Union - -import attrs - -from . import validators - -__lsp_version__ = "3.17.0" - - -@enum.unique -class SemanticTokenTypes(str, enum.Enum): - """A set of predefined token types. This set is not fixed - an clients can specify additional token types via the - corresponding client capabilities. - - @since 3.16.0""" - - # Since: 3.16.0 - Namespace = "namespace" - Type = "type" - """Represents a generic type. Acts as a fallback for types which can't be mapped to - a specific type like class or enum.""" - Class = "class" - Enum = "enum" - Interface = "interface" - Struct = "struct" - TypeParameter = "typeParameter" - Parameter = "parameter" - Variable = "variable" - Property = "property" - EnumMember = "enumMember" - Event = "event" - Function = "function" - Method = "method" - Macro = "macro" - Keyword = "keyword" - Modifier = "modifier" - Comment = "comment" - String = "string" - Number = "number" - Regexp = "regexp" - Operator = "operator" - Decorator = "decorator" - """@since 3.17.0""" - # Since: 3.17.0 - - -@enum.unique -class SemanticTokenModifiers(str, enum.Enum): - """A set of predefined token modifiers. This set is not fixed - an clients can specify additional token types via the - corresponding client capabilities. - - @since 3.16.0""" - - # Since: 3.16.0 - Declaration = "declaration" - Definition = "definition" - Readonly = "readonly" - Static = "static" - Deprecated = "deprecated" - Abstract = "abstract" - Async = "async" - Modification = "modification" - Documentation = "documentation" - DefaultLibrary = "defaultLibrary" - - -@enum.unique -class DocumentDiagnosticReportKind(str, enum.Enum): - """The document diagnostic report kinds. - - @since 3.17.0""" - - # Since: 3.17.0 - Full = "full" - """A diagnostic report with a full - set of problems.""" - Unchanged = "unchanged" - """A report indicating that the last - returned report is still accurate.""" - - -class ErrorCodes(int, enum.Enum): - """Predefined error codes.""" - - ParseError = -32700 - InvalidRequest = -32600 - MethodNotFound = -32601 - InvalidParams = -32602 - InternalError = -32603 - ServerNotInitialized = -32002 - """Error code indicating that a server received a notification or - request before the server has received the `initialize` request.""" - UnknownErrorCode = -32001 - - -class LSPErrorCodes(int, enum.Enum): - RequestFailed = -32803 - """A request failed but it was syntactically correct, e.g the - method name was known and the parameters were valid. The error - message should contain human readable information about why - the request failed. - - @since 3.17.0""" - # Since: 3.17.0 - ServerCancelled = -32802 - """The server cancelled the request. This error code should - only be used for requests that explicitly support being - server cancellable. - - @since 3.17.0""" - # Since: 3.17.0 - ContentModified = -32801 - """The server detected that the content of a document got - modified outside normal conditions. A server should - NOT send this error code if it detects a content change - in it unprocessed messages. The result even computed - on an older state might still be useful for the client. - - If a client decides that a result is not of any use anymore - the client should cancel the request.""" - RequestCancelled = -32800 - """The client has canceled a request and a server as detected - the cancel.""" - - -@enum.unique -class FoldingRangeKind(str, enum.Enum): - """A set of predefined range kinds.""" - - Comment = "comment" - """Folding range for a comment""" - Imports = "imports" - """Folding range for an import or include""" - Region = "region" - """Folding range for a region (e.g. `#region`)""" - - -@enum.unique -class SymbolKind(int, enum.Enum): - """A symbol kind.""" - - File = 1 - Module = 2 - Namespace = 3 - Package = 4 - Class = 5 - Method = 6 - Property = 7 - Field = 8 - Constructor = 9 - Enum = 10 - Interface = 11 - Function = 12 - Variable = 13 - Constant = 14 - String = 15 - Number = 16 - Boolean = 17 - Array = 18 - Object = 19 - Key = 20 - Null = 21 - EnumMember = 22 - Struct = 23 - Event = 24 - Operator = 25 - TypeParameter = 26 - - -@enum.unique -class SymbolTag(int, enum.Enum): - """Symbol tags are extra annotations that tweak the rendering of a symbol. - - @since 3.16""" - - # Since: 3.16 - Deprecated = 1 - """Render a symbol as obsolete, usually using a strike-out.""" - - -@enum.unique -class UniquenessLevel(str, enum.Enum): - """Moniker uniqueness level to define scope of the moniker. - - @since 3.16.0""" - - # Since: 3.16.0 - Document = "document" - """The moniker is only unique inside a document""" - Project = "project" - """The moniker is unique inside a project for which a dump got created""" - Group = "group" - """The moniker is unique inside the group to which a project belongs""" - Scheme = "scheme" - """The moniker is unique inside the moniker scheme.""" - Global = "global" - """The moniker is globally unique""" - - -@enum.unique -class MonikerKind(str, enum.Enum): - """The moniker kind. - - @since 3.16.0""" - - # Since: 3.16.0 - Import = "import" - """The moniker represent a symbol that is imported into a project""" - Export = "export" - """The moniker represents a symbol that is exported from a project""" - Local = "local" - """The moniker represents a symbol that is local to a project (e.g. a local - variable of a function, a class not visible outside the project, ...)""" - - -@enum.unique -class InlayHintKind(int, enum.Enum): - """Inlay hint kinds. - - @since 3.17.0""" - - # Since: 3.17.0 - Type = 1 - """An inlay hint that for a type annotation.""" - Parameter = 2 - """An inlay hint that is for a parameter.""" - - -@enum.unique -class MessageType(int, enum.Enum): - """The message type""" - - Error = 1 - """An error message.""" - Warning = 2 - """A warning message.""" - Info = 3 - """An information message.""" - Log = 4 - """A log message.""" - Debug = 5 - """A debug message. - - @since 3.18.0""" - # Since: 3.18.0 - - -@enum.unique -class TextDocumentSyncKind(int, enum.Enum): - """Defines how the host (editor) should sync - document changes to the language server.""" - - None_ = 0 - """Documents should not be synced at all.""" - Full = 1 - """Documents are synced by always sending the full content - of the document.""" - Incremental = 2 - """Documents are synced by sending the full content on open. - After that only incremental updates to the document are - send.""" - - -@enum.unique -class TextDocumentSaveReason(int, enum.Enum): - """Represents reasons why a text document is saved.""" - - Manual = 1 - """Manually triggered, e.g. by the user pressing save, by starting debugging, - or by an API call.""" - AfterDelay = 2 - """Automatic after a delay.""" - FocusOut = 3 - """When the editor lost focus.""" - - -@enum.unique -class CompletionItemKind(int, enum.Enum): - """The kind of a completion entry.""" - - Text = 1 - Method = 2 - Function = 3 - Constructor = 4 - Field = 5 - Variable = 6 - Class = 7 - Interface = 8 - Module = 9 - Property = 10 - Unit = 11 - Value = 12 - Enum = 13 - Keyword = 14 - Snippet = 15 - Color = 16 - File = 17 - Reference = 18 - Folder = 19 - EnumMember = 20 - Constant = 21 - Struct = 22 - Event = 23 - Operator = 24 - TypeParameter = 25 - - -@enum.unique -class CompletionItemTag(int, enum.Enum): - """Completion item tags are extra annotations that tweak the rendering of a completion - item. - - @since 3.15.0""" - - # Since: 3.15.0 - Deprecated = 1 - """Render a completion as obsolete, usually using a strike-out.""" - - -@enum.unique -class InsertTextFormat(int, enum.Enum): - """Defines whether the insert text in a completion item should be interpreted as - plain text or a snippet.""" - - PlainText = 1 - """The primary text to be inserted is treated as a plain string.""" - Snippet = 2 - """The primary text to be inserted is treated as a snippet. - - A snippet can define tab stops and placeholders with `$1`, `$2` - and `${3:foo}`. `$0` defines the final tab stop, it defaults to - the end of the snippet. Placeholders with equal identifiers are linked, - that is typing in one will update others too. - - See also: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#snippet_syntax""" - - -@enum.unique -class InsertTextMode(int, enum.Enum): - """How whitespace and indentation is handled during completion - item insertion. - - @since 3.16.0""" - - # Since: 3.16.0 - AsIs = 1 - """The insertion or replace strings is taken as it is. If the - value is multi line the lines below the cursor will be - inserted using the indentation defined in the string value. - The client will not apply any kind of adjustments to the - string.""" - AdjustIndentation = 2 - """The editor adjusts leading whitespace of new lines so that - they match the indentation up to the cursor of the line for - which the item is accepted. - - Consider a line like this: <2tabs><3tabs>foo. Accepting a - multi line completion item is indented using 2 tabs and all - following lines inserted will be indented using 2 tabs as well.""" - - -@enum.unique -class DocumentHighlightKind(int, enum.Enum): - """A document highlight kind.""" - - Text = 1 - """A textual occurrence.""" - Read = 2 - """Read-access of a symbol, like reading a variable.""" - Write = 3 - """Write-access of a symbol, like writing to a variable.""" - - -@enum.unique -class CodeActionKind(str, enum.Enum): - """A set of predefined code action kinds""" - - Empty = "" - """Empty kind.""" - QuickFix = "quickfix" - """Base kind for quickfix actions: 'quickfix'""" - Refactor = "refactor" - """Base kind for refactoring actions: 'refactor'""" - RefactorExtract = "refactor.extract" - """Base kind for refactoring extraction actions: 'refactor.extract' - - Example extract actions: - - - Extract method - - Extract function - - Extract variable - - Extract interface from class - - ...""" - RefactorInline = "refactor.inline" - """Base kind for refactoring inline actions: 'refactor.inline' - - Example inline actions: - - - Inline function - - Inline variable - - Inline constant - - ...""" - RefactorRewrite = "refactor.rewrite" - """Base kind for refactoring rewrite actions: 'refactor.rewrite' - - Example rewrite actions: - - - Convert JavaScript function to class - - Add or remove parameter - - Encapsulate field - - Make method static - - Move method to base class - - ...""" - Source = "source" - """Base kind for source actions: `source` - - Source code actions apply to the entire file.""" - SourceOrganizeImports = "source.organizeImports" - """Base kind for an organize imports source action: `source.organizeImports`""" - SourceFixAll = "source.fixAll" - """Base kind for auto-fix source actions: `source.fixAll`. - - Fix all actions automatically fix errors that have a clear fix that do not require user input. - They should not suppress errors or perform unsafe fixes such as generating new types or classes. - - @since 3.15.0""" - # Since: 3.15.0 - - -@enum.unique -class TraceValues(str, enum.Enum): - Off = "off" - """Turn tracing off.""" - Messages = "messages" - """Trace messages only.""" - Verbose = "verbose" - """Verbose message tracing.""" - - -@enum.unique -class MarkupKind(str, enum.Enum): - """Describes the content type that a client supports in various - result literals like `Hover`, `ParameterInfo` or `CompletionItem`. - - Please note that `MarkupKinds` must not start with a `$`. This kinds - are reserved for internal usage.""" - - PlainText = "plaintext" - """Plain text is supported as a content format""" - Markdown = "markdown" - """Markdown is supported as a content format""" - - -@enum.unique -class InlineCompletionTriggerKind(int, enum.Enum): - """Describes how an {@link InlineCompletionItemProvider inline completion provider} was triggered. - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - Invoked = 0 - """Completion was triggered explicitly by a user gesture.""" - Automatic = 1 - """Completion was triggered automatically while editing.""" - - -@enum.unique -class PositionEncodingKind(str, enum.Enum): - """A set of predefined position encoding kinds. - - @since 3.17.0""" - - # Since: 3.17.0 - Utf8 = "utf-8" - """Character offsets count UTF-8 code units (e.g. bytes).""" - Utf16 = "utf-16" - """Character offsets count UTF-16 code units. - - This is the default and must always be supported - by servers""" - Utf32 = "utf-32" - """Character offsets count UTF-32 code units. - - Implementation note: these are the same as Unicode codepoints, - so this `PositionEncodingKind` may also be used for an - encoding-agnostic representation of character offsets.""" - - -@enum.unique -class FileChangeType(int, enum.Enum): - """The file event type""" - - Created = 1 - """The file got created.""" - Changed = 2 - """The file got changed.""" - Deleted = 3 - """The file got deleted.""" - - -@enum.unique -class WatchKind(int, enum.Enum): - Create = 1 - """Interested in create events.""" - Change = 2 - """Interested in change events""" - Delete = 4 - """Interested in delete events""" - - -@enum.unique -class DiagnosticSeverity(int, enum.Enum): - """The diagnostic's severity.""" - - Error = 1 - """Reports an error.""" - Warning = 2 - """Reports a warning.""" - Information = 3 - """Reports an information.""" - Hint = 4 - """Reports a hint.""" - - -@enum.unique -class DiagnosticTag(int, enum.Enum): - """The diagnostic tags. - - @since 3.15.0""" - - # Since: 3.15.0 - Unnecessary = 1 - """Unused or unnecessary code. - - Clients are allowed to render diagnostics with this tag faded out instead of having - an error squiggle.""" - Deprecated = 2 - """Deprecated or obsolete code. - - Clients are allowed to rendered diagnostics with this tag strike through.""" - - -@enum.unique -class CompletionTriggerKind(int, enum.Enum): - """How a completion was triggered""" - - Invoked = 1 - """Completion was triggered by typing an identifier (24x7 code - complete), manual invocation (e.g Ctrl+Space) or via API.""" - TriggerCharacter = 2 - """Completion was triggered by a trigger character specified by - the `triggerCharacters` properties of the `CompletionRegistrationOptions`.""" - TriggerForIncompleteCompletions = 3 - """Completion was re-triggered as current completion list is incomplete""" - - -@enum.unique -class SignatureHelpTriggerKind(int, enum.Enum): - """How a signature help was triggered. - - @since 3.15.0""" - - # Since: 3.15.0 - Invoked = 1 - """Signature help was invoked manually by the user or by a command.""" - TriggerCharacter = 2 - """Signature help was triggered by a trigger character.""" - ContentChange = 3 - """Signature help was triggered by the cursor moving or by the document content changing.""" - - -@enum.unique -class CodeActionTriggerKind(int, enum.Enum): - """The reason why code actions were requested. - - @since 3.17.0""" - - # Since: 3.17.0 - Invoked = 1 - """Code actions were explicitly requested by the user or by an extension.""" - Automatic = 2 - """Code actions were requested automatically. - - This typically happens when current selection in a file changes, but can - also be triggered when file content changes.""" - - -@enum.unique -class FileOperationPatternKind(str, enum.Enum): - """A pattern kind describing if a glob pattern matches a file a folder or - both. - - @since 3.16.0""" - - # Since: 3.16.0 - File = "file" - """The pattern matches a file only.""" - Folder = "folder" - """The pattern matches a folder only.""" - - -@enum.unique -class NotebookCellKind(int, enum.Enum): - """A notebook cell kind. - - @since 3.17.0""" - - # Since: 3.17.0 - Markup = 1 - """A markup-cell is formatted source that is used for display.""" - Code = 2 - """A code-cell is source code.""" - - -@enum.unique -class ResourceOperationKind(str, enum.Enum): - Create = "create" - """Supports creating new files and folders.""" - Rename = "rename" - """Supports renaming existing files and folders.""" - Delete = "delete" - """Supports deleting existing files and folders.""" - - -@enum.unique -class FailureHandlingKind(str, enum.Enum): - Abort = "abort" - """Applying the workspace change is simply aborted if one of the changes provided - fails. All operations executed before the failing operation stay executed.""" - Transactional = "transactional" - """All operations are executed transactional. That means they either all - succeed or no changes at all are applied to the workspace.""" - TextOnlyTransactional = "textOnlyTransactional" - """If the workspace edit contains only textual file changes they are executed transactional. - If resource changes (create, rename or delete file) are part of the change the failure - handling strategy is abort.""" - Undo = "undo" - """The client tries to undo the operations already executed. But there is no - guarantee that this is succeeding.""" - - -@enum.unique -class PrepareSupportDefaultBehavior(int, enum.Enum): - Identifier = 1 - """The client's default behavior is to select the identifier - according the to language's syntax rule.""" - - -@enum.unique -class TokenFormat(str, enum.Enum): - Relative = "relative" - - -class LSPObject: - """LSP object definition. - @since 3.17.0""" - - # Since: 3.17.0 - pass - - -Definition = Union["Location", List["Location"]] -"""The definition of a symbol represented as one or many {@link Location locations}. -For most programming languages there is only one location at which a symbol is -defined. - -Servers should prefer returning `DefinitionLink` over `Definition` if supported -by the client.""" - - -DefinitionLink = Union["LocationLink", "LocationLink"] -"""Information about where a symbol is defined. - -Provides additional metadata over normal {@link Location location} definitions, including the range of -the defining symbol""" - - -LSPArray = List["LSPAny"] -"""LSP arrays. -@since 3.17.0""" -# Since: 3.17.0 - - -LSPAny = Union[Any, None] -"""The LSP any type. -Please note that strictly speaking a property with the value `undefined` -can't be converted into JSON preserving the property name. However for -convenience it is allowed and assumed that all these properties are -optional as well. -@since 3.17.0""" -# Since: 3.17.0 - - -Declaration = Union["Location", List["Location"]] -"""The declaration of a symbol representation as one or many {@link Location locations}.""" - - -DeclarationLink = Union["LocationLink", "LocationLink"] -"""Information about where a symbol is declared. - -Provides additional metadata over normal {@link Location location} declarations, including the range of -the declaring symbol. - -Servers should prefer returning `DeclarationLink` over `Declaration` if supported -by the client.""" - - -InlineValue = Union[ - "InlineValueText", "InlineValueVariableLookup", "InlineValueEvaluatableExpression" -] -"""Inline value information can be provided by different means: -- directly as a text value (class InlineValueText). -- as a name to use for a variable lookup (class InlineValueVariableLookup) -- as an evaluatable expression (class InlineValueEvaluatableExpression) -The InlineValue types combines all inline value types into one type. - -@since 3.17.0""" -# Since: 3.17.0 - - -DocumentDiagnosticReport = Union[ - "RelatedFullDocumentDiagnosticReport", "RelatedUnchangedDocumentDiagnosticReport" -] -"""The result of a document diagnostic pull request. A report can -either be a full report containing all diagnostics for the -requested document or an unchanged report indicating that nothing -has changed in terms of diagnostics in comparison to the last -pull request. - -@since 3.17.0""" -# Since: 3.17.0 - - -@attrs.define -class PrepareRenameResult_Type1: - range: "Range" = attrs.field() - - placeholder: str = attrs.field(validator=attrs.validators.instance_of(str)) - - -@attrs.define -class PrepareRenameResult_Type2: - default_behavior: bool = attrs.field(validator=attrs.validators.instance_of(bool)) - - -PrepareRenameResult = Union[ - "Range", "PrepareRenameResult_Type1", "PrepareRenameResult_Type2" -] - - -DocumentSelector = List["DocumentFilter"] -"""A document selector is the combination of one or many document filters. - -@sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**/tsconfig.json' }]`; - -The use of a string as a document filter is deprecated @since 3.16.0.""" -# Since: 3.16.0. - - -ProgressToken = Union[int, str] - - -ChangeAnnotationIdentifier = str -"""An identifier to refer to a change annotation stored with a workspace edit.""" - - -WorkspaceDocumentDiagnosticReport = Union[ - "WorkspaceFullDocumentDiagnosticReport", - "WorkspaceUnchangedDocumentDiagnosticReport", -] -"""A workspace diagnostic document report. - -@since 3.17.0""" -# Since: 3.17.0 - - -@attrs.define -class TextDocumentContentChangeEvent_Type1: - range: "Range" = attrs.field() - """The range of the document that changed.""" - - text: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The new text for the provided range.""" - - range_length: Optional[int] = attrs.field( - validator=attrs.validators.optional(validators.uinteger_validator), default=None - ) - """The optional length of the range that got replaced. - - @deprecated use range instead.""" - - -@attrs.define -class TextDocumentContentChangeEvent_Type2: - text: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The new text of the whole document.""" - - -TextDocumentContentChangeEvent = Union[ - "TextDocumentContentChangeEvent_Type1", "TextDocumentContentChangeEvent_Type2" -] -"""An event describing a change to a text document. If only a text is provided -it is considered to be the full content of the document.""" - - -@attrs.define -class MarkedString_Type1: - language: str = attrs.field(validator=attrs.validators.instance_of(str)) - - value: str = attrs.field(validator=attrs.validators.instance_of(str)) - - -MarkedString = Union[str, "MarkedString_Type1"] -"""MarkedString can be used to render human readable text. It is either a markdown string -or a code-block that provides a language and a code snippet. The language identifier -is semantically equal to the optional language identifier in fenced code blocks in GitHub -issues. See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting - -The pair of a language and a value is an equivalent to markdown: -```${language} -${value} -``` - -Note that markdown strings will be sanitized - that means html will be escaped. -@deprecated use MarkupContent instead.""" - - -DocumentFilter = Union["TextDocumentFilter", "NotebookCellTextDocumentFilter"] -"""A document filter describes a top level text document or -a notebook cell document. - -@since 3.17.0 - proposed support for NotebookCellTextDocumentFilter.""" -# Since: 3.17.0 - proposed support for NotebookCellTextDocumentFilter. - - -GlobPattern = Union["Pattern", "RelativePattern"] -"""The glob pattern. Either a string pattern or a relative pattern. - -@since 3.17.0""" -# Since: 3.17.0 - - -@attrs.define -class TextDocumentFilter_Type1: - language: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A language id, like `typescript`.""" - - scheme: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A Uri {@link Uri.scheme scheme}, like `file` or `untitled`.""" - - pattern: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples.""" - - -@attrs.define -class TextDocumentFilter_Type2: - scheme: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A Uri {@link Uri.scheme scheme}, like `file` or `untitled`.""" - - language: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A language id, like `typescript`.""" - - pattern: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples.""" - - -@attrs.define -class TextDocumentFilter_Type3: - pattern: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples.""" - - language: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A language id, like `typescript`.""" - - scheme: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A Uri {@link Uri.scheme scheme}, like `file` or `untitled`.""" - - -TextDocumentFilter = Union[ - "TextDocumentFilter_Type1", "TextDocumentFilter_Type2", "TextDocumentFilter_Type3" -] -"""A document filter denotes a document by different properties like -the {@link TextDocument.languageId language}, the {@link Uri.scheme scheme} of -its resource, or a glob-pattern that is applied to the {@link TextDocument.fileName path}. - -Glob patterns can have the following syntax: -- `*` to match one or more characters in a path segment -- `?` to match on one character in a path segment -- `**` to match any number of path segments, including none -- `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) -- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) -- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) - -@sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }` -@sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }` - -@since 3.17.0""" -# Since: 3.17.0 - - -@attrs.define -class NotebookDocumentFilter_Type1: - notebook_type: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The type of the enclosing notebook.""" - - scheme: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A Uri {@link Uri.scheme scheme}, like `file` or `untitled`.""" - - pattern: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A glob pattern.""" - - -@attrs.define -class NotebookDocumentFilter_Type2: - scheme: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A Uri {@link Uri.scheme scheme}, like `file` or `untitled`.""" - - notebook_type: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The type of the enclosing notebook.""" - - pattern: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A glob pattern.""" - - -@attrs.define -class NotebookDocumentFilter_Type3: - pattern: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A glob pattern.""" - - notebook_type: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The type of the enclosing notebook.""" - - scheme: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A Uri {@link Uri.scheme scheme}, like `file` or `untitled`.""" - - -NotebookDocumentFilter = Union[ - "NotebookDocumentFilter_Type1", - "NotebookDocumentFilter_Type2", - "NotebookDocumentFilter_Type3", -] -"""A notebook document filter denotes a notebook document by -different properties. The properties will be match -against the notebook's URI (same as with documents) - -@since 3.17.0""" -# Since: 3.17.0 - - -Pattern = str -"""The glob pattern to watch relative to the base path. Glob patterns can have the following syntax: -- `*` to match one or more characters in a path segment -- `?` to match on one character in a path segment -- `**` to match any number of path segments, including none -- `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) -- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) -- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) - -@since 3.17.0""" -# Since: 3.17.0 - - -@attrs.define -class TextDocumentPositionParams: - """A parameter literal used in requests to pass a text document and a position inside that - document.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - -@attrs.define -class WorkDoneProgressParams: - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class PartialResultParams: - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class ImplementationParams: - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class Location: - """Represents a location inside a resource, such as a line - inside a text file.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - - range: "Range" = attrs.field() - - def __eq__(self, o: object) -> bool: - if not isinstance(o, Location): - return NotImplemented - return (self.uri == o.uri) and (self.range == o.range) - - def __repr__(self) -> str: - return f"{self.uri}:{self.range!r}" - - -@attrs.define -class TextDocumentRegistrationOptions: - """General text document registration options.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - -@attrs.define -class WorkDoneProgressOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class ImplementationOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class StaticRegistrationOptions: - """Static registration options to be returned in the initialize - request.""" - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class ImplementationRegistrationOptions: - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class TypeDefinitionParams: - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class TypeDefinitionOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class TypeDefinitionRegistrationOptions: - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class WorkspaceFolder: - """A workspace folder inside a client.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The associated URI for this workspace folder.""" - - name: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The name of the workspace folder. Used to refer to this - workspace folder in the user interface.""" - - -@attrs.define -class DidChangeWorkspaceFoldersParams: - """The parameters of a `workspace/didChangeWorkspaceFolders` notification.""" - - event: "WorkspaceFoldersChangeEvent" = attrs.field() - """The actual workspace folder change event.""" - - -@attrs.define -class ConfigurationParams: - """The parameters of a configuration request.""" - - items: List["ConfigurationItem"] = attrs.field() - - -@attrs.define -class DocumentColorParams: - """Parameters for a {@link DocumentColorRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class ColorInformation: - """Represents a color range from a document.""" - - range: "Range" = attrs.field() - """The range in the document where this color appears.""" - - color: "Color" = attrs.field() - """The actual color value for this color range.""" - - -@attrs.define -class DocumentColorOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentColorRegistrationOptions: - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class ColorPresentationParams: - """Parameters for a {@link ColorPresentationRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - color: "Color" = attrs.field() - """The color to request presentations for.""" - - range: "Range" = attrs.field() - """The range where the color would be inserted. Serves as a context.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class ColorPresentation: - label: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The label of this color presentation. It will be shown on the color - picker header. By default this is also the text that is inserted when selecting - this color presentation.""" - - text_edit: Optional["TextEdit"] = attrs.field(default=None) - """An {@link TextEdit edit} which is applied to a document when selecting - this presentation for the color. When `falsy` the {@link ColorPresentation.label label} - is used.""" - - additional_text_edits: Optional[List["TextEdit"]] = attrs.field(default=None) - """An optional array of additional {@link TextEdit text edits} that are applied when - selecting this color presentation. Edits must not overlap with the main {@link ColorPresentation.textEdit edit} nor with themselves.""" - - -@attrs.define -class FoldingRangeParams: - """Parameters for a {@link FoldingRangeRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class FoldingRange: - """Represents a folding range. To be valid, start and end line must be bigger than zero and smaller - than the number of lines in the document. Clients are free to ignore invalid ranges. - """ - - start_line: int = attrs.field(validator=validators.uinteger_validator) - """The zero-based start line of the range to fold. The folded area starts after the line's last character. - To be valid, the end must be zero or larger and smaller than the number of lines in the document.""" - - end_line: int = attrs.field(validator=validators.uinteger_validator) - """The zero-based end line of the range to fold. The folded area ends with the line's last character. - To be valid, the end must be zero or larger and smaller than the number of lines in the document.""" - - start_character: Optional[int] = attrs.field( - validator=attrs.validators.optional(validators.uinteger_validator), default=None - ) - """The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line.""" - - end_character: Optional[int] = attrs.field( - validator=attrs.validators.optional(validators.uinteger_validator), default=None - ) - """The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line.""" - - kind: Optional[Union[FoldingRangeKind, str]] = attrs.field(default=None) - """Describes the kind of the folding range such as `comment' or 'region'. The kind - is used to categorize folding ranges and used by commands like 'Fold all comments'. - See {@link FoldingRangeKind} for an enumeration of standardized kinds.""" - - collapsed_text: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The text that the client should show when the specified range is - collapsed. If not defined or not supported by the client, a default - will be chosen by the client. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class FoldingRangeOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class FoldingRangeRegistrationOptions: - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class DeclarationParams: - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class DeclarationOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DeclarationRegistrationOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class SelectionRangeParams: - """A parameter literal used in selection range requests.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - positions: List["Position"] = attrs.field() - """The positions inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class SelectionRange: - """A selection range represents a part of a selection hierarchy. A selection range - may have a parent selection range that contains it.""" - - range: "Range" = attrs.field() - """The {@link Range range} of this selection range.""" - - parent: Optional["SelectionRange"] = attrs.field(default=None) - """The parent selection range containing this range. Therefore `parent.range` must contain `this.range`.""" - - -@attrs.define -class SelectionRangeOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class SelectionRangeRegistrationOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class WorkDoneProgressCreateParams: - token: ProgressToken = attrs.field() - """The token to be used to report progress.""" - - -@attrs.define -class WorkDoneProgressCancelParams: - token: ProgressToken = attrs.field() - """The token to be used to report progress.""" - - -@attrs.define -class CallHierarchyPrepareParams: - """The parameter of a `textDocument/prepareCallHierarchy` request. - - @since 3.16.0""" - - # Since: 3.16.0 - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class CallHierarchyItem: - """Represents programming constructs like functions or constructors in the context - of call hierarchy. - - @since 3.16.0""" - - # Since: 3.16.0 - - name: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The name of this item.""" - - kind: SymbolKind = attrs.field() - """The kind of this item.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The resource identifier of this item.""" - - range: "Range" = attrs.field() - """The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code.""" - - selection_range: "Range" = attrs.field() - """The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. - Must be contained by the {@link CallHierarchyItem.range `range`}.""" - - tags: Optional[List[SymbolTag]] = attrs.field(default=None) - """Tags for this item.""" - - detail: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """More detail for this item, e.g. the signature of a function.""" - - data: Optional[LSPAny] = attrs.field(default=None) - """A data entry field that is preserved between a call hierarchy prepare and - incoming calls or outgoing calls requests.""" - - -@attrs.define -class CallHierarchyOptions: - """Call hierarchy options used during static registration. - - @since 3.16.0""" - - # Since: 3.16.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class CallHierarchyRegistrationOptions: - """Call hierarchy options used during static or dynamic registration. - - @since 3.16.0""" - - # Since: 3.16.0 - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class CallHierarchyIncomingCallsParams: - """The parameter of a `callHierarchy/incomingCalls` request. - - @since 3.16.0""" - - # Since: 3.16.0 - - item: CallHierarchyItem = attrs.field() - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class CallHierarchyIncomingCall: - """Represents an incoming call, e.g. a caller of a method or constructor. - - @since 3.16.0""" - - # Since: 3.16.0 - - from_: CallHierarchyItem = attrs.field() - """The item that makes the call.""" - - from_ranges: List["Range"] = attrs.field() - """The ranges at which the calls appear. This is relative to the caller - denoted by {@link CallHierarchyIncomingCall.from `this.from`}.""" - - -@attrs.define -class CallHierarchyOutgoingCallsParams: - """The parameter of a `callHierarchy/outgoingCalls` request. - - @since 3.16.0""" - - # Since: 3.16.0 - - item: CallHierarchyItem = attrs.field() - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class CallHierarchyOutgoingCall: - """Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc. - - @since 3.16.0""" - - # Since: 3.16.0 - - to: CallHierarchyItem = attrs.field() - """The item that is called.""" - - from_ranges: List["Range"] = attrs.field() - """The range at which this item is called. This is the range relative to the caller, e.g the item - passed to {@link CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls `provideCallHierarchyOutgoingCalls`} - and not {@link CallHierarchyOutgoingCall.to `this.to`}.""" - - -@attrs.define -class SemanticTokensParams: - """@since 3.16.0""" - - # Since: 3.16.0 - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class SemanticTokens: - """@since 3.16.0""" - - # Since: 3.16.0 - - data: List[int] = attrs.field() - """The actual tokens.""" - - result_id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """An optional result id. If provided and clients support delta updating - the client will include the result id in the next semantic token request. - A server can then instead of computing all semantic tokens again simply - send a delta.""" - - -@attrs.define -class SemanticTokensPartialResult: - """@since 3.16.0""" - - # Since: 3.16.0 - - data: List[int] = attrs.field() - - -@attrs.define -class SemanticTokensOptionsFullType1: - delta: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server supports deltas for full documents.""" - - -@attrs.define -class SemanticTokensOptions: - """@since 3.16.0""" - - # Since: 3.16.0 - - legend: "SemanticTokensLegend" = attrs.field() - """The legend used by the server""" - - range: Optional[Union[bool, Any]] = attrs.field(default=None) - """Server supports providing semantic tokens for a specific range - of a document.""" - - full: Optional[Union[bool, "SemanticTokensOptionsFullType1"]] = attrs.field( - default=None - ) - """Server supports providing semantic tokens for a full document.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class SemanticTokensRegistrationOptionsFullType1: - delta: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server supports deltas for full documents.""" - - -@attrs.define -class SemanticTokensRegistrationOptions: - """@since 3.16.0""" - - # Since: 3.16.0 - - legend: "SemanticTokensLegend" = attrs.field() - """The legend used by the server""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - range: Optional[Union[bool, Any]] = attrs.field(default=None) - """Server supports providing semantic tokens for a specific range - of a document.""" - - full: Optional[ - Union[bool, "SemanticTokensRegistrationOptionsFullType1"] - ] = attrs.field(default=None) - """Server supports providing semantic tokens for a full document.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class SemanticTokensDeltaParams: - """@since 3.16.0""" - - # Since: 3.16.0 - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - previous_result_id: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The result id of a previous response. The result Id can either point to a full response - or a delta response depending on what was received last.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class SemanticTokensDelta: - """@since 3.16.0""" - - # Since: 3.16.0 - - edits: List["SemanticTokensEdit"] = attrs.field() - """The semantic token edits to transform a previous result into a new result.""" - - result_id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - - -@attrs.define -class SemanticTokensDeltaPartialResult: - """@since 3.16.0""" - - # Since: 3.16.0 - - edits: List["SemanticTokensEdit"] = attrs.field() - - -@attrs.define -class SemanticTokensRangeParams: - """@since 3.16.0""" - - # Since: 3.16.0 - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - range: "Range" = attrs.field() - """The range the semantic tokens are requested for.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class ShowDocumentParams: - """Params to show a resource in the UI. - - @since 3.16.0""" - - # Since: 3.16.0 - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The uri to show.""" - - external: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Indicates to show the resource in an external program. - To show, for example, `https://code.visualstudio.com/` - in the default WEB browser set `external` to `true`.""" - - take_focus: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """An optional property to indicate whether the editor - showing the document should take focus or not. - Clients might ignore this property if an external - program is started.""" - - selection: Optional["Range"] = attrs.field(default=None) - """An optional selection range if the document is a text - document. Clients might ignore the property if an - external program is started or the file is not a text - file.""" - - -@attrs.define -class ShowDocumentResult: - """The result of a showDocument request. - - @since 3.16.0""" - - # Since: 3.16.0 - - success: bool = attrs.field(validator=attrs.validators.instance_of(bool)) - """A boolean indicating if the show was successful.""" - - -@attrs.define -class LinkedEditingRangeParams: - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class LinkedEditingRanges: - """The result of a linked editing range request. - - @since 3.16.0""" - - # Since: 3.16.0 - - ranges: List["Range"] = attrs.field() - """A list of ranges that can be edited together. The ranges must have - identical length and contain identical text content. The ranges cannot overlap.""" - - word_pattern: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """An optional word pattern (regular expression) that describes valid contents for - the given ranges. If no pattern is provided, the client configuration's word - pattern will be used.""" - - -@attrs.define -class LinkedEditingRangeOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class LinkedEditingRangeRegistrationOptions: - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class CreateFilesParams: - """The parameters sent in notifications/requests for user-initiated creation of - files. - - @since 3.16.0""" - - # Since: 3.16.0 - - files: List["FileCreate"] = attrs.field() - """An array of all files/folders created in this operation.""" - - -@attrs.define -class WorkspaceEdit: - """A workspace edit represents changes to many resources managed in the workspace. The edit - should either provide `changes` or `documentChanges`. If documentChanges are present - they are preferred over `changes` if the client can handle versioned document edits. - - Since version 3.13.0 a workspace edit can contain resource operations as well. If resource - operations are present clients need to execute the operations in the order in which they - are provided. So a workspace edit for example can consist of the following two changes: - (1) a create file a.txt and (2) a text document edit which insert text into file a.txt. - - An invalid sequence (e.g. (1) delete file a.txt and (2) insert text into file a.txt) will - cause failure of the operation. How the client recovers from the failure is described by - the client capability: `workspace.workspaceEdit.failureHandling`""" - - changes: Optional[Dict[str, List["TextEdit"]]] = attrs.field(default=None) - """Holds changes to existing resources.""" - - document_changes: Optional[ - List[Union["TextDocumentEdit", "CreateFile", "RenameFile", "DeleteFile"]] - ] = attrs.field(default=None) - """Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes - are either an array of `TextDocumentEdit`s to express changes to n different text documents - where each text document edit addresses a specific version of a text document. Or it can contain - above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. - - Whether a client supports versioned document edits is expressed via - `workspace.workspaceEdit.documentChanges` client capability. - - If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then - only plain `TextEdit`s using the `changes` property are supported.""" - - change_annotations: Optional[ - Dict[ChangeAnnotationIdentifier, "ChangeAnnotation"] - ] = attrs.field(default=None) - """A map of change annotations that can be referenced in `AnnotatedTextEdit`s or create, rename and - delete file / folder operations. - - Whether clients honor this property depends on the client capability `workspace.changeAnnotationSupport`. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class FileOperationRegistrationOptions: - """The options to register for file operations. - - @since 3.16.0""" - - # Since: 3.16.0 - - filters: List["FileOperationFilter"] = attrs.field() - """The actual filters.""" - - -@attrs.define -class RenameFilesParams: - """The parameters sent in notifications/requests for user-initiated renames of - files. - - @since 3.16.0""" - - # Since: 3.16.0 - - files: List["FileRename"] = attrs.field() - """An array of all files/folders renamed in this operation. When a folder is renamed, only - the folder will be included, and not its children.""" - - -@attrs.define -class DeleteFilesParams: - """The parameters sent in notifications/requests for user-initiated deletes of - files. - - @since 3.16.0""" - - # Since: 3.16.0 - - files: List["FileDelete"] = attrs.field() - """An array of all files/folders deleted in this operation.""" - - -@attrs.define -class MonikerParams: - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class Moniker: - """Moniker definition to match LSIF 0.5 moniker definition. - - @since 3.16.0""" - - # Since: 3.16.0 - - scheme: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The scheme of the moniker. For example tsc or .Net""" - - identifier: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The identifier of the moniker. The value is opaque in LSIF however - schema owners are allowed to define the structure if they want.""" - - unique: UniquenessLevel = attrs.field() - """The scope in which the moniker is unique""" - - kind: Optional[MonikerKind] = attrs.field(default=None) - """The moniker kind if known.""" - - -@attrs.define -class MonikerOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class MonikerRegistrationOptions: - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class TypeHierarchyPrepareParams: - """The parameter of a `textDocument/prepareTypeHierarchy` request. - - @since 3.17.0""" - - # Since: 3.17.0 - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class TypeHierarchyItem: - """@since 3.17.0""" - - # Since: 3.17.0 - - name: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The name of this item.""" - - kind: SymbolKind = attrs.field() - """The kind of this item.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The resource identifier of this item.""" - - range: "Range" = attrs.field() - """The range enclosing this symbol not including leading/trailing whitespace - but everything else, e.g. comments and code.""" - - selection_range: "Range" = attrs.field() - """The range that should be selected and revealed when this symbol is being - picked, e.g. the name of a function. Must be contained by the - {@link TypeHierarchyItem.range `range`}.""" - - tags: Optional[List[SymbolTag]] = attrs.field(default=None) - """Tags for this item.""" - - detail: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """More detail for this item, e.g. the signature of a function.""" - - data: Optional[LSPAny] = attrs.field(default=None) - """A data entry field that is preserved between a type hierarchy prepare and - supertypes or subtypes requests. It could also be used to identify the - type hierarchy in the server, helping improve the performance on - resolving supertypes and subtypes.""" - - -@attrs.define -class TypeHierarchyOptions: - """Type hierarchy options used during static registration. - - @since 3.17.0""" - - # Since: 3.17.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class TypeHierarchyRegistrationOptions: - """Type hierarchy options used during static or dynamic registration. - - @since 3.17.0""" - - # Since: 3.17.0 - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class TypeHierarchySupertypesParams: - """The parameter of a `typeHierarchy/supertypes` request. - - @since 3.17.0""" - - # Since: 3.17.0 - - item: TypeHierarchyItem = attrs.field() - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class TypeHierarchySubtypesParams: - """The parameter of a `typeHierarchy/subtypes` request. - - @since 3.17.0""" - - # Since: 3.17.0 - - item: TypeHierarchyItem = attrs.field() - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class InlineValueParams: - """A parameter literal used in inline value requests. - - @since 3.17.0""" - - # Since: 3.17.0 - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - range: "Range" = attrs.field() - """The document range for which inline values should be computed.""" - - context: "InlineValueContext" = attrs.field() - """Additional information about the context in which inline values were - requested.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class InlineValueOptions: - """Inline value options used during static registration. - - @since 3.17.0""" - - # Since: 3.17.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class InlineValueRegistrationOptions: - """Inline value options used during static or dynamic registration. - - @since 3.17.0""" - - # Since: 3.17.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class InlayHintParams: - """A parameter literal used in inlay hint requests. - - @since 3.17.0""" - - # Since: 3.17.0 - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - range: "Range" = attrs.field() - """The document range for which inlay hints should be computed.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class InlayHint: - """Inlay hint information. - - @since 3.17.0""" - - # Since: 3.17.0 - - position: "Position" = attrs.field() - """The position of this hint.""" - - label: Union[str, List["InlayHintLabelPart"]] = attrs.field() - """The label of this hint. A human readable string or an array of - InlayHintLabelPart label parts. - - *Note* that neither the string nor the label part can be empty.""" - - kind: Optional[InlayHintKind] = attrs.field(default=None) - """The kind of this hint. Can be omitted in which case the client - should fall back to a reasonable default.""" - - text_edits: Optional[List["TextEdit"]] = attrs.field(default=None) - """Optional text edits that are performed when accepting this inlay hint. - - *Note* that edits are expected to change the document so that the inlay - hint (or its nearest variant) is now part of the document and the inlay - hint itself is now obsolete.""" - - tooltip: Optional[Union[str, "MarkupContent"]] = attrs.field(default=None) - """The tooltip text when you hover over this item.""" - - padding_left: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Render padding before the hint. - - Note: Padding should use the editor's background color, not the - background color of the hint itself. That means padding can be used - to visually align/separate an inlay hint.""" - - padding_right: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Render padding after the hint. - - Note: Padding should use the editor's background color, not the - background color of the hint itself. That means padding can be used - to visually align/separate an inlay hint.""" - - data: Optional[LSPAny] = attrs.field(default=None) - """A data entry field that is preserved on an inlay hint between - a `textDocument/inlayHint` and a `inlayHint/resolve` request.""" - - -@attrs.define -class InlayHintOptions: - """Inlay hint options used during static registration. - - @since 3.17.0""" - - # Since: 3.17.0 - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server provides support to resolve additional - information for an inlay hint item.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class InlayHintRegistrationOptions: - """Inlay hint options used during static or dynamic registration. - - @since 3.17.0""" - - # Since: 3.17.0 - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server provides support to resolve additional - information for an inlay hint item.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class DocumentDiagnosticParams: - """Parameters of the document diagnostic request. - - @since 3.17.0""" - - # Since: 3.17.0 - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - identifier: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The additional identifier provided during registration.""" - - previous_result_id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The result id of a previous response if provided.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class DocumentDiagnosticReportPartialResult: - """A partial result for a document diagnostic report. - - @since 3.17.0""" - - # Since: 3.17.0 - - related_documents: Dict[ - str, Union["FullDocumentDiagnosticReport", "UnchangedDocumentDiagnosticReport"] - ] = attrs.field() - - -@attrs.define -class DiagnosticServerCancellationData: - """Cancellation data returned from a diagnostic request. - - @since 3.17.0""" - - # Since: 3.17.0 - - retrigger_request: bool = attrs.field(validator=attrs.validators.instance_of(bool)) - - -@attrs.define -class DiagnosticOptions: - """Diagnostic options. - - @since 3.17.0""" - - # Since: 3.17.0 - - inter_file_dependencies: bool = attrs.field( - validator=attrs.validators.instance_of(bool) - ) - """Whether the language has inter file dependencies meaning that - editing code in one file can result in a different diagnostic - set in another file. Inter file dependencies are common for - most programming languages and typically uncommon for linters.""" - - workspace_diagnostics: bool = attrs.field( - validator=attrs.validators.instance_of(bool) - ) - """The server provides support for workspace diagnostics as well.""" - - identifier: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """An optional identifier under which the diagnostics are - managed by the client.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DiagnosticRegistrationOptions: - """Diagnostic registration options. - - @since 3.17.0""" - - # Since: 3.17.0 - - inter_file_dependencies: bool = attrs.field( - validator=attrs.validators.instance_of(bool) - ) - """Whether the language has inter file dependencies meaning that - editing code in one file can result in a different diagnostic - set in another file. Inter file dependencies are common for - most programming languages and typically uncommon for linters.""" - - workspace_diagnostics: bool = attrs.field( - validator=attrs.validators.instance_of(bool) - ) - """The server provides support for workspace diagnostics as well.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - identifier: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """An optional identifier under which the diagnostics are - managed by the client.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class WorkspaceDiagnosticParams: - """Parameters of the workspace diagnostic request. - - @since 3.17.0""" - - # Since: 3.17.0 - - previous_result_ids: List["PreviousResultId"] = attrs.field() - """The currently known diagnostic reports with their - previous result ids.""" - - identifier: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The additional identifier provided during registration.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class WorkspaceDiagnosticReport: - """A workspace diagnostic report. - - @since 3.17.0""" - - # Since: 3.17.0 - - items: List[WorkspaceDocumentDiagnosticReport] = attrs.field() - - -@attrs.define -class WorkspaceDiagnosticReportPartialResult: - """A partial result for a workspace diagnostic report. - - @since 3.17.0""" - - # Since: 3.17.0 - - items: List[WorkspaceDocumentDiagnosticReport] = attrs.field() - - -@attrs.define -class DidOpenNotebookDocumentParams: - """The params sent in an open notebook document notification. - - @since 3.17.0""" - - # Since: 3.17.0 - - notebook_document: "NotebookDocument" = attrs.field() - """The notebook document that got opened.""" - - cell_text_documents: List["TextDocumentItem"] = attrs.field() - """The text documents that represent the content - of a notebook cell.""" - - -@attrs.define -class DidChangeNotebookDocumentParams: - """The params sent in a change notebook document notification. - - @since 3.17.0""" - - # Since: 3.17.0 - - notebook_document: "VersionedNotebookDocumentIdentifier" = attrs.field() - """The notebook document that did change. The version number points - to the version after all provided changes have been applied. If - only the text document content of a cell changes the notebook version - doesn't necessarily have to change.""" - - change: "NotebookDocumentChangeEvent" = attrs.field() - """The actual changes to the notebook document. - - The changes describe single state changes to the notebook document. - So if there are two changes c1 (at array index 0) and c2 (at array - index 1) for a notebook in state S then c1 moves the notebook from - S to S' and c2 from S' to S''. So c1 is computed on the state S and - c2 is computed on the state S'. - - To mirror the content of a notebook using change events use the following approach: - - start with the same initial content - - apply the 'notebookDocument/didChange' notifications in the order you receive them. - - apply the `NotebookChangeEvent`s in a single notification in the order - you receive them.""" - - -@attrs.define -class DidSaveNotebookDocumentParams: - """The params sent in a save notebook document notification. - - @since 3.17.0""" - - # Since: 3.17.0 - - notebook_document: "NotebookDocumentIdentifier" = attrs.field() - """The notebook document that got saved.""" - - -@attrs.define -class DidCloseNotebookDocumentParams: - """The params sent in a close notebook document notification. - - @since 3.17.0""" - - # Since: 3.17.0 - - notebook_document: "NotebookDocumentIdentifier" = attrs.field() - """The notebook document that got closed.""" - - cell_text_documents: List["TextDocumentIdentifier"] = attrs.field() - """The text documents that represent the content - of a notebook cell that got closed.""" - - -@attrs.define -class InlineCompletionParams: - """A parameter literal used in inline completion requests. - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - - context: "InlineCompletionContext" = attrs.field() - """Additional information about the context in which inline completions were - requested.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class InlineCompletionList: - """Represents a collection of {@link InlineCompletionItem inline completion items} to be presented in the editor. - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - - items: List["InlineCompletionItem"] = attrs.field() - """The inline completion items""" - - -@attrs.define -class InlineCompletionItem: - """An inline completion item represents a text snippet that is proposed inline to complete text that is being typed. - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - - insert_text: Union[str, "StringValue"] = attrs.field() - """The text to replace the range with. Must be set.""" - - filter_text: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A text that is used to decide if this inline completion should be shown. When `falsy` the {@link InlineCompletionItem.insertText} is used.""" - - range: Optional["Range"] = attrs.field(default=None) - """The range to replace. Must begin and end on the same line.""" - - command: Optional["Command"] = attrs.field(default=None) - """An optional {@link Command} that is executed *after* inserting this completion.""" - - -@attrs.define -class InlineCompletionOptions: - """Inline completion options used during static registration. - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class InlineCompletionRegistrationOptions: - """Inline completion options used during static or dynamic registration. - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class RegistrationParams: - registrations: List["Registration"] = attrs.field() - - -@attrs.define -class UnregistrationParams: - unregisterations: List["Unregistration"] = attrs.field() - - -@attrs.define -class InitializeParamsClientInfoType: - name: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The name of the client as defined by the client.""" - - version: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The client's version as defined by the client.""" - - -@attrs.define -class _InitializeParams: - """The initialize parameters""" - - capabilities: "ClientCapabilities" = attrs.field() - """The capabilities provided by the client (editor or tool)""" - - process_id: Optional[Union[int, None]] = attrs.field(default=None) - """The process Id of the parent process that started - the server. - - Is `null` if the process has not been started by another process. - If the parent process is not alive then the server should exit.""" - - client_info: Optional["InitializeParamsClientInfoType"] = attrs.field(default=None) - """Information about the client - - @since 3.15.0""" - # Since: 3.15.0 - - locale: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The locale the client is currently showing the user interface - in. This must not necessarily be the locale of the operating - system. - - Uses IETF language tags as the value's syntax - (See https://en.wikipedia.org/wiki/IETF_language_tag) - - @since 3.16.0""" - # Since: 3.16.0 - - root_path: Optional[Union[str, None]] = attrs.field(default=None) - """The rootPath of the workspace. Is null - if no folder is open. - - @deprecated in favour of rootUri.""" - - root_uri: Optional[Union[str, None]] = attrs.field(default=None) - """The rootUri of the workspace. Is null if no - folder is open. If both `rootPath` and `rootUri` are set - `rootUri` wins. - - @deprecated in favour of workspaceFolders.""" - - initialization_options: Optional[LSPAny] = attrs.field(default=None) - """User provided initialization options.""" - - trace: Optional[TraceValues] = attrs.field(default=None) - """The initial trace setting. If omitted trace is disabled ('off').""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class WorkspaceFoldersInitializeParams: - workspace_folders: Optional[Union[List[WorkspaceFolder], None]] = attrs.field( - default=None - ) - """The workspace folders configured in the client when the server starts. - - This property is only available if the client supports workspace folders. - It can be `null` if the client supports workspace folders but none are - configured. - - @since 3.6.0""" - # Since: 3.6.0 - - -@attrs.define -class InitializeParams: - capabilities: "ClientCapabilities" = attrs.field() - """The capabilities provided by the client (editor or tool)""" - - process_id: Optional[Union[int, None]] = attrs.field(default=None) - """The process Id of the parent process that started - the server. - - Is `null` if the process has not been started by another process. - If the parent process is not alive then the server should exit.""" - - client_info: Optional["InitializeParamsClientInfoType"] = attrs.field(default=None) - """Information about the client - - @since 3.15.0""" - # Since: 3.15.0 - - locale: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The locale the client is currently showing the user interface - in. This must not necessarily be the locale of the operating - system. - - Uses IETF language tags as the value's syntax - (See https://en.wikipedia.org/wiki/IETF_language_tag) - - @since 3.16.0""" - # Since: 3.16.0 - - root_path: Optional[Union[str, None]] = attrs.field(default=None) - """The rootPath of the workspace. Is null - if no folder is open. - - @deprecated in favour of rootUri.""" - - root_uri: Optional[Union[str, None]] = attrs.field(default=None) - """The rootUri of the workspace. Is null if no - folder is open. If both `rootPath` and `rootUri` are set - `rootUri` wins. - - @deprecated in favour of workspaceFolders.""" - - initialization_options: Optional[LSPAny] = attrs.field(default=None) - """User provided initialization options.""" - - trace: Optional[TraceValues] = attrs.field(default=None) - """The initial trace setting. If omitted trace is disabled ('off').""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - workspace_folders: Optional[Union[List[WorkspaceFolder], None]] = attrs.field( - default=None - ) - """The workspace folders configured in the client when the server starts. - - This property is only available if the client supports workspace folders. - It can be `null` if the client supports workspace folders but none are - configured. - - @since 3.6.0""" - # Since: 3.6.0 - - -@attrs.define -class InitializeResultServerInfoType: - name: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The name of the server as defined by the server.""" - - version: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The server's version as defined by the server.""" - - -@attrs.define -class InitializeResult: - """The result returned from an initialize request.""" - - capabilities: "ServerCapabilities" = attrs.field() - """The capabilities the language server provides.""" - - server_info: Optional["InitializeResultServerInfoType"] = attrs.field(default=None) - """Information about the server. - - @since 3.15.0""" - # Since: 3.15.0 - - -@attrs.define -class InitializeError: - """The data type of the ResponseError if the - initialize request fails.""" - - retry: bool = attrs.field(validator=attrs.validators.instance_of(bool)) - """Indicates whether the client execute the following retry logic: - (1) show the message provided by the ResponseError to the user - (2) user selects retry or cancel - (3) if user selected retry the initialize method is sent again.""" - - -@attrs.define -class InitializedParams: - pass - - -@attrs.define -class DidChangeConfigurationParams: - """The parameters of a change configuration notification.""" - - settings: LSPAny = attrs.field() - """The actual changed settings""" - - -@attrs.define -class DidChangeConfigurationRegistrationOptions: - section: Optional[Union[str, List[str]]] = attrs.field(default=None) - - -@attrs.define -class ShowMessageParams: - """The parameters of a notification message.""" - - type: MessageType = attrs.field() - """The message type. See {@link MessageType}""" - - message: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The actual message.""" - - -@attrs.define -class ShowMessageRequestParams: - type: MessageType = attrs.field() - """The message type. See {@link MessageType}""" - - message: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The actual message.""" - - actions: Optional[List["MessageActionItem"]] = attrs.field(default=None) - """The message action items to present.""" - - -@attrs.define -class MessageActionItem: - title: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A short title like 'Retry', 'Open Log' etc.""" - - -@attrs.define -class LogMessageParams: - """The log message parameters.""" - - type: MessageType = attrs.field() - """The message type. See {@link MessageType}""" - - message: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The actual message.""" - - -@attrs.define -class DidOpenTextDocumentParams: - """The parameters sent in an open text document notification""" - - text_document: "TextDocumentItem" = attrs.field() - """The document that was opened.""" - - -@attrs.define -class DidChangeTextDocumentParams: - """The change text document notification's parameters.""" - - text_document: "VersionedTextDocumentIdentifier" = attrs.field() - """The document that did change. The version number points - to the version after all provided content changes have - been applied.""" - - content_changes: List[TextDocumentContentChangeEvent] = attrs.field() - """The actual content changes. The content changes describe single state changes - to the document. So if there are two content changes c1 (at array index 0) and - c2 (at array index 1) for a document in state S then c1 moves the document from - S to S' and c2 from S' to S''. So c1 is computed on the state S and c2 is computed - on the state S'. - - To mirror the content of a document using change events use the following approach: - - start with the same initial content - - apply the 'textDocument/didChange' notifications in the order you receive them. - - apply the `TextDocumentContentChangeEvent`s in a single notification in the order - you receive them.""" - - -@attrs.define -class TextDocumentChangeRegistrationOptions: - """Describe options to be used when registered for text document change events.""" - - sync_kind: TextDocumentSyncKind = attrs.field() - """How documents are synced to the server.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - -@attrs.define -class DidCloseTextDocumentParams: - """The parameters sent in a close text document notification""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The document that was closed.""" - - -@attrs.define -class DidSaveTextDocumentParams: - """The parameters sent in a save text document notification""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The document that was saved.""" - - text: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """Optional the content when saved. Depends on the includeText value - when the save notification was requested.""" - - -@attrs.define -class SaveOptions: - """Save options.""" - - include_text: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client is supposed to include the content on save.""" - - -@attrs.define -class TextDocumentSaveRegistrationOptions: - """Save registration options.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - include_text: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client is supposed to include the content on save.""" - - -@attrs.define -class WillSaveTextDocumentParams: - """The parameters sent in a will save text document notification.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The document that will be saved.""" - - reason: TextDocumentSaveReason = attrs.field() - """The 'TextDocumentSaveReason'.""" - - -@attrs.define -class TextEdit: - """A text edit applicable to a text document.""" - - range: "Range" = attrs.field() - """The range of the text document to be manipulated. To insert - text into a document create a range where start === end.""" - - new_text: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The string to be inserted. For delete operations use an - empty string.""" - - -@attrs.define -class DidChangeWatchedFilesParams: - """The watched files change notification's parameters.""" - - changes: List["FileEvent"] = attrs.field() - """The actual file events.""" - - -@attrs.define -class DidChangeWatchedFilesRegistrationOptions: - """Describe options to be used when registered for text document change events.""" - - watchers: List["FileSystemWatcher"] = attrs.field() - """The watchers to register.""" - - -@attrs.define -class PublishDiagnosticsParams: - """The publish diagnostic notification's parameters.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The URI for which diagnostic information is reported.""" - - diagnostics: List["Diagnostic"] = attrs.field() - """An array of diagnostic information items.""" - - version: Optional[int] = attrs.field( - validator=attrs.validators.optional(validators.integer_validator), default=None - ) - """Optional the version number of the document the diagnostics are published for. - - @since 3.15.0""" - # Since: 3.15.0 - - -@attrs.define -class CompletionParams: - """Completion parameters""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - context: Optional["CompletionContext"] = attrs.field(default=None) - """The completion context. This is only available it the client specifies - to send this using the client capability `textDocument.completion.contextSupport === true`""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class CompletionItem: - """A completion item represents a text snippet that is - proposed to complete text that is being typed.""" - - label: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The label of this completion item. - - The label property is also by default the text that - is inserted when selecting this completion. - - If label details are provided the label itself should - be an unqualified name of the completion item.""" - - label_details: Optional["CompletionItemLabelDetails"] = attrs.field(default=None) - """Additional details for the label - - @since 3.17.0""" - # Since: 3.17.0 - - kind: Optional[CompletionItemKind] = attrs.field(default=None) - """The kind of this completion item. Based of the kind - an icon is chosen by the editor.""" - - tags: Optional[List[CompletionItemTag]] = attrs.field(default=None) - """Tags for this completion item. - - @since 3.15.0""" - # Since: 3.15.0 - - detail: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A human-readable string with additional information - about this item, like type or symbol information.""" - - documentation: Optional[Union[str, "MarkupContent"]] = attrs.field(default=None) - """A human-readable string that represents a doc-comment.""" - - deprecated: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Indicates if this item is deprecated. - @deprecated Use `tags` instead.""" - - preselect: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Select this item when showing. - - *Note* that only one completion item can be selected and that the - tool / client decides which item that is. The rule is that the *first* - item of those that match best is selected.""" - - sort_text: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A string that should be used when comparing this item - with other items. When `falsy` the {@link CompletionItem.label label} - is used.""" - - filter_text: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A string that should be used when filtering a set of - completion items. When `falsy` the {@link CompletionItem.label label} - is used.""" - - insert_text: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A string that should be inserted into a document when selecting - this completion. When `falsy` the {@link CompletionItem.label label} - is used. - - The `insertText` is subject to interpretation by the client side. - Some tools might not take the string literally. For example - VS Code when code complete is requested in this example - `con` and a completion item with an `insertText` of - `console` is provided it will only insert `sole`. Therefore it is - recommended to use `textEdit` instead since it avoids additional client - side interpretation.""" - - insert_text_format: Optional[InsertTextFormat] = attrs.field(default=None) - """The format of the insert text. The format applies to both the - `insertText` property and the `newText` property of a provided - `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`. - - Please note that the insertTextFormat doesn't apply to - `additionalTextEdits`.""" - - insert_text_mode: Optional[InsertTextMode] = attrs.field(default=None) - """How whitespace and indentation is handled during completion - item insertion. If not provided the clients default value depends on - the `textDocument.completion.insertTextMode` client capability. - - @since 3.16.0""" - # Since: 3.16.0 - - text_edit: Optional[Union[TextEdit, "InsertReplaceEdit"]] = attrs.field( - default=None - ) - """An {@link TextEdit edit} which is applied to a document when selecting - this completion. When an edit is provided the value of - {@link CompletionItem.insertText insertText} is ignored. - - Most editors support two different operations when accepting a completion - item. One is to insert a completion text and the other is to replace an - existing text with a completion text. Since this can usually not be - predetermined by a server it can report both ranges. Clients need to - signal support for `InsertReplaceEdits` via the - `textDocument.completion.insertReplaceSupport` client capability - property. - - *Note 1:* The text edit's range as well as both ranges from an insert - replace edit must be a [single line] and they must contain the position - at which completion has been requested. - *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range - must be a prefix of the edit's replace range, that means it must be - contained and starting at the same position. - - @since 3.16.0 additional type `InsertReplaceEdit`""" - # Since: 3.16.0 additional type `InsertReplaceEdit` - - text_edit_text: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The edit text used if the completion item is part of a CompletionList and - CompletionList defines an item default for the text edit range. - - Clients will only honor this property if they opt into completion list - item defaults using the capability `completionList.itemDefaults`. - - If not provided and a list's default range is provided the label - property is used as a text. - - @since 3.17.0""" - # Since: 3.17.0 - - additional_text_edits: Optional[List[TextEdit]] = attrs.field(default=None) - """An optional array of additional {@link TextEdit text edits} that are applied when - selecting this completion. Edits must not overlap (including the same insert position) - with the main {@link CompletionItem.textEdit edit} nor with themselves. - - Additional text edits should be used to change text unrelated to the current cursor position - (for example adding an import statement at the top of the file if the completion item will - insert an unqualified type).""" - - commit_characters: Optional[List[str]] = attrs.field(default=None) - """An optional set of characters that when pressed while this completion is active will accept it first and - then type that character. *Note* that all commit characters should have `length=1` and that superfluous - characters will be ignored.""" - - command: Optional["Command"] = attrs.field(default=None) - """An optional {@link Command command} that is executed *after* inserting this completion. *Note* that - additional modifications to the current document should be described with the - {@link CompletionItem.additionalTextEdits additionalTextEdits}-property.""" - - data: Optional[LSPAny] = attrs.field(default=None) - """A data entry field that is preserved on a completion item between a - {@link CompletionRequest} and a {@link CompletionResolveRequest}.""" - - -@attrs.define -class CompletionListItemDefaultsTypeEditRangeType1: - insert: "Range" = attrs.field() - - replace: "Range" = attrs.field() - - -@attrs.define -class CompletionListItemDefaultsType: - commit_characters: Optional[List[str]] = attrs.field(default=None) - """A default commit character set. - - @since 3.17.0""" - # Since: 3.17.0 - - edit_range: Optional[ - Union["Range", "CompletionListItemDefaultsTypeEditRangeType1"] - ] = attrs.field(default=None) - """A default edit range. - - @since 3.17.0""" - # Since: 3.17.0 - - insert_text_format: Optional[InsertTextFormat] = attrs.field(default=None) - """A default insert text format. - - @since 3.17.0""" - # Since: 3.17.0 - - insert_text_mode: Optional[InsertTextMode] = attrs.field(default=None) - """A default insert text mode. - - @since 3.17.0""" - # Since: 3.17.0 - - data: Optional[LSPAny] = attrs.field(default=None) - """A default data value. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class CompletionList: - """Represents a collection of {@link CompletionItem completion items} to be presented - in the editor.""" - - is_incomplete: bool = attrs.field(validator=attrs.validators.instance_of(bool)) - """This list it not complete. Further typing results in recomputing this list. - - Recomputed lists have all their items replaced (not appended) in the - incomplete completion sessions.""" - - items: List[CompletionItem] = attrs.field() - """The completion items.""" - - item_defaults: Optional["CompletionListItemDefaultsType"] = attrs.field( - default=None - ) - """In many cases the items of an actual completion result share the same - value for properties like `commitCharacters` or the range of a text - edit. A completion list can therefore define item defaults which will - be used if a completion item itself doesn't specify the value. - - If a completion list specifies a default value and a completion item - also specifies a corresponding value the one from the item is used. - - Servers are only allowed to return default values if the client - signals support for this via the `completionList.itemDefaults` - capability. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class CompletionOptionsCompletionItemType: - label_details_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server has support for completion item label - details (see also `CompletionItemLabelDetails`) when - receiving a completion item in a resolve call. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class CompletionOptions: - """Completion options.""" - - trigger_characters: Optional[List[str]] = attrs.field(default=None) - """Most tools trigger completion request automatically without explicitly requesting - it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user - starts to type an identifier. For example if the user types `c` in a JavaScript file - code complete will automatically pop up present `console` besides others as a - completion item. Characters that make up identifiers don't need to be listed here. - - If code complete should automatically be trigger on characters not being valid inside - an identifier (for example `.` in JavaScript) list them in `triggerCharacters`.""" - - all_commit_characters: Optional[List[str]] = attrs.field(default=None) - """The list of all possible characters that commit a completion. This field can be used - if clients don't support individual commit characters per completion item. See - `ClientCapabilities.textDocument.completion.completionItem.commitCharactersSupport` - - If a server provides both `allCommitCharacters` and commit characters on an individual - completion item the ones on the completion item win. - - @since 3.2.0""" - # Since: 3.2.0 - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server provides support to resolve additional - information for a completion item.""" - - completion_item: Optional["CompletionOptionsCompletionItemType"] = attrs.field( - default=None - ) - """The server supports the following `CompletionItem` specific - capabilities. - - @since 3.17.0""" - # Since: 3.17.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class CompletionRegistrationOptionsCompletionItemType: - label_details_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server has support for completion item label - details (see also `CompletionItemLabelDetails`) when - receiving a completion item in a resolve call. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class CompletionRegistrationOptions: - """Registration options for a {@link CompletionRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - trigger_characters: Optional[List[str]] = attrs.field(default=None) - """Most tools trigger completion request automatically without explicitly requesting - it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user - starts to type an identifier. For example if the user types `c` in a JavaScript file - code complete will automatically pop up present `console` besides others as a - completion item. Characters that make up identifiers don't need to be listed here. - - If code complete should automatically be trigger on characters not being valid inside - an identifier (for example `.` in JavaScript) list them in `triggerCharacters`.""" - - all_commit_characters: Optional[List[str]] = attrs.field(default=None) - """The list of all possible characters that commit a completion. This field can be used - if clients don't support individual commit characters per completion item. See - `ClientCapabilities.textDocument.completion.completionItem.commitCharactersSupport` - - If a server provides both `allCommitCharacters` and commit characters on an individual - completion item the ones on the completion item win. - - @since 3.2.0""" - # Since: 3.2.0 - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server provides support to resolve additional - information for a completion item.""" - - completion_item: Optional[ - "CompletionRegistrationOptionsCompletionItemType" - ] = attrs.field(default=None) - """The server supports the following `CompletionItem` specific - capabilities. - - @since 3.17.0""" - # Since: 3.17.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class HoverParams: - """Parameters for a {@link HoverRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class Hover: - """The result of a hover request.""" - - contents: Union["MarkupContent", MarkedString, List[MarkedString]] = attrs.field() - """The hover's content""" - - range: Optional["Range"] = attrs.field(default=None) - """An optional range inside the text document that is used to - visualize the hover, e.g. by changing the background color.""" - - -@attrs.define -class HoverOptions: - """Hover options.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class HoverRegistrationOptions: - """Registration options for a {@link HoverRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class SignatureHelpParams: - """Parameters for a {@link SignatureHelpRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - context: Optional["SignatureHelpContext"] = attrs.field(default=None) - """The signature help context. This is only available if the client specifies - to send this using the client capability `textDocument.signatureHelp.contextSupport === true` - - @since 3.15.0""" - # Since: 3.15.0 - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class SignatureHelp: - """Signature help represents the signature of something - callable. There can be multiple signature but only one - active and only one active parameter.""" - - signatures: List["SignatureInformation"] = attrs.field() - """One or more signatures.""" - - active_signature: Optional[int] = attrs.field( - validator=attrs.validators.optional(validators.uinteger_validator), default=None - ) - """The active signature. If omitted or the value lies outside the - range of `signatures` the value defaults to zero or is ignored if - the `SignatureHelp` has no signatures. - - Whenever possible implementors should make an active decision about - the active signature and shouldn't rely on a default value. - - In future version of the protocol this property might become - mandatory to better express this.""" - - active_parameter: Optional[int] = attrs.field( - validator=attrs.validators.optional(validators.uinteger_validator), default=None - ) - """The active parameter of the active signature. If omitted or the value - lies outside the range of `signatures[activeSignature].parameters` - defaults to 0 if the active signature has parameters. If - the active signature has no parameters it is ignored. - In future version of the protocol this property might become - mandatory to better express the active parameter if the - active signature does have any.""" - - -@attrs.define -class SignatureHelpOptions: - """Server Capabilities for a {@link SignatureHelpRequest}.""" - - trigger_characters: Optional[List[str]] = attrs.field(default=None) - """List of characters that trigger signature help automatically.""" - - retrigger_characters: Optional[List[str]] = attrs.field(default=None) - """List of characters that re-trigger signature help. - - These trigger characters are only active when signature help is already showing. All trigger characters - are also counted as re-trigger characters. - - @since 3.15.0""" - # Since: 3.15.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class SignatureHelpRegistrationOptions: - """Registration options for a {@link SignatureHelpRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - trigger_characters: Optional[List[str]] = attrs.field(default=None) - """List of characters that trigger signature help automatically.""" - - retrigger_characters: Optional[List[str]] = attrs.field(default=None) - """List of characters that re-trigger signature help. - - These trigger characters are only active when signature help is already showing. All trigger characters - are also counted as re-trigger characters. - - @since 3.15.0""" - # Since: 3.15.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DefinitionParams: - """Parameters for a {@link DefinitionRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class DefinitionOptions: - """Server Capabilities for a {@link DefinitionRequest}.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DefinitionRegistrationOptions: - """Registration options for a {@link DefinitionRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class ReferenceParams: - """Parameters for a {@link ReferencesRequest}.""" - - context: "ReferenceContext" = attrs.field() - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class ReferenceOptions: - """Reference options.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class ReferenceRegistrationOptions: - """Registration options for a {@link ReferencesRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentHighlightParams: - """Parameters for a {@link DocumentHighlightRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class DocumentHighlight: - """A document highlight is a range inside a text document which deserves - special attention. Usually a document highlight is visualized by changing - the background color of its range.""" - - range: "Range" = attrs.field() - """The range this highlight applies to.""" - - kind: Optional[DocumentHighlightKind] = attrs.field(default=None) - """The highlight kind, default is {@link DocumentHighlightKind.Text text}.""" - - -@attrs.define -class DocumentHighlightOptions: - """Provider options for a {@link DocumentHighlightRequest}.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentHighlightRegistrationOptions: - """Registration options for a {@link DocumentHighlightRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentSymbolParams: - """Parameters for a {@link DocumentSymbolRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class BaseSymbolInformation: - """A base for all symbol information.""" - - name: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The name of this symbol.""" - - kind: SymbolKind = attrs.field() - """The kind of this symbol.""" - - tags: Optional[List[SymbolTag]] = attrs.field(default=None) - """Tags for this symbol. - - @since 3.16.0""" - # Since: 3.16.0 - - container_name: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The name of the symbol containing this symbol. This information is for - user interface purposes (e.g. to render a qualifier in the user interface - if necessary). It can't be used to re-infer a hierarchy for the document - symbols.""" - - -@attrs.define -class SymbolInformation: - """Represents information about programming constructs like variables, classes, - interfaces etc.""" - - location: Location = attrs.field() - """The location of this symbol. The location's range is used by a tool - to reveal the location in the editor. If the symbol is selected in the - tool the range's start information is used to position the cursor. So - the range usually spans more than the actual symbol's name and does - normally include things like visibility modifiers. - - The range doesn't have to denote a node range in the sense of an abstract - syntax tree. It can therefore not be used to re-construct a hierarchy of - the symbols.""" - - name: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The name of this symbol.""" - - kind: SymbolKind = attrs.field() - """The kind of this symbol.""" - - deprecated: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Indicates if this symbol is deprecated. - - @deprecated Use tags instead""" - - tags: Optional[List[SymbolTag]] = attrs.field(default=None) - """Tags for this symbol. - - @since 3.16.0""" - # Since: 3.16.0 - - container_name: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The name of the symbol containing this symbol. This information is for - user interface purposes (e.g. to render a qualifier in the user interface - if necessary). It can't be used to re-infer a hierarchy for the document - symbols.""" - - -@attrs.define -class DocumentSymbol: - """Represents programming constructs like variables, classes, interfaces etc. - that appear in a document. Document symbols can be hierarchical and they - have two ranges: one that encloses its definition and one that points to - its most interesting range, e.g. the range of an identifier.""" - - name: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The name of this symbol. Will be displayed in the user interface and therefore must not be - an empty string or a string only consisting of white spaces.""" - - kind: SymbolKind = attrs.field() - """The kind of this symbol.""" - - range: "Range" = attrs.field() - """The range enclosing this symbol not including leading/trailing whitespace but everything else - like comments. This information is typically used to determine if the clients cursor is - inside the symbol to reveal in the symbol in the UI.""" - - selection_range: "Range" = attrs.field() - """The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. - Must be contained by the `range`.""" - - detail: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """More detail for this symbol, e.g the signature of a function.""" - - tags: Optional[List[SymbolTag]] = attrs.field(default=None) - """Tags for this document symbol. - - @since 3.16.0""" - # Since: 3.16.0 - - deprecated: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Indicates if this symbol is deprecated. - - @deprecated Use tags instead""" - - children: Optional[List["DocumentSymbol"]] = attrs.field(default=None) - """Children of this symbol, e.g. properties of a class.""" - - -@attrs.define -class DocumentSymbolOptions: - """Provider options for a {@link DocumentSymbolRequest}.""" - - label: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A human-readable string that is shown when multiple outlines trees - are shown for the same document. - - @since 3.16.0""" - # Since: 3.16.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentSymbolRegistrationOptions: - """Registration options for a {@link DocumentSymbolRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - label: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A human-readable string that is shown when multiple outlines trees - are shown for the same document. - - @since 3.16.0""" - # Since: 3.16.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class CodeActionParams: - """The parameters of a {@link CodeActionRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The document in which the command was invoked.""" - - range: "Range" = attrs.field() - """The range for which the command was invoked.""" - - context: "CodeActionContext" = attrs.field() - """Context carrying additional information.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class Command: - """Represents a reference to a command. Provides a title which - will be used to represent a command in the UI and, optionally, - an array of arguments which will be passed to the command handler - function when invoked.""" - - title: str = attrs.field(validator=attrs.validators.instance_of(str)) - """Title of the command, like `save`.""" - - command: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The identifier of the actual command handler.""" - - arguments: Optional[List[LSPAny]] = attrs.field(default=None) - """Arguments that the command handler should be - invoked with.""" - - -@attrs.define -class CodeActionDisabledType: - reason: str = attrs.field(validator=attrs.validators.instance_of(str)) - """Human readable description of why the code action is currently disabled. - - This is displayed in the code actions UI.""" - - -@attrs.define -class CodeAction: - """A code action represents a change that can be performed in code, e.g. to fix a problem or - to refactor code. - - A CodeAction must set either `edit` and/or a `command`. If both are supplied, the `edit` is applied first, then the `command` is executed. - """ - - title: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A short, human-readable, title for this code action.""" - - kind: Optional[Union[CodeActionKind, str]] = attrs.field(default=None) - """The kind of the code action. - - Used to filter code actions.""" - - diagnostics: Optional[List["Diagnostic"]] = attrs.field(default=None) - """The diagnostics that this code action resolves.""" - - is_preferred: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted - by keybindings. - - A quick fix should be marked preferred if it properly addresses the underlying error. - A refactoring should be marked preferred if it is the most reasonable choice of actions to take. - - @since 3.15.0""" - # Since: 3.15.0 - - disabled: Optional["CodeActionDisabledType"] = attrs.field(default=None) - """Marks that the code action cannot currently be applied. - - Clients should follow the following guidelines regarding disabled code actions: - - - Disabled code actions are not shown in automatic [lightbulbs](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) - code action menus. - - - Disabled actions are shown as faded out in the code action menu when the user requests a more specific type - of code action, such as refactorings. - - - If the user has a [keybinding](https://code.visualstudio.com/docs/editor/refactoring#_keybindings-for-code-actions) - that auto applies a code action and only disabled code actions are returned, the client should show the user an - error message with `reason` in the editor. - - @since 3.16.0""" - # Since: 3.16.0 - - edit: Optional[WorkspaceEdit] = attrs.field(default=None) - """The workspace edit this code action performs.""" - - command: Optional[Command] = attrs.field(default=None) - """A command this code action executes. If a code action - provides an edit and a command, first the edit is - executed and then the command.""" - - data: Optional[LSPAny] = attrs.field(default=None) - """A data entry field that is preserved on a code action between - a `textDocument/codeAction` and a `codeAction/resolve` request. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class CodeActionOptions: - """Provider options for a {@link CodeActionRequest}.""" - - code_action_kinds: Optional[List[Union[CodeActionKind, str]]] = attrs.field( - default=None - ) - """CodeActionKinds that this server may return. - - The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server - may list out every specific kind they provide.""" - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server provides support to resolve additional - information for a code action. - - @since 3.16.0""" - # Since: 3.16.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class CodeActionRegistrationOptions: - """Registration options for a {@link CodeActionRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - code_action_kinds: Optional[List[Union[CodeActionKind, str]]] = attrs.field( - default=None - ) - """CodeActionKinds that this server may return. - - The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server - may list out every specific kind they provide.""" - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server provides support to resolve additional - information for a code action. - - @since 3.16.0""" - # Since: 3.16.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class WorkspaceSymbolParams: - """The parameters of a {@link WorkspaceSymbolRequest}.""" - - query: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A query string to filter symbols by. Clients may send an empty - string here to request all symbols.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class WorkspaceSymbolLocationType1: - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - - -@attrs.define -class WorkspaceSymbol: - """A special workspace symbol that supports locations without a range. - - See also SymbolInformation. - - @since 3.17.0""" - - # Since: 3.17.0 - - location: Union[Location, "WorkspaceSymbolLocationType1"] = attrs.field() - """The location of the symbol. Whether a server is allowed to - return a location without a range depends on the client - capability `workspace.symbol.resolveSupport`. - - See SymbolInformation#location for more details.""" - - name: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The name of this symbol.""" - - kind: SymbolKind = attrs.field() - """The kind of this symbol.""" - - data: Optional[LSPAny] = attrs.field(default=None) - """A data entry field that is preserved on a workspace symbol between a - workspace symbol request and a workspace symbol resolve request.""" - - tags: Optional[List[SymbolTag]] = attrs.field(default=None) - """Tags for this symbol. - - @since 3.16.0""" - # Since: 3.16.0 - - container_name: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The name of the symbol containing this symbol. This information is for - user interface purposes (e.g. to render a qualifier in the user interface - if necessary). It can't be used to re-infer a hierarchy for the document - symbols.""" - - -@attrs.define -class WorkspaceSymbolOptions: - """Server capabilities for a {@link WorkspaceSymbolRequest}.""" - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server provides support to resolve additional - information for a workspace symbol. - - @since 3.17.0""" - # Since: 3.17.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class WorkspaceSymbolRegistrationOptions: - """Registration options for a {@link WorkspaceSymbolRequest}.""" - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server provides support to resolve additional - information for a workspace symbol. - - @since 3.17.0""" - # Since: 3.17.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class CodeLensParams: - """The parameters of a {@link CodeLensRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The document to request code lens for.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class CodeLens: - """A code lens represents a {@link Command command} that should be shown along with - source text, like the number of references, a way to run tests, etc. - - A code lens is _unresolved_ when no command is associated to it. For performance - reasons the creation of a code lens and resolving should be done in two stages.""" - - range: "Range" = attrs.field() - """The range in which this code lens is valid. Should only span a single line.""" - - command: Optional[Command] = attrs.field(default=None) - """The command this code lens represents.""" - - data: Optional[LSPAny] = attrs.field(default=None) - """A data entry field that is preserved on a code lens item between - a {@link CodeLensRequest} and a {@link CodeLensResolveRequest}""" - - -@attrs.define -class CodeLensOptions: - """Code Lens provider options of a {@link CodeLensRequest}.""" - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Code lens has a resolve provider as well.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class CodeLensRegistrationOptions: - """Registration options for a {@link CodeLensRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Code lens has a resolve provider as well.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentLinkParams: - """The parameters of a {@link DocumentLinkRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The document to provide document links for.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - partial_result_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report partial results (e.g. streaming) to - the client.""" - - -@attrs.define -class DocumentLink: - """A document link is a range in a text document that links to an internal or external resource, like another - text document or a web site.""" - - range: "Range" = attrs.field() - """The range this link applies to.""" - - target: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The uri this link points to. If missing a resolve request is sent later.""" - - tooltip: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The tooltip text when you hover over this link. - - If a tooltip is provided, is will be displayed in a string that includes instructions on how to - trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS, - user settings, and localization. - - @since 3.15.0""" - # Since: 3.15.0 - - data: Optional[LSPAny] = attrs.field(default=None) - """A data entry field that is preserved on a document link between a - DocumentLinkRequest and a DocumentLinkResolveRequest.""" - - -@attrs.define -class DocumentLinkOptions: - """Provider options for a {@link DocumentLinkRequest}.""" - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Document links have a resolve provider as well.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentLinkRegistrationOptions: - """Registration options for a {@link DocumentLinkRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - resolve_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Document links have a resolve provider as well.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentFormattingParams: - """The parameters of a {@link DocumentFormattingRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The document to format.""" - - options: "FormattingOptions" = attrs.field() - """The format options.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class DocumentFormattingOptions: - """Provider options for a {@link DocumentFormattingRequest}.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentFormattingRegistrationOptions: - """Registration options for a {@link DocumentFormattingRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentRangeFormattingParams: - """The parameters of a {@link DocumentRangeFormattingRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The document to format.""" - - range: "Range" = attrs.field() - """The range to format""" - - options: "FormattingOptions" = attrs.field() - """The format options""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class DocumentRangeFormattingOptions: - """Provider options for a {@link DocumentRangeFormattingRequest}.""" - - ranges_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the server supports formatting multiple ranges at once. - - @since 3.18.0 - @proposed""" - # Since: 3.18.0 - # Proposed - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentRangeFormattingRegistrationOptions: - """Registration options for a {@link DocumentRangeFormattingRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - ranges_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the server supports formatting multiple ranges at once. - - @since 3.18.0 - @proposed""" - # Since: 3.18.0 - # Proposed - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class DocumentRangesFormattingParams: - """The parameters of a {@link DocumentRangesFormattingRequest}. - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - - text_document: "TextDocumentIdentifier" = attrs.field() - """The document to format.""" - - ranges: List["Range"] = attrs.field() - """The ranges to format""" - - options: "FormattingOptions" = attrs.field() - """The format options""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class DocumentOnTypeFormattingParams: - """The parameters of a {@link DocumentOnTypeFormattingRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The document to format.""" - - position: "Position" = attrs.field() - """The position around which the on type formatting should happen. - This is not necessarily the exact position where the character denoted - by the property `ch` got typed.""" - - ch: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The character that has been typed that triggered the formatting - on type request. That is not necessarily the last character that - got inserted into the document since the client could auto insert - characters as well (e.g. like automatic brace completion).""" - - options: "FormattingOptions" = attrs.field() - """The formatting options.""" - - -@attrs.define -class DocumentOnTypeFormattingOptions: - """Provider options for a {@link DocumentOnTypeFormattingRequest}.""" - - first_trigger_character: str = attrs.field( - validator=attrs.validators.instance_of(str) - ) - """A character on which formatting should be triggered, like `{`.""" - - more_trigger_character: Optional[List[str]] = attrs.field(default=None) - """More trigger characters.""" - - -@attrs.define -class DocumentOnTypeFormattingRegistrationOptions: - """Registration options for a {@link DocumentOnTypeFormattingRequest}.""" - - first_trigger_character: str = attrs.field( - validator=attrs.validators.instance_of(str) - ) - """A character on which formatting should be triggered, like `{`.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - more_trigger_character: Optional[List[str]] = attrs.field(default=None) - """More trigger characters.""" - - -@attrs.define -class RenameParams: - """The parameters of a {@link RenameRequest}.""" - - text_document: "TextDocumentIdentifier" = attrs.field() - """The document to rename.""" - - position: "Position" = attrs.field() - """The position at which this request was sent.""" - - new_name: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The new name of the symbol. If the given name is not valid the - request must return a {@link ResponseError} with an - appropriate message set.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class RenameOptions: - """Provider options for a {@link RenameRequest}.""" - - prepare_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Renames should be checked and tested before being executed. - - @since version 3.12.0""" - # Since: version 3.12.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class RenameRegistrationOptions: - """Registration options for a {@link RenameRequest}.""" - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - prepare_provider: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Renames should be checked and tested before being executed. - - @since version 3.12.0""" - # Since: version 3.12.0 - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class PrepareRenameParams: - text_document: "TextDocumentIdentifier" = attrs.field() - """The text document.""" - - position: "Position" = attrs.field() - """The position inside the text document.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class ExecuteCommandParams: - """The parameters of a {@link ExecuteCommandRequest}.""" - - command: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The identifier of the actual command handler.""" - - arguments: Optional[List[LSPAny]] = attrs.field(default=None) - """Arguments that the command should be invoked with.""" - - work_done_token: Optional[ProgressToken] = attrs.field(default=None) - """An optional token that a server can use to report work done progress.""" - - -@attrs.define -class ExecuteCommandOptions: - """The server capabilities of a {@link ExecuteCommandRequest}.""" - - commands: List[str] = attrs.field() - """The commands to be executed on the server""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class ExecuteCommandRegistrationOptions: - """Registration options for a {@link ExecuteCommandRequest}.""" - - commands: List[str] = attrs.field() - """The commands to be executed on the server""" - - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - -@attrs.define -class ApplyWorkspaceEditParams: - """The parameters passed via an apply workspace edit request.""" - - edit: WorkspaceEdit = attrs.field() - """The edits to apply.""" - - label: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """An optional label of the workspace edit. This label is - presented in the user interface for example on an undo - stack to undo the workspace edit.""" - - -@attrs.define -class ApplyWorkspaceEditResult: - """The result returned from the apply workspace edit request. - - @since 3.17 renamed from ApplyWorkspaceEditResponse""" - - # Since: 3.17 renamed from ApplyWorkspaceEditResponse - - applied: bool = attrs.field(validator=attrs.validators.instance_of(bool)) - """Indicates whether the edit was applied or not.""" - - failure_reason: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """An optional textual description for why the edit was not applied. - This may be used by the server for diagnostic logging or to provide - a suitable error for a request that triggered the edit.""" - - failed_change: Optional[int] = attrs.field( - validator=attrs.validators.optional(validators.uinteger_validator), default=None - ) - """Depending on the client's failure handling strategy `failedChange` might - contain the index of the change that failed. This property is only available - if the client signals a `failureHandlingStrategy` in its client capabilities.""" - - -@attrs.define -class WorkDoneProgressBegin: - title: str = attrs.field(validator=attrs.validators.instance_of(str)) - """Mandatory title of the progress operation. Used to briefly inform about - the kind of operation being performed. - - Examples: "Indexing" or "Linking dependencies".""" - - kind: str = attrs.field(validator=attrs.validators.in_(["begin"]), default="begin") - - cancellable: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Controls if a cancel button should show to allow the user to cancel the - long running operation. Clients that don't support cancellation are allowed - to ignore the setting.""" - - message: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """Optional, more detailed associated progress message. Contains - complementary information to the `title`. - - Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". - If unset, the previous progress message (if any) is still valid.""" - - percentage: Optional[int] = attrs.field( - validator=attrs.validators.optional(validators.uinteger_validator), default=None - ) - """Optional progress percentage to display (value 100 is considered 100%). - If not provided infinite progress is assumed and clients are allowed - to ignore the `percentage` value in subsequent in report notifications. - - The value should be steadily rising. Clients are free to ignore values - that are not following this rule. The value range is [0, 100].""" - - -@attrs.define -class WorkDoneProgressReport: - kind: str = attrs.field( - validator=attrs.validators.in_(["report"]), default="report" - ) - - cancellable: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Controls enablement state of a cancel button. - - Clients that don't support cancellation or don't support controlling the button's - enablement state are allowed to ignore the property.""" - - message: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """Optional, more detailed associated progress message. Contains - complementary information to the `title`. - - Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". - If unset, the previous progress message (if any) is still valid.""" - - percentage: Optional[int] = attrs.field( - validator=attrs.validators.optional(validators.uinteger_validator), default=None - ) - """Optional progress percentage to display (value 100 is considered 100%). - If not provided infinite progress is assumed and clients are allowed - to ignore the `percentage` value in subsequent in report notifications. - - The value should be steadily rising. Clients are free to ignore values - that are not following this rule. The value range is [0, 100]""" - - -@attrs.define -class WorkDoneProgressEnd: - kind: str = attrs.field(validator=attrs.validators.in_(["end"]), default="end") - - message: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """Optional, a final message indicating to for example indicate the outcome - of the operation.""" - - -@attrs.define -class SetTraceParams: - value: TraceValues = attrs.field() - - -@attrs.define -class LogTraceParams: - message: str = attrs.field(validator=attrs.validators.instance_of(str)) - - verbose: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - - -@attrs.define -class CancelParams: - id: Union[int, str] = attrs.field() - """The request id to cancel.""" - - -@attrs.define -class ProgressParams: - token: ProgressToken = attrs.field() - """The progress token provided by the client or server.""" - - value: LSPAny = attrs.field() - """The progress data.""" - - -@attrs.define -class LocationLink: - """Represents the connection of two locations. Provides additional metadata over normal {@link Location locations}, - including an origin range.""" - - target_uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The target resource identifier of this link.""" - - target_range: "Range" = attrs.field() - """The full target range of this link. If the target for example is a symbol then target range is the - range enclosing this symbol not including leading/trailing whitespace but everything else - like comments. This information is typically used to highlight the range in the editor.""" - - target_selection_range: "Range" = attrs.field() - """The range that should be selected and revealed when this link is being followed, e.g the name of a function. - Must be contained by the `targetRange`. See also `DocumentSymbol#range`""" - - origin_selection_range: Optional["Range"] = attrs.field(default=None) - """Span of the origin of this link. - - Used as the underlined span for mouse interaction. Defaults to the word range at - the definition position.""" - - -@attrs.define -class Range: - """A range in a text document expressed as (zero-based) start and end positions. - - If you want to specify a range that contains a line including the line ending - character(s) then use an end position denoting the start of the next line. - For example: - ```ts - { - start: { line: 5, character: 23 } - end : { line 6, character : 0 } - } - ```""" - - start: "Position" = attrs.field() - """The range's start position.""" - - end: "Position" = attrs.field() - """The range's end position.""" - - def __eq__(self, o: object) -> bool: - if not isinstance(o, Range): - return NotImplemented - return (self.start == o.start) and (self.end == o.end) - - def __repr__(self) -> str: - return f"{self.start!r}-{self.end!r}" - - -@attrs.define -class WorkspaceFoldersChangeEvent: - """The workspace folder change event.""" - - added: List[WorkspaceFolder] = attrs.field() - """The array of added workspace folders""" - - removed: List[WorkspaceFolder] = attrs.field() - """The array of the removed workspace folders""" - - -@attrs.define -class ConfigurationItem: - scope_uri: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The scope to get the configuration section for.""" - - section: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The configuration section asked for.""" - - -@attrs.define -class TextDocumentIdentifier: - """A literal to identify a text document in the client.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The text document's uri.""" - - -@attrs.define -class Color: - """Represents a color in RGBA space.""" - - red: float = attrs.field(validator=attrs.validators.instance_of(float)) - """The red component of this color in the range [0-1].""" - - green: float = attrs.field(validator=attrs.validators.instance_of(float)) - """The green component of this color in the range [0-1].""" - - blue: float = attrs.field(validator=attrs.validators.instance_of(float)) - """The blue component of this color in the range [0-1].""" - - alpha: float = attrs.field(validator=attrs.validators.instance_of(float)) - """The alpha component of this color in the range [0-1].""" - - -@attrs.define -@functools.total_ordering -class Position: - """Position in a text document expressed as zero-based line and character - offset. Prior to 3.17 the offsets were always based on a UTF-16 string - representation. So a string of the form `a𐐀b` the character offset of the - character `a` is 0, the character offset of `𐐀` is 1 and the character - offset of b is 3 since `𐐀` is represented using two code units in UTF-16. - Since 3.17 clients and servers can agree on a different string encoding - representation (e.g. UTF-8). The client announces it's supported encoding - via the client capability [`general.positionEncodings`](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#clientCapabilities). - The value is an array of position encodings the client supports, with - decreasing preference (e.g. the encoding at index `0` is the most preferred - one). To stay backwards compatible the only mandatory encoding is UTF-16 - represented via the string `utf-16`. The server can pick one of the - encodings offered by the client and signals that encoding back to the - client via the initialize result's property - [`capabilities.positionEncoding`](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#serverCapabilities). If the string value - `utf-16` is missing from the client's capability `general.positionEncodings` - servers can safely assume that the client supports UTF-16. If the server - omits the position encoding in its initialize result the encoding defaults - to the string value `utf-16`. Implementation considerations: since the - conversion from one encoding into another requires the content of the - file / line the conversion is best done where the file is read which is - usually on the server side. - - Positions are line end character agnostic. So you can not specify a position - that denotes `\r|\n` or `\n|` where `|` represents the character offset. - - @since 3.17.0 - support for negotiated position encoding.""" - - # Since: 3.17.0 - support for negotiated position encoding. - - line: int = attrs.field(validator=validators.uinteger_validator) - """Line position in a document (zero-based). - - If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document. - If a line number is negative, it defaults to 0.""" - - character: int = attrs.field(validator=validators.uinteger_validator) - """Character offset on a line in a document (zero-based). - - The meaning of this offset is determined by the negotiated - `PositionEncodingKind`. - - If the character value is greater than the line length it defaults back to the - line length.""" - - def __eq__(self, o: object) -> bool: - if not isinstance(o, Position): - return NotImplemented - return (self.line, self.character) == (o.line, o.character) - - def __gt__(self, o: "Position") -> bool: - if not isinstance(o, Position): - return NotImplemented - return (self.line, self.character) > (o.line, o.character) - - def __repr__(self) -> str: - return f"{self.line}:{self.character}" - - -@attrs.define -class SemanticTokensEdit: - """@since 3.16.0""" - - # Since: 3.16.0 - - start: int = attrs.field(validator=validators.uinteger_validator) - """The start offset of the edit.""" - - delete_count: int = attrs.field(validator=validators.uinteger_validator) - """The count of elements to remove.""" - - data: Optional[List[int]] = attrs.field(default=None) - """The elements to insert.""" - - -@attrs.define -class FileCreate: - """Represents information on a file/folder create. - - @since 3.16.0""" - - # Since: 3.16.0 - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A file:// URI for the location of the file/folder being created.""" - - -@attrs.define -class TextDocumentEdit: - """Describes textual changes on a text document. A TextDocumentEdit describes all changes - on a document version Si and after they are applied move the document to version Si+1. - So the creator of a TextDocumentEdit doesn't need to sort the array of edits or do any - kind of ordering. However the edits must be non overlapping.""" - - text_document: "OptionalVersionedTextDocumentIdentifier" = attrs.field() - """The text document to change.""" - - edits: List[Union[TextEdit, "AnnotatedTextEdit"]] = attrs.field() - """The edits to be applied. - - @since 3.16.0 - support for AnnotatedTextEdit. This is guarded using a - client capability.""" - # Since: 3.16.0 - support for AnnotatedTextEdit. This is guarded using aclient capability. - - -@attrs.define -class ResourceOperation: - """A generic resource operation.""" - - kind: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The resource operation kind.""" - - annotation_id: Optional[ChangeAnnotationIdentifier] = attrs.field(default=None) - """An optional annotation identifier describing the operation. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class CreateFile: - """Create file operation.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The resource to create.""" - - kind: str = attrs.field( - validator=attrs.validators.in_(["create"]), default="create" - ) - """A create""" - - options: Optional["CreateFileOptions"] = attrs.field(default=None) - """Additional options""" - - annotation_id: Optional[ChangeAnnotationIdentifier] = attrs.field(default=None) - """An optional annotation identifier describing the operation. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class RenameFile: - """Rename file operation""" - - old_uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The old (existing) location.""" - - new_uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The new location.""" - - kind: str = attrs.field( - validator=attrs.validators.in_(["rename"]), default="rename" - ) - """A rename""" - - options: Optional["RenameFileOptions"] = attrs.field(default=None) - """Rename options.""" - - annotation_id: Optional[ChangeAnnotationIdentifier] = attrs.field(default=None) - """An optional annotation identifier describing the operation. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class DeleteFile: - """Delete file operation""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The file to delete.""" - - kind: str = attrs.field( - validator=attrs.validators.in_(["delete"]), default="delete" - ) - """A delete""" - - options: Optional["DeleteFileOptions"] = attrs.field(default=None) - """Delete options.""" - - annotation_id: Optional[ChangeAnnotationIdentifier] = attrs.field(default=None) - """An optional annotation identifier describing the operation. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class ChangeAnnotation: - """Additional information that describes document changes. - - @since 3.16.0""" - - # Since: 3.16.0 - - label: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A human-readable string describing the actual change. The string - is rendered prominent in the user interface.""" - - needs_confirmation: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """A flag which indicates that user confirmation is needed - before applying the change.""" - - description: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A human-readable string which is rendered less prominent in - the user interface.""" - - -@attrs.define -class FileOperationFilter: - """A filter to describe in which file operation requests or notifications - the server is interested in receiving. - - @since 3.16.0""" - - # Since: 3.16.0 - - pattern: "FileOperationPattern" = attrs.field() - """The actual file operation pattern.""" - - scheme: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A Uri scheme like `file` or `untitled`.""" - - -@attrs.define -class FileRename: - """Represents information on a file/folder rename. - - @since 3.16.0""" - - # Since: 3.16.0 - - old_uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A file:// URI for the original location of the file/folder being renamed.""" - - new_uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A file:// URI for the new location of the file/folder being renamed.""" - - -@attrs.define -class FileDelete: - """Represents information on a file/folder delete. - - @since 3.16.0""" - - # Since: 3.16.0 - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A file:// URI for the location of the file/folder being deleted.""" - - -@attrs.define -class InlineValueContext: - """@since 3.17.0""" - - # Since: 3.17.0 - - frame_id: int = attrs.field(validator=validators.integer_validator) - """The stack frame (as a DAP Id) where the execution has stopped.""" - - stopped_location: Range = attrs.field() - """The document range where execution has stopped. - Typically the end position of the range denotes the line where the inline values are shown.""" - - -@attrs.define -class InlineValueText: - """Provide inline value as text. - - @since 3.17.0""" - - # Since: 3.17.0 - - range: Range = attrs.field() - """The document range for which the inline value applies.""" - - text: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The text of the inline value.""" - - -@attrs.define -class InlineValueVariableLookup: - """Provide inline value through a variable lookup. - If only a range is specified, the variable name will be extracted from the underlying document. - An optional variable name can be used to override the extracted name. - - @since 3.17.0""" - - # Since: 3.17.0 - - range: Range = attrs.field() - """The document range for which the inline value applies. - The range is used to extract the variable name from the underlying document.""" - - case_sensitive_lookup: bool = attrs.field( - validator=attrs.validators.instance_of(bool) - ) - """How to perform the lookup.""" - - variable_name: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """If specified the name of the variable to look up.""" - - -@attrs.define -class InlineValueEvaluatableExpression: - """Provide an inline value through an expression evaluation. - If only a range is specified, the expression will be extracted from the underlying document. - An optional expression can be used to override the extracted expression. - - @since 3.17.0""" - - # Since: 3.17.0 - - range: Range = attrs.field() - """The document range for which the inline value applies. - The range is used to extract the evaluatable expression from the underlying document.""" - - expression: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """If specified the expression overrides the extracted expression.""" - - -@attrs.define -class InlayHintLabelPart: - """An inlay hint label part allows for interactive and composite labels - of inlay hints. - - @since 3.17.0""" - - # Since: 3.17.0 - - value: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The value of this label part.""" - - tooltip: Optional[Union[str, "MarkupContent"]] = attrs.field(default=None) - """The tooltip text when you hover over this label part. Depending on - the client capability `inlayHint.resolveSupport` clients might resolve - this property late using the resolve request.""" - - location: Optional[Location] = attrs.field(default=None) - """An optional source code location that represents this - label part. - - The editor will use this location for the hover and for code navigation - features: This part will become a clickable link that resolves to the - definition of the symbol at the given location (not necessarily the - location itself), it shows the hover that shows at the given location, - and it shows a context menu with further code navigation commands. - - Depending on the client capability `inlayHint.resolveSupport` clients - might resolve this property late using the resolve request.""" - - command: Optional[Command] = attrs.field(default=None) - """An optional command for this label part. - - Depending on the client capability `inlayHint.resolveSupport` clients - might resolve this property late using the resolve request.""" - - -@attrs.define -class MarkupContent: - """A `MarkupContent` literal represents a string value which content is interpreted base on its - kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds. - - If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues. - See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting - - Here is an example how such a string can be constructed using JavaScript / TypeScript: - ```ts - let markdown: MarkdownContent = { - kind: MarkupKind.Markdown, - value: [ - '# Header', - 'Some text', - '```typescript', - 'someCode();', - '```' - ].join('\n') - }; - ``` - - *Please Note* that clients might sanitize the return markdown. A client could decide to - remove HTML from the markdown to avoid script execution.""" - - kind: MarkupKind = attrs.field() - """The type of the Markup""" - - value: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The content itself""" - - -@attrs.define -class FullDocumentDiagnosticReport: - """A diagnostic report with a full set of problems. - - @since 3.17.0""" - - # Since: 3.17.0 - - items: List["Diagnostic"] = attrs.field() - """The actual items.""" - - kind: str = attrs.field(validator=attrs.validators.in_(["full"]), default="full") - """A full document diagnostic report.""" - - result_id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """An optional result id. If provided it will - be sent on the next diagnostic request for the - same document.""" - - -@attrs.define -class RelatedFullDocumentDiagnosticReport: - """A full diagnostic report with a set of related documents. - - @since 3.17.0""" - - # Since: 3.17.0 - - items: List["Diagnostic"] = attrs.field() - """The actual items.""" - - related_documents: Optional[ - Dict[ - str, - Union[FullDocumentDiagnosticReport, "UnchangedDocumentDiagnosticReport"], - ] - ] = attrs.field(default=None) - """Diagnostics of related documents. This information is useful - in programming languages where code in a file A can generate - diagnostics in a file B which A depends on. An example of - such a language is C/C++ where marco definitions in a file - a.cpp and result in errors in a header file b.hpp. - - @since 3.17.0""" - # Since: 3.17.0 - - kind: str = attrs.field(validator=attrs.validators.in_(["full"]), default="full") - """A full document diagnostic report.""" - - result_id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """An optional result id. If provided it will - be sent on the next diagnostic request for the - same document.""" - - -@attrs.define -class UnchangedDocumentDiagnosticReport: - """A diagnostic report indicating that the last returned - report is still accurate. - - @since 3.17.0""" - - # Since: 3.17.0 - - result_id: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A result id which will be sent on the next - diagnostic request for the same document.""" - - kind: str = attrs.field( - validator=attrs.validators.in_(["unchanged"]), default="unchanged" - ) - """A document diagnostic report indicating - no changes to the last result. A server can - only return `unchanged` if result ids are - provided.""" - - -@attrs.define -class RelatedUnchangedDocumentDiagnosticReport: - """An unchanged diagnostic report with a set of related documents. - - @since 3.17.0""" - - # Since: 3.17.0 - - result_id: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A result id which will be sent on the next - diagnostic request for the same document.""" - - related_documents: Optional[ - Dict[ - str, Union[FullDocumentDiagnosticReport, UnchangedDocumentDiagnosticReport] - ] - ] = attrs.field(default=None) - """Diagnostics of related documents. This information is useful - in programming languages where code in a file A can generate - diagnostics in a file B which A depends on. An example of - such a language is C/C++ where marco definitions in a file - a.cpp and result in errors in a header file b.hpp. - - @since 3.17.0""" - # Since: 3.17.0 - - kind: str = attrs.field( - validator=attrs.validators.in_(["unchanged"]), default="unchanged" - ) - """A document diagnostic report indicating - no changes to the last result. A server can - only return `unchanged` if result ids are - provided.""" - - -@attrs.define -class PreviousResultId: - """A previous result id in a workspace pull request. - - @since 3.17.0""" - - # Since: 3.17.0 - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The URI for which the client knowns a - result id.""" - - value: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The value of the previous result id.""" - - -@attrs.define -class NotebookDocument: - """A notebook document. - - @since 3.17.0""" - - # Since: 3.17.0 - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The notebook document's uri.""" - - notebook_type: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The type of the notebook.""" - - version: int = attrs.field(validator=validators.integer_validator) - """The version number of this document (it will increase after each - change, including undo/redo).""" - - cells: List["NotebookCell"] = attrs.field() - """The cells of a notebook.""" - - metadata: Optional[LSPObject] = attrs.field(default=None) - """Additional metadata stored with the notebook - document. - - Note: should always be an object literal (e.g. LSPObject)""" - - -@attrs.define -class TextDocumentItem: - """An item to transfer a text document from the client to the - server.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The text document's uri.""" - - language_id: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The text document's language identifier.""" - - version: int = attrs.field(validator=validators.integer_validator) - """The version number of this document (it will increase after each - change, including undo/redo).""" - - text: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The content of the opened text document.""" - - -@attrs.define -class VersionedNotebookDocumentIdentifier: - """A versioned notebook document identifier. - - @since 3.17.0""" - - # Since: 3.17.0 - - version: int = attrs.field(validator=validators.integer_validator) - """The version number of this notebook document.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The notebook document's uri.""" - - -@attrs.define -class NotebookDocumentChangeEventCellsTypeStructureType: - array: "NotebookCellArrayChange" = attrs.field() - """The change to the cell array.""" - - did_open: Optional[List[TextDocumentItem]] = attrs.field(default=None) - """Additional opened cell text documents.""" - - did_close: Optional[List[TextDocumentIdentifier]] = attrs.field(default=None) - """Additional closed cell text documents.""" - - -@attrs.define -class NotebookDocumentChangeEventCellsTypeTextContentType: - document: "VersionedTextDocumentIdentifier" = attrs.field() - - changes: List[TextDocumentContentChangeEvent] = attrs.field() - - -@attrs.define -class NotebookDocumentChangeEventCellsType: - structure: Optional[ - "NotebookDocumentChangeEventCellsTypeStructureType" - ] = attrs.field(default=None) - """Changes to the cell structure to add or - remove cells.""" - - data: Optional[List["NotebookCell"]] = attrs.field(default=None) - """Changes to notebook cells properties like its - kind, execution summary or metadata.""" - - text_content: Optional[ - List["NotebookDocumentChangeEventCellsTypeTextContentType"] - ] = attrs.field(default=None) - """Changes to the text content of notebook cells.""" - - -@attrs.define -class NotebookDocumentChangeEvent: - """A change event for a notebook document. - - @since 3.17.0""" - - # Since: 3.17.0 - - metadata: Optional[LSPObject] = attrs.field(default=None) - """The changed meta data if any. - - Note: should always be an object literal (e.g. LSPObject)""" - - cells: Optional["NotebookDocumentChangeEventCellsType"] = attrs.field(default=None) - """Changes to cells""" - - -@attrs.define -class NotebookDocumentIdentifier: - """A literal to identify a notebook document in the client. - - @since 3.17.0""" - - # Since: 3.17.0 - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The notebook document's uri.""" - - -@attrs.define -class InlineCompletionContext: - """Provides information about the context in which an inline completion was requested. - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - - trigger_kind: InlineCompletionTriggerKind = attrs.field() - """Describes how the inline completion was triggered.""" - - selected_completion_info: Optional["SelectedCompletionInfo"] = attrs.field( - default=None - ) - """Provides information about the currently selected item in the autocomplete widget if it is visible.""" - - -@attrs.define -class StringValue: - """A string value used as a snippet is a template which allows to insert text - and to control the editor cursor when insertion happens. - - A snippet can define tab stops and placeholders with `$1`, `$2` - and `${3:foo}`. `$0` defines the final tab stop, it defaults to - the end of the snippet. Variables are defined with `$name` and - `${name:default value}`. - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - - value: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The snippet string.""" - - kind: str = attrs.field( - validator=attrs.validators.in_(["snippet"]), default="snippet" - ) - """The kind of string value.""" - - -@attrs.define -class Registration: - """General parameters to register for a notification or to register a provider.""" - - id: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The id used to register the request. The id can be used to deregister - the request again.""" - - method: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The method / capability to register for.""" - - register_options: Optional[LSPAny] = attrs.field(default=None) - """Options necessary for the registration.""" - - -@attrs.define -class Unregistration: - """General parameters to unregister a request or notification.""" - - id: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The id used to unregister the request or notification. Usually an id - provided during the register request.""" - - method: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The method to unregister for.""" - - -@attrs.define -class ServerCapabilitiesWorkspaceType: - workspace_folders: Optional["WorkspaceFoldersServerCapabilities"] = attrs.field( - default=None - ) - """The server supports workspace folder. - - @since 3.6.0""" - # Since: 3.6.0 - - file_operations: Optional["FileOperationOptions"] = attrs.field(default=None) - """The server is interested in notifications/requests for operations on files. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class ServerCapabilities: - """Defines the capabilities provided by a language - server.""" - - position_encoding: Optional[Union[PositionEncodingKind, str]] = attrs.field( - default=None - ) - """The position encoding the server picked from the encodings offered - by the client via the client capability `general.positionEncodings`. - - If the client didn't provide any position encodings the only valid - value that a server can return is 'utf-16'. - - If omitted it defaults to 'utf-16'. - - @since 3.17.0""" - # Since: 3.17.0 - - text_document_sync: Optional[ - Union["TextDocumentSyncOptions", TextDocumentSyncKind] - ] = attrs.field(default=None) - """Defines how text documents are synced. Is either a detailed structure - defining each notification or for backwards compatibility the - TextDocumentSyncKind number.""" - - notebook_document_sync: Optional[ - Union["NotebookDocumentSyncOptions", "NotebookDocumentSyncRegistrationOptions"] - ] = attrs.field(default=None) - """Defines how notebook documents are synced. - - @since 3.17.0""" - # Since: 3.17.0 - - completion_provider: Optional[CompletionOptions] = attrs.field(default=None) - """The server provides completion support.""" - - hover_provider: Optional[Union[bool, HoverOptions]] = attrs.field(default=None) - """The server provides hover support.""" - - signature_help_provider: Optional[SignatureHelpOptions] = attrs.field(default=None) - """The server provides signature help support.""" - - declaration_provider: Optional[ - Union[bool, DeclarationOptions, DeclarationRegistrationOptions] - ] = attrs.field(default=None) - """The server provides Goto Declaration support.""" - - definition_provider: Optional[Union[bool, DefinitionOptions]] = attrs.field( - default=None - ) - """The server provides goto definition support.""" - - type_definition_provider: Optional[ - Union[bool, TypeDefinitionOptions, TypeDefinitionRegistrationOptions] - ] = attrs.field(default=None) - """The server provides Goto Type Definition support.""" - - implementation_provider: Optional[ - Union[bool, ImplementationOptions, ImplementationRegistrationOptions] - ] = attrs.field(default=None) - """The server provides Goto Implementation support.""" - - references_provider: Optional[Union[bool, ReferenceOptions]] = attrs.field( - default=None - ) - """The server provides find references support.""" - - document_highlight_provider: Optional[ - Union[bool, DocumentHighlightOptions] - ] = attrs.field(default=None) - """The server provides document highlight support.""" - - document_symbol_provider: Optional[ - Union[bool, DocumentSymbolOptions] - ] = attrs.field(default=None) - """The server provides document symbol support.""" - - code_action_provider: Optional[Union[bool, CodeActionOptions]] = attrs.field( - default=None - ) - """The server provides code actions. CodeActionOptions may only be - specified if the client states that it supports - `codeActionLiteralSupport` in its initial `initialize` request.""" - - code_lens_provider: Optional[CodeLensOptions] = attrs.field(default=None) - """The server provides code lens.""" - - document_link_provider: Optional[DocumentLinkOptions] = attrs.field(default=None) - """The server provides document link support.""" - - color_provider: Optional[ - Union[bool, DocumentColorOptions, DocumentColorRegistrationOptions] - ] = attrs.field(default=None) - """The server provides color provider support.""" - - workspace_symbol_provider: Optional[ - Union[bool, WorkspaceSymbolOptions] - ] = attrs.field(default=None) - """The server provides workspace symbol support.""" - - document_formatting_provider: Optional[ - Union[bool, DocumentFormattingOptions] - ] = attrs.field(default=None) - """The server provides document formatting.""" - - document_range_formatting_provider: Optional[ - Union[bool, DocumentRangeFormattingOptions] - ] = attrs.field(default=None) - """The server provides document range formatting.""" - - document_on_type_formatting_provider: Optional[ - DocumentOnTypeFormattingOptions - ] = attrs.field(default=None) - """The server provides document formatting on typing.""" - - rename_provider: Optional[Union[bool, RenameOptions]] = attrs.field(default=None) - """The server provides rename support. RenameOptions may only be - specified if the client states that it supports - `prepareSupport` in its initial `initialize` request.""" - - folding_range_provider: Optional[ - Union[bool, FoldingRangeOptions, FoldingRangeRegistrationOptions] - ] = attrs.field(default=None) - """The server provides folding provider support.""" - - selection_range_provider: Optional[ - Union[bool, SelectionRangeOptions, SelectionRangeRegistrationOptions] - ] = attrs.field(default=None) - """The server provides selection range support.""" - - execute_command_provider: Optional[ExecuteCommandOptions] = attrs.field( - default=None - ) - """The server provides execute command support.""" - - call_hierarchy_provider: Optional[ - Union[bool, CallHierarchyOptions, CallHierarchyRegistrationOptions] - ] = attrs.field(default=None) - """The server provides call hierarchy support. - - @since 3.16.0""" - # Since: 3.16.0 - - linked_editing_range_provider: Optional[ - Union[bool, LinkedEditingRangeOptions, LinkedEditingRangeRegistrationOptions] - ] = attrs.field(default=None) - """The server provides linked editing range support. - - @since 3.16.0""" - # Since: 3.16.0 - - semantic_tokens_provider: Optional[ - Union[SemanticTokensOptions, SemanticTokensRegistrationOptions] - ] = attrs.field(default=None) - """The server provides semantic tokens support. - - @since 3.16.0""" - # Since: 3.16.0 - - moniker_provider: Optional[ - Union[bool, MonikerOptions, MonikerRegistrationOptions] - ] = attrs.field(default=None) - """The server provides moniker support. - - @since 3.16.0""" - # Since: 3.16.0 - - type_hierarchy_provider: Optional[ - Union[bool, TypeHierarchyOptions, TypeHierarchyRegistrationOptions] - ] = attrs.field(default=None) - """The server provides type hierarchy support. - - @since 3.17.0""" - # Since: 3.17.0 - - inline_value_provider: Optional[ - Union[bool, InlineValueOptions, InlineValueRegistrationOptions] - ] = attrs.field(default=None) - """The server provides inline values. - - @since 3.17.0""" - # Since: 3.17.0 - - inlay_hint_provider: Optional[ - Union[bool, InlayHintOptions, InlayHintRegistrationOptions] - ] = attrs.field(default=None) - """The server provides inlay hints. - - @since 3.17.0""" - # Since: 3.17.0 - - diagnostic_provider: Optional[ - Union[DiagnosticOptions, DiagnosticRegistrationOptions] - ] = attrs.field(default=None) - """The server has support for pull model diagnostics. - - @since 3.17.0""" - # Since: 3.17.0 - - inline_completion_provider: Optional[ - Union[bool, InlineCompletionOptions] - ] = attrs.field(default=None) - """Inline completion options used during static registration. - - @since 3.18.0 - @proposed""" - # Since: 3.18.0 - # Proposed - - workspace: Optional["ServerCapabilitiesWorkspaceType"] = attrs.field(default=None) - """Workspace specific server capabilities.""" - - experimental: Optional[LSPAny] = attrs.field(default=None) - """Experimental server capabilities.""" - - -@attrs.define -class VersionedTextDocumentIdentifier: - """A text document identifier to denote a specific version of a text document.""" - - version: int = attrs.field(validator=validators.integer_validator) - """The version number of this document.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The text document's uri.""" - - -@attrs.define -class FileEvent: - """An event describing a file change.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The file's uri.""" - - type: FileChangeType = attrs.field() - """The change type.""" - - -@attrs.define -class FileSystemWatcher: - glob_pattern: GlobPattern = attrs.field() - """The glob pattern to watch. See {@link GlobPattern glob pattern} for more detail. - - @since 3.17.0 support for relative patterns.""" - # Since: 3.17.0 support for relative patterns. - - kind: Optional[Union[WatchKind, int]] = attrs.field(default=None) - """The kind of events of interest. If omitted it defaults - to WatchKind.Create | WatchKind.Change | WatchKind.Delete - which is 7.""" - - -@attrs.define -class Diagnostic: - """Represents a diagnostic, such as a compiler error or warning. Diagnostic objects - are only valid in the scope of a resource.""" - - range: Range = attrs.field() - """The range at which the message applies""" - - message: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The diagnostic's message. It usually appears in the user interface""" - - severity: Optional[DiagnosticSeverity] = attrs.field(default=None) - """The diagnostic's severity. Can be omitted. If omitted it is up to the - client to interpret diagnostics as error, warning, info or hint.""" - - code: Optional[Union[int, str]] = attrs.field(default=None) - """The diagnostic's code, which usually appear in the user interface.""" - - code_description: Optional["CodeDescription"] = attrs.field(default=None) - """An optional property to describe the error code. - Requires the code field (above) to be present/not null. - - @since 3.16.0""" - # Since: 3.16.0 - - source: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A human-readable string describing the source of this - diagnostic, e.g. 'typescript' or 'super lint'. It usually - appears in the user interface.""" - - tags: Optional[List[DiagnosticTag]] = attrs.field(default=None) - """Additional metadata about the diagnostic. - - @since 3.15.0""" - # Since: 3.15.0 - - related_information: Optional[List["DiagnosticRelatedInformation"]] = attrs.field( - default=None - ) - """An array of related diagnostic information, e.g. when symbol-names within - a scope collide all definitions can be marked via this property.""" - - data: Optional[LSPAny] = attrs.field(default=None) - """A data entry field that is preserved between a `textDocument/publishDiagnostics` - notification and `textDocument/codeAction` request. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class CompletionContext: - """Contains additional information about the context in which a completion request is triggered.""" - - trigger_kind: CompletionTriggerKind = attrs.field() - """How the completion was triggered.""" - - trigger_character: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The trigger character (a single character) that has trigger code complete. - Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`""" - - -@attrs.define -class CompletionItemLabelDetails: - """Additional details for a completion item label. - - @since 3.17.0""" - - # Since: 3.17.0 - - detail: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """An optional string which is rendered less prominently directly after {@link CompletionItem.label label}, - without any spacing. Should be used for function signatures and type annotations.""" - - description: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """An optional string which is rendered less prominently after {@link CompletionItem.detail}. Should be used - for fully qualified names and file paths.""" - - -@attrs.define -class InsertReplaceEdit: - """A special text edit to provide an insert and a replace operation. - - @since 3.16.0""" - - # Since: 3.16.0 - - new_text: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The string to be inserted.""" - - insert: Range = attrs.field() - """The range if the insert is requested""" - - replace: Range = attrs.field() - """The range if the replace is requested.""" - - -@attrs.define -class SignatureHelpContext: - """Additional information about the context in which a signature help request was triggered. - - @since 3.15.0""" - - # Since: 3.15.0 - - trigger_kind: SignatureHelpTriggerKind = attrs.field() - """Action that caused signature help to be triggered.""" - - is_retrigger: bool = attrs.field(validator=attrs.validators.instance_of(bool)) - """`true` if signature help was already showing when it was triggered. - - Retriggers occurs when the signature help is already active and can be caused by actions such as - typing a trigger character, a cursor move, or document content changes.""" - - trigger_character: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """Character that caused signature help to be triggered. - - This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter`""" - - active_signature_help: Optional[SignatureHelp] = attrs.field(default=None) - """The currently active `SignatureHelp`. - - The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on - the user navigating through available signatures.""" - - -@attrs.define -class SignatureInformation: - """Represents the signature of something callable. A signature - can have a label, like a function-name, a doc-comment, and - a set of parameters.""" - - label: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The label of this signature. Will be shown in - the UI.""" - - documentation: Optional[Union[str, MarkupContent]] = attrs.field(default=None) - """The human-readable doc-comment of this signature. Will be shown - in the UI but can be omitted.""" - - parameters: Optional[List["ParameterInformation"]] = attrs.field(default=None) - """The parameters of this signature.""" - - active_parameter: Optional[int] = attrs.field( - validator=attrs.validators.optional(validators.uinteger_validator), default=None - ) - """The index of the active parameter. - - If provided, this is used in place of `SignatureHelp.activeParameter`. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class ReferenceContext: - """Value-object that contains additional information when - requesting references.""" - - include_declaration: bool = attrs.field( - validator=attrs.validators.instance_of(bool) - ) - """Include the declaration of the current symbol.""" - - -@attrs.define -class CodeActionContext: - """Contains additional diagnostic information about the context in which - a {@link CodeActionProvider.provideCodeActions code action} is run.""" - - diagnostics: List[Diagnostic] = attrs.field() - """An array of diagnostics known on the client side overlapping the range provided to the - `textDocument/codeAction` request. They are provided so that the server knows which - errors are currently presented to the user for the given range. There is no guarantee - that these accurately reflect the error state of the resource. The primary parameter - to compute code actions is the provided range.""" - - only: Optional[List[Union[CodeActionKind, str]]] = attrs.field(default=None) - """Requested kind of actions to return. - - Actions not of this kind are filtered out by the client before being shown. So servers - can omit computing them.""" - - trigger_kind: Optional[CodeActionTriggerKind] = attrs.field(default=None) - """The reason why code actions were requested. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class FormattingOptions: - """Value-object describing what options formatting should use.""" - - tab_size: int = attrs.field(validator=validators.uinteger_validator) - """Size of a tab in spaces.""" - - insert_spaces: bool = attrs.field(validator=attrs.validators.instance_of(bool)) - """Prefer spaces over tabs.""" - - trim_trailing_whitespace: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Trim trailing whitespace on a line. - - @since 3.15.0""" - # Since: 3.15.0 - - insert_final_newline: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Insert a newline character at the end of the file if one does not exist. - - @since 3.15.0""" - # Since: 3.15.0 - - trim_final_newlines: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Trim all newlines after the final newline at the end of the file. - - @since 3.15.0""" - # Since: 3.15.0 - - -@attrs.define -class SemanticTokensLegend: - """@since 3.16.0""" - - # Since: 3.16.0 - - token_types: List[str] = attrs.field() - """The token types a server uses.""" - - token_modifiers: List[str] = attrs.field() - """The token modifiers a server uses.""" - - -@attrs.define -class OptionalVersionedTextDocumentIdentifier: - """A text document identifier to optionally denote a specific version of a text document.""" - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The text document's uri.""" - - version: Optional[Union[int, None]] = attrs.field(default=None) - """The version number of this document. If a versioned text document identifier - is sent from the server to the client and the file is not open in the editor - (the server has not received an open notification before) the server can send - `null` to indicate that the version is unknown and the content on disk is the - truth (as specified with document content ownership).""" - - -@attrs.define -class AnnotatedTextEdit: - """A special text edit with an additional change annotation. - - @since 3.16.0.""" - - # Since: 3.16.0. - - annotation_id: ChangeAnnotationIdentifier = attrs.field() - """The actual identifier of the change annotation""" - - range: Range = attrs.field() - """The range of the text document to be manipulated. To insert - text into a document create a range where start === end.""" - - new_text: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The string to be inserted. For delete operations use an - empty string.""" - - -@attrs.define -class CreateFileOptions: - """Options to create a file.""" - - overwrite: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Overwrite existing file. Overwrite wins over `ignoreIfExists`""" - - ignore_if_exists: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Ignore if exists.""" - - -@attrs.define -class RenameFileOptions: - """Rename file options""" - - overwrite: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Overwrite target if existing. Overwrite wins over `ignoreIfExists`""" - - ignore_if_exists: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Ignores if target exists.""" - - -@attrs.define -class DeleteFileOptions: - """Delete file options""" - - recursive: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Delete the content recursively if a folder is denoted.""" - - ignore_if_not_exists: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Ignore the operation if the file doesn't exist.""" - - -@attrs.define -class FileOperationPattern: - """A pattern to describe in which file operation requests or notifications - the server is interested in receiving. - - @since 3.16.0""" - - # Since: 3.16.0 - - glob: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The glob pattern to match. Glob patterns can have the following syntax: - - `*` to match one or more characters in a path segment - - `?` to match on one character in a path segment - - `**` to match any number of path segments, including none - - `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) - - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) - - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)""" - - matches: Optional[FileOperationPatternKind] = attrs.field(default=None) - """Whether to match files or folders with this pattern. - - Matches both if undefined.""" - - options: Optional["FileOperationPatternOptions"] = attrs.field(default=None) - """Additional options used during matching.""" - - -@attrs.define -class WorkspaceFullDocumentDiagnosticReport: - """A full document diagnostic report for a workspace diagnostic result. - - @since 3.17.0""" - - # Since: 3.17.0 - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The URI for which diagnostic information is reported.""" - - items: List[Diagnostic] = attrs.field() - """The actual items.""" - - version: Optional[Union[int, None]] = attrs.field(default=None) - """The version number for which the diagnostics are reported. - If the document is not marked as open `null` can be provided.""" - - kind: str = attrs.field(validator=attrs.validators.in_(["full"]), default="full") - """A full document diagnostic report.""" - - result_id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """An optional result id. If provided it will - be sent on the next diagnostic request for the - same document.""" - - -@attrs.define -class WorkspaceUnchangedDocumentDiagnosticReport: - """An unchanged document diagnostic report for a workspace diagnostic result. - - @since 3.17.0""" - - # Since: 3.17.0 - - uri: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The URI for which diagnostic information is reported.""" - - result_id: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A result id which will be sent on the next - diagnostic request for the same document.""" - - version: Optional[Union[int, None]] = attrs.field(default=None) - """The version number for which the diagnostics are reported. - If the document is not marked as open `null` can be provided.""" - - kind: str = attrs.field( - validator=attrs.validators.in_(["unchanged"]), default="unchanged" - ) - """A document diagnostic report indicating - no changes to the last result. A server can - only return `unchanged` if result ids are - provided.""" - - -@attrs.define -class NotebookCell: - """A notebook cell. - - A cell's document URI must be unique across ALL notebook - cells and can therefore be used to uniquely identify a - notebook cell or the cell's text document. - - @since 3.17.0""" - - # Since: 3.17.0 - - kind: NotebookCellKind = attrs.field() - """The cell's kind""" - - document: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The URI of the cell's text document - content.""" - - metadata: Optional[LSPObject] = attrs.field(default=None) - """Additional metadata stored with the cell. - - Note: should always be an object literal (e.g. LSPObject)""" - - execution_summary: Optional["ExecutionSummary"] = attrs.field(default=None) - """Additional execution summary information - if supported by the client.""" - - -@attrs.define -class NotebookCellArrayChange: - """A change describing how to move a `NotebookCell` - array from state S to S'. - - @since 3.17.0""" - - # Since: 3.17.0 - - start: int = attrs.field(validator=validators.uinteger_validator) - """The start oftest of the cell that changed.""" - - delete_count: int = attrs.field(validator=validators.uinteger_validator) - """The deleted cells""" - - cells: Optional[List[NotebookCell]] = attrs.field(default=None) - """The new cells, if any""" - - -@attrs.define -class SelectedCompletionInfo: - """Describes the currently selected completion item. - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - - range: Range = attrs.field() - """The range that will be replaced if this completion item is accepted.""" - - text: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The text the range will be replaced with if this completion is accepted.""" - - -@attrs.define -class ClientCapabilities: - """Defines the capabilities provided by the client.""" - - workspace: Optional["WorkspaceClientCapabilities"] = attrs.field(default=None) - """Workspace specific client capabilities.""" - - text_document: Optional["TextDocumentClientCapabilities"] = attrs.field( - default=None - ) - """Text document specific client capabilities.""" - - notebook_document: Optional["NotebookDocumentClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the notebook document support. - - @since 3.17.0""" - # Since: 3.17.0 - - window: Optional["WindowClientCapabilities"] = attrs.field(default=None) - """Window specific client capabilities.""" - - general: Optional["GeneralClientCapabilities"] = attrs.field(default=None) - """General client capabilities. - - @since 3.16.0""" - # Since: 3.16.0 - - experimental: Optional[LSPAny] = attrs.field(default=None) - """Experimental client capabilities.""" - - -@attrs.define -class TextDocumentSyncOptions: - open_close: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Open and close notifications are sent to the server. If omitted open close notification should not - be sent.""" - - change: Optional[TextDocumentSyncKind] = attrs.field(default=None) - """Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full - and TextDocumentSyncKind.Incremental. If omitted it defaults to TextDocumentSyncKind.None.""" - - will_save: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """If present will save notifications are sent to the server. If omitted the notification should not be - sent.""" - - will_save_wait_until: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """If present will save wait until requests are sent to the server. If omitted the request should not be - sent.""" - - save: Optional[Union[bool, SaveOptions]] = attrs.field(default=None) - """If present save notifications are sent to the server. If omitted the notification should not be - sent.""" - - -@attrs.define -class NotebookDocumentSyncOptionsNotebookSelectorType1CellsType: - language: str = attrs.field(validator=attrs.validators.instance_of(str)) - - -@attrs.define -class NotebookDocumentSyncOptionsNotebookSelectorType1: - notebook: Union[str, NotebookDocumentFilter] = attrs.field() - """The notebook to be synced If a string - value is provided it matches against the - notebook type. '*' matches every notebook.""" - - cells: Optional[ - List["NotebookDocumentSyncOptionsNotebookSelectorType1CellsType"] - ] = attrs.field(default=None) - """The cells of the matching notebook to be synced.""" - - -@attrs.define -class NotebookDocumentSyncOptionsNotebookSelectorType2CellsType: - language: str = attrs.field(validator=attrs.validators.instance_of(str)) - - -@attrs.define -class NotebookDocumentSyncOptionsNotebookSelectorType2: - cells: List[ - "NotebookDocumentSyncOptionsNotebookSelectorType2CellsType" - ] = attrs.field() - """The cells of the matching notebook to be synced.""" - - notebook: Optional[Union[str, NotebookDocumentFilter]] = attrs.field(default=None) - """The notebook to be synced If a string - value is provided it matches against the - notebook type. '*' matches every notebook.""" - - -@attrs.define -class NotebookDocumentSyncOptions: - """Options specific to a notebook plus its cells - to be synced to the server. - - If a selector provides a notebook document - filter but no cell selector all cells of a - matching notebook document will be synced. - - If a selector provides no notebook document - filter but only a cell selector all notebook - document that contain at least one matching - cell will be synced. - - @since 3.17.0""" - - # Since: 3.17.0 - - notebook_selector: List[ - Union[ - "NotebookDocumentSyncOptionsNotebookSelectorType1", - "NotebookDocumentSyncOptionsNotebookSelectorType2", - ] - ] = attrs.field() - """The notebooks to be synced""" - - save: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether save notification should be forwarded to - the server. Will only be honored if mode === `notebook`.""" - - -@attrs.define -class NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1CellsType: - language: str = attrs.field(validator=attrs.validators.instance_of(str)) - - -@attrs.define -class NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1: - notebook: Union[str, NotebookDocumentFilter] = attrs.field() - """The notebook to be synced If a string - value is provided it matches against the - notebook type. '*' matches every notebook.""" - - cells: Optional[ - List["NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1CellsType"] - ] = attrs.field(default=None) - """The cells of the matching notebook to be synced.""" - - -@attrs.define -class NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2CellsType: - language: str = attrs.field(validator=attrs.validators.instance_of(str)) - - -@attrs.define -class NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2: - cells: List[ - "NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2CellsType" - ] = attrs.field() - """The cells of the matching notebook to be synced.""" - - notebook: Optional[Union[str, NotebookDocumentFilter]] = attrs.field(default=None) - """The notebook to be synced If a string - value is provided it matches against the - notebook type. '*' matches every notebook.""" - - -@attrs.define -class NotebookDocumentSyncRegistrationOptions: - """Registration options specific to a notebook. - - @since 3.17.0""" - - # Since: 3.17.0 - - notebook_selector: List[ - Union[ - "NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1", - "NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2", - ] - ] = attrs.field() - """The notebooks to be synced""" - - save: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether save notification should be forwarded to - the server. Will only be honored if mode === `notebook`.""" - - id: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The id used to register the request. The id can be used to deregister - the request again. See also Registration#id.""" - - -@attrs.define -class WorkspaceFoldersServerCapabilities: - supported: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The server has support for workspace folders""" - - change_notifications: Optional[Union[str, bool]] = attrs.field(default=None) - """Whether the server wants to receive workspace folder - change notifications. - - If a string is provided the string is treated as an ID - under which the notification is registered on the client - side. The ID can be used to unregister for these events - using the `client/unregisterCapability` request.""" - - -@attrs.define -class FileOperationOptions: - """Options for notifications/requests for user operations on files. - - @since 3.16.0""" - - # Since: 3.16.0 - - did_create: Optional[FileOperationRegistrationOptions] = attrs.field(default=None) - """The server is interested in receiving didCreateFiles notifications.""" - - will_create: Optional[FileOperationRegistrationOptions] = attrs.field(default=None) - """The server is interested in receiving willCreateFiles requests.""" - - did_rename: Optional[FileOperationRegistrationOptions] = attrs.field(default=None) - """The server is interested in receiving didRenameFiles notifications.""" - - will_rename: Optional[FileOperationRegistrationOptions] = attrs.field(default=None) - """The server is interested in receiving willRenameFiles requests.""" - - did_delete: Optional[FileOperationRegistrationOptions] = attrs.field(default=None) - """The server is interested in receiving didDeleteFiles file notifications.""" - - will_delete: Optional[FileOperationRegistrationOptions] = attrs.field(default=None) - """The server is interested in receiving willDeleteFiles file requests.""" - - -@attrs.define -class CodeDescription: - """Structure to capture a description for an error code. - - @since 3.16.0""" - - # Since: 3.16.0 - - href: str = attrs.field(validator=attrs.validators.instance_of(str)) - """An URI to open with more information about the diagnostic error.""" - - -@attrs.define -class DiagnosticRelatedInformation: - """Represents a related message and source code location for a diagnostic. This should be - used to point to code locations that cause or related to a diagnostics, e.g when duplicating - a symbol in a scope.""" - - location: Location = attrs.field() - """The location of this related diagnostic information.""" - - message: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The message of this related diagnostic information.""" - - -@attrs.define -class ParameterInformation: - """Represents a parameter of a callable-signature. A parameter can - have a label and a doc-comment.""" - - label: Union[str, Tuple[int, int]] = attrs.field() - """The label of this parameter information. - - Either a string or an inclusive start and exclusive end offsets within its containing - signature label. (see SignatureInformation.label). The offsets are based on a UTF-16 - string representation as `Position` and `Range` does. - - *Note*: a label of type string should be a substring of its containing signature label. - Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`.""" - - documentation: Optional[Union[str, MarkupContent]] = attrs.field(default=None) - """The human-readable doc-comment of this parameter. Will be shown - in the UI but can be omitted.""" - - -@attrs.define -class NotebookCellTextDocumentFilter: - """A notebook cell text document filter denotes a cell text - document by different properties. - - @since 3.17.0""" - - # Since: 3.17.0 - - notebook: Union[str, NotebookDocumentFilter] = attrs.field() - """A filter that matches against the notebook - containing the notebook cell. If a string - value is provided it matches against the - notebook type. '*' matches every notebook.""" - - language: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """A language id like `python`. - - Will be matched against the language id of the - notebook cell document. '*' matches every language.""" - - -@attrs.define -class FileOperationPatternOptions: - """Matching options for the file operation pattern. - - @since 3.16.0""" - - # Since: 3.16.0 - - ignore_case: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The pattern should be matched ignoring casing.""" - - -@attrs.define -class ExecutionSummary: - execution_order: int = attrs.field(validator=validators.uinteger_validator) - """A strict monotonically increasing value - indicating the execution order of a cell - inside a notebook.""" - - success: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the execution was successful or - not if known by the client.""" - - -@attrs.define -class WorkspaceClientCapabilities: - """Workspace specific client capabilities.""" - - apply_edit: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports applying batch edits - to the workspace by supporting the request - 'workspace/applyEdit'""" - - workspace_edit: Optional["WorkspaceEditClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to `WorkspaceEdit`s.""" - - did_change_configuration: Optional[ - "DidChangeConfigurationClientCapabilities" - ] = attrs.field(default=None) - """Capabilities specific to the `workspace/didChangeConfiguration` notification.""" - - did_change_watched_files: Optional[ - "DidChangeWatchedFilesClientCapabilities" - ] = attrs.field(default=None) - """Capabilities specific to the `workspace/didChangeWatchedFiles` notification.""" - - symbol: Optional["WorkspaceSymbolClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the `workspace/symbol` request.""" - - execute_command: Optional["ExecuteCommandClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `workspace/executeCommand` request.""" - - workspace_folders: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client has support for workspace folders. - - @since 3.6.0""" - # Since: 3.6.0 - - configuration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports `workspace/configuration` requests. - - @since 3.6.0""" - # Since: 3.6.0 - - semantic_tokens: Optional[ - "SemanticTokensWorkspaceClientCapabilities" - ] = attrs.field(default=None) - """Capabilities specific to the semantic token requests scoped to the - workspace. - - @since 3.16.0.""" - # Since: 3.16.0. - - code_lens: Optional["CodeLensWorkspaceClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the code lens requests scoped to the - workspace. - - @since 3.16.0.""" - # Since: 3.16.0. - - file_operations: Optional["FileOperationClientCapabilities"] = attrs.field( - default=None - ) - """The client has support for file notifications/requests for user operations on files. - - Since 3.16.0""" - - inline_value: Optional["InlineValueWorkspaceClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the inline values requests scoped to the - workspace. - - @since 3.17.0.""" - # Since: 3.17.0. - - inlay_hint: Optional["InlayHintWorkspaceClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the inlay hint requests scoped to the - workspace. - - @since 3.17.0.""" - # Since: 3.17.0. - - diagnostics: Optional["DiagnosticWorkspaceClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the diagnostic requests scoped to the - workspace. - - @since 3.17.0.""" - # Since: 3.17.0. - - folding_range: Optional["FoldingRangeWorkspaceClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the folding range requests scoped to the workspace. - - @since 3.18.0 - @proposed""" - # Since: 3.18.0 - # Proposed - - -@attrs.define -class TextDocumentClientCapabilities: - """Text document specific client capabilities.""" - - synchronization: Optional["TextDocumentSyncClientCapabilities"] = attrs.field( - default=None - ) - """Defines which synchronization capabilities the client supports.""" - - completion: Optional["CompletionClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the `textDocument/completion` request.""" - - hover: Optional["HoverClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the `textDocument/hover` request.""" - - signature_help: Optional["SignatureHelpClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `textDocument/signatureHelp` request.""" - - declaration: Optional["DeclarationClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the `textDocument/declaration` request. - - @since 3.14.0""" - # Since: 3.14.0 - - definition: Optional["DefinitionClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the `textDocument/definition` request.""" - - type_definition: Optional["TypeDefinitionClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `textDocument/typeDefinition` request. - - @since 3.6.0""" - # Since: 3.6.0 - - implementation: Optional["ImplementationClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `textDocument/implementation` request. - - @since 3.6.0""" - # Since: 3.6.0 - - references: Optional["ReferenceClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the `textDocument/references` request.""" - - document_highlight: Optional["DocumentHighlightClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `textDocument/documentHighlight` request.""" - - document_symbol: Optional["DocumentSymbolClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `textDocument/documentSymbol` request.""" - - code_action: Optional["CodeActionClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the `textDocument/codeAction` request.""" - - code_lens: Optional["CodeLensClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the `textDocument/codeLens` request.""" - - document_link: Optional["DocumentLinkClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `textDocument/documentLink` request.""" - - color_provider: Optional["DocumentColorClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `textDocument/documentColor` and the - `textDocument/colorPresentation` request. - - @since 3.6.0""" - # Since: 3.6.0 - - formatting: Optional["DocumentFormattingClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `textDocument/formatting` request.""" - - range_formatting: Optional[ - "DocumentRangeFormattingClientCapabilities" - ] = attrs.field(default=None) - """Capabilities specific to the `textDocument/rangeFormatting` request.""" - - on_type_formatting: Optional[ - "DocumentOnTypeFormattingClientCapabilities" - ] = attrs.field(default=None) - """Capabilities specific to the `textDocument/onTypeFormatting` request.""" - - rename: Optional["RenameClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the `textDocument/rename` request.""" - - folding_range: Optional["FoldingRangeClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `textDocument/foldingRange` request. - - @since 3.10.0""" - # Since: 3.10.0 - - selection_range: Optional["SelectionRangeClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `textDocument/selectionRange` request. - - @since 3.15.0""" - # Since: 3.15.0 - - publish_diagnostics: Optional["PublishDiagnosticsClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the `textDocument/publishDiagnostics` notification.""" - - call_hierarchy: Optional["CallHierarchyClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the various call hierarchy requests. - - @since 3.16.0""" - # Since: 3.16.0 - - semantic_tokens: Optional["SemanticTokensClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the various semantic token request. - - @since 3.16.0""" - # Since: 3.16.0 - - linked_editing_range: Optional[ - "LinkedEditingRangeClientCapabilities" - ] = attrs.field(default=None) - """Capabilities specific to the `textDocument/linkedEditingRange` request. - - @since 3.16.0""" - # Since: 3.16.0 - - moniker: Optional["MonikerClientCapabilities"] = attrs.field(default=None) - """Client capabilities specific to the `textDocument/moniker` request. - - @since 3.16.0""" - # Since: 3.16.0 - - type_hierarchy: Optional["TypeHierarchyClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the various type hierarchy requests. - - @since 3.17.0""" - # Since: 3.17.0 - - inline_value: Optional["InlineValueClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the `textDocument/inlineValue` request. - - @since 3.17.0""" - # Since: 3.17.0 - - inlay_hint: Optional["InlayHintClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the `textDocument/inlayHint` request. - - @since 3.17.0""" - # Since: 3.17.0 - - diagnostic: Optional["DiagnosticClientCapabilities"] = attrs.field(default=None) - """Capabilities specific to the diagnostic pull model. - - @since 3.17.0""" - # Since: 3.17.0 - - inline_completion: Optional["InlineCompletionClientCapabilities"] = attrs.field( - default=None - ) - """Client capabilities specific to inline completions. - - @since 3.18.0 - @proposed""" - # Since: 3.18.0 - # Proposed - - -@attrs.define -class NotebookDocumentClientCapabilities: - """Capabilities specific to the notebook document support. - - @since 3.17.0""" - - # Since: 3.17.0 - - synchronization: "NotebookDocumentSyncClientCapabilities" = attrs.field() - """Capabilities specific to notebook document synchronization - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class WindowClientCapabilities: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """It indicates whether the client supports server initiated - progress using the `window/workDoneProgress/create` request. - - The capability also controls Whether client supports handling - of progress notifications. If set servers are allowed to report a - `workDoneProgress` property in the request specific server - capabilities. - - @since 3.15.0""" - # Since: 3.15.0 - - show_message: Optional["ShowMessageRequestClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the showMessage request. - - @since 3.16.0""" - # Since: 3.16.0 - - show_document: Optional["ShowDocumentClientCapabilities"] = attrs.field( - default=None - ) - """Capabilities specific to the showDocument request. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class GeneralClientCapabilitiesStaleRequestSupportType: - cancel: bool = attrs.field(validator=attrs.validators.instance_of(bool)) - """The client will actively cancel the request.""" - - retry_on_content_modified: List[str] = attrs.field() - """The list of requests for which the client - will retry the request if it receives a - response with error code `ContentModified`""" - - -@attrs.define -class GeneralClientCapabilities: - """General client capabilities. - - @since 3.16.0""" - - # Since: 3.16.0 - - stale_request_support: Optional[ - "GeneralClientCapabilitiesStaleRequestSupportType" - ] = attrs.field(default=None) - """Client capability that signals how the client - handles stale requests (e.g. a request - for which the client will not process the response - anymore since the information is outdated). - - @since 3.17.0""" - # Since: 3.17.0 - - regular_expressions: Optional["RegularExpressionsClientCapabilities"] = attrs.field( - default=None - ) - """Client capabilities specific to regular expressions. - - @since 3.16.0""" - # Since: 3.16.0 - - markdown: Optional["MarkdownClientCapabilities"] = attrs.field(default=None) - """Client capabilities specific to the client's markdown parser. - - @since 3.16.0""" - # Since: 3.16.0 - - position_encodings: Optional[List[Union[PositionEncodingKind, str]]] = attrs.field( - default=None - ) - """The position encodings supported by the client. Client and server - have to agree on the same position encoding to ensure that offsets - (e.g. character position in a line) are interpreted the same on both - sides. - - To keep the protocol backwards compatible the following applies: if - the value 'utf-16' is missing from the array of position encodings - servers can assume that the client supports UTF-16. UTF-16 is - therefore a mandatory encoding. - - If omitted it defaults to ['utf-16']. - - Implementation considerations: since the conversion from one encoding - into another requires the content of the file / line the conversion - is best done where the file is read which is usually on the server - side. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class RelativePattern: - """A relative pattern is a helper to construct glob patterns that are matched - relatively to a base URI. The common value for a `baseUri` is a workspace - folder root, but it can be another absolute URI as well. - - @since 3.17.0""" - - # Since: 3.17.0 - - base_uri: Union[WorkspaceFolder, str] = attrs.field() - """A workspace folder or a base URI to which this pattern will be matched - against relatively.""" - - pattern: Pattern = attrs.field() - """The actual glob pattern;""" - - -@attrs.define -class WorkspaceEditClientCapabilitiesChangeAnnotationSupportType: - groups_on_label: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client groups edits with equal labels into tree nodes, - for instance all edits labelled with "Changes in Strings" would - be a tree node.""" - - -@attrs.define -class WorkspaceEditClientCapabilities: - document_changes: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports versioned document changes in `WorkspaceEdit`s""" - - resource_operations: Optional[List[ResourceOperationKind]] = attrs.field( - default=None - ) - """The resource operations the client supports. Clients should at least - support 'create', 'rename' and 'delete' files and folders. - - @since 3.13.0""" - # Since: 3.13.0 - - failure_handling: Optional[FailureHandlingKind] = attrs.field(default=None) - """The failure handling strategy of a client if applying the workspace edit - fails. - - @since 3.13.0""" - # Since: 3.13.0 - - normalizes_line_endings: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client normalizes line endings to the client specific - setting. - If set to `true` the client will normalize line ending characters - in a workspace edit to the client-specified new line - character. - - @since 3.16.0""" - # Since: 3.16.0 - - change_annotation_support: Optional[ - "WorkspaceEditClientCapabilitiesChangeAnnotationSupportType" - ] = attrs.field(default=None) - """Whether the client in general supports change annotations on text edits, - create file, rename file and delete file changes. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class DidChangeConfigurationClientCapabilities: - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Did change configuration notification supports dynamic registration.""" - - -@attrs.define -class DidChangeWatchedFilesClientCapabilities: - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Did change watched files notification supports dynamic registration. Please note - that the current protocol doesn't support static configuration for file changes - from the server side.""" - - relative_pattern_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client has support for {@link RelativePattern relative pattern} - or not. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class WorkspaceSymbolClientCapabilitiesSymbolKindType: - value_set: Optional[List[SymbolKind]] = attrs.field(default=None) - """The symbol kind values the client supports. When this - property exists the client also guarantees that it will - handle values outside its set gracefully and falls back - to a default value when unknown. - - If this property is not present the client only supports - the symbol kinds from `File` to `Array` as defined in - the initial version of the protocol.""" - - -@attrs.define -class WorkspaceSymbolClientCapabilitiesTagSupportType: - value_set: List[SymbolTag] = attrs.field() - """The tags supported by the client.""" - - -@attrs.define -class WorkspaceSymbolClientCapabilitiesResolveSupportType: - properties: List[str] = attrs.field() - """The properties that a client can resolve lazily. Usually - `location.range`""" - - -@attrs.define -class WorkspaceSymbolClientCapabilities: - """Client capabilities for a {@link WorkspaceSymbolRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Symbol request supports dynamic registration.""" - - symbol_kind: Optional[ - "WorkspaceSymbolClientCapabilitiesSymbolKindType" - ] = attrs.field(default=None) - """Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.""" - - tag_support: Optional[ - "WorkspaceSymbolClientCapabilitiesTagSupportType" - ] = attrs.field(default=None) - """The client supports tags on `SymbolInformation`. - Clients supporting tags have to handle unknown tags gracefully. - - @since 3.16.0""" - # Since: 3.16.0 - - resolve_support: Optional[ - "WorkspaceSymbolClientCapabilitiesResolveSupportType" - ] = attrs.field(default=None) - """The client support partial workspace symbols. The client will send the - request `workspaceSymbol/resolve` to the server to resolve additional - properties. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class ExecuteCommandClientCapabilities: - """The client capabilities of a {@link ExecuteCommandRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Execute command supports dynamic registration.""" - - -@attrs.define -class SemanticTokensWorkspaceClientCapabilities: - """@since 3.16.0""" - - # Since: 3.16.0 - - refresh_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client implementation supports a refresh request sent from - the server to the client. - - Note that this event is global and will force the client to refresh all - semantic tokens currently shown. It should be used with absolute care - and is useful for situation where a server for example detects a project - wide change that requires such a calculation.""" - - -@attrs.define -class CodeLensWorkspaceClientCapabilities: - """@since 3.16.0""" - - # Since: 3.16.0 - - refresh_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client implementation supports a refresh request sent from the - server to the client. - - Note that this event is global and will force the client to refresh all - code lenses currently shown. It should be used with absolute care and is - useful for situation where a server for example detect a project wide - change that requires such a calculation.""" - - -@attrs.define -class FileOperationClientCapabilities: - """Capabilities relating to events from file operations by the user in the client. - - These events do not come from the file system, they come from user operations - like renaming a file in the UI. - - @since 3.16.0""" - - # Since: 3.16.0 - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client supports dynamic registration for file requests/notifications.""" - - did_create: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client has support for sending didCreateFiles notifications.""" - - will_create: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client has support for sending willCreateFiles requests.""" - - did_rename: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client has support for sending didRenameFiles notifications.""" - - will_rename: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client has support for sending willRenameFiles requests.""" - - did_delete: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client has support for sending didDeleteFiles notifications.""" - - will_delete: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client has support for sending willDeleteFiles requests.""" - - -@attrs.define -class InlineValueWorkspaceClientCapabilities: - """Client workspace capabilities specific to inline values. - - @since 3.17.0""" - - # Since: 3.17.0 - - refresh_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client implementation supports a refresh request sent from the - server to the client. - - Note that this event is global and will force the client to refresh all - inline values currently shown. It should be used with absolute care and is - useful for situation where a server for example detects a project wide - change that requires such a calculation.""" - - -@attrs.define -class InlayHintWorkspaceClientCapabilities: - """Client workspace capabilities specific to inlay hints. - - @since 3.17.0""" - - # Since: 3.17.0 - - refresh_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client implementation supports a refresh request sent from - the server to the client. - - Note that this event is global and will force the client to refresh all - inlay hints currently shown. It should be used with absolute care and - is useful for situation where a server for example detects a project wide - change that requires such a calculation.""" - - -@attrs.define -class DiagnosticWorkspaceClientCapabilities: - """Workspace client capabilities specific to diagnostic pull requests. - - @since 3.17.0""" - - # Since: 3.17.0 - - refresh_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client implementation supports a refresh request sent from - the server to the client. - - Note that this event is global and will force the client to refresh all - pulled diagnostics currently shown. It should be used with absolute care and - is useful for situation where a server for example detects a project wide - change that requires such a calculation.""" - - -@attrs.define -class FoldingRangeWorkspaceClientCapabilities: - """Client workspace capabilities specific to folding ranges - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - - refresh_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client implementation supports a refresh request sent from the - server to the client. - - Note that this event is global and will force the client to refresh all - folding ranges currently shown. It should be used with absolute care and is - useful for situation where a server for example detects a project wide - change that requires such a calculation. - - @since 3.18.0 - @proposed""" - # Since: 3.18.0 - # Proposed - - -@attrs.define -class TextDocumentSyncClientCapabilities: - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether text document synchronization supports dynamic registration.""" - - will_save: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports sending will save notifications.""" - - will_save_wait_until: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports sending a will save request and - waits for a response providing text edits which will - be applied to the document before it is saved.""" - - did_save: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports did save notifications.""" - - -@attrs.define -class CompletionClientCapabilitiesCompletionItemTypeTagSupportType: - value_set: List[CompletionItemTag] = attrs.field() - """The tags supported by the client.""" - - -@attrs.define -class CompletionClientCapabilitiesCompletionItemTypeResolveSupportType: - properties: List[str] = attrs.field() - """The properties that a client can resolve lazily.""" - - -@attrs.define -class CompletionClientCapabilitiesCompletionItemTypeInsertTextModeSupportType: - value_set: List[InsertTextMode] = attrs.field() - - -@attrs.define -class CompletionClientCapabilitiesCompletionItemType: - snippet_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Client supports snippets as insert text. - - A snippet can define tab stops and placeholders with `$1`, `$2` - and `${3:foo}`. `$0` defines the final tab stop, it defaults to - the end of the snippet. Placeholders with equal identifiers are linked, - that is typing in one will update others too.""" - - commit_characters_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Client supports commit characters on a completion item.""" - - documentation_format: Optional[List[MarkupKind]] = attrs.field(default=None) - """Client supports the following content formats for the documentation - property. The order describes the preferred format of the client.""" - - deprecated_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Client supports the deprecated property on a completion item.""" - - preselect_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Client supports the preselect property on a completion item.""" - - tag_support: Optional[ - "CompletionClientCapabilitiesCompletionItemTypeTagSupportType" - ] = attrs.field(default=None) - """Client supports the tag property on a completion item. Clients supporting - tags have to handle unknown tags gracefully. Clients especially need to - preserve unknown tags when sending a completion item back to the server in - a resolve call. - - @since 3.15.0""" - # Since: 3.15.0 - - insert_replace_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Client support insert replace edit to control different behavior if a - completion item is inserted in the text or should replace text. - - @since 3.16.0""" - # Since: 3.16.0 - - resolve_support: Optional[ - "CompletionClientCapabilitiesCompletionItemTypeResolveSupportType" - ] = attrs.field(default=None) - """Indicates which properties a client can resolve lazily on a completion - item. Before version 3.16.0 only the predefined properties `documentation` - and `details` could be resolved lazily. - - @since 3.16.0""" - # Since: 3.16.0 - - insert_text_mode_support: Optional[ - "CompletionClientCapabilitiesCompletionItemTypeInsertTextModeSupportType" - ] = attrs.field(default=None) - """The client supports the `insertTextMode` property on - a completion item to override the whitespace handling mode - as defined by the client (see `insertTextMode`). - - @since 3.16.0""" - # Since: 3.16.0 - - label_details_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client has support for completion item label - details (see also `CompletionItemLabelDetails`). - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class CompletionClientCapabilitiesCompletionItemKindType: - value_set: Optional[List[CompletionItemKind]] = attrs.field(default=None) - """The completion item kind values the client supports. When this - property exists the client also guarantees that it will - handle values outside its set gracefully and falls back - to a default value when unknown. - - If this property is not present the client only supports - the completion items kinds from `Text` to `Reference` as defined in - the initial version of the protocol.""" - - -@attrs.define -class CompletionClientCapabilitiesCompletionListType: - item_defaults: Optional[List[str]] = attrs.field(default=None) - """The client supports the following itemDefaults on - a completion list. - - The value lists the supported property names of the - `CompletionList.itemDefaults` object. If omitted - no properties are supported. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class CompletionClientCapabilities: - """Completion client capabilities""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether completion supports dynamic registration.""" - - completion_item: Optional[ - "CompletionClientCapabilitiesCompletionItemType" - ] = attrs.field(default=None) - """The client supports the following `CompletionItem` specific - capabilities.""" - - completion_item_kind: Optional[ - "CompletionClientCapabilitiesCompletionItemKindType" - ] = attrs.field(default=None) - - insert_text_mode: Optional[InsertTextMode] = attrs.field(default=None) - """Defines how the client handles whitespace and indentation - when accepting a completion item that uses multi line - text in either `insertText` or `textEdit`. - - @since 3.17.0""" - # Since: 3.17.0 - - context_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports to send additional context information for a - `textDocument/completion` request.""" - - completion_list: Optional[ - "CompletionClientCapabilitiesCompletionListType" - ] = attrs.field(default=None) - """The client supports the following `CompletionList` specific - capabilities. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class HoverClientCapabilities: - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether hover supports dynamic registration.""" - - content_format: Optional[List[MarkupKind]] = attrs.field(default=None) - """Client supports the following content formats for the content - property. The order describes the preferred format of the client.""" - - -@attrs.define -class SignatureHelpClientCapabilitiesSignatureInformationTypeParameterInformationType: - label_offset_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports processing label offsets instead of a - simple label string. - - @since 3.14.0""" - # Since: 3.14.0 - - -@attrs.define -class SignatureHelpClientCapabilitiesSignatureInformationType: - documentation_format: Optional[List[MarkupKind]] = attrs.field(default=None) - """Client supports the following content formats for the documentation - property. The order describes the preferred format of the client.""" - - parameter_information: Optional[ - "SignatureHelpClientCapabilitiesSignatureInformationTypeParameterInformationType" - ] = attrs.field(default=None) - """Client capabilities specific to parameter information.""" - - active_parameter_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports the `activeParameter` property on `SignatureInformation` - literal. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class SignatureHelpClientCapabilities: - """Client Capabilities for a {@link SignatureHelpRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether signature help supports dynamic registration.""" - - signature_information: Optional[ - "SignatureHelpClientCapabilitiesSignatureInformationType" - ] = attrs.field(default=None) - """The client supports the following `SignatureInformation` - specific properties.""" - - context_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports to send additional context information for a - `textDocument/signatureHelp` request. A client that opts into - contextSupport will also support the `retriggerCharacters` on - `SignatureHelpOptions`. - - @since 3.15.0""" - # Since: 3.15.0 - - -@attrs.define -class DeclarationClientCapabilities: - """@since 3.14.0""" - - # Since: 3.14.0 - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether declaration supports dynamic registration. If this is set to `true` - the client supports the new `DeclarationRegistrationOptions` return value - for the corresponding server capability as well.""" - - link_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports additional metadata in the form of declaration links.""" - - -@attrs.define -class DefinitionClientCapabilities: - """Client Capabilities for a {@link DefinitionRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether definition supports dynamic registration.""" - - link_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports additional metadata in the form of definition links. - - @since 3.14.0""" - # Since: 3.14.0 - - -@attrs.define -class TypeDefinitionClientCapabilities: - """Since 3.6.0""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration. If this is set to `true` - the client supports the new `TypeDefinitionRegistrationOptions` return value - for the corresponding server capability as well.""" - - link_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports additional metadata in the form of definition links. - - Since 3.14.0""" - - -@attrs.define -class ImplementationClientCapabilities: - """@since 3.6.0""" - - # Since: 3.6.0 - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration. If this is set to `true` - the client supports the new `ImplementationRegistrationOptions` return value - for the corresponding server capability as well.""" - - link_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports additional metadata in the form of definition links. - - @since 3.14.0""" - # Since: 3.14.0 - - -@attrs.define -class ReferenceClientCapabilities: - """Client Capabilities for a {@link ReferencesRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether references supports dynamic registration.""" - - -@attrs.define -class DocumentHighlightClientCapabilities: - """Client Capabilities for a {@link DocumentHighlightRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether document highlight supports dynamic registration.""" - - -@attrs.define -class DocumentSymbolClientCapabilitiesSymbolKindType: - value_set: Optional[List[SymbolKind]] = attrs.field(default=None) - """The symbol kind values the client supports. When this - property exists the client also guarantees that it will - handle values outside its set gracefully and falls back - to a default value when unknown. - - If this property is not present the client only supports - the symbol kinds from `File` to `Array` as defined in - the initial version of the protocol.""" - - -@attrs.define -class DocumentSymbolClientCapabilitiesTagSupportType: - value_set: List[SymbolTag] = attrs.field() - """The tags supported by the client.""" - - -@attrs.define -class DocumentSymbolClientCapabilities: - """Client Capabilities for a {@link DocumentSymbolRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether document symbol supports dynamic registration.""" - - symbol_kind: Optional[ - "DocumentSymbolClientCapabilitiesSymbolKindType" - ] = attrs.field(default=None) - """Specific capabilities for the `SymbolKind` in the - `textDocument/documentSymbol` request.""" - - hierarchical_document_symbol_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports hierarchical document symbols.""" - - tag_support: Optional[ - "DocumentSymbolClientCapabilitiesTagSupportType" - ] = attrs.field(default=None) - """The client supports tags on `SymbolInformation`. Tags are supported on - `DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true. - Clients supporting tags have to handle unknown tags gracefully. - - @since 3.16.0""" - # Since: 3.16.0 - - label_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports an additional label presented in the UI when - registering a document symbol provider. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class CodeActionClientCapabilitiesCodeActionLiteralSupportTypeCodeActionKindType: - value_set: List[Union[CodeActionKind, str]] = attrs.field() - """The code action kind values the client supports. When this - property exists the client also guarantees that it will - handle values outside its set gracefully and falls back - to a default value when unknown.""" - - -@attrs.define -class CodeActionClientCapabilitiesCodeActionLiteralSupportType: - code_action_kind: "CodeActionClientCapabilitiesCodeActionLiteralSupportTypeCodeActionKindType" = ( - attrs.field() - ) - """The code action kind is support with the following value - set.""" - - -@attrs.define -class CodeActionClientCapabilitiesResolveSupportType: - properties: List[str] = attrs.field() - """The properties that a client can resolve lazily.""" - - -@attrs.define -class CodeActionClientCapabilities: - """The Client Capabilities of a {@link CodeActionRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether code action supports dynamic registration.""" - - code_action_literal_support: Optional[ - "CodeActionClientCapabilitiesCodeActionLiteralSupportType" - ] = attrs.field(default=None) - """The client support code action literals of type `CodeAction` as a valid - response of the `textDocument/codeAction` request. If the property is not - set the request can only return `Command` literals. - - @since 3.8.0""" - # Since: 3.8.0 - - is_preferred_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether code action supports the `isPreferred` property. - - @since 3.15.0""" - # Since: 3.15.0 - - disabled_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether code action supports the `disabled` property. - - @since 3.16.0""" - # Since: 3.16.0 - - data_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether code action supports the `data` property which is - preserved between a `textDocument/codeAction` and a - `codeAction/resolve` request. - - @since 3.16.0""" - # Since: 3.16.0 - - resolve_support: Optional[ - "CodeActionClientCapabilitiesResolveSupportType" - ] = attrs.field(default=None) - """Whether the client supports resolving additional code action - properties via a separate `codeAction/resolve` request. - - @since 3.16.0""" - # Since: 3.16.0 - - honors_change_annotations: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client honors the change annotations in - text edits and resource operations returned via the - `CodeAction#edit` property by for example presenting - the workspace edit in the user interface and asking - for confirmation. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class CodeLensClientCapabilities: - """The client capabilities of a {@link CodeLensRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether code lens supports dynamic registration.""" - - -@attrs.define -class DocumentLinkClientCapabilities: - """The client capabilities of a {@link DocumentLinkRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether document link supports dynamic registration.""" - - tooltip_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client supports the `tooltip` property on `DocumentLink`. - - @since 3.15.0""" - # Since: 3.15.0 - - -@attrs.define -class DocumentColorClientCapabilities: - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration. If this is set to `true` - the client supports the new `DocumentColorRegistrationOptions` return value - for the corresponding server capability as well.""" - - -@attrs.define -class DocumentFormattingClientCapabilities: - """Client capabilities of a {@link DocumentFormattingRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether formatting supports dynamic registration.""" - - -@attrs.define -class DocumentRangeFormattingClientCapabilities: - """Client capabilities of a {@link DocumentRangeFormattingRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether range formatting supports dynamic registration.""" - - ranges_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client supports formatting multiple ranges at once. - - @since 3.18.0 - @proposed""" - # Since: 3.18.0 - # Proposed - - -@attrs.define -class DocumentOnTypeFormattingClientCapabilities: - """Client capabilities of a {@link DocumentOnTypeFormattingRequest}.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether on type formatting supports dynamic registration.""" - - -@attrs.define -class RenameClientCapabilities: - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether rename supports dynamic registration.""" - - prepare_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Client supports testing for validity of rename operations - before execution. - - @since 3.12.0""" - # Since: 3.12.0 - - prepare_support_default_behavior: Optional[ - PrepareSupportDefaultBehavior - ] = attrs.field(default=None) - """Client supports the default behavior result. - - The value indicates the default behavior used by the - client. - - @since 3.16.0""" - # Since: 3.16.0 - - honors_change_annotations: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client honors the change annotations in - text edits and resource operations returned via the - rename request's workspace edit by for example presenting - the workspace edit in the user interface and asking - for confirmation. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class FoldingRangeClientCapabilitiesFoldingRangeKindType: - value_set: Optional[List[Union[FoldingRangeKind, str]]] = attrs.field(default=None) - """The folding range kind values the client supports. When this - property exists the client also guarantees that it will - handle values outside its set gracefully and falls back - to a default value when unknown.""" - - -@attrs.define -class FoldingRangeClientCapabilitiesFoldingRangeType: - collapsed_text: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """If set, the client signals that it supports setting collapsedText on - folding ranges to display custom labels instead of the default text. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class FoldingRangeClientCapabilities: - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration for folding range - providers. If this is set to `true` the client supports the new - `FoldingRangeRegistrationOptions` return value for the corresponding - server capability as well.""" - - range_limit: Optional[int] = attrs.field( - validator=attrs.validators.optional(validators.uinteger_validator), default=None - ) - """The maximum number of folding ranges that the client prefers to receive - per document. The value serves as a hint, servers are free to follow the - limit.""" - - line_folding_only: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """If set, the client signals that it only supports folding complete lines. - If set, client will ignore specified `startCharacter` and `endCharacter` - properties in a FoldingRange.""" - - folding_range_kind: Optional[ - "FoldingRangeClientCapabilitiesFoldingRangeKindType" - ] = attrs.field(default=None) - """Specific options for the folding range kind. - - @since 3.17.0""" - # Since: 3.17.0 - - folding_range: Optional[ - "FoldingRangeClientCapabilitiesFoldingRangeType" - ] = attrs.field(default=None) - """Specific options for the folding range. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class SelectionRangeClientCapabilities: - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration for selection range providers. If this is set to `true` - the client supports the new `SelectionRangeRegistrationOptions` return value for the corresponding server - capability as well.""" - - -@attrs.define -class PublishDiagnosticsClientCapabilitiesTagSupportType: - value_set: List[DiagnosticTag] = attrs.field() - """The tags supported by the client.""" - - -@attrs.define -class PublishDiagnosticsClientCapabilities: - """The publish diagnostic client capabilities.""" - - related_information: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the clients accepts diagnostics with related information.""" - - tag_support: Optional[ - "PublishDiagnosticsClientCapabilitiesTagSupportType" - ] = attrs.field(default=None) - """Client supports the tag property to provide meta data about a diagnostic. - Clients supporting tags have to handle unknown tags gracefully. - - @since 3.15.0""" - # Since: 3.15.0 - - version_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client interprets the version property of the - `textDocument/publishDiagnostics` notification's parameter. - - @since 3.15.0""" - # Since: 3.15.0 - - code_description_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Client supports a codeDescription property - - @since 3.16.0""" - # Since: 3.16.0 - - data_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether code action supports the `data` property which is - preserved between a `textDocument/publishDiagnostics` and - `textDocument/codeAction` request. - - @since 3.16.0""" - # Since: 3.16.0 - - -@attrs.define -class CallHierarchyClientCapabilities: - """@since 3.16.0""" - - # Since: 3.16.0 - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration. If this is set to `true` - the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - return value for the corresponding server capability as well.""" - - -@attrs.define -class SemanticTokensClientCapabilitiesRequestsTypeFullType1: - delta: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client will send the `textDocument/semanticTokens/full/delta` request if - the server provides a corresponding handler.""" - - -@attrs.define -class SemanticTokensClientCapabilitiesRequestsType: - range: Optional[Union[bool, Any]] = attrs.field(default=None) - """The client will send the `textDocument/semanticTokens/range` request if - the server provides a corresponding handler.""" - - full: Optional[ - Union[bool, "SemanticTokensClientCapabilitiesRequestsTypeFullType1"] - ] = attrs.field(default=None) - """The client will send the `textDocument/semanticTokens/full` request if - the server provides a corresponding handler.""" - - -@attrs.define -class SemanticTokensClientCapabilities: - """@since 3.16.0""" - - # Since: 3.16.0 - - requests: "SemanticTokensClientCapabilitiesRequestsType" = attrs.field() - """Which requests the client supports and might send to the server - depending on the server's capability. Please note that clients might not - show semantic tokens or degrade some of the user experience if a range - or full request is advertised by the client but not provided by the - server. If for example the client capability `requests.full` and - `request.range` are both set to true but the server only provides a - range provider the client might not render a minimap correctly or might - even decide to not show any semantic tokens at all.""" - - token_types: List[str] = attrs.field() - """The token types that the client supports.""" - - token_modifiers: List[str] = attrs.field() - """The token modifiers that the client supports.""" - - formats: List[TokenFormat] = attrs.field() - """The token formats the clients supports.""" - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration. If this is set to `true` - the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - return value for the corresponding server capability as well.""" - - overlapping_token_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client supports tokens that can overlap each other.""" - - multiline_token_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client supports tokens that can span multiple lines.""" - - server_cancel_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client allows the server to actively cancel a - semantic token request, e.g. supports returning - LSPErrorCodes.ServerCancelled. If a server does the client - needs to retrigger the request. - - @since 3.17.0""" - # Since: 3.17.0 - - augments_syntax_tokens: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client uses semantic tokens to augment existing - syntax tokens. If set to `true` client side created syntax - tokens and semantic tokens are both used for colorization. If - set to `false` the client only uses the returned semantic tokens - for colorization. - - If the value is `undefined` then the client behavior is not - specified. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class LinkedEditingRangeClientCapabilities: - """Client capabilities for the linked editing range request. - - @since 3.16.0""" - - # Since: 3.16.0 - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration. If this is set to `true` - the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - return value for the corresponding server capability as well.""" - - -@attrs.define -class MonikerClientCapabilities: - """Client capabilities specific to the moniker request. - - @since 3.16.0""" - - # Since: 3.16.0 - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether moniker supports dynamic registration. If this is set to `true` - the client supports the new `MonikerRegistrationOptions` return value - for the corresponding server capability as well.""" - - -@attrs.define -class TypeHierarchyClientCapabilities: - """@since 3.17.0""" - - # Since: 3.17.0 - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration. If this is set to `true` - the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - return value for the corresponding server capability as well.""" - - -@attrs.define -class InlineValueClientCapabilities: - """Client capabilities specific to inline values. - - @since 3.17.0""" - - # Since: 3.17.0 - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration for inline value providers.""" - - -@attrs.define -class InlayHintClientCapabilitiesResolveSupportType: - properties: List[str] = attrs.field() - """The properties that a client can resolve lazily.""" - - -@attrs.define -class InlayHintClientCapabilities: - """Inlay hint client capabilities. - - @since 3.17.0""" - - # Since: 3.17.0 - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether inlay hints support dynamic registration.""" - - resolve_support: Optional[ - "InlayHintClientCapabilitiesResolveSupportType" - ] = attrs.field(default=None) - """Indicates which properties a client can resolve lazily on an inlay - hint.""" - - -@attrs.define -class DiagnosticClientCapabilities: - """Client capabilities specific to diagnostic pull requests. - - @since 3.17.0""" - - # Since: 3.17.0 - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration. If this is set to `true` - the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - return value for the corresponding server capability as well.""" - - related_document_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the clients supports related documents for document diagnostic pulls.""" - - -@attrs.define -class InlineCompletionClientCapabilities: - """Client capabilities specific to inline completions. - - @since 3.18.0 - @proposed""" - - # Since: 3.18.0 - # Proposed - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration for inline completion providers.""" - - -@attrs.define -class NotebookDocumentSyncClientCapabilities: - """Notebook specific client capabilities. - - @since 3.17.0""" - - # Since: 3.17.0 - - dynamic_registration: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether implementation supports dynamic registration. If this is - set to `true` the client supports the new - `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - return value for the corresponding server capability as well.""" - - execution_summary_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """The client supports sending execution summary data per cell.""" - - -@attrs.define -class ShowMessageRequestClientCapabilitiesMessageActionItemType: - additional_properties_support: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - """Whether the client supports additional attributes which - are preserved and send back to the server in the - request's response.""" - - -@attrs.define -class ShowMessageRequestClientCapabilities: - """Show message request client capabilities""" - - message_action_item: Optional[ - "ShowMessageRequestClientCapabilitiesMessageActionItemType" - ] = attrs.field(default=None) - """Capabilities specific to the `MessageActionItem` type.""" - - -@attrs.define -class ShowDocumentClientCapabilities: - """Client capabilities for the showDocument request. - - @since 3.16.0""" - - # Since: 3.16.0 - - support: bool = attrs.field(validator=attrs.validators.instance_of(bool)) - """The client has support for the showDocument - request.""" - - -@attrs.define -class RegularExpressionsClientCapabilities: - """Client capabilities specific to regular expressions. - - @since 3.16.0""" - - # Since: 3.16.0 - - engine: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The engine's name.""" - - version: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The engine's version.""" - - -@attrs.define -class MarkdownClientCapabilities: - """Client capabilities specific to the used markdown parser. - - @since 3.16.0""" - - # Since: 3.16.0 - - parser: str = attrs.field(validator=attrs.validators.instance_of(str)) - """The name of the parser.""" - - version: Optional[str] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(str)), - default=None, - ) - """The version of the parser.""" - - allowed_tags: Optional[List[str]] = attrs.field(default=None) - """A list of HTML tags that the client allows / supports in - Markdown. - - @since 3.17.0""" - # Since: 3.17.0 - - -@attrs.define -class TextDocumentColorPresentationOptions: - work_done_progress: Optional[bool] = attrs.field( - validator=attrs.validators.optional(attrs.validators.instance_of(bool)), - default=None, - ) - - document_selector: Optional[Union[DocumentSelector, None]] = attrs.field( - default=None - ) - """A document selector to identify the scope of the registration. If set to null - the document selector provided on the client side will be used.""" - - -@attrs.define -class ResponseError: - code: int = attrs.field(validator=validators.integer_validator) - """A number indicating the error type that occurred.""" - message: str = attrs.field(validator=attrs.validators.instance_of(str)) - """A string providing a short description of the error.""" - data: Optional[LSPAny] = attrs.field(default=None) - """A primitive or structured value that contains additional information - about the error. Can be omitted.""" - - -@attrs.define -class ResponseErrorMessage: - id: Optional[Union[int, str]] = attrs.field(default=None) - """The request id where the error occurred.""" - error: Optional[ResponseError] = attrs.field(default=None) - """The error object in case a request fails.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentImplementationRequest: - """A request to resolve the implementation locations of a symbol at a given text - document position. The request's parameter is of type {@link TextDocumentPositionParams} - the response is of type {@link Definition} or a Thenable that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: ImplementationParams = attrs.field() - method: str = "textDocument/implementation" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentImplementationResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[Definition, List[DefinitionLink], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentTypeDefinitionRequest: - """A request to resolve the type definition locations of a symbol at a given text - document position. The request's parameter is of type {@link TextDocumentPositionParams} - the response is of type {@link Definition} or a Thenable that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: TypeDefinitionParams = attrs.field() - method: str = "textDocument/typeDefinition" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentTypeDefinitionResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[Definition, List[DefinitionLink], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceWorkspaceFoldersRequest: - """The `workspace/workspaceFolders` is sent from the server to the client to fetch the open workspace folders.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: Optional[None] = attrs.field(default=None) - method: str = "workspace/workspaceFolders" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceWorkspaceFoldersResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[WorkspaceFolder], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -WorkspaceConfigurationParams = ConfigurationParams - - -@attrs.define -class WorkspaceConfigurationRequest: - """The 'workspace/configuration' request is sent from the server to the client to fetch a certain - configuration setting. - - This pull model replaces the old push model were the client signaled configuration change via an - event. If the server still needs to react to configuration changes (since the server caches the - result of `workspace/configuration` requests) the server should register for an empty configuration - change event and empty the cache if such an event is received.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: WorkspaceConfigurationParams = attrs.field() - method: str = "workspace/configuration" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceConfigurationResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: List[LSPAny] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDocumentColorRequest: - """A request to list all color symbols found in a given text document. The request's - parameter is of type {@link DocumentColorParams} the - response is of type {@link ColorInformation ColorInformation[]} or a Thenable - that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DocumentColorParams = attrs.field() - method: str = "textDocument/documentColor" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDocumentColorResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: List[ColorInformation] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentColorPresentationRequest: - """A request to list all presentation for a color. The request's - parameter is of type {@link ColorPresentationParams} the - response is of type {@link ColorInformation ColorInformation[]} or a Thenable - that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: ColorPresentationParams = attrs.field() - method: str = "textDocument/colorPresentation" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentColorPresentationResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: List[ColorPresentation] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentFoldingRangeRequest: - """A request to provide folding ranges in a document. The request's - parameter is of type {@link FoldingRangeParams}, the - response is of type {@link FoldingRangeList} or a Thenable - that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: FoldingRangeParams = attrs.field() - method: str = "textDocument/foldingRange" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentFoldingRangeResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[FoldingRange], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceFoldingRangeRefreshRequest: - """@since 3.18.0 - @proposed""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: Optional[None] = attrs.field(default=None) - method: str = "workspace/foldingRange/refresh" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceFoldingRangeRefreshResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: None = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDeclarationRequest: - """A request to resolve the type definition locations of a symbol at a given text - document position. The request's parameter is of type {@link TextDocumentPositionParams} - the response is of type {@link Declaration} or a typed array of {@link DeclarationLink} - or a Thenable that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DeclarationParams = attrs.field() - method: str = "textDocument/declaration" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDeclarationResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[Declaration, List[DeclarationLink], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentSelectionRangeRequest: - """A request to provide selection ranges in a document. The request's - parameter is of type {@link SelectionRangeParams}, the - response is of type {@link SelectionRange SelectionRange[]} or a Thenable - that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: SelectionRangeParams = attrs.field() - method: str = "textDocument/selectionRange" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentSelectionRangeResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[SelectionRange], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WindowWorkDoneProgressCreateRequest: - """The `window/workDoneProgress/create` request is sent from the server to the client to initiate progress - reporting from the server.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: WorkDoneProgressCreateParams = attrs.field() - method: str = "window/workDoneProgress/create" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WindowWorkDoneProgressCreateResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: None = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentPrepareCallHierarchyRequest: - """A request to result a `CallHierarchyItem` in a document at a given position. - Can be used as an input to an incoming or outgoing call hierarchy. - - @since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: CallHierarchyPrepareParams = attrs.field() - method: str = "textDocument/prepareCallHierarchy" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentPrepareCallHierarchyResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[CallHierarchyItem], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class CallHierarchyIncomingCallsRequest: - """A request to resolve the incoming calls for a given `CallHierarchyItem`. - - @since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: CallHierarchyIncomingCallsParams = attrs.field() - method: str = "callHierarchy/incomingCalls" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class CallHierarchyIncomingCallsResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[CallHierarchyIncomingCall], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class CallHierarchyOutgoingCallsRequest: - """A request to resolve the outgoing calls for a given `CallHierarchyItem`. - - @since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: CallHierarchyOutgoingCallsParams = attrs.field() - method: str = "callHierarchy/outgoingCalls" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class CallHierarchyOutgoingCallsResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[CallHierarchyOutgoingCall], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentSemanticTokensFullRequest: - """@since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: SemanticTokensParams = attrs.field() - method: str = "textDocument/semanticTokens/full" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentSemanticTokensFullResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[SemanticTokens, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentSemanticTokensFullDeltaRequest: - """@since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: SemanticTokensDeltaParams = attrs.field() - method: str = "textDocument/semanticTokens/full/delta" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentSemanticTokensFullDeltaResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[SemanticTokens, SemanticTokensDelta, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentSemanticTokensRangeRequest: - """@since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: SemanticTokensRangeParams = attrs.field() - method: str = "textDocument/semanticTokens/range" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentSemanticTokensRangeResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[SemanticTokens, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceSemanticTokensRefreshRequest: - """@since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: Optional[None] = attrs.field(default=None) - method: str = "workspace/semanticTokens/refresh" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceSemanticTokensRefreshResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: None = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WindowShowDocumentRequest: - """A request to show a document. This request might open an - external program depending on the value of the URI to open. - For example a request to open `https://code.visualstudio.com/` - will very likely open the URI in a WEB browser. - - @since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: ShowDocumentParams = attrs.field() - method: str = "window/showDocument" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WindowShowDocumentResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: ShowDocumentResult = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentLinkedEditingRangeRequest: - """A request to provide ranges that can be edited together. - - @since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: LinkedEditingRangeParams = attrs.field() - method: str = "textDocument/linkedEditingRange" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentLinkedEditingRangeResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[LinkedEditingRanges, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceWillCreateFilesRequest: - """The will create files request is sent from the client to the server before files are actually - created as long as the creation is triggered from within the client. - - The request can return a `WorkspaceEdit` which will be applied to workspace before the - files are created. Hence the `WorkspaceEdit` can not manipulate the content of the file - to be created. - - @since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: CreateFilesParams = attrs.field() - method: str = "workspace/willCreateFiles" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceWillCreateFilesResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[WorkspaceEdit, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceWillRenameFilesRequest: - """The will rename files request is sent from the client to the server before files are actually - renamed as long as the rename is triggered from within the client. - - @since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: RenameFilesParams = attrs.field() - method: str = "workspace/willRenameFiles" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceWillRenameFilesResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[WorkspaceEdit, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceWillDeleteFilesRequest: - """The did delete files notification is sent from the client to the server when - files were deleted from within the client. - - @since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DeleteFilesParams = attrs.field() - method: str = "workspace/willDeleteFiles" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceWillDeleteFilesResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[WorkspaceEdit, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentMonikerRequest: - """A request to get the moniker of a symbol at a given text document position. - The request parameter is of type {@link TextDocumentPositionParams}. - The response is of type {@link Moniker Moniker[]} or `null`.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: MonikerParams = attrs.field() - method: str = "textDocument/moniker" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentMonikerResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[Moniker], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentPrepareTypeHierarchyRequest: - """A request to result a `TypeHierarchyItem` in a document at a given position. - Can be used as an input to a subtypes or supertypes type hierarchy. - - @since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: TypeHierarchyPrepareParams = attrs.field() - method: str = "textDocument/prepareTypeHierarchy" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentPrepareTypeHierarchyResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[TypeHierarchyItem], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TypeHierarchySupertypesRequest: - """A request to resolve the supertypes for a given `TypeHierarchyItem`. - - @since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: TypeHierarchySupertypesParams = attrs.field() - method: str = "typeHierarchy/supertypes" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TypeHierarchySupertypesResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[TypeHierarchyItem], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TypeHierarchySubtypesRequest: - """A request to resolve the subtypes for a given `TypeHierarchyItem`. - - @since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: TypeHierarchySubtypesParams = attrs.field() - method: str = "typeHierarchy/subtypes" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TypeHierarchySubtypesResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[TypeHierarchyItem], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentInlineValueRequest: - """A request to provide inline values in a document. The request's parameter is of - type {@link InlineValueParams}, the response is of type - {@link InlineValue InlineValue[]} or a Thenable that resolves to such. - - @since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: InlineValueParams = attrs.field() - method: str = "textDocument/inlineValue" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentInlineValueResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[InlineValue], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceInlineValueRefreshRequest: - """@since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: Optional[None] = attrs.field(default=None) - method: str = "workspace/inlineValue/refresh" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceInlineValueRefreshResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: None = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentInlayHintRequest: - """A request to provide inlay hints in a document. The request's parameter is of - type {@link InlayHintsParams}, the response is of type - {@link InlayHint InlayHint[]} or a Thenable that resolves to such. - - @since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: InlayHintParams = attrs.field() - method: str = "textDocument/inlayHint" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentInlayHintResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[InlayHint], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class InlayHintResolveRequest: - """A request to resolve additional properties for an inlay hint. - The request's parameter is of type {@link InlayHint}, the response is - of type {@link InlayHint} or a Thenable that resolves to such. - - @since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: InlayHint = attrs.field() - method: str = "inlayHint/resolve" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class InlayHintResolveResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: InlayHint = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceInlayHintRefreshRequest: - """@since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: Optional[None] = attrs.field(default=None) - method: str = "workspace/inlayHint/refresh" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceInlayHintRefreshResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: None = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDiagnosticRequest: - """The document diagnostic request definition. - - @since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DocumentDiagnosticParams = attrs.field() - method: str = "textDocument/diagnostic" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDiagnosticResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: DocumentDiagnosticReport = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceDiagnosticRequest: - """The workspace diagnostic request definition. - - @since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: WorkspaceDiagnosticParams = attrs.field() - method: str = "workspace/diagnostic" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceDiagnosticResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: WorkspaceDiagnosticReport = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceDiagnosticRefreshRequest: - """The diagnostic refresh request definition. - - @since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: Optional[None] = attrs.field(default=None) - method: str = "workspace/diagnostic/refresh" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceDiagnosticRefreshResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: None = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentInlineCompletionRequest: - """A request to provide inline completions in a document. The request's parameter is of - type {@link InlineCompletionParams}, the response is of type - {@link InlineCompletion InlineCompletion[]} or a Thenable that resolves to such. - - @since 3.18.0 - @proposed""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: InlineCompletionParams = attrs.field() - method: str = "textDocument/inlineCompletion" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentInlineCompletionResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[InlineCompletionList, List[InlineCompletionItem], None] = attrs.field( - default=None - ) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class ClientRegisterCapabilityRequest: - """The `client/registerCapability` request is sent from the server to the client to register a new capability - handler on the client side.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: RegistrationParams = attrs.field() - method: str = "client/registerCapability" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class ClientRegisterCapabilityResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: None = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class ClientUnregisterCapabilityRequest: - """The `client/unregisterCapability` request is sent from the server to the client to unregister a previously registered capability - handler on the client side.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: UnregistrationParams = attrs.field() - method: str = "client/unregisterCapability" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class ClientUnregisterCapabilityResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: None = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class InitializeRequest: - """The initialize request is sent from the client to the server. - It is sent once as the request after starting up the server. - The requests parameter is of type {@link InitializeParams} - the response if of type {@link InitializeResult} of a Thenable that - resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: InitializeParams = attrs.field() - method: str = "initialize" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class InitializeResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: InitializeResult = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class ShutdownRequest: - """A shutdown request is sent from the client to the server. - It is sent once when the client decides to shutdown the - server. The only notification that is sent after a shutdown request - is the exit event.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: Optional[None] = attrs.field(default=None) - method: str = "shutdown" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class ShutdownResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: None = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WindowShowMessageRequestRequest: - """The show message request is sent from the server to the client to show a message - and a set of options actions to the user.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: ShowMessageRequestParams = attrs.field() - method: str = "window/showMessageRequest" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WindowShowMessageRequestResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[MessageActionItem, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentWillSaveWaitUntilRequest: - """A document will save request is sent from the client to the server before - the document is actually saved. The request can return an array of TextEdits - which will be applied to the text document before it is saved. Please note that - clients might drop results if computing the text edits took too long or if a - server constantly fails on this request. This is done to keep the save fast and - reliable.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: WillSaveTextDocumentParams = attrs.field() - method: str = "textDocument/willSaveWaitUntil" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentWillSaveWaitUntilResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[TextEdit], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentCompletionRequest: - """Request to request completion at a given text document position. The request's - parameter is of type {@link TextDocumentPosition} the response - is of type {@link CompletionItem CompletionItem[]} or {@link CompletionList} - or a Thenable that resolves to such. - - The request can delay the computation of the {@link CompletionItem.detail `detail`} - and {@link CompletionItem.documentation `documentation`} properties to the `completionItem/resolve` - request. However, properties that are needed for the initial sorting and filtering, like `sortText`, - `filterText`, `insertText`, and `textEdit`, must not be changed during resolve.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: CompletionParams = attrs.field() - method: str = "textDocument/completion" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentCompletionResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[CompletionItem], CompletionList, None] = attrs.field( - default=None - ) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class CompletionItemResolveRequest: - """Request to resolve additional information for a given completion item.The request's - parameter is of type {@link CompletionItem} the response - is of type {@link CompletionItem} or a Thenable that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: CompletionItem = attrs.field() - method: str = "completionItem/resolve" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class CompletionItemResolveResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: CompletionItem = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentHoverRequest: - """Request to request hover information at a given text document position. The request's - parameter is of type {@link TextDocumentPosition} the response is of - type {@link Hover} or a Thenable that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: HoverParams = attrs.field() - method: str = "textDocument/hover" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentHoverResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[Hover, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentSignatureHelpRequest: - id: Union[int, str] = attrs.field() - """The request id.""" - params: SignatureHelpParams = attrs.field() - method: str = "textDocument/signatureHelp" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentSignatureHelpResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[SignatureHelp, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDefinitionRequest: - """A request to resolve the definition location of a symbol at a given text - document position. The request's parameter is of type {@link TextDocumentPosition} - the response is of either type {@link Definition} or a typed array of - {@link DefinitionLink} or a Thenable that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DefinitionParams = attrs.field() - method: str = "textDocument/definition" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDefinitionResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[Definition, List[DefinitionLink], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentReferencesRequest: - """A request to resolve project-wide references for the symbol denoted - by the given text document position. The request's parameter is of - type {@link ReferenceParams} the response is of type - {@link Location Location[]} or a Thenable that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: ReferenceParams = attrs.field() - method: str = "textDocument/references" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentReferencesResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[Location], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDocumentHighlightRequest: - """Request to resolve a {@link DocumentHighlight} for a given - text document position. The request's parameter is of type {@link TextDocumentPosition} - the request response is an array of type {@link DocumentHighlight} - or a Thenable that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DocumentHighlightParams = attrs.field() - method: str = "textDocument/documentHighlight" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDocumentHighlightResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[DocumentHighlight], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDocumentSymbolRequest: - """A request to list all symbols found in a given text document. The request's - parameter is of type {@link TextDocumentIdentifier} the - response is of type {@link SymbolInformation SymbolInformation[]} or a Thenable - that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DocumentSymbolParams = attrs.field() - method: str = "textDocument/documentSymbol" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDocumentSymbolResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[SymbolInformation], List[DocumentSymbol], None] = attrs.field( - default=None - ) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentCodeActionRequest: - """A request to provide commands for the given text document and range.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: CodeActionParams = attrs.field() - method: str = "textDocument/codeAction" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentCodeActionResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[Union[Command, CodeAction]], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class CodeActionResolveRequest: - """Request to resolve additional information for a given code action.The request's - parameter is of type {@link CodeAction} the response - is of type {@link CodeAction} or a Thenable that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: CodeAction = attrs.field() - method: str = "codeAction/resolve" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class CodeActionResolveResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: CodeAction = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceSymbolRequest: - """A request to list project-wide symbols matching the query string given - by the {@link WorkspaceSymbolParams}. The response is - of type {@link SymbolInformation SymbolInformation[]} or a Thenable that - resolves to such. - - @since 3.17.0 - support for WorkspaceSymbol in the returned data. Clients - need to advertise support for WorkspaceSymbols via the client capability - `workspace.symbol.resolveSupport`.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: WorkspaceSymbolParams = attrs.field() - method: str = "workspace/symbol" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceSymbolResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[SymbolInformation], List[WorkspaceSymbol], None] = attrs.field( - default=None - ) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceSymbolResolveRequest: - """A request to resolve the range inside the workspace - symbol's location. - - @since 3.17.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: WorkspaceSymbol = attrs.field() - method: str = "workspaceSymbol/resolve" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceSymbolResolveResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: WorkspaceSymbol = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentCodeLensRequest: - """A request to provide code lens for the given text document.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: CodeLensParams = attrs.field() - method: str = "textDocument/codeLens" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentCodeLensResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[CodeLens], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class CodeLensResolveRequest: - """A request to resolve a command for a given code lens.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: CodeLens = attrs.field() - method: str = "codeLens/resolve" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class CodeLensResolveResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: CodeLens = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceCodeLensRefreshRequest: - """A request to refresh all code actions - - @since 3.16.0""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: Optional[None] = attrs.field(default=None) - method: str = "workspace/codeLens/refresh" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceCodeLensRefreshResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: None = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDocumentLinkRequest: - """A request to provide document links""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DocumentLinkParams = attrs.field() - method: str = "textDocument/documentLink" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDocumentLinkResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[DocumentLink], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class DocumentLinkResolveRequest: - """Request to resolve additional information for a given document link. The request's - parameter is of type {@link DocumentLink} the response - is of type {@link DocumentLink} or a Thenable that resolves to such.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DocumentLink = attrs.field() - method: str = "documentLink/resolve" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class DocumentLinkResolveResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: DocumentLink = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentFormattingRequest: - """A request to format a whole document.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DocumentFormattingParams = attrs.field() - method: str = "textDocument/formatting" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentFormattingResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[TextEdit], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentRangeFormattingRequest: - """A request to format a range in a document.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DocumentRangeFormattingParams = attrs.field() - method: str = "textDocument/rangeFormatting" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentRangeFormattingResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[TextEdit], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentRangesFormattingRequest: - """A request to format ranges in a document. - - @since 3.18.0 - @proposed""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DocumentRangesFormattingParams = attrs.field() - method: str = "textDocument/rangesFormatting" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentRangesFormattingResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[TextEdit], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentOnTypeFormattingRequest: - """A request to format a document on type.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: DocumentOnTypeFormattingParams = attrs.field() - method: str = "textDocument/onTypeFormatting" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentOnTypeFormattingResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[List[TextEdit], None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentRenameRequest: - """A request to rename a symbol.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: RenameParams = attrs.field() - method: str = "textDocument/rename" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentRenameResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[WorkspaceEdit, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentPrepareRenameRequest: - """A request to test and perform the setup necessary for a rename. - - @since 3.16 - support for default behavior""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: PrepareRenameParams = attrs.field() - method: str = "textDocument/prepareRename" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentPrepareRenameResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[PrepareRenameResult, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceExecuteCommandRequest: - """A request send from the client to the server to execute a command. The request might return - a workspace edit which the client will apply to the workspace.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: ExecuteCommandParams = attrs.field() - method: str = "workspace/executeCommand" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceExecuteCommandResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: Union[LSPAny, None] = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceApplyEditRequest: - """A request sent from the server to the client to modified certain resources.""" - - id: Union[int, str] = attrs.field() - """The request id.""" - params: ApplyWorkspaceEditParams = attrs.field() - method: str = "workspace/applyEdit" - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceApplyEditResponse: - id: Optional[Union[int, str]] = attrs.field() - """The request id.""" - result: ApplyWorkspaceEditResult = attrs.field(default=None) - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceDidChangeWorkspaceFoldersNotification: - """The `workspace/didChangeWorkspaceFolders` notification is sent from the client to the server when the workspace - folder configuration changes.""" - - params: DidChangeWorkspaceFoldersParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["workspace/didChangeWorkspaceFolders"]), - default="workspace/didChangeWorkspaceFolders", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WindowWorkDoneProgressCancelNotification: - """The `window/workDoneProgress/cancel` notification is sent from the client to the server to cancel a progress - initiated on the server side.""" - - params: WorkDoneProgressCancelParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["window/workDoneProgress/cancel"]), - default="window/workDoneProgress/cancel", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceDidCreateFilesNotification: - """The did create files notification is sent from the client to the server when - files were created from within the client. - - @since 3.16.0""" - - params: CreateFilesParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["workspace/didCreateFiles"]), - default="workspace/didCreateFiles", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceDidRenameFilesNotification: - """The did rename files notification is sent from the client to the server when - files were renamed from within the client. - - @since 3.16.0""" - - params: RenameFilesParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["workspace/didRenameFiles"]), - default="workspace/didRenameFiles", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceDidDeleteFilesNotification: - """The will delete files request is sent from the client to the server before files are actually - deleted as long as the deletion is triggered from within the client. - - @since 3.16.0""" - - params: DeleteFilesParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["workspace/didDeleteFiles"]), - default="workspace/didDeleteFiles", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class NotebookDocumentDidOpenNotification: - """A notification sent when a notebook opens. - - @since 3.17.0""" - - params: DidOpenNotebookDocumentParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["notebookDocument/didOpen"]), - default="notebookDocument/didOpen", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class NotebookDocumentDidChangeNotification: - params: DidChangeNotebookDocumentParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["notebookDocument/didChange"]), - default="notebookDocument/didChange", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class NotebookDocumentDidSaveNotification: - """A notification sent when a notebook document is saved. - - @since 3.17.0""" - - params: DidSaveNotebookDocumentParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["notebookDocument/didSave"]), - default="notebookDocument/didSave", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class NotebookDocumentDidCloseNotification: - """A notification sent when a notebook closes. - - @since 3.17.0""" - - params: DidCloseNotebookDocumentParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["notebookDocument/didClose"]), - default="notebookDocument/didClose", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class InitializedNotification: - """The initialized notification is sent from the client to the - server after the client is fully initialized and the server - is allowed to send requests from the server to the client.""" - - params: InitializedParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["initialized"]), - default="initialized", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class ExitNotification: - """The exit event is sent from the client to the server to - ask the server to exit its process.""" - - params: Optional[None] = attrs.field(default=None) - method: str = attrs.field( - validator=attrs.validators.in_(["exit"]), - default="exit", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceDidChangeConfigurationNotification: - """The configuration change notification is sent from the client to the server - when the client's configuration has changed. The notification contains - the changed configuration as defined by the language client.""" - - params: DidChangeConfigurationParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["workspace/didChangeConfiguration"]), - default="workspace/didChangeConfiguration", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WindowShowMessageNotification: - """The show message notification is sent from a server to a client to ask - the client to display a particular message in the user interface.""" - - params: ShowMessageParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["window/showMessage"]), - default="window/showMessage", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WindowLogMessageNotification: - """The log message notification is sent from the server to the client to ask - the client to log a particular message.""" - - params: LogMessageParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["window/logMessage"]), - default="window/logMessage", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TelemetryEventNotification: - """The telemetry event notification is sent from the server to the client to ask - the client to log telemetry data.""" - - params: LSPAny = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["telemetry/event"]), - default="telemetry/event", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDidOpenNotification: - """The document open notification is sent from the client to the server to signal - newly opened text documents. The document's truth is now managed by the client - and the server must not try to read the document's truth using the document's - uri. Open in this sense means it is managed by the client. It doesn't necessarily - mean that its content is presented in an editor. An open notification must not - be sent more than once without a corresponding close notification send before. - This means open and close notification must be balanced and the max open count - is one.""" - - params: DidOpenTextDocumentParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["textDocument/didOpen"]), - default="textDocument/didOpen", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDidChangeNotification: - """The document change notification is sent from the client to the server to signal - changes to a text document.""" - - params: DidChangeTextDocumentParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["textDocument/didChange"]), - default="textDocument/didChange", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDidCloseNotification: - """The document close notification is sent from the client to the server when - the document got closed in the client. The document's truth now exists where - the document's uri points to (e.g. if the document's uri is a file uri the - truth now exists on disk). As with the open notification the close notification - is about managing the document's content. Receiving a close notification - doesn't mean that the document was open in an editor before. A close - notification requires a previous open notification to be sent.""" - - params: DidCloseTextDocumentParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["textDocument/didClose"]), - default="textDocument/didClose", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentDidSaveNotification: - """The document save notification is sent from the client to the server when - the document got saved in the client.""" - - params: DidSaveTextDocumentParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["textDocument/didSave"]), - default="textDocument/didSave", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentWillSaveNotification: - """A document will save notification is sent from the client to the server before - the document is actually saved.""" - - params: WillSaveTextDocumentParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["textDocument/willSave"]), - default="textDocument/willSave", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class WorkspaceDidChangeWatchedFilesNotification: - """The watched files notification is sent from the client to the server when - the client detects changes to file watched by the language client.""" - - params: DidChangeWatchedFilesParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["workspace/didChangeWatchedFiles"]), - default="workspace/didChangeWatchedFiles", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class TextDocumentPublishDiagnosticsNotification: - """Diagnostics notification are sent from the server to the client to signal - results of validation runs.""" - - params: PublishDiagnosticsParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["textDocument/publishDiagnostics"]), - default="textDocument/publishDiagnostics", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class SetTraceNotification: - params: SetTraceParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["$/setTrace"]), - default="$/setTrace", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class LogTraceNotification: - params: LogTraceParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["$/logTrace"]), - default="$/logTrace", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class CancelRequestNotification: - params: CancelParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["$/cancelRequest"]), - default="$/cancelRequest", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@attrs.define -class ProgressNotification: - params: ProgressParams = attrs.field() - method: str = attrs.field( - validator=attrs.validators.in_(["$/progress"]), - default="$/progress", - ) - """The method to be invoked.""" - jsonrpc: str = attrs.field(default="2.0") - - -@enum.unique -class MessageDirection(enum.Enum): - Both = "both" - ClientToServer = "clientToServer" - ServerToClient = "serverToClient" - - -CALL_HIERARCHY_INCOMING_CALLS = "callHierarchy/incomingCalls" -CALL_HIERARCHY_OUTGOING_CALLS = "callHierarchy/outgoingCalls" -CANCEL_REQUEST = "$/cancelRequest" -CLIENT_REGISTER_CAPABILITY = "client/registerCapability" -CLIENT_UNREGISTER_CAPABILITY = "client/unregisterCapability" -CODE_ACTION_RESOLVE = "codeAction/resolve" -CODE_LENS_RESOLVE = "codeLens/resolve" -COMPLETION_ITEM_RESOLVE = "completionItem/resolve" -DOCUMENT_LINK_RESOLVE = "documentLink/resolve" -EXIT = "exit" -INITIALIZE = "initialize" -INITIALIZED = "initialized" -INLAY_HINT_RESOLVE = "inlayHint/resolve" -LOG_TRACE = "$/logTrace" -NOTEBOOK_DOCUMENT_DID_CHANGE = "notebookDocument/didChange" -NOTEBOOK_DOCUMENT_DID_CLOSE = "notebookDocument/didClose" -NOTEBOOK_DOCUMENT_DID_OPEN = "notebookDocument/didOpen" -NOTEBOOK_DOCUMENT_DID_SAVE = "notebookDocument/didSave" -PROGRESS = "$/progress" -SET_TRACE = "$/setTrace" -SHUTDOWN = "shutdown" -TELEMETRY_EVENT = "telemetry/event" -TEXT_DOCUMENT_CODE_ACTION = "textDocument/codeAction" -TEXT_DOCUMENT_CODE_LENS = "textDocument/codeLens" -TEXT_DOCUMENT_COLOR_PRESENTATION = "textDocument/colorPresentation" -TEXT_DOCUMENT_COMPLETION = "textDocument/completion" -TEXT_DOCUMENT_DECLARATION = "textDocument/declaration" -TEXT_DOCUMENT_DEFINITION = "textDocument/definition" -TEXT_DOCUMENT_DIAGNOSTIC = "textDocument/diagnostic" -TEXT_DOCUMENT_DID_CHANGE = "textDocument/didChange" -TEXT_DOCUMENT_DID_CLOSE = "textDocument/didClose" -TEXT_DOCUMENT_DID_OPEN = "textDocument/didOpen" -TEXT_DOCUMENT_DID_SAVE = "textDocument/didSave" -TEXT_DOCUMENT_DOCUMENT_COLOR = "textDocument/documentColor" -TEXT_DOCUMENT_DOCUMENT_HIGHLIGHT = "textDocument/documentHighlight" -TEXT_DOCUMENT_DOCUMENT_LINK = "textDocument/documentLink" -TEXT_DOCUMENT_DOCUMENT_SYMBOL = "textDocument/documentSymbol" -TEXT_DOCUMENT_FOLDING_RANGE = "textDocument/foldingRange" -TEXT_DOCUMENT_FORMATTING = "textDocument/formatting" -TEXT_DOCUMENT_HOVER = "textDocument/hover" -TEXT_DOCUMENT_IMPLEMENTATION = "textDocument/implementation" -TEXT_DOCUMENT_INLAY_HINT = "textDocument/inlayHint" -TEXT_DOCUMENT_INLINE_COMPLETION = "textDocument/inlineCompletion" -TEXT_DOCUMENT_INLINE_VALUE = "textDocument/inlineValue" -TEXT_DOCUMENT_LINKED_EDITING_RANGE = "textDocument/linkedEditingRange" -TEXT_DOCUMENT_MONIKER = "textDocument/moniker" -TEXT_DOCUMENT_ON_TYPE_FORMATTING = "textDocument/onTypeFormatting" -TEXT_DOCUMENT_PREPARE_CALL_HIERARCHY = "textDocument/prepareCallHierarchy" -TEXT_DOCUMENT_PREPARE_RENAME = "textDocument/prepareRename" -TEXT_DOCUMENT_PREPARE_TYPE_HIERARCHY = "textDocument/prepareTypeHierarchy" -TEXT_DOCUMENT_PUBLISH_DIAGNOSTICS = "textDocument/publishDiagnostics" -TEXT_DOCUMENT_RANGES_FORMATTING = "textDocument/rangesFormatting" -TEXT_DOCUMENT_RANGE_FORMATTING = "textDocument/rangeFormatting" -TEXT_DOCUMENT_REFERENCES = "textDocument/references" -TEXT_DOCUMENT_RENAME = "textDocument/rename" -TEXT_DOCUMENT_SELECTION_RANGE = "textDocument/selectionRange" -TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL = "textDocument/semanticTokens/full" -TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL_DELTA = "textDocument/semanticTokens/full/delta" -TEXT_DOCUMENT_SEMANTIC_TOKENS_RANGE = "textDocument/semanticTokens/range" -TEXT_DOCUMENT_SIGNATURE_HELP = "textDocument/signatureHelp" -TEXT_DOCUMENT_TYPE_DEFINITION = "textDocument/typeDefinition" -TEXT_DOCUMENT_WILL_SAVE = "textDocument/willSave" -TEXT_DOCUMENT_WILL_SAVE_WAIT_UNTIL = "textDocument/willSaveWaitUntil" -TYPE_HIERARCHY_SUBTYPES = "typeHierarchy/subtypes" -TYPE_HIERARCHY_SUPERTYPES = "typeHierarchy/supertypes" -WINDOW_LOG_MESSAGE = "window/logMessage" -WINDOW_SHOW_DOCUMENT = "window/showDocument" -WINDOW_SHOW_MESSAGE = "window/showMessage" -WINDOW_SHOW_MESSAGE_REQUEST = "window/showMessageRequest" -WINDOW_WORK_DONE_PROGRESS_CANCEL = "window/workDoneProgress/cancel" -WINDOW_WORK_DONE_PROGRESS_CREATE = "window/workDoneProgress/create" -WORKSPACE_APPLY_EDIT = "workspace/applyEdit" -WORKSPACE_CODE_LENS_REFRESH = "workspace/codeLens/refresh" -WORKSPACE_CONFIGURATION = "workspace/configuration" -WORKSPACE_DIAGNOSTIC = "workspace/diagnostic" -WORKSPACE_DIAGNOSTIC_REFRESH = "workspace/diagnostic/refresh" -WORKSPACE_DID_CHANGE_CONFIGURATION = "workspace/didChangeConfiguration" -WORKSPACE_DID_CHANGE_WATCHED_FILES = "workspace/didChangeWatchedFiles" -WORKSPACE_DID_CHANGE_WORKSPACE_FOLDERS = "workspace/didChangeWorkspaceFolders" -WORKSPACE_DID_CREATE_FILES = "workspace/didCreateFiles" -WORKSPACE_DID_DELETE_FILES = "workspace/didDeleteFiles" -WORKSPACE_DID_RENAME_FILES = "workspace/didRenameFiles" -WORKSPACE_EXECUTE_COMMAND = "workspace/executeCommand" -WORKSPACE_FOLDING_RANGE_REFRESH = "workspace/foldingRange/refresh" -WORKSPACE_INLAY_HINT_REFRESH = "workspace/inlayHint/refresh" -WORKSPACE_INLINE_VALUE_REFRESH = "workspace/inlineValue/refresh" -WORKSPACE_SEMANTIC_TOKENS_REFRESH = "workspace/semanticTokens/refresh" -WORKSPACE_SYMBOL = "workspace/symbol" -WORKSPACE_SYMBOL_RESOLVE = "workspaceSymbol/resolve" -WORKSPACE_WILL_CREATE_FILES = "workspace/willCreateFiles" -WORKSPACE_WILL_DELETE_FILES = "workspace/willDeleteFiles" -WORKSPACE_WILL_RENAME_FILES = "workspace/willRenameFiles" -WORKSPACE_WORKSPACE_FOLDERS = "workspace/workspaceFolders" - -METHOD_TO_TYPES = { - # Requests - CALL_HIERARCHY_INCOMING_CALLS: ( - CallHierarchyIncomingCallsRequest, - CallHierarchyIncomingCallsResponse, - CallHierarchyIncomingCallsParams, - None, - ), - CALL_HIERARCHY_OUTGOING_CALLS: ( - CallHierarchyOutgoingCallsRequest, - CallHierarchyOutgoingCallsResponse, - CallHierarchyOutgoingCallsParams, - None, - ), - CLIENT_REGISTER_CAPABILITY: ( - ClientRegisterCapabilityRequest, - ClientRegisterCapabilityResponse, - RegistrationParams, - None, - ), - CLIENT_UNREGISTER_CAPABILITY: ( - ClientUnregisterCapabilityRequest, - ClientUnregisterCapabilityResponse, - UnregistrationParams, - None, - ), - CODE_ACTION_RESOLVE: ( - CodeActionResolveRequest, - CodeActionResolveResponse, - CodeAction, - None, - ), - CODE_LENS_RESOLVE: ( - CodeLensResolveRequest, - CodeLensResolveResponse, - CodeLens, - None, - ), - COMPLETION_ITEM_RESOLVE: ( - CompletionItemResolveRequest, - CompletionItemResolveResponse, - CompletionItem, - None, - ), - DOCUMENT_LINK_RESOLVE: ( - DocumentLinkResolveRequest, - DocumentLinkResolveResponse, - DocumentLink, - None, - ), - INITIALIZE: (InitializeRequest, InitializeResponse, InitializeParams, None), - INLAY_HINT_RESOLVE: ( - InlayHintResolveRequest, - InlayHintResolveResponse, - InlayHint, - None, - ), - SHUTDOWN: (ShutdownRequest, ShutdownResponse, None, None), - TEXT_DOCUMENT_CODE_ACTION: ( - TextDocumentCodeActionRequest, - TextDocumentCodeActionResponse, - CodeActionParams, - CodeActionRegistrationOptions, - ), - TEXT_DOCUMENT_CODE_LENS: ( - TextDocumentCodeLensRequest, - TextDocumentCodeLensResponse, - CodeLensParams, - CodeLensRegistrationOptions, - ), - TEXT_DOCUMENT_COLOR_PRESENTATION: ( - TextDocumentColorPresentationRequest, - TextDocumentColorPresentationResponse, - ColorPresentationParams, - TextDocumentColorPresentationOptions, - ), - TEXT_DOCUMENT_COMPLETION: ( - TextDocumentCompletionRequest, - TextDocumentCompletionResponse, - CompletionParams, - CompletionRegistrationOptions, - ), - TEXT_DOCUMENT_DECLARATION: ( - TextDocumentDeclarationRequest, - TextDocumentDeclarationResponse, - DeclarationParams, - DeclarationRegistrationOptions, - ), - TEXT_DOCUMENT_DEFINITION: ( - TextDocumentDefinitionRequest, - TextDocumentDefinitionResponse, - DefinitionParams, - DefinitionRegistrationOptions, - ), - TEXT_DOCUMENT_DIAGNOSTIC: ( - TextDocumentDiagnosticRequest, - TextDocumentDiagnosticResponse, - DocumentDiagnosticParams, - DiagnosticRegistrationOptions, - ), - TEXT_DOCUMENT_DOCUMENT_COLOR: ( - TextDocumentDocumentColorRequest, - TextDocumentDocumentColorResponse, - DocumentColorParams, - DocumentColorRegistrationOptions, - ), - TEXT_DOCUMENT_DOCUMENT_HIGHLIGHT: ( - TextDocumentDocumentHighlightRequest, - TextDocumentDocumentHighlightResponse, - DocumentHighlightParams, - DocumentHighlightRegistrationOptions, - ), - TEXT_DOCUMENT_DOCUMENT_LINK: ( - TextDocumentDocumentLinkRequest, - TextDocumentDocumentLinkResponse, - DocumentLinkParams, - DocumentLinkRegistrationOptions, - ), - TEXT_DOCUMENT_DOCUMENT_SYMBOL: ( - TextDocumentDocumentSymbolRequest, - TextDocumentDocumentSymbolResponse, - DocumentSymbolParams, - DocumentSymbolRegistrationOptions, - ), - TEXT_DOCUMENT_FOLDING_RANGE: ( - TextDocumentFoldingRangeRequest, - TextDocumentFoldingRangeResponse, - FoldingRangeParams, - FoldingRangeRegistrationOptions, - ), - TEXT_DOCUMENT_FORMATTING: ( - TextDocumentFormattingRequest, - TextDocumentFormattingResponse, - DocumentFormattingParams, - DocumentFormattingRegistrationOptions, - ), - TEXT_DOCUMENT_HOVER: ( - TextDocumentHoverRequest, - TextDocumentHoverResponse, - HoverParams, - HoverRegistrationOptions, - ), - TEXT_DOCUMENT_IMPLEMENTATION: ( - TextDocumentImplementationRequest, - TextDocumentImplementationResponse, - ImplementationParams, - ImplementationRegistrationOptions, - ), - TEXT_DOCUMENT_INLAY_HINT: ( - TextDocumentInlayHintRequest, - TextDocumentInlayHintResponse, - InlayHintParams, - InlayHintRegistrationOptions, - ), - TEXT_DOCUMENT_INLINE_COMPLETION: ( - TextDocumentInlineCompletionRequest, - TextDocumentInlineCompletionResponse, - InlineCompletionParams, - InlineCompletionRegistrationOptions, - ), - TEXT_DOCUMENT_INLINE_VALUE: ( - TextDocumentInlineValueRequest, - TextDocumentInlineValueResponse, - InlineValueParams, - InlineValueRegistrationOptions, - ), - TEXT_DOCUMENT_LINKED_EDITING_RANGE: ( - TextDocumentLinkedEditingRangeRequest, - TextDocumentLinkedEditingRangeResponse, - LinkedEditingRangeParams, - LinkedEditingRangeRegistrationOptions, - ), - TEXT_DOCUMENT_MONIKER: ( - TextDocumentMonikerRequest, - TextDocumentMonikerResponse, - MonikerParams, - MonikerRegistrationOptions, - ), - TEXT_DOCUMENT_ON_TYPE_FORMATTING: ( - TextDocumentOnTypeFormattingRequest, - TextDocumentOnTypeFormattingResponse, - DocumentOnTypeFormattingParams, - DocumentOnTypeFormattingRegistrationOptions, - ), - TEXT_DOCUMENT_PREPARE_CALL_HIERARCHY: ( - TextDocumentPrepareCallHierarchyRequest, - TextDocumentPrepareCallHierarchyResponse, - CallHierarchyPrepareParams, - CallHierarchyRegistrationOptions, - ), - TEXT_DOCUMENT_PREPARE_RENAME: ( - TextDocumentPrepareRenameRequest, - TextDocumentPrepareRenameResponse, - PrepareRenameParams, - None, - ), - TEXT_DOCUMENT_PREPARE_TYPE_HIERARCHY: ( - TextDocumentPrepareTypeHierarchyRequest, - TextDocumentPrepareTypeHierarchyResponse, - TypeHierarchyPrepareParams, - TypeHierarchyRegistrationOptions, - ), - TEXT_DOCUMENT_RANGES_FORMATTING: ( - TextDocumentRangesFormattingRequest, - TextDocumentRangesFormattingResponse, - DocumentRangesFormattingParams, - DocumentRangeFormattingRegistrationOptions, - ), - TEXT_DOCUMENT_RANGE_FORMATTING: ( - TextDocumentRangeFormattingRequest, - TextDocumentRangeFormattingResponse, - DocumentRangeFormattingParams, - DocumentRangeFormattingRegistrationOptions, - ), - TEXT_DOCUMENT_REFERENCES: ( - TextDocumentReferencesRequest, - TextDocumentReferencesResponse, - ReferenceParams, - ReferenceRegistrationOptions, - ), - TEXT_DOCUMENT_RENAME: ( - TextDocumentRenameRequest, - TextDocumentRenameResponse, - RenameParams, - RenameRegistrationOptions, - ), - TEXT_DOCUMENT_SELECTION_RANGE: ( - TextDocumentSelectionRangeRequest, - TextDocumentSelectionRangeResponse, - SelectionRangeParams, - SelectionRangeRegistrationOptions, - ), - TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL: ( - TextDocumentSemanticTokensFullRequest, - TextDocumentSemanticTokensFullResponse, - SemanticTokensParams, - SemanticTokensRegistrationOptions, - ), - TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL_DELTA: ( - TextDocumentSemanticTokensFullDeltaRequest, - TextDocumentSemanticTokensFullDeltaResponse, - SemanticTokensDeltaParams, - SemanticTokensRegistrationOptions, - ), - TEXT_DOCUMENT_SEMANTIC_TOKENS_RANGE: ( - TextDocumentSemanticTokensRangeRequest, - TextDocumentSemanticTokensRangeResponse, - SemanticTokensRangeParams, - None, - ), - TEXT_DOCUMENT_SIGNATURE_HELP: ( - TextDocumentSignatureHelpRequest, - TextDocumentSignatureHelpResponse, - SignatureHelpParams, - SignatureHelpRegistrationOptions, - ), - TEXT_DOCUMENT_TYPE_DEFINITION: ( - TextDocumentTypeDefinitionRequest, - TextDocumentTypeDefinitionResponse, - TypeDefinitionParams, - TypeDefinitionRegistrationOptions, - ), - TEXT_DOCUMENT_WILL_SAVE_WAIT_UNTIL: ( - TextDocumentWillSaveWaitUntilRequest, - TextDocumentWillSaveWaitUntilResponse, - WillSaveTextDocumentParams, - TextDocumentRegistrationOptions, - ), - TYPE_HIERARCHY_SUBTYPES: ( - TypeHierarchySubtypesRequest, - TypeHierarchySubtypesResponse, - TypeHierarchySubtypesParams, - None, - ), - TYPE_HIERARCHY_SUPERTYPES: ( - TypeHierarchySupertypesRequest, - TypeHierarchySupertypesResponse, - TypeHierarchySupertypesParams, - None, - ), - WINDOW_SHOW_DOCUMENT: ( - WindowShowDocumentRequest, - WindowShowDocumentResponse, - ShowDocumentParams, - None, - ), - WINDOW_SHOW_MESSAGE_REQUEST: ( - WindowShowMessageRequestRequest, - WindowShowMessageRequestResponse, - ShowMessageRequestParams, - None, - ), - WINDOW_WORK_DONE_PROGRESS_CREATE: ( - WindowWorkDoneProgressCreateRequest, - WindowWorkDoneProgressCreateResponse, - WorkDoneProgressCreateParams, - None, - ), - WORKSPACE_APPLY_EDIT: ( - WorkspaceApplyEditRequest, - WorkspaceApplyEditResponse, - ApplyWorkspaceEditParams, - None, - ), - WORKSPACE_CODE_LENS_REFRESH: ( - WorkspaceCodeLensRefreshRequest, - WorkspaceCodeLensRefreshResponse, - None, - None, - ), - WORKSPACE_CONFIGURATION: ( - WorkspaceConfigurationRequest, - WorkspaceConfigurationResponse, - ConfigurationParams, - None, - ), - WORKSPACE_DIAGNOSTIC: ( - WorkspaceDiagnosticRequest, - WorkspaceDiagnosticResponse, - WorkspaceDiagnosticParams, - None, - ), - WORKSPACE_DIAGNOSTIC_REFRESH: ( - WorkspaceDiagnosticRefreshRequest, - WorkspaceDiagnosticRefreshResponse, - None, - None, - ), - WORKSPACE_EXECUTE_COMMAND: ( - WorkspaceExecuteCommandRequest, - WorkspaceExecuteCommandResponse, - ExecuteCommandParams, - ExecuteCommandRegistrationOptions, - ), - WORKSPACE_FOLDING_RANGE_REFRESH: ( - WorkspaceFoldingRangeRefreshRequest, - WorkspaceFoldingRangeRefreshResponse, - None, - None, - ), - WORKSPACE_INLAY_HINT_REFRESH: ( - WorkspaceInlayHintRefreshRequest, - WorkspaceInlayHintRefreshResponse, - None, - None, - ), - WORKSPACE_INLINE_VALUE_REFRESH: ( - WorkspaceInlineValueRefreshRequest, - WorkspaceInlineValueRefreshResponse, - None, - None, - ), - WORKSPACE_SEMANTIC_TOKENS_REFRESH: ( - WorkspaceSemanticTokensRefreshRequest, - WorkspaceSemanticTokensRefreshResponse, - None, - None, - ), - WORKSPACE_SYMBOL: ( - WorkspaceSymbolRequest, - WorkspaceSymbolResponse, - WorkspaceSymbolParams, - WorkspaceSymbolRegistrationOptions, - ), - WORKSPACE_SYMBOL_RESOLVE: ( - WorkspaceSymbolResolveRequest, - WorkspaceSymbolResolveResponse, - WorkspaceSymbol, - None, - ), - WORKSPACE_WILL_CREATE_FILES: ( - WorkspaceWillCreateFilesRequest, - WorkspaceWillCreateFilesResponse, - CreateFilesParams, - FileOperationRegistrationOptions, - ), - WORKSPACE_WILL_DELETE_FILES: ( - WorkspaceWillDeleteFilesRequest, - WorkspaceWillDeleteFilesResponse, - DeleteFilesParams, - FileOperationRegistrationOptions, - ), - WORKSPACE_WILL_RENAME_FILES: ( - WorkspaceWillRenameFilesRequest, - WorkspaceWillRenameFilesResponse, - RenameFilesParams, - FileOperationRegistrationOptions, - ), - WORKSPACE_WORKSPACE_FOLDERS: ( - WorkspaceWorkspaceFoldersRequest, - WorkspaceWorkspaceFoldersResponse, - None, - None, - ), - # Notifications - CANCEL_REQUEST: (CancelRequestNotification, None, CancelParams, None), - EXIT: (ExitNotification, None, None, None), - INITIALIZED: (InitializedNotification, None, InitializedParams, None), - LOG_TRACE: (LogTraceNotification, None, LogTraceParams, None), - NOTEBOOK_DOCUMENT_DID_CHANGE: ( - NotebookDocumentDidChangeNotification, - None, - DidChangeNotebookDocumentParams, - None, - ), - NOTEBOOK_DOCUMENT_DID_CLOSE: ( - NotebookDocumentDidCloseNotification, - None, - DidCloseNotebookDocumentParams, - None, - ), - NOTEBOOK_DOCUMENT_DID_OPEN: ( - NotebookDocumentDidOpenNotification, - None, - DidOpenNotebookDocumentParams, - None, - ), - NOTEBOOK_DOCUMENT_DID_SAVE: ( - NotebookDocumentDidSaveNotification, - None, - DidSaveNotebookDocumentParams, - None, - ), - PROGRESS: (ProgressNotification, None, ProgressParams, None), - SET_TRACE: (SetTraceNotification, None, SetTraceParams, None), - TELEMETRY_EVENT: (TelemetryEventNotification, None, LSPAny, None), - TEXT_DOCUMENT_DID_CHANGE: ( - TextDocumentDidChangeNotification, - None, - DidChangeTextDocumentParams, - TextDocumentChangeRegistrationOptions, - ), - TEXT_DOCUMENT_DID_CLOSE: ( - TextDocumentDidCloseNotification, - None, - DidCloseTextDocumentParams, - TextDocumentRegistrationOptions, - ), - TEXT_DOCUMENT_DID_OPEN: ( - TextDocumentDidOpenNotification, - None, - DidOpenTextDocumentParams, - TextDocumentRegistrationOptions, - ), - TEXT_DOCUMENT_DID_SAVE: ( - TextDocumentDidSaveNotification, - None, - DidSaveTextDocumentParams, - TextDocumentSaveRegistrationOptions, - ), - TEXT_DOCUMENT_PUBLISH_DIAGNOSTICS: ( - TextDocumentPublishDiagnosticsNotification, - None, - PublishDiagnosticsParams, - None, - ), - TEXT_DOCUMENT_WILL_SAVE: ( - TextDocumentWillSaveNotification, - None, - WillSaveTextDocumentParams, - TextDocumentRegistrationOptions, - ), - WINDOW_LOG_MESSAGE: (WindowLogMessageNotification, None, LogMessageParams, None), - WINDOW_SHOW_MESSAGE: (WindowShowMessageNotification, None, ShowMessageParams, None), - WINDOW_WORK_DONE_PROGRESS_CANCEL: ( - WindowWorkDoneProgressCancelNotification, - None, - WorkDoneProgressCancelParams, - None, - ), - WORKSPACE_DID_CHANGE_CONFIGURATION: ( - WorkspaceDidChangeConfigurationNotification, - None, - DidChangeConfigurationParams, - DidChangeConfigurationRegistrationOptions, - ), - WORKSPACE_DID_CHANGE_WATCHED_FILES: ( - WorkspaceDidChangeWatchedFilesNotification, - None, - DidChangeWatchedFilesParams, - DidChangeWatchedFilesRegistrationOptions, - ), - WORKSPACE_DID_CHANGE_WORKSPACE_FOLDERS: ( - WorkspaceDidChangeWorkspaceFoldersNotification, - None, - DidChangeWorkspaceFoldersParams, - None, - ), - WORKSPACE_DID_CREATE_FILES: ( - WorkspaceDidCreateFilesNotification, - None, - CreateFilesParams, - FileOperationRegistrationOptions, - ), - WORKSPACE_DID_DELETE_FILES: ( - WorkspaceDidDeleteFilesNotification, - None, - DeleteFilesParams, - FileOperationRegistrationOptions, - ), - WORKSPACE_DID_RENAME_FILES: ( - WorkspaceDidRenameFilesNotification, - None, - RenameFilesParams, - FileOperationRegistrationOptions, - ), -} -REQUESTS = Union[ - CallHierarchyIncomingCallsRequest, - CallHierarchyOutgoingCallsRequest, - ClientRegisterCapabilityRequest, - ClientUnregisterCapabilityRequest, - CodeActionResolveRequest, - CodeLensResolveRequest, - CompletionItemResolveRequest, - DocumentLinkResolveRequest, - InitializeRequest, - InlayHintResolveRequest, - ShutdownRequest, - TextDocumentCodeActionRequest, - TextDocumentCodeLensRequest, - TextDocumentColorPresentationRequest, - TextDocumentCompletionRequest, - TextDocumentDeclarationRequest, - TextDocumentDefinitionRequest, - TextDocumentDiagnosticRequest, - TextDocumentDocumentColorRequest, - TextDocumentDocumentHighlightRequest, - TextDocumentDocumentLinkRequest, - TextDocumentDocumentSymbolRequest, - TextDocumentFoldingRangeRequest, - TextDocumentFormattingRequest, - TextDocumentHoverRequest, - TextDocumentImplementationRequest, - TextDocumentInlayHintRequest, - TextDocumentInlineCompletionRequest, - TextDocumentInlineValueRequest, - TextDocumentLinkedEditingRangeRequest, - TextDocumentMonikerRequest, - TextDocumentOnTypeFormattingRequest, - TextDocumentPrepareCallHierarchyRequest, - TextDocumentPrepareRenameRequest, - TextDocumentPrepareTypeHierarchyRequest, - TextDocumentRangeFormattingRequest, - TextDocumentRangesFormattingRequest, - TextDocumentReferencesRequest, - TextDocumentRenameRequest, - TextDocumentSelectionRangeRequest, - TextDocumentSemanticTokensFullDeltaRequest, - TextDocumentSemanticTokensFullRequest, - TextDocumentSemanticTokensRangeRequest, - TextDocumentSignatureHelpRequest, - TextDocumentTypeDefinitionRequest, - TextDocumentWillSaveWaitUntilRequest, - TypeHierarchySubtypesRequest, - TypeHierarchySupertypesRequest, - WindowShowDocumentRequest, - WindowShowMessageRequestRequest, - WindowWorkDoneProgressCreateRequest, - WorkspaceApplyEditRequest, - WorkspaceCodeLensRefreshRequest, - WorkspaceConfigurationRequest, - WorkspaceDiagnosticRefreshRequest, - WorkspaceDiagnosticRequest, - WorkspaceExecuteCommandRequest, - WorkspaceFoldingRangeRefreshRequest, - WorkspaceInlayHintRefreshRequest, - WorkspaceInlineValueRefreshRequest, - WorkspaceSemanticTokensRefreshRequest, - WorkspaceSymbolRequest, - WorkspaceSymbolResolveRequest, - WorkspaceWillCreateFilesRequest, - WorkspaceWillDeleteFilesRequest, - WorkspaceWillRenameFilesRequest, - WorkspaceWorkspaceFoldersRequest, -] -RESPONSES = Union[ - CallHierarchyIncomingCallsResponse, - CallHierarchyOutgoingCallsResponse, - ClientRegisterCapabilityResponse, - ClientUnregisterCapabilityResponse, - CodeActionResolveResponse, - CodeLensResolveResponse, - CompletionItemResolveResponse, - DocumentLinkResolveResponse, - InitializeResponse, - InlayHintResolveResponse, - ShutdownResponse, - TextDocumentCodeActionResponse, - TextDocumentCodeLensResponse, - TextDocumentColorPresentationResponse, - TextDocumentCompletionResponse, - TextDocumentDeclarationResponse, - TextDocumentDefinitionResponse, - TextDocumentDiagnosticResponse, - TextDocumentDocumentColorResponse, - TextDocumentDocumentHighlightResponse, - TextDocumentDocumentLinkResponse, - TextDocumentDocumentSymbolResponse, - TextDocumentFoldingRangeResponse, - TextDocumentFormattingResponse, - TextDocumentHoverResponse, - TextDocumentImplementationResponse, - TextDocumentInlayHintResponse, - TextDocumentInlineCompletionResponse, - TextDocumentInlineValueResponse, - TextDocumentLinkedEditingRangeResponse, - TextDocumentMonikerResponse, - TextDocumentOnTypeFormattingResponse, - TextDocumentPrepareCallHierarchyResponse, - TextDocumentPrepareRenameResponse, - TextDocumentPrepareTypeHierarchyResponse, - TextDocumentRangeFormattingResponse, - TextDocumentRangesFormattingResponse, - TextDocumentReferencesResponse, - TextDocumentRenameResponse, - TextDocumentSelectionRangeResponse, - TextDocumentSemanticTokensFullDeltaResponse, - TextDocumentSemanticTokensFullResponse, - TextDocumentSemanticTokensRangeResponse, - TextDocumentSignatureHelpResponse, - TextDocumentTypeDefinitionResponse, - TextDocumentWillSaveWaitUntilResponse, - TypeHierarchySubtypesResponse, - TypeHierarchySupertypesResponse, - WindowShowDocumentResponse, - WindowShowMessageRequestResponse, - WindowWorkDoneProgressCreateResponse, - WorkspaceApplyEditResponse, - WorkspaceCodeLensRefreshResponse, - WorkspaceConfigurationResponse, - WorkspaceDiagnosticRefreshResponse, - WorkspaceDiagnosticResponse, - WorkspaceExecuteCommandResponse, - WorkspaceFoldingRangeRefreshResponse, - WorkspaceInlayHintRefreshResponse, - WorkspaceInlineValueRefreshResponse, - WorkspaceSemanticTokensRefreshResponse, - WorkspaceSymbolResolveResponse, - WorkspaceSymbolResponse, - WorkspaceWillCreateFilesResponse, - WorkspaceWillDeleteFilesResponse, - WorkspaceWillRenameFilesResponse, - WorkspaceWorkspaceFoldersResponse, -] -NOTIFICATIONS = Union[ - CancelRequestNotification, - ExitNotification, - InitializedNotification, - LogTraceNotification, - NotebookDocumentDidChangeNotification, - NotebookDocumentDidCloseNotification, - NotebookDocumentDidOpenNotification, - NotebookDocumentDidSaveNotification, - ProgressNotification, - SetTraceNotification, - TelemetryEventNotification, - TextDocumentDidChangeNotification, - TextDocumentDidCloseNotification, - TextDocumentDidOpenNotification, - TextDocumentDidSaveNotification, - TextDocumentPublishDiagnosticsNotification, - TextDocumentWillSaveNotification, - WindowLogMessageNotification, - WindowShowMessageNotification, - WindowWorkDoneProgressCancelNotification, - WorkspaceDidChangeConfigurationNotification, - WorkspaceDidChangeWatchedFilesNotification, - WorkspaceDidChangeWorkspaceFoldersNotification, - WorkspaceDidCreateFilesNotification, - WorkspaceDidDeleteFilesNotification, - WorkspaceDidRenameFilesNotification, -] -MESSAGE_TYPES = Union[REQUESTS, RESPONSES, NOTIFICATIONS, ResponseErrorMessage] - -_KEYWORD_CLASSES = [CallHierarchyIncomingCall] - - -def is_keyword_class(cls: type) -> bool: - """Returns true if the class has a property that may be python keyword.""" - return any(cls is c for c in _KEYWORD_CLASSES) - - -_SPECIAL_CLASSES = [ - CallHierarchyIncomingCallsRequest, - CallHierarchyIncomingCallsResponse, - CallHierarchyOutgoingCallsRequest, - CallHierarchyOutgoingCallsResponse, - CallHierarchyRegistrationOptions, - CancelRequestNotification, - ClientRegisterCapabilityRequest, - ClientRegisterCapabilityResponse, - ClientUnregisterCapabilityRequest, - ClientUnregisterCapabilityResponse, - CodeActionRegistrationOptions, - CodeActionResolveRequest, - CodeActionResolveResponse, - CodeLensRegistrationOptions, - CodeLensResolveRequest, - CodeLensResolveResponse, - CompletionItemResolveRequest, - CompletionItemResolveResponse, - CompletionRegistrationOptions, - CreateFile, - DeclarationRegistrationOptions, - DefinitionRegistrationOptions, - DeleteFile, - DiagnosticRegistrationOptions, - DocumentColorRegistrationOptions, - DocumentFormattingRegistrationOptions, - DocumentHighlightRegistrationOptions, - DocumentLinkRegistrationOptions, - DocumentLinkResolveRequest, - DocumentLinkResolveResponse, - DocumentOnTypeFormattingRegistrationOptions, - DocumentRangeFormattingRegistrationOptions, - DocumentSymbolRegistrationOptions, - ExitNotification, - FoldingRangeRegistrationOptions, - FullDocumentDiagnosticReport, - HoverRegistrationOptions, - ImplementationRegistrationOptions, - InitializeParams, - InitializeRequest, - InitializeResponse, - InitializedNotification, - InlayHintRegistrationOptions, - InlayHintResolveRequest, - InlayHintResolveResponse, - InlineCompletionRegistrationOptions, - InlineValueRegistrationOptions, - LinkedEditingRangeRegistrationOptions, - LogTraceNotification, - MonikerRegistrationOptions, - NotebookDocumentDidChangeNotification, - NotebookDocumentDidCloseNotification, - NotebookDocumentDidOpenNotification, - NotebookDocumentDidSaveNotification, - OptionalVersionedTextDocumentIdentifier, - ProgressNotification, - ReferenceRegistrationOptions, - RelatedFullDocumentDiagnosticReport, - RelatedUnchangedDocumentDiagnosticReport, - RenameFile, - RenameRegistrationOptions, - ResponseErrorMessage, - SelectionRangeRegistrationOptions, - SemanticTokensRegistrationOptions, - SetTraceNotification, - ShutdownRequest, - ShutdownResponse, - SignatureHelpRegistrationOptions, - StringValue, - TelemetryEventNotification, - TextDocumentChangeRegistrationOptions, - TextDocumentCodeActionRequest, - TextDocumentCodeActionResponse, - TextDocumentCodeLensRequest, - TextDocumentCodeLensResponse, - TextDocumentColorPresentationOptions, - TextDocumentColorPresentationRequest, - TextDocumentColorPresentationResponse, - TextDocumentCompletionRequest, - TextDocumentCompletionResponse, - TextDocumentDeclarationRequest, - TextDocumentDeclarationResponse, - TextDocumentDefinitionRequest, - TextDocumentDefinitionResponse, - TextDocumentDiagnosticRequest, - TextDocumentDiagnosticResponse, - TextDocumentDidChangeNotification, - TextDocumentDidCloseNotification, - TextDocumentDidOpenNotification, - TextDocumentDidSaveNotification, - TextDocumentDocumentColorRequest, - TextDocumentDocumentColorResponse, - TextDocumentDocumentHighlightRequest, - TextDocumentDocumentHighlightResponse, - TextDocumentDocumentLinkRequest, - TextDocumentDocumentLinkResponse, - TextDocumentDocumentSymbolRequest, - TextDocumentDocumentSymbolResponse, - TextDocumentFoldingRangeRequest, - TextDocumentFoldingRangeResponse, - TextDocumentFormattingRequest, - TextDocumentFormattingResponse, - TextDocumentHoverRequest, - TextDocumentHoverResponse, - TextDocumentImplementationRequest, - TextDocumentImplementationResponse, - TextDocumentInlayHintRequest, - TextDocumentInlayHintResponse, - TextDocumentInlineCompletionRequest, - TextDocumentInlineCompletionResponse, - TextDocumentInlineValueRequest, - TextDocumentInlineValueResponse, - TextDocumentLinkedEditingRangeRequest, - TextDocumentLinkedEditingRangeResponse, - TextDocumentMonikerRequest, - TextDocumentMonikerResponse, - TextDocumentOnTypeFormattingRequest, - TextDocumentOnTypeFormattingResponse, - TextDocumentPrepareCallHierarchyRequest, - TextDocumentPrepareCallHierarchyResponse, - TextDocumentPrepareRenameRequest, - TextDocumentPrepareRenameResponse, - TextDocumentPrepareTypeHierarchyRequest, - TextDocumentPrepareTypeHierarchyResponse, - TextDocumentPublishDiagnosticsNotification, - TextDocumentRangeFormattingRequest, - TextDocumentRangeFormattingResponse, - TextDocumentRangesFormattingRequest, - TextDocumentRangesFormattingResponse, - TextDocumentReferencesRequest, - TextDocumentReferencesResponse, - TextDocumentRegistrationOptions, - TextDocumentRenameRequest, - TextDocumentRenameResponse, - TextDocumentSaveRegistrationOptions, - TextDocumentSelectionRangeRequest, - TextDocumentSelectionRangeResponse, - TextDocumentSemanticTokensFullDeltaRequest, - TextDocumentSemanticTokensFullDeltaResponse, - TextDocumentSemanticTokensFullRequest, - TextDocumentSemanticTokensFullResponse, - TextDocumentSemanticTokensRangeRequest, - TextDocumentSemanticTokensRangeResponse, - TextDocumentSignatureHelpRequest, - TextDocumentSignatureHelpResponse, - TextDocumentTypeDefinitionRequest, - TextDocumentTypeDefinitionResponse, - TextDocumentWillSaveNotification, - TextDocumentWillSaveWaitUntilRequest, - TextDocumentWillSaveWaitUntilResponse, - TypeDefinitionRegistrationOptions, - TypeHierarchyRegistrationOptions, - TypeHierarchySubtypesRequest, - TypeHierarchySubtypesResponse, - TypeHierarchySupertypesRequest, - TypeHierarchySupertypesResponse, - UnchangedDocumentDiagnosticReport, - WindowLogMessageNotification, - WindowShowDocumentRequest, - WindowShowDocumentResponse, - WindowShowMessageNotification, - WindowShowMessageRequestRequest, - WindowShowMessageRequestResponse, - WindowWorkDoneProgressCancelNotification, - WindowWorkDoneProgressCreateRequest, - WindowWorkDoneProgressCreateResponse, - WorkDoneProgressBegin, - WorkDoneProgressEnd, - WorkDoneProgressReport, - WorkspaceApplyEditRequest, - WorkspaceApplyEditResponse, - WorkspaceCodeLensRefreshRequest, - WorkspaceCodeLensRefreshResponse, - WorkspaceConfigurationRequest, - WorkspaceConfigurationResponse, - WorkspaceDiagnosticRefreshRequest, - WorkspaceDiagnosticRefreshResponse, - WorkspaceDiagnosticRequest, - WorkspaceDiagnosticResponse, - WorkspaceDidChangeConfigurationNotification, - WorkspaceDidChangeWatchedFilesNotification, - WorkspaceDidChangeWorkspaceFoldersNotification, - WorkspaceDidCreateFilesNotification, - WorkspaceDidDeleteFilesNotification, - WorkspaceDidRenameFilesNotification, - WorkspaceExecuteCommandRequest, - WorkspaceExecuteCommandResponse, - WorkspaceFoldersInitializeParams, - WorkspaceFoldingRangeRefreshRequest, - WorkspaceFoldingRangeRefreshResponse, - WorkspaceFullDocumentDiagnosticReport, - WorkspaceInlayHintRefreshRequest, - WorkspaceInlayHintRefreshResponse, - WorkspaceInlineValueRefreshRequest, - WorkspaceInlineValueRefreshResponse, - WorkspaceSemanticTokensRefreshRequest, - WorkspaceSemanticTokensRefreshResponse, - WorkspaceSymbolRequest, - WorkspaceSymbolResolveRequest, - WorkspaceSymbolResolveResponse, - WorkspaceSymbolResponse, - WorkspaceUnchangedDocumentDiagnosticReport, - WorkspaceWillCreateFilesRequest, - WorkspaceWillCreateFilesResponse, - WorkspaceWillDeleteFilesRequest, - WorkspaceWillDeleteFilesResponse, - WorkspaceWillRenameFilesRequest, - WorkspaceWillRenameFilesResponse, - WorkspaceWorkspaceFoldersRequest, - WorkspaceWorkspaceFoldersResponse, - _InitializeParams, -] - - -def is_special_class(cls: type) -> bool: - """Returns true if the class or its properties require special handling.""" - return any(cls is c for c in _SPECIAL_CLASSES) - - -_SPECIAL_PROPERTIES = [ - "CallHierarchyIncomingCallsRequest.jsonrpc", - "CallHierarchyIncomingCallsRequest.method", - "CallHierarchyIncomingCallsResponse.jsonrpc", - "CallHierarchyIncomingCallsResponse.result", - "CallHierarchyOutgoingCallsRequest.jsonrpc", - "CallHierarchyOutgoingCallsRequest.method", - "CallHierarchyOutgoingCallsResponse.jsonrpc", - "CallHierarchyOutgoingCallsResponse.result", - "CallHierarchyRegistrationOptions.document_selector", - "CancelRequestNotification.jsonrpc", - "CancelRequestNotification.method", - "ClientRegisterCapabilityRequest.jsonrpc", - "ClientRegisterCapabilityRequest.method", - "ClientRegisterCapabilityResponse.jsonrpc", - "ClientRegisterCapabilityResponse.result", - "ClientUnregisterCapabilityRequest.jsonrpc", - "ClientUnregisterCapabilityRequest.method", - "ClientUnregisterCapabilityResponse.jsonrpc", - "ClientUnregisterCapabilityResponse.result", - "CodeActionRegistrationOptions.document_selector", - "CodeActionResolveRequest.jsonrpc", - "CodeActionResolveRequest.method", - "CodeActionResolveResponse.jsonrpc", - "CodeActionResolveResponse.result", - "CodeLensRegistrationOptions.document_selector", - "CodeLensResolveRequest.jsonrpc", - "CodeLensResolveRequest.method", - "CodeLensResolveResponse.jsonrpc", - "CodeLensResolveResponse.result", - "CompletionItemResolveRequest.jsonrpc", - "CompletionItemResolveRequest.method", - "CompletionItemResolveResponse.jsonrpc", - "CompletionItemResolveResponse.result", - "CompletionRegistrationOptions.document_selector", - "CreateFile.kind", - "DeclarationRegistrationOptions.document_selector", - "DefinitionRegistrationOptions.document_selector", - "DeleteFile.kind", - "DiagnosticRegistrationOptions.document_selector", - "DocumentColorRegistrationOptions.document_selector", - "DocumentFormattingRegistrationOptions.document_selector", - "DocumentHighlightRegistrationOptions.document_selector", - "DocumentLinkRegistrationOptions.document_selector", - "DocumentLinkResolveRequest.jsonrpc", - "DocumentLinkResolveRequest.method", - "DocumentLinkResolveResponse.jsonrpc", - "DocumentLinkResolveResponse.result", - "DocumentOnTypeFormattingRegistrationOptions.document_selector", - "DocumentRangeFormattingRegistrationOptions.document_selector", - "DocumentSymbolRegistrationOptions.document_selector", - "ExitNotification.jsonrpc", - "ExitNotification.method", - "FoldingRangeRegistrationOptions.document_selector", - "FullDocumentDiagnosticReport.kind", - "HoverRegistrationOptions.document_selector", - "ImplementationRegistrationOptions.document_selector", - "InitializeParams.process_id", - "InitializeParams.root_path", - "InitializeParams.root_uri", - "InitializeParams.workspace_folders", - "InitializeRequest.jsonrpc", - "InitializeRequest.method", - "InitializeResponse.jsonrpc", - "InitializeResponse.result", - "InitializedNotification.jsonrpc", - "InitializedNotification.method", - "InlayHintRegistrationOptions.document_selector", - "InlayHintResolveRequest.jsonrpc", - "InlayHintResolveRequest.method", - "InlayHintResolveResponse.jsonrpc", - "InlayHintResolveResponse.result", - "InlineCompletionRegistrationOptions.document_selector", - "InlineValueRegistrationOptions.document_selector", - "LinkedEditingRangeRegistrationOptions.document_selector", - "LogTraceNotification.jsonrpc", - "LogTraceNotification.method", - "MonikerRegistrationOptions.document_selector", - "NotebookDocumentDidChangeNotification.jsonrpc", - "NotebookDocumentDidChangeNotification.method", - "NotebookDocumentDidCloseNotification.jsonrpc", - "NotebookDocumentDidCloseNotification.method", - "NotebookDocumentDidOpenNotification.jsonrpc", - "NotebookDocumentDidOpenNotification.method", - "NotebookDocumentDidSaveNotification.jsonrpc", - "NotebookDocumentDidSaveNotification.method", - "OptionalVersionedTextDocumentIdentifier.version", - "ProgressNotification.jsonrpc", - "ProgressNotification.method", - "ReferenceRegistrationOptions.document_selector", - "RelatedFullDocumentDiagnosticReport.kind", - "RelatedUnchangedDocumentDiagnosticReport.kind", - "RenameFile.kind", - "RenameRegistrationOptions.document_selector", - "ResponseErrorMessage.error", - "ResponseErrorMessage.jsonrpc", - "SelectionRangeRegistrationOptions.document_selector", - "SemanticTokensRegistrationOptions.document_selector", - "SetTraceNotification.jsonrpc", - "SetTraceNotification.method", - "ShutdownRequest.jsonrpc", - "ShutdownRequest.method", - "ShutdownResponse.jsonrpc", - "ShutdownResponse.result", - "SignatureHelpRegistrationOptions.document_selector", - "StringValue.kind", - "TelemetryEventNotification.jsonrpc", - "TelemetryEventNotification.method", - "TextDocumentChangeRegistrationOptions.document_selector", - "TextDocumentCodeActionRequest.jsonrpc", - "TextDocumentCodeActionRequest.method", - "TextDocumentCodeActionResponse.jsonrpc", - "TextDocumentCodeActionResponse.result", - "TextDocumentCodeLensRequest.jsonrpc", - "TextDocumentCodeLensRequest.method", - "TextDocumentCodeLensResponse.jsonrpc", - "TextDocumentCodeLensResponse.result", - "TextDocumentColorPresentationOptions.document_selector", - "TextDocumentColorPresentationRequest.jsonrpc", - "TextDocumentColorPresentationRequest.method", - "TextDocumentColorPresentationResponse.jsonrpc", - "TextDocumentColorPresentationResponse.result", - "TextDocumentCompletionRequest.jsonrpc", - "TextDocumentCompletionRequest.method", - "TextDocumentCompletionResponse.jsonrpc", - "TextDocumentCompletionResponse.result", - "TextDocumentDeclarationRequest.jsonrpc", - "TextDocumentDeclarationRequest.method", - "TextDocumentDeclarationResponse.jsonrpc", - "TextDocumentDeclarationResponse.result", - "TextDocumentDefinitionRequest.jsonrpc", - "TextDocumentDefinitionRequest.method", - "TextDocumentDefinitionResponse.jsonrpc", - "TextDocumentDefinitionResponse.result", - "TextDocumentDiagnosticRequest.jsonrpc", - "TextDocumentDiagnosticRequest.method", - "TextDocumentDiagnosticResponse.jsonrpc", - "TextDocumentDiagnosticResponse.result", - "TextDocumentDidChangeNotification.jsonrpc", - "TextDocumentDidChangeNotification.method", - "TextDocumentDidCloseNotification.jsonrpc", - "TextDocumentDidCloseNotification.method", - "TextDocumentDidOpenNotification.jsonrpc", - "TextDocumentDidOpenNotification.method", - "TextDocumentDidSaveNotification.jsonrpc", - "TextDocumentDidSaveNotification.method", - "TextDocumentDocumentColorRequest.jsonrpc", - "TextDocumentDocumentColorRequest.method", - "TextDocumentDocumentColorResponse.jsonrpc", - "TextDocumentDocumentColorResponse.result", - "TextDocumentDocumentHighlightRequest.jsonrpc", - "TextDocumentDocumentHighlightRequest.method", - "TextDocumentDocumentHighlightResponse.jsonrpc", - "TextDocumentDocumentHighlightResponse.result", - "TextDocumentDocumentLinkRequest.jsonrpc", - "TextDocumentDocumentLinkRequest.method", - "TextDocumentDocumentLinkResponse.jsonrpc", - "TextDocumentDocumentLinkResponse.result", - "TextDocumentDocumentSymbolRequest.jsonrpc", - "TextDocumentDocumentSymbolRequest.method", - "TextDocumentDocumentSymbolResponse.jsonrpc", - "TextDocumentDocumentSymbolResponse.result", - "TextDocumentFoldingRangeRequest.jsonrpc", - "TextDocumentFoldingRangeRequest.method", - "TextDocumentFoldingRangeResponse.jsonrpc", - "TextDocumentFoldingRangeResponse.result", - "TextDocumentFormattingRequest.jsonrpc", - "TextDocumentFormattingRequest.method", - "TextDocumentFormattingResponse.jsonrpc", - "TextDocumentFormattingResponse.result", - "TextDocumentHoverRequest.jsonrpc", - "TextDocumentHoverRequest.method", - "TextDocumentHoverResponse.jsonrpc", - "TextDocumentHoverResponse.result", - "TextDocumentImplementationRequest.jsonrpc", - "TextDocumentImplementationRequest.method", - "TextDocumentImplementationResponse.jsonrpc", - "TextDocumentImplementationResponse.result", - "TextDocumentInlayHintRequest.jsonrpc", - "TextDocumentInlayHintRequest.method", - "TextDocumentInlayHintResponse.jsonrpc", - "TextDocumentInlayHintResponse.result", - "TextDocumentInlineCompletionRequest.jsonrpc", - "TextDocumentInlineCompletionRequest.method", - "TextDocumentInlineCompletionResponse.jsonrpc", - "TextDocumentInlineCompletionResponse.result", - "TextDocumentInlineValueRequest.jsonrpc", - "TextDocumentInlineValueRequest.method", - "TextDocumentInlineValueResponse.jsonrpc", - "TextDocumentInlineValueResponse.result", - "TextDocumentLinkedEditingRangeRequest.jsonrpc", - "TextDocumentLinkedEditingRangeRequest.method", - "TextDocumentLinkedEditingRangeResponse.jsonrpc", - "TextDocumentLinkedEditingRangeResponse.result", - "TextDocumentMonikerRequest.jsonrpc", - "TextDocumentMonikerRequest.method", - "TextDocumentMonikerResponse.jsonrpc", - "TextDocumentMonikerResponse.result", - "TextDocumentOnTypeFormattingRequest.jsonrpc", - "TextDocumentOnTypeFormattingRequest.method", - "TextDocumentOnTypeFormattingResponse.jsonrpc", - "TextDocumentOnTypeFormattingResponse.result", - "TextDocumentPrepareCallHierarchyRequest.jsonrpc", - "TextDocumentPrepareCallHierarchyRequest.method", - "TextDocumentPrepareCallHierarchyResponse.jsonrpc", - "TextDocumentPrepareCallHierarchyResponse.result", - "TextDocumentPrepareRenameRequest.jsonrpc", - "TextDocumentPrepareRenameRequest.method", - "TextDocumentPrepareRenameResponse.jsonrpc", - "TextDocumentPrepareRenameResponse.result", - "TextDocumentPrepareTypeHierarchyRequest.jsonrpc", - "TextDocumentPrepareTypeHierarchyRequest.method", - "TextDocumentPrepareTypeHierarchyResponse.jsonrpc", - "TextDocumentPrepareTypeHierarchyResponse.result", - "TextDocumentPublishDiagnosticsNotification.jsonrpc", - "TextDocumentPublishDiagnosticsNotification.method", - "TextDocumentRangeFormattingRequest.jsonrpc", - "TextDocumentRangeFormattingRequest.method", - "TextDocumentRangeFormattingResponse.jsonrpc", - "TextDocumentRangeFormattingResponse.result", - "TextDocumentRangesFormattingRequest.jsonrpc", - "TextDocumentRangesFormattingRequest.method", - "TextDocumentRangesFormattingResponse.jsonrpc", - "TextDocumentRangesFormattingResponse.result", - "TextDocumentReferencesRequest.jsonrpc", - "TextDocumentReferencesRequest.method", - "TextDocumentReferencesResponse.jsonrpc", - "TextDocumentReferencesResponse.result", - "TextDocumentRegistrationOptions.document_selector", - "TextDocumentRenameRequest.jsonrpc", - "TextDocumentRenameRequest.method", - "TextDocumentRenameResponse.jsonrpc", - "TextDocumentRenameResponse.result", - "TextDocumentSaveRegistrationOptions.document_selector", - "TextDocumentSelectionRangeRequest.jsonrpc", - "TextDocumentSelectionRangeRequest.method", - "TextDocumentSelectionRangeResponse.jsonrpc", - "TextDocumentSelectionRangeResponse.result", - "TextDocumentSemanticTokensFullDeltaRequest.jsonrpc", - "TextDocumentSemanticTokensFullDeltaRequest.method", - "TextDocumentSemanticTokensFullDeltaResponse.jsonrpc", - "TextDocumentSemanticTokensFullDeltaResponse.result", - "TextDocumentSemanticTokensFullRequest.jsonrpc", - "TextDocumentSemanticTokensFullRequest.method", - "TextDocumentSemanticTokensFullResponse.jsonrpc", - "TextDocumentSemanticTokensFullResponse.result", - "TextDocumentSemanticTokensRangeRequest.jsonrpc", - "TextDocumentSemanticTokensRangeRequest.method", - "TextDocumentSemanticTokensRangeResponse.jsonrpc", - "TextDocumentSemanticTokensRangeResponse.result", - "TextDocumentSignatureHelpRequest.jsonrpc", - "TextDocumentSignatureHelpRequest.method", - "TextDocumentSignatureHelpResponse.jsonrpc", - "TextDocumentSignatureHelpResponse.result", - "TextDocumentTypeDefinitionRequest.jsonrpc", - "TextDocumentTypeDefinitionRequest.method", - "TextDocumentTypeDefinitionResponse.jsonrpc", - "TextDocumentTypeDefinitionResponse.result", - "TextDocumentWillSaveNotification.jsonrpc", - "TextDocumentWillSaveNotification.method", - "TextDocumentWillSaveWaitUntilRequest.jsonrpc", - "TextDocumentWillSaveWaitUntilRequest.method", - "TextDocumentWillSaveWaitUntilResponse.jsonrpc", - "TextDocumentWillSaveWaitUntilResponse.result", - "TypeDefinitionRegistrationOptions.document_selector", - "TypeHierarchyRegistrationOptions.document_selector", - "TypeHierarchySubtypesRequest.jsonrpc", - "TypeHierarchySubtypesRequest.method", - "TypeHierarchySubtypesResponse.jsonrpc", - "TypeHierarchySubtypesResponse.result", - "TypeHierarchySupertypesRequest.jsonrpc", - "TypeHierarchySupertypesRequest.method", - "TypeHierarchySupertypesResponse.jsonrpc", - "TypeHierarchySupertypesResponse.result", - "UnchangedDocumentDiagnosticReport.kind", - "WindowLogMessageNotification.jsonrpc", - "WindowLogMessageNotification.method", - "WindowShowDocumentRequest.jsonrpc", - "WindowShowDocumentRequest.method", - "WindowShowDocumentResponse.jsonrpc", - "WindowShowDocumentResponse.result", - "WindowShowMessageNotification.jsonrpc", - "WindowShowMessageNotification.method", - "WindowShowMessageRequestRequest.jsonrpc", - "WindowShowMessageRequestRequest.method", - "WindowShowMessageRequestResponse.jsonrpc", - "WindowShowMessageRequestResponse.result", - "WindowWorkDoneProgressCancelNotification.jsonrpc", - "WindowWorkDoneProgressCancelNotification.method", - "WindowWorkDoneProgressCreateRequest.jsonrpc", - "WindowWorkDoneProgressCreateRequest.method", - "WindowWorkDoneProgressCreateResponse.jsonrpc", - "WindowWorkDoneProgressCreateResponse.result", - "WorkDoneProgressBegin.kind", - "WorkDoneProgressEnd.kind", - "WorkDoneProgressReport.kind", - "WorkspaceApplyEditRequest.jsonrpc", - "WorkspaceApplyEditRequest.method", - "WorkspaceApplyEditResponse.jsonrpc", - "WorkspaceApplyEditResponse.result", - "WorkspaceCodeLensRefreshRequest.jsonrpc", - "WorkspaceCodeLensRefreshRequest.method", - "WorkspaceCodeLensRefreshResponse.jsonrpc", - "WorkspaceCodeLensRefreshResponse.result", - "WorkspaceConfigurationRequest.jsonrpc", - "WorkspaceConfigurationRequest.method", - "WorkspaceConfigurationResponse.jsonrpc", - "WorkspaceConfigurationResponse.result", - "WorkspaceDiagnosticRefreshRequest.jsonrpc", - "WorkspaceDiagnosticRefreshRequest.method", - "WorkspaceDiagnosticRefreshResponse.jsonrpc", - "WorkspaceDiagnosticRefreshResponse.result", - "WorkspaceDiagnosticRequest.jsonrpc", - "WorkspaceDiagnosticRequest.method", - "WorkspaceDiagnosticResponse.jsonrpc", - "WorkspaceDiagnosticResponse.result", - "WorkspaceDidChangeConfigurationNotification.jsonrpc", - "WorkspaceDidChangeConfigurationNotification.method", - "WorkspaceDidChangeWatchedFilesNotification.jsonrpc", - "WorkspaceDidChangeWatchedFilesNotification.method", - "WorkspaceDidChangeWorkspaceFoldersNotification.jsonrpc", - "WorkspaceDidChangeWorkspaceFoldersNotification.method", - "WorkspaceDidCreateFilesNotification.jsonrpc", - "WorkspaceDidCreateFilesNotification.method", - "WorkspaceDidDeleteFilesNotification.jsonrpc", - "WorkspaceDidDeleteFilesNotification.method", - "WorkspaceDidRenameFilesNotification.jsonrpc", - "WorkspaceDidRenameFilesNotification.method", - "WorkspaceExecuteCommandRequest.jsonrpc", - "WorkspaceExecuteCommandRequest.method", - "WorkspaceExecuteCommandResponse.jsonrpc", - "WorkspaceExecuteCommandResponse.result", - "WorkspaceFoldersInitializeParams.workspace_folders", - "WorkspaceFoldingRangeRefreshRequest.jsonrpc", - "WorkspaceFoldingRangeRefreshRequest.method", - "WorkspaceFoldingRangeRefreshResponse.jsonrpc", - "WorkspaceFoldingRangeRefreshResponse.result", - "WorkspaceFullDocumentDiagnosticReport.kind", - "WorkspaceFullDocumentDiagnosticReport.version", - "WorkspaceInlayHintRefreshRequest.jsonrpc", - "WorkspaceInlayHintRefreshRequest.method", - "WorkspaceInlayHintRefreshResponse.jsonrpc", - "WorkspaceInlayHintRefreshResponse.result", - "WorkspaceInlineValueRefreshRequest.jsonrpc", - "WorkspaceInlineValueRefreshRequest.method", - "WorkspaceInlineValueRefreshResponse.jsonrpc", - "WorkspaceInlineValueRefreshResponse.result", - "WorkspaceSemanticTokensRefreshRequest.jsonrpc", - "WorkspaceSemanticTokensRefreshRequest.method", - "WorkspaceSemanticTokensRefreshResponse.jsonrpc", - "WorkspaceSemanticTokensRefreshResponse.result", - "WorkspaceSymbolRequest.jsonrpc", - "WorkspaceSymbolRequest.method", - "WorkspaceSymbolResolveRequest.jsonrpc", - "WorkspaceSymbolResolveRequest.method", - "WorkspaceSymbolResolveResponse.jsonrpc", - "WorkspaceSymbolResolveResponse.result", - "WorkspaceSymbolResponse.jsonrpc", - "WorkspaceSymbolResponse.result", - "WorkspaceUnchangedDocumentDiagnosticReport.kind", - "WorkspaceUnchangedDocumentDiagnosticReport.version", - "WorkspaceWillCreateFilesRequest.jsonrpc", - "WorkspaceWillCreateFilesRequest.method", - "WorkspaceWillCreateFilesResponse.jsonrpc", - "WorkspaceWillCreateFilesResponse.result", - "WorkspaceWillDeleteFilesRequest.jsonrpc", - "WorkspaceWillDeleteFilesRequest.method", - "WorkspaceWillDeleteFilesResponse.jsonrpc", - "WorkspaceWillDeleteFilesResponse.result", - "WorkspaceWillRenameFilesRequest.jsonrpc", - "WorkspaceWillRenameFilesRequest.method", - "WorkspaceWillRenameFilesResponse.jsonrpc", - "WorkspaceWillRenameFilesResponse.result", - "WorkspaceWorkspaceFoldersRequest.jsonrpc", - "WorkspaceWorkspaceFoldersRequest.method", - "WorkspaceWorkspaceFoldersResponse.jsonrpc", - "WorkspaceWorkspaceFoldersResponse.result", - "_InitializeParams.process_id", - "_InitializeParams.root_path", - "_InitializeParams.root_uri", -] - - -def is_special_property(cls: type, property_name: str) -> bool: - """Returns true if the class or its properties require special handling. - Example: - Consider RenameRegistrationOptions - * document_selector property: - When you set `document_selector` to None in python it has to be preserved when - serializing it. Since the serialized JSON value `{"document_selector": null}` - means use the Clients document selector. Omitting it might throw error. - * prepare_provider property - This property does NOT need special handling, since omitting it or using - `{"prepare_provider": null}` in JSON has the same meaning. - """ - qualified_name = f"{cls.__name__}.{property_name}" - return qualified_name in _SPECIAL_PROPERTIES - - -ALL_TYPES_MAP: Dict[str, Union[type, object]] = { - "AnnotatedTextEdit": AnnotatedTextEdit, - "ApplyWorkspaceEditParams": ApplyWorkspaceEditParams, - "ApplyWorkspaceEditResult": ApplyWorkspaceEditResult, - "BaseSymbolInformation": BaseSymbolInformation, - "CallHierarchyClientCapabilities": CallHierarchyClientCapabilities, - "CallHierarchyIncomingCall": CallHierarchyIncomingCall, - "CallHierarchyIncomingCallsParams": CallHierarchyIncomingCallsParams, - "CallHierarchyIncomingCallsRequest": CallHierarchyIncomingCallsRequest, - "CallHierarchyIncomingCallsResponse": CallHierarchyIncomingCallsResponse, - "CallHierarchyItem": CallHierarchyItem, - "CallHierarchyOptions": CallHierarchyOptions, - "CallHierarchyOutgoingCall": CallHierarchyOutgoingCall, - "CallHierarchyOutgoingCallsParams": CallHierarchyOutgoingCallsParams, - "CallHierarchyOutgoingCallsRequest": CallHierarchyOutgoingCallsRequest, - "CallHierarchyOutgoingCallsResponse": CallHierarchyOutgoingCallsResponse, - "CallHierarchyPrepareParams": CallHierarchyPrepareParams, - "CallHierarchyRegistrationOptions": CallHierarchyRegistrationOptions, - "CancelParams": CancelParams, - "CancelRequestNotification": CancelRequestNotification, - "ChangeAnnotation": ChangeAnnotation, - "ChangeAnnotationIdentifier": ChangeAnnotationIdentifier, - "ClientCapabilities": ClientCapabilities, - "ClientRegisterCapabilityRequest": ClientRegisterCapabilityRequest, - "ClientRegisterCapabilityResponse": ClientRegisterCapabilityResponse, - "ClientUnregisterCapabilityRequest": ClientUnregisterCapabilityRequest, - "ClientUnregisterCapabilityResponse": ClientUnregisterCapabilityResponse, - "CodeAction": CodeAction, - "CodeActionClientCapabilities": CodeActionClientCapabilities, - "CodeActionClientCapabilitiesCodeActionLiteralSupportType": CodeActionClientCapabilitiesCodeActionLiteralSupportType, - "CodeActionClientCapabilitiesCodeActionLiteralSupportTypeCodeActionKindType": CodeActionClientCapabilitiesCodeActionLiteralSupportTypeCodeActionKindType, - "CodeActionClientCapabilitiesResolveSupportType": CodeActionClientCapabilitiesResolveSupportType, - "CodeActionContext": CodeActionContext, - "CodeActionDisabledType": CodeActionDisabledType, - "CodeActionKind": CodeActionKind, - "CodeActionOptions": CodeActionOptions, - "CodeActionParams": CodeActionParams, - "CodeActionRegistrationOptions": CodeActionRegistrationOptions, - "CodeActionResolveRequest": CodeActionResolveRequest, - "CodeActionResolveResponse": CodeActionResolveResponse, - "CodeActionTriggerKind": CodeActionTriggerKind, - "CodeDescription": CodeDescription, - "CodeLens": CodeLens, - "CodeLensClientCapabilities": CodeLensClientCapabilities, - "CodeLensOptions": CodeLensOptions, - "CodeLensParams": CodeLensParams, - "CodeLensRegistrationOptions": CodeLensRegistrationOptions, - "CodeLensResolveRequest": CodeLensResolveRequest, - "CodeLensResolveResponse": CodeLensResolveResponse, - "CodeLensWorkspaceClientCapabilities": CodeLensWorkspaceClientCapabilities, - "Color": Color, - "ColorInformation": ColorInformation, - "ColorPresentation": ColorPresentation, - "ColorPresentationParams": ColorPresentationParams, - "Command": Command, - "CompletionClientCapabilities": CompletionClientCapabilities, - "CompletionClientCapabilitiesCompletionItemKindType": CompletionClientCapabilitiesCompletionItemKindType, - "CompletionClientCapabilitiesCompletionItemType": CompletionClientCapabilitiesCompletionItemType, - "CompletionClientCapabilitiesCompletionItemTypeInsertTextModeSupportType": CompletionClientCapabilitiesCompletionItemTypeInsertTextModeSupportType, - "CompletionClientCapabilitiesCompletionItemTypeResolveSupportType": CompletionClientCapabilitiesCompletionItemTypeResolveSupportType, - "CompletionClientCapabilitiesCompletionItemTypeTagSupportType": CompletionClientCapabilitiesCompletionItemTypeTagSupportType, - "CompletionClientCapabilitiesCompletionListType": CompletionClientCapabilitiesCompletionListType, - "CompletionContext": CompletionContext, - "CompletionItem": CompletionItem, - "CompletionItemKind": CompletionItemKind, - "CompletionItemLabelDetails": CompletionItemLabelDetails, - "CompletionItemResolveRequest": CompletionItemResolveRequest, - "CompletionItemResolveResponse": CompletionItemResolveResponse, - "CompletionItemTag": CompletionItemTag, - "CompletionList": CompletionList, - "CompletionListItemDefaultsType": CompletionListItemDefaultsType, - "CompletionListItemDefaultsTypeEditRangeType1": CompletionListItemDefaultsTypeEditRangeType1, - "CompletionOptions": CompletionOptions, - "CompletionOptionsCompletionItemType": CompletionOptionsCompletionItemType, - "CompletionParams": CompletionParams, - "CompletionRegistrationOptions": CompletionRegistrationOptions, - "CompletionRegistrationOptionsCompletionItemType": CompletionRegistrationOptionsCompletionItemType, - "CompletionTriggerKind": CompletionTriggerKind, - "ConfigurationItem": ConfigurationItem, - "ConfigurationParams": ConfigurationParams, - "CreateFile": CreateFile, - "CreateFileOptions": CreateFileOptions, - "CreateFilesParams": CreateFilesParams, - "Declaration": Declaration, - "DeclarationClientCapabilities": DeclarationClientCapabilities, - "DeclarationLink": DeclarationLink, - "DeclarationOptions": DeclarationOptions, - "DeclarationParams": DeclarationParams, - "DeclarationRegistrationOptions": DeclarationRegistrationOptions, - "Definition": Definition, - "DefinitionClientCapabilities": DefinitionClientCapabilities, - "DefinitionLink": DefinitionLink, - "DefinitionOptions": DefinitionOptions, - "DefinitionParams": DefinitionParams, - "DefinitionRegistrationOptions": DefinitionRegistrationOptions, - "DeleteFile": DeleteFile, - "DeleteFileOptions": DeleteFileOptions, - "DeleteFilesParams": DeleteFilesParams, - "Diagnostic": Diagnostic, - "DiagnosticClientCapabilities": DiagnosticClientCapabilities, - "DiagnosticOptions": DiagnosticOptions, - "DiagnosticRegistrationOptions": DiagnosticRegistrationOptions, - "DiagnosticRelatedInformation": DiagnosticRelatedInformation, - "DiagnosticServerCancellationData": DiagnosticServerCancellationData, - "DiagnosticSeverity": DiagnosticSeverity, - "DiagnosticTag": DiagnosticTag, - "DiagnosticWorkspaceClientCapabilities": DiagnosticWorkspaceClientCapabilities, - "DidChangeConfigurationClientCapabilities": DidChangeConfigurationClientCapabilities, - "DidChangeConfigurationParams": DidChangeConfigurationParams, - "DidChangeConfigurationRegistrationOptions": DidChangeConfigurationRegistrationOptions, - "DidChangeNotebookDocumentParams": DidChangeNotebookDocumentParams, - "DidChangeTextDocumentParams": DidChangeTextDocumentParams, - "DidChangeWatchedFilesClientCapabilities": DidChangeWatchedFilesClientCapabilities, - "DidChangeWatchedFilesParams": DidChangeWatchedFilesParams, - "DidChangeWatchedFilesRegistrationOptions": DidChangeWatchedFilesRegistrationOptions, - "DidChangeWorkspaceFoldersParams": DidChangeWorkspaceFoldersParams, - "DidCloseNotebookDocumentParams": DidCloseNotebookDocumentParams, - "DidCloseTextDocumentParams": DidCloseTextDocumentParams, - "DidOpenNotebookDocumentParams": DidOpenNotebookDocumentParams, - "DidOpenTextDocumentParams": DidOpenTextDocumentParams, - "DidSaveNotebookDocumentParams": DidSaveNotebookDocumentParams, - "DidSaveTextDocumentParams": DidSaveTextDocumentParams, - "DocumentColorClientCapabilities": DocumentColorClientCapabilities, - "DocumentColorOptions": DocumentColorOptions, - "DocumentColorParams": DocumentColorParams, - "DocumentColorRegistrationOptions": DocumentColorRegistrationOptions, - "DocumentDiagnosticParams": DocumentDiagnosticParams, - "DocumentDiagnosticReport": DocumentDiagnosticReport, - "DocumentDiagnosticReportKind": DocumentDiagnosticReportKind, - "DocumentDiagnosticReportPartialResult": DocumentDiagnosticReportPartialResult, - "DocumentFilter": DocumentFilter, - "DocumentFormattingClientCapabilities": DocumentFormattingClientCapabilities, - "DocumentFormattingOptions": DocumentFormattingOptions, - "DocumentFormattingParams": DocumentFormattingParams, - "DocumentFormattingRegistrationOptions": DocumentFormattingRegistrationOptions, - "DocumentHighlight": DocumentHighlight, - "DocumentHighlightClientCapabilities": DocumentHighlightClientCapabilities, - "DocumentHighlightKind": DocumentHighlightKind, - "DocumentHighlightOptions": DocumentHighlightOptions, - "DocumentHighlightParams": DocumentHighlightParams, - "DocumentHighlightRegistrationOptions": DocumentHighlightRegistrationOptions, - "DocumentLink": DocumentLink, - "DocumentLinkClientCapabilities": DocumentLinkClientCapabilities, - "DocumentLinkOptions": DocumentLinkOptions, - "DocumentLinkParams": DocumentLinkParams, - "DocumentLinkRegistrationOptions": DocumentLinkRegistrationOptions, - "DocumentLinkResolveRequest": DocumentLinkResolveRequest, - "DocumentLinkResolveResponse": DocumentLinkResolveResponse, - "DocumentOnTypeFormattingClientCapabilities": DocumentOnTypeFormattingClientCapabilities, - "DocumentOnTypeFormattingOptions": DocumentOnTypeFormattingOptions, - "DocumentOnTypeFormattingParams": DocumentOnTypeFormattingParams, - "DocumentOnTypeFormattingRegistrationOptions": DocumentOnTypeFormattingRegistrationOptions, - "DocumentRangeFormattingClientCapabilities": DocumentRangeFormattingClientCapabilities, - "DocumentRangeFormattingOptions": DocumentRangeFormattingOptions, - "DocumentRangeFormattingParams": DocumentRangeFormattingParams, - "DocumentRangeFormattingRegistrationOptions": DocumentRangeFormattingRegistrationOptions, - "DocumentRangesFormattingParams": DocumentRangesFormattingParams, - "DocumentSelector": DocumentSelector, - "DocumentSymbol": DocumentSymbol, - "DocumentSymbolClientCapabilities": DocumentSymbolClientCapabilities, - "DocumentSymbolClientCapabilitiesSymbolKindType": DocumentSymbolClientCapabilitiesSymbolKindType, - "DocumentSymbolClientCapabilitiesTagSupportType": DocumentSymbolClientCapabilitiesTagSupportType, - "DocumentSymbolOptions": DocumentSymbolOptions, - "DocumentSymbolParams": DocumentSymbolParams, - "DocumentSymbolRegistrationOptions": DocumentSymbolRegistrationOptions, - "ErrorCodes": ErrorCodes, - "ExecuteCommandClientCapabilities": ExecuteCommandClientCapabilities, - "ExecuteCommandOptions": ExecuteCommandOptions, - "ExecuteCommandParams": ExecuteCommandParams, - "ExecuteCommandRegistrationOptions": ExecuteCommandRegistrationOptions, - "ExecutionSummary": ExecutionSummary, - "ExitNotification": ExitNotification, - "FailureHandlingKind": FailureHandlingKind, - "FileChangeType": FileChangeType, - "FileCreate": FileCreate, - "FileDelete": FileDelete, - "FileEvent": FileEvent, - "FileOperationClientCapabilities": FileOperationClientCapabilities, - "FileOperationFilter": FileOperationFilter, - "FileOperationOptions": FileOperationOptions, - "FileOperationPattern": FileOperationPattern, - "FileOperationPatternKind": FileOperationPatternKind, - "FileOperationPatternOptions": FileOperationPatternOptions, - "FileOperationRegistrationOptions": FileOperationRegistrationOptions, - "FileRename": FileRename, - "FileSystemWatcher": FileSystemWatcher, - "FoldingRange": FoldingRange, - "FoldingRangeClientCapabilities": FoldingRangeClientCapabilities, - "FoldingRangeClientCapabilitiesFoldingRangeKindType": FoldingRangeClientCapabilitiesFoldingRangeKindType, - "FoldingRangeClientCapabilitiesFoldingRangeType": FoldingRangeClientCapabilitiesFoldingRangeType, - "FoldingRangeKind": FoldingRangeKind, - "FoldingRangeOptions": FoldingRangeOptions, - "FoldingRangeParams": FoldingRangeParams, - "FoldingRangeRegistrationOptions": FoldingRangeRegistrationOptions, - "FoldingRangeWorkspaceClientCapabilities": FoldingRangeWorkspaceClientCapabilities, - "FormattingOptions": FormattingOptions, - "FullDocumentDiagnosticReport": FullDocumentDiagnosticReport, - "GeneralClientCapabilities": GeneralClientCapabilities, - "GeneralClientCapabilitiesStaleRequestSupportType": GeneralClientCapabilitiesStaleRequestSupportType, - "GlobPattern": GlobPattern, - "Hover": Hover, - "HoverClientCapabilities": HoverClientCapabilities, - "HoverOptions": HoverOptions, - "HoverParams": HoverParams, - "HoverRegistrationOptions": HoverRegistrationOptions, - "ImplementationClientCapabilities": ImplementationClientCapabilities, - "ImplementationOptions": ImplementationOptions, - "ImplementationParams": ImplementationParams, - "ImplementationRegistrationOptions": ImplementationRegistrationOptions, - "InitializeError": InitializeError, - "InitializeParams": InitializeParams, - "InitializeParamsClientInfoType": InitializeParamsClientInfoType, - "InitializeRequest": InitializeRequest, - "InitializeResponse": InitializeResponse, - "InitializeResult": InitializeResult, - "InitializeResultServerInfoType": InitializeResultServerInfoType, - "InitializedNotification": InitializedNotification, - "InitializedParams": InitializedParams, - "InlayHint": InlayHint, - "InlayHintClientCapabilities": InlayHintClientCapabilities, - "InlayHintClientCapabilitiesResolveSupportType": InlayHintClientCapabilitiesResolveSupportType, - "InlayHintKind": InlayHintKind, - "InlayHintLabelPart": InlayHintLabelPart, - "InlayHintOptions": InlayHintOptions, - "InlayHintParams": InlayHintParams, - "InlayHintRegistrationOptions": InlayHintRegistrationOptions, - "InlayHintResolveRequest": InlayHintResolveRequest, - "InlayHintResolveResponse": InlayHintResolveResponse, - "InlayHintWorkspaceClientCapabilities": InlayHintWorkspaceClientCapabilities, - "InlineCompletionClientCapabilities": InlineCompletionClientCapabilities, - "InlineCompletionContext": InlineCompletionContext, - "InlineCompletionItem": InlineCompletionItem, - "InlineCompletionList": InlineCompletionList, - "InlineCompletionOptions": InlineCompletionOptions, - "InlineCompletionParams": InlineCompletionParams, - "InlineCompletionRegistrationOptions": InlineCompletionRegistrationOptions, - "InlineCompletionTriggerKind": InlineCompletionTriggerKind, - "InlineValue": InlineValue, - "InlineValueClientCapabilities": InlineValueClientCapabilities, - "InlineValueContext": InlineValueContext, - "InlineValueEvaluatableExpression": InlineValueEvaluatableExpression, - "InlineValueOptions": InlineValueOptions, - "InlineValueParams": InlineValueParams, - "InlineValueRegistrationOptions": InlineValueRegistrationOptions, - "InlineValueText": InlineValueText, - "InlineValueVariableLookup": InlineValueVariableLookup, - "InlineValueWorkspaceClientCapabilities": InlineValueWorkspaceClientCapabilities, - "InsertReplaceEdit": InsertReplaceEdit, - "InsertTextFormat": InsertTextFormat, - "InsertTextMode": InsertTextMode, - "LSPAny": LSPAny, - "LSPArray": LSPArray, - "LSPErrorCodes": LSPErrorCodes, - "LSPObject": LSPObject, - "LinkedEditingRangeClientCapabilities": LinkedEditingRangeClientCapabilities, - "LinkedEditingRangeOptions": LinkedEditingRangeOptions, - "LinkedEditingRangeParams": LinkedEditingRangeParams, - "LinkedEditingRangeRegistrationOptions": LinkedEditingRangeRegistrationOptions, - "LinkedEditingRanges": LinkedEditingRanges, - "Location": Location, - "LocationLink": LocationLink, - "LogMessageParams": LogMessageParams, - "LogTraceNotification": LogTraceNotification, - "LogTraceParams": LogTraceParams, - "MarkdownClientCapabilities": MarkdownClientCapabilities, - "MarkedString": MarkedString, - "MarkedString_Type1": MarkedString_Type1, - "MarkupContent": MarkupContent, - "MarkupKind": MarkupKind, - "MessageActionItem": MessageActionItem, - "MessageDirection": MessageDirection, - "MessageType": MessageType, - "Moniker": Moniker, - "MonikerClientCapabilities": MonikerClientCapabilities, - "MonikerKind": MonikerKind, - "MonikerOptions": MonikerOptions, - "MonikerParams": MonikerParams, - "MonikerRegistrationOptions": MonikerRegistrationOptions, - "NotebookCell": NotebookCell, - "NotebookCellArrayChange": NotebookCellArrayChange, - "NotebookCellKind": NotebookCellKind, - "NotebookCellTextDocumentFilter": NotebookCellTextDocumentFilter, - "NotebookDocument": NotebookDocument, - "NotebookDocumentChangeEvent": NotebookDocumentChangeEvent, - "NotebookDocumentChangeEventCellsType": NotebookDocumentChangeEventCellsType, - "NotebookDocumentChangeEventCellsTypeStructureType": NotebookDocumentChangeEventCellsTypeStructureType, - "NotebookDocumentChangeEventCellsTypeTextContentType": NotebookDocumentChangeEventCellsTypeTextContentType, - "NotebookDocumentClientCapabilities": NotebookDocumentClientCapabilities, - "NotebookDocumentDidChangeNotification": NotebookDocumentDidChangeNotification, - "NotebookDocumentDidCloseNotification": NotebookDocumentDidCloseNotification, - "NotebookDocumentDidOpenNotification": NotebookDocumentDidOpenNotification, - "NotebookDocumentDidSaveNotification": NotebookDocumentDidSaveNotification, - "NotebookDocumentFilter": NotebookDocumentFilter, - "NotebookDocumentFilter_Type1": NotebookDocumentFilter_Type1, - "NotebookDocumentFilter_Type2": NotebookDocumentFilter_Type2, - "NotebookDocumentFilter_Type3": NotebookDocumentFilter_Type3, - "NotebookDocumentIdentifier": NotebookDocumentIdentifier, - "NotebookDocumentSyncClientCapabilities": NotebookDocumentSyncClientCapabilities, - "NotebookDocumentSyncOptions": NotebookDocumentSyncOptions, - "NotebookDocumentSyncOptionsNotebookSelectorType1": NotebookDocumentSyncOptionsNotebookSelectorType1, - "NotebookDocumentSyncOptionsNotebookSelectorType1CellsType": NotebookDocumentSyncOptionsNotebookSelectorType1CellsType, - "NotebookDocumentSyncOptionsNotebookSelectorType2": NotebookDocumentSyncOptionsNotebookSelectorType2, - "NotebookDocumentSyncOptionsNotebookSelectorType2CellsType": NotebookDocumentSyncOptionsNotebookSelectorType2CellsType, - "NotebookDocumentSyncRegistrationOptions": NotebookDocumentSyncRegistrationOptions, - "NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1": NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1, - "NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1CellsType": NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1CellsType, - "NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2": NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2, - "NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2CellsType": NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2CellsType, - "OptionalVersionedTextDocumentIdentifier": OptionalVersionedTextDocumentIdentifier, - "ParameterInformation": ParameterInformation, - "PartialResultParams": PartialResultParams, - "Pattern": Pattern, - "Position": Position, - "PositionEncodingKind": PositionEncodingKind, - "PrepareRenameParams": PrepareRenameParams, - "PrepareRenameResult": PrepareRenameResult, - "PrepareRenameResult_Type1": PrepareRenameResult_Type1, - "PrepareRenameResult_Type2": PrepareRenameResult_Type2, - "PrepareSupportDefaultBehavior": PrepareSupportDefaultBehavior, - "PreviousResultId": PreviousResultId, - "ProgressNotification": ProgressNotification, - "ProgressParams": ProgressParams, - "ProgressToken": ProgressToken, - "PublishDiagnosticsClientCapabilities": PublishDiagnosticsClientCapabilities, - "PublishDiagnosticsClientCapabilitiesTagSupportType": PublishDiagnosticsClientCapabilitiesTagSupportType, - "PublishDiagnosticsParams": PublishDiagnosticsParams, - "Range": Range, - "ReferenceClientCapabilities": ReferenceClientCapabilities, - "ReferenceContext": ReferenceContext, - "ReferenceOptions": ReferenceOptions, - "ReferenceParams": ReferenceParams, - "ReferenceRegistrationOptions": ReferenceRegistrationOptions, - "Registration": Registration, - "RegistrationParams": RegistrationParams, - "RegularExpressionsClientCapabilities": RegularExpressionsClientCapabilities, - "RelatedFullDocumentDiagnosticReport": RelatedFullDocumentDiagnosticReport, - "RelatedUnchangedDocumentDiagnosticReport": RelatedUnchangedDocumentDiagnosticReport, - "RelativePattern": RelativePattern, - "RenameClientCapabilities": RenameClientCapabilities, - "RenameFile": RenameFile, - "RenameFileOptions": RenameFileOptions, - "RenameFilesParams": RenameFilesParams, - "RenameOptions": RenameOptions, - "RenameParams": RenameParams, - "RenameRegistrationOptions": RenameRegistrationOptions, - "ResourceOperation": ResourceOperation, - "ResourceOperationKind": ResourceOperationKind, - "ResponseError": ResponseError, - "ResponseErrorMessage": ResponseErrorMessage, - "SaveOptions": SaveOptions, - "SelectedCompletionInfo": SelectedCompletionInfo, - "SelectionRange": SelectionRange, - "SelectionRangeClientCapabilities": SelectionRangeClientCapabilities, - "SelectionRangeOptions": SelectionRangeOptions, - "SelectionRangeParams": SelectionRangeParams, - "SelectionRangeRegistrationOptions": SelectionRangeRegistrationOptions, - "SemanticTokenModifiers": SemanticTokenModifiers, - "SemanticTokenTypes": SemanticTokenTypes, - "SemanticTokens": SemanticTokens, - "SemanticTokensClientCapabilities": SemanticTokensClientCapabilities, - "SemanticTokensClientCapabilitiesRequestsType": SemanticTokensClientCapabilitiesRequestsType, - "SemanticTokensClientCapabilitiesRequestsTypeFullType1": SemanticTokensClientCapabilitiesRequestsTypeFullType1, - "SemanticTokensDelta": SemanticTokensDelta, - "SemanticTokensDeltaParams": SemanticTokensDeltaParams, - "SemanticTokensDeltaPartialResult": SemanticTokensDeltaPartialResult, - "SemanticTokensEdit": SemanticTokensEdit, - "SemanticTokensLegend": SemanticTokensLegend, - "SemanticTokensOptions": SemanticTokensOptions, - "SemanticTokensOptionsFullType1": SemanticTokensOptionsFullType1, - "SemanticTokensParams": SemanticTokensParams, - "SemanticTokensPartialResult": SemanticTokensPartialResult, - "SemanticTokensRangeParams": SemanticTokensRangeParams, - "SemanticTokensRegistrationOptions": SemanticTokensRegistrationOptions, - "SemanticTokensRegistrationOptionsFullType1": SemanticTokensRegistrationOptionsFullType1, - "SemanticTokensWorkspaceClientCapabilities": SemanticTokensWorkspaceClientCapabilities, - "ServerCapabilities": ServerCapabilities, - "ServerCapabilitiesWorkspaceType": ServerCapabilitiesWorkspaceType, - "SetTraceNotification": SetTraceNotification, - "SetTraceParams": SetTraceParams, - "ShowDocumentClientCapabilities": ShowDocumentClientCapabilities, - "ShowDocumentParams": ShowDocumentParams, - "ShowDocumentResult": ShowDocumentResult, - "ShowMessageParams": ShowMessageParams, - "ShowMessageRequestClientCapabilities": ShowMessageRequestClientCapabilities, - "ShowMessageRequestClientCapabilitiesMessageActionItemType": ShowMessageRequestClientCapabilitiesMessageActionItemType, - "ShowMessageRequestParams": ShowMessageRequestParams, - "ShutdownRequest": ShutdownRequest, - "ShutdownResponse": ShutdownResponse, - "SignatureHelp": SignatureHelp, - "SignatureHelpClientCapabilities": SignatureHelpClientCapabilities, - "SignatureHelpClientCapabilitiesSignatureInformationType": SignatureHelpClientCapabilitiesSignatureInformationType, - "SignatureHelpClientCapabilitiesSignatureInformationTypeParameterInformationType": SignatureHelpClientCapabilitiesSignatureInformationTypeParameterInformationType, - "SignatureHelpContext": SignatureHelpContext, - "SignatureHelpOptions": SignatureHelpOptions, - "SignatureHelpParams": SignatureHelpParams, - "SignatureHelpRegistrationOptions": SignatureHelpRegistrationOptions, - "SignatureHelpTriggerKind": SignatureHelpTriggerKind, - "SignatureInformation": SignatureInformation, - "StaticRegistrationOptions": StaticRegistrationOptions, - "StringValue": StringValue, - "SymbolInformation": SymbolInformation, - "SymbolKind": SymbolKind, - "SymbolTag": SymbolTag, - "TelemetryEventNotification": TelemetryEventNotification, - "TextDocumentChangeRegistrationOptions": TextDocumentChangeRegistrationOptions, - "TextDocumentClientCapabilities": TextDocumentClientCapabilities, - "TextDocumentCodeActionRequest": TextDocumentCodeActionRequest, - "TextDocumentCodeActionResponse": TextDocumentCodeActionResponse, - "TextDocumentCodeLensRequest": TextDocumentCodeLensRequest, - "TextDocumentCodeLensResponse": TextDocumentCodeLensResponse, - "TextDocumentColorPresentationOptions": TextDocumentColorPresentationOptions, - "TextDocumentColorPresentationRequest": TextDocumentColorPresentationRequest, - "TextDocumentColorPresentationResponse": TextDocumentColorPresentationResponse, - "TextDocumentCompletionRequest": TextDocumentCompletionRequest, - "TextDocumentCompletionResponse": TextDocumentCompletionResponse, - "TextDocumentContentChangeEvent": TextDocumentContentChangeEvent, - "TextDocumentContentChangeEvent_Type1": TextDocumentContentChangeEvent_Type1, - "TextDocumentContentChangeEvent_Type2": TextDocumentContentChangeEvent_Type2, - "TextDocumentDeclarationRequest": TextDocumentDeclarationRequest, - "TextDocumentDeclarationResponse": TextDocumentDeclarationResponse, - "TextDocumentDefinitionRequest": TextDocumentDefinitionRequest, - "TextDocumentDefinitionResponse": TextDocumentDefinitionResponse, - "TextDocumentDiagnosticRequest": TextDocumentDiagnosticRequest, - "TextDocumentDiagnosticResponse": TextDocumentDiagnosticResponse, - "TextDocumentDidChangeNotification": TextDocumentDidChangeNotification, - "TextDocumentDidCloseNotification": TextDocumentDidCloseNotification, - "TextDocumentDidOpenNotification": TextDocumentDidOpenNotification, - "TextDocumentDidSaveNotification": TextDocumentDidSaveNotification, - "TextDocumentDocumentColorRequest": TextDocumentDocumentColorRequest, - "TextDocumentDocumentColorResponse": TextDocumentDocumentColorResponse, - "TextDocumentDocumentHighlightRequest": TextDocumentDocumentHighlightRequest, - "TextDocumentDocumentHighlightResponse": TextDocumentDocumentHighlightResponse, - "TextDocumentDocumentLinkRequest": TextDocumentDocumentLinkRequest, - "TextDocumentDocumentLinkResponse": TextDocumentDocumentLinkResponse, - "TextDocumentDocumentSymbolRequest": TextDocumentDocumentSymbolRequest, - "TextDocumentDocumentSymbolResponse": TextDocumentDocumentSymbolResponse, - "TextDocumentEdit": TextDocumentEdit, - "TextDocumentFilter": TextDocumentFilter, - "TextDocumentFilter_Type1": TextDocumentFilter_Type1, - "TextDocumentFilter_Type2": TextDocumentFilter_Type2, - "TextDocumentFilter_Type3": TextDocumentFilter_Type3, - "TextDocumentFoldingRangeRequest": TextDocumentFoldingRangeRequest, - "TextDocumentFoldingRangeResponse": TextDocumentFoldingRangeResponse, - "TextDocumentFormattingRequest": TextDocumentFormattingRequest, - "TextDocumentFormattingResponse": TextDocumentFormattingResponse, - "TextDocumentHoverRequest": TextDocumentHoverRequest, - "TextDocumentHoverResponse": TextDocumentHoverResponse, - "TextDocumentIdentifier": TextDocumentIdentifier, - "TextDocumentImplementationRequest": TextDocumentImplementationRequest, - "TextDocumentImplementationResponse": TextDocumentImplementationResponse, - "TextDocumentInlayHintRequest": TextDocumentInlayHintRequest, - "TextDocumentInlayHintResponse": TextDocumentInlayHintResponse, - "TextDocumentInlineCompletionRequest": TextDocumentInlineCompletionRequest, - "TextDocumentInlineCompletionResponse": TextDocumentInlineCompletionResponse, - "TextDocumentInlineValueRequest": TextDocumentInlineValueRequest, - "TextDocumentInlineValueResponse": TextDocumentInlineValueResponse, - "TextDocumentItem": TextDocumentItem, - "TextDocumentLinkedEditingRangeRequest": TextDocumentLinkedEditingRangeRequest, - "TextDocumentLinkedEditingRangeResponse": TextDocumentLinkedEditingRangeResponse, - "TextDocumentMonikerRequest": TextDocumentMonikerRequest, - "TextDocumentMonikerResponse": TextDocumentMonikerResponse, - "TextDocumentOnTypeFormattingRequest": TextDocumentOnTypeFormattingRequest, - "TextDocumentOnTypeFormattingResponse": TextDocumentOnTypeFormattingResponse, - "TextDocumentPositionParams": TextDocumentPositionParams, - "TextDocumentPrepareCallHierarchyRequest": TextDocumentPrepareCallHierarchyRequest, - "TextDocumentPrepareCallHierarchyResponse": TextDocumentPrepareCallHierarchyResponse, - "TextDocumentPrepareRenameRequest": TextDocumentPrepareRenameRequest, - "TextDocumentPrepareRenameResponse": TextDocumentPrepareRenameResponse, - "TextDocumentPrepareTypeHierarchyRequest": TextDocumentPrepareTypeHierarchyRequest, - "TextDocumentPrepareTypeHierarchyResponse": TextDocumentPrepareTypeHierarchyResponse, - "TextDocumentPublishDiagnosticsNotification": TextDocumentPublishDiagnosticsNotification, - "TextDocumentRangeFormattingRequest": TextDocumentRangeFormattingRequest, - "TextDocumentRangeFormattingResponse": TextDocumentRangeFormattingResponse, - "TextDocumentRangesFormattingRequest": TextDocumentRangesFormattingRequest, - "TextDocumentRangesFormattingResponse": TextDocumentRangesFormattingResponse, - "TextDocumentReferencesRequest": TextDocumentReferencesRequest, - "TextDocumentReferencesResponse": TextDocumentReferencesResponse, - "TextDocumentRegistrationOptions": TextDocumentRegistrationOptions, - "TextDocumentRenameRequest": TextDocumentRenameRequest, - "TextDocumentRenameResponse": TextDocumentRenameResponse, - "TextDocumentSaveReason": TextDocumentSaveReason, - "TextDocumentSaveRegistrationOptions": TextDocumentSaveRegistrationOptions, - "TextDocumentSelectionRangeRequest": TextDocumentSelectionRangeRequest, - "TextDocumentSelectionRangeResponse": TextDocumentSelectionRangeResponse, - "TextDocumentSemanticTokensFullDeltaRequest": TextDocumentSemanticTokensFullDeltaRequest, - "TextDocumentSemanticTokensFullDeltaResponse": TextDocumentSemanticTokensFullDeltaResponse, - "TextDocumentSemanticTokensFullRequest": TextDocumentSemanticTokensFullRequest, - "TextDocumentSemanticTokensFullResponse": TextDocumentSemanticTokensFullResponse, - "TextDocumentSemanticTokensRangeRequest": TextDocumentSemanticTokensRangeRequest, - "TextDocumentSemanticTokensRangeResponse": TextDocumentSemanticTokensRangeResponse, - "TextDocumentSignatureHelpRequest": TextDocumentSignatureHelpRequest, - "TextDocumentSignatureHelpResponse": TextDocumentSignatureHelpResponse, - "TextDocumentSyncClientCapabilities": TextDocumentSyncClientCapabilities, - "TextDocumentSyncKind": TextDocumentSyncKind, - "TextDocumentSyncOptions": TextDocumentSyncOptions, - "TextDocumentTypeDefinitionRequest": TextDocumentTypeDefinitionRequest, - "TextDocumentTypeDefinitionResponse": TextDocumentTypeDefinitionResponse, - "TextDocumentWillSaveNotification": TextDocumentWillSaveNotification, - "TextDocumentWillSaveWaitUntilRequest": TextDocumentWillSaveWaitUntilRequest, - "TextDocumentWillSaveWaitUntilResponse": TextDocumentWillSaveWaitUntilResponse, - "TextEdit": TextEdit, - "TokenFormat": TokenFormat, - "TraceValues": TraceValues, - "TypeDefinitionClientCapabilities": TypeDefinitionClientCapabilities, - "TypeDefinitionOptions": TypeDefinitionOptions, - "TypeDefinitionParams": TypeDefinitionParams, - "TypeDefinitionRegistrationOptions": TypeDefinitionRegistrationOptions, - "TypeHierarchyClientCapabilities": TypeHierarchyClientCapabilities, - "TypeHierarchyItem": TypeHierarchyItem, - "TypeHierarchyOptions": TypeHierarchyOptions, - "TypeHierarchyPrepareParams": TypeHierarchyPrepareParams, - "TypeHierarchyRegistrationOptions": TypeHierarchyRegistrationOptions, - "TypeHierarchySubtypesParams": TypeHierarchySubtypesParams, - "TypeHierarchySubtypesRequest": TypeHierarchySubtypesRequest, - "TypeHierarchySubtypesResponse": TypeHierarchySubtypesResponse, - "TypeHierarchySupertypesParams": TypeHierarchySupertypesParams, - "TypeHierarchySupertypesRequest": TypeHierarchySupertypesRequest, - "TypeHierarchySupertypesResponse": TypeHierarchySupertypesResponse, - "UnchangedDocumentDiagnosticReport": UnchangedDocumentDiagnosticReport, - "UniquenessLevel": UniquenessLevel, - "Unregistration": Unregistration, - "UnregistrationParams": UnregistrationParams, - "VersionedNotebookDocumentIdentifier": VersionedNotebookDocumentIdentifier, - "VersionedTextDocumentIdentifier": VersionedTextDocumentIdentifier, - "WatchKind": WatchKind, - "WillSaveTextDocumentParams": WillSaveTextDocumentParams, - "WindowClientCapabilities": WindowClientCapabilities, - "WindowLogMessageNotification": WindowLogMessageNotification, - "WindowShowDocumentRequest": WindowShowDocumentRequest, - "WindowShowDocumentResponse": WindowShowDocumentResponse, - "WindowShowMessageNotification": WindowShowMessageNotification, - "WindowShowMessageRequestRequest": WindowShowMessageRequestRequest, - "WindowShowMessageRequestResponse": WindowShowMessageRequestResponse, - "WindowWorkDoneProgressCancelNotification": WindowWorkDoneProgressCancelNotification, - "WindowWorkDoneProgressCreateRequest": WindowWorkDoneProgressCreateRequest, - "WindowWorkDoneProgressCreateResponse": WindowWorkDoneProgressCreateResponse, - "WorkDoneProgressBegin": WorkDoneProgressBegin, - "WorkDoneProgressCancelParams": WorkDoneProgressCancelParams, - "WorkDoneProgressCreateParams": WorkDoneProgressCreateParams, - "WorkDoneProgressEnd": WorkDoneProgressEnd, - "WorkDoneProgressOptions": WorkDoneProgressOptions, - "WorkDoneProgressParams": WorkDoneProgressParams, - "WorkDoneProgressReport": WorkDoneProgressReport, - "WorkspaceApplyEditRequest": WorkspaceApplyEditRequest, - "WorkspaceApplyEditResponse": WorkspaceApplyEditResponse, - "WorkspaceClientCapabilities": WorkspaceClientCapabilities, - "WorkspaceCodeLensRefreshRequest": WorkspaceCodeLensRefreshRequest, - "WorkspaceCodeLensRefreshResponse": WorkspaceCodeLensRefreshResponse, - "WorkspaceConfigurationParams": WorkspaceConfigurationParams, - "WorkspaceConfigurationRequest": WorkspaceConfigurationRequest, - "WorkspaceConfigurationResponse": WorkspaceConfigurationResponse, - "WorkspaceDiagnosticParams": WorkspaceDiagnosticParams, - "WorkspaceDiagnosticRefreshRequest": WorkspaceDiagnosticRefreshRequest, - "WorkspaceDiagnosticRefreshResponse": WorkspaceDiagnosticRefreshResponse, - "WorkspaceDiagnosticReport": WorkspaceDiagnosticReport, - "WorkspaceDiagnosticReportPartialResult": WorkspaceDiagnosticReportPartialResult, - "WorkspaceDiagnosticRequest": WorkspaceDiagnosticRequest, - "WorkspaceDiagnosticResponse": WorkspaceDiagnosticResponse, - "WorkspaceDidChangeConfigurationNotification": WorkspaceDidChangeConfigurationNotification, - "WorkspaceDidChangeWatchedFilesNotification": WorkspaceDidChangeWatchedFilesNotification, - "WorkspaceDidChangeWorkspaceFoldersNotification": WorkspaceDidChangeWorkspaceFoldersNotification, - "WorkspaceDidCreateFilesNotification": WorkspaceDidCreateFilesNotification, - "WorkspaceDidDeleteFilesNotification": WorkspaceDidDeleteFilesNotification, - "WorkspaceDidRenameFilesNotification": WorkspaceDidRenameFilesNotification, - "WorkspaceDocumentDiagnosticReport": WorkspaceDocumentDiagnosticReport, - "WorkspaceEdit": WorkspaceEdit, - "WorkspaceEditClientCapabilities": WorkspaceEditClientCapabilities, - "WorkspaceEditClientCapabilitiesChangeAnnotationSupportType": WorkspaceEditClientCapabilitiesChangeAnnotationSupportType, - "WorkspaceExecuteCommandRequest": WorkspaceExecuteCommandRequest, - "WorkspaceExecuteCommandResponse": WorkspaceExecuteCommandResponse, - "WorkspaceFolder": WorkspaceFolder, - "WorkspaceFoldersChangeEvent": WorkspaceFoldersChangeEvent, - "WorkspaceFoldersInitializeParams": WorkspaceFoldersInitializeParams, - "WorkspaceFoldersServerCapabilities": WorkspaceFoldersServerCapabilities, - "WorkspaceFoldingRangeRefreshRequest": WorkspaceFoldingRangeRefreshRequest, - "WorkspaceFoldingRangeRefreshResponse": WorkspaceFoldingRangeRefreshResponse, - "WorkspaceFullDocumentDiagnosticReport": WorkspaceFullDocumentDiagnosticReport, - "WorkspaceInlayHintRefreshRequest": WorkspaceInlayHintRefreshRequest, - "WorkspaceInlayHintRefreshResponse": WorkspaceInlayHintRefreshResponse, - "WorkspaceInlineValueRefreshRequest": WorkspaceInlineValueRefreshRequest, - "WorkspaceInlineValueRefreshResponse": WorkspaceInlineValueRefreshResponse, - "WorkspaceSemanticTokensRefreshRequest": WorkspaceSemanticTokensRefreshRequest, - "WorkspaceSemanticTokensRefreshResponse": WorkspaceSemanticTokensRefreshResponse, - "WorkspaceSymbol": WorkspaceSymbol, - "WorkspaceSymbolClientCapabilities": WorkspaceSymbolClientCapabilities, - "WorkspaceSymbolClientCapabilitiesResolveSupportType": WorkspaceSymbolClientCapabilitiesResolveSupportType, - "WorkspaceSymbolClientCapabilitiesSymbolKindType": WorkspaceSymbolClientCapabilitiesSymbolKindType, - "WorkspaceSymbolClientCapabilitiesTagSupportType": WorkspaceSymbolClientCapabilitiesTagSupportType, - "WorkspaceSymbolLocationType1": WorkspaceSymbolLocationType1, - "WorkspaceSymbolOptions": WorkspaceSymbolOptions, - "WorkspaceSymbolParams": WorkspaceSymbolParams, - "WorkspaceSymbolRegistrationOptions": WorkspaceSymbolRegistrationOptions, - "WorkspaceSymbolRequest": WorkspaceSymbolRequest, - "WorkspaceSymbolResolveRequest": WorkspaceSymbolResolveRequest, - "WorkspaceSymbolResolveResponse": WorkspaceSymbolResolveResponse, - "WorkspaceSymbolResponse": WorkspaceSymbolResponse, - "WorkspaceUnchangedDocumentDiagnosticReport": WorkspaceUnchangedDocumentDiagnosticReport, - "WorkspaceWillCreateFilesRequest": WorkspaceWillCreateFilesRequest, - "WorkspaceWillCreateFilesResponse": WorkspaceWillCreateFilesResponse, - "WorkspaceWillDeleteFilesRequest": WorkspaceWillDeleteFilesRequest, - "WorkspaceWillDeleteFilesResponse": WorkspaceWillDeleteFilesResponse, - "WorkspaceWillRenameFilesRequest": WorkspaceWillRenameFilesRequest, - "WorkspaceWillRenameFilesResponse": WorkspaceWillRenameFilesResponse, - "WorkspaceWorkspaceFoldersRequest": WorkspaceWorkspaceFoldersRequest, - "WorkspaceWorkspaceFoldersResponse": WorkspaceWorkspaceFoldersResponse, - "_InitializeParams": _InitializeParams, -} - -_MESSAGE_DIRECTION: Dict[str, str] = { - # Request methods - CALL_HIERARCHY_INCOMING_CALLS: "clientToServer", - CALL_HIERARCHY_OUTGOING_CALLS: "clientToServer", - CLIENT_REGISTER_CAPABILITY: "serverToClient", - CLIENT_UNREGISTER_CAPABILITY: "serverToClient", - CODE_ACTION_RESOLVE: "clientToServer", - CODE_LENS_RESOLVE: "clientToServer", - COMPLETION_ITEM_RESOLVE: "clientToServer", - DOCUMENT_LINK_RESOLVE: "clientToServer", - INITIALIZE: "clientToServer", - INLAY_HINT_RESOLVE: "clientToServer", - SHUTDOWN: "clientToServer", - TEXT_DOCUMENT_CODE_ACTION: "clientToServer", - TEXT_DOCUMENT_CODE_LENS: "clientToServer", - TEXT_DOCUMENT_COLOR_PRESENTATION: "clientToServer", - TEXT_DOCUMENT_COMPLETION: "clientToServer", - TEXT_DOCUMENT_DECLARATION: "clientToServer", - TEXT_DOCUMENT_DEFINITION: "clientToServer", - TEXT_DOCUMENT_DIAGNOSTIC: "clientToServer", - TEXT_DOCUMENT_DOCUMENT_COLOR: "clientToServer", - TEXT_DOCUMENT_DOCUMENT_HIGHLIGHT: "clientToServer", - TEXT_DOCUMENT_DOCUMENT_LINK: "clientToServer", - TEXT_DOCUMENT_DOCUMENT_SYMBOL: "clientToServer", - TEXT_DOCUMENT_FOLDING_RANGE: "clientToServer", - TEXT_DOCUMENT_FORMATTING: "clientToServer", - TEXT_DOCUMENT_HOVER: "clientToServer", - TEXT_DOCUMENT_IMPLEMENTATION: "clientToServer", - TEXT_DOCUMENT_INLAY_HINT: "clientToServer", - TEXT_DOCUMENT_INLINE_COMPLETION: "clientToServer", - TEXT_DOCUMENT_INLINE_VALUE: "clientToServer", - TEXT_DOCUMENT_LINKED_EDITING_RANGE: "clientToServer", - TEXT_DOCUMENT_MONIKER: "clientToServer", - TEXT_DOCUMENT_ON_TYPE_FORMATTING: "clientToServer", - TEXT_DOCUMENT_PREPARE_CALL_HIERARCHY: "clientToServer", - TEXT_DOCUMENT_PREPARE_RENAME: "clientToServer", - TEXT_DOCUMENT_PREPARE_TYPE_HIERARCHY: "clientToServer", - TEXT_DOCUMENT_RANGES_FORMATTING: "clientToServer", - TEXT_DOCUMENT_RANGE_FORMATTING: "clientToServer", - TEXT_DOCUMENT_REFERENCES: "clientToServer", - TEXT_DOCUMENT_RENAME: "clientToServer", - TEXT_DOCUMENT_SELECTION_RANGE: "clientToServer", - TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL: "clientToServer", - TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL_DELTA: "clientToServer", - TEXT_DOCUMENT_SEMANTIC_TOKENS_RANGE: "clientToServer", - TEXT_DOCUMENT_SIGNATURE_HELP: "clientToServer", - TEXT_DOCUMENT_TYPE_DEFINITION: "clientToServer", - TEXT_DOCUMENT_WILL_SAVE_WAIT_UNTIL: "clientToServer", - TYPE_HIERARCHY_SUBTYPES: "clientToServer", - TYPE_HIERARCHY_SUPERTYPES: "clientToServer", - WINDOW_SHOW_DOCUMENT: "serverToClient", - WINDOW_SHOW_MESSAGE_REQUEST: "serverToClient", - WINDOW_WORK_DONE_PROGRESS_CREATE: "serverToClient", - WORKSPACE_APPLY_EDIT: "serverToClient", - WORKSPACE_CODE_LENS_REFRESH: "serverToClient", - WORKSPACE_CONFIGURATION: "serverToClient", - WORKSPACE_DIAGNOSTIC: "clientToServer", - WORKSPACE_DIAGNOSTIC_REFRESH: "serverToClient", - WORKSPACE_EXECUTE_COMMAND: "clientToServer", - WORKSPACE_FOLDING_RANGE_REFRESH: "serverToClient", - WORKSPACE_INLAY_HINT_REFRESH: "serverToClient", - WORKSPACE_INLINE_VALUE_REFRESH: "serverToClient", - WORKSPACE_SEMANTIC_TOKENS_REFRESH: "serverToClient", - WORKSPACE_SYMBOL: "clientToServer", - WORKSPACE_SYMBOL_RESOLVE: "clientToServer", - WORKSPACE_WILL_CREATE_FILES: "clientToServer", - WORKSPACE_WILL_DELETE_FILES: "clientToServer", - WORKSPACE_WILL_RENAME_FILES: "clientToServer", - WORKSPACE_WORKSPACE_FOLDERS: "serverToClient", - # Notification methods - CANCEL_REQUEST: "both", - EXIT: "clientToServer", - INITIALIZED: "clientToServer", - LOG_TRACE: "serverToClient", - NOTEBOOK_DOCUMENT_DID_CHANGE: "clientToServer", - NOTEBOOK_DOCUMENT_DID_CLOSE: "clientToServer", - NOTEBOOK_DOCUMENT_DID_OPEN: "clientToServer", - NOTEBOOK_DOCUMENT_DID_SAVE: "clientToServer", - PROGRESS: "both", - SET_TRACE: "clientToServer", - TELEMETRY_EVENT: "serverToClient", - TEXT_DOCUMENT_DID_CHANGE: "clientToServer", - TEXT_DOCUMENT_DID_CLOSE: "clientToServer", - TEXT_DOCUMENT_DID_OPEN: "clientToServer", - TEXT_DOCUMENT_DID_SAVE: "clientToServer", - TEXT_DOCUMENT_PUBLISH_DIAGNOSTICS: "serverToClient", - TEXT_DOCUMENT_WILL_SAVE: "clientToServer", - WINDOW_LOG_MESSAGE: "serverToClient", - WINDOW_SHOW_MESSAGE: "serverToClient", - WINDOW_WORK_DONE_PROGRESS_CANCEL: "clientToServer", - WORKSPACE_DID_CHANGE_CONFIGURATION: "clientToServer", - WORKSPACE_DID_CHANGE_WATCHED_FILES: "clientToServer", - WORKSPACE_DID_CHANGE_WORKSPACE_FOLDERS: "clientToServer", - WORKSPACE_DID_CREATE_FILES: "clientToServer", - WORKSPACE_DID_DELETE_FILES: "clientToServer", - WORKSPACE_DID_RENAME_FILES: "clientToServer", -} - - -def message_direction(method: str) -> str: - """Returns message direction clientToServer, serverToClient or both.""" - return _MESSAGE_DIRECTION[method] diff --git a/server/libs/lsprotocol/validators.py b/server/libs/lsprotocol/validators.py deleted file mode 100644 index a0f00c7..0000000 --- a/server/libs/lsprotocol/validators.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - - -from typing import TYPE_CHECKING, Any - -if TYPE_CHECKING: - import attrs - -INTEGER_MIN_VALUE = -(2**31) -INTEGER_MAX_VALUE = 2**31 - 1 - - -def integer_validator( - instance: Any, - attribute: "attrs.Attribute[int]", - value: Any, -) -> bool: - """Validates that integer value belongs in the range expected by LSP.""" - if not isinstance(value, int) or not ( - INTEGER_MIN_VALUE <= value <= INTEGER_MAX_VALUE - ): - name = attribute.name if hasattr(attribute, "name") else str(attribute) - raise ValueError( - f"{instance.__class__.__qualname__}.{name} should be in range [{INTEGER_MIN_VALUE}:{INTEGER_MAX_VALUE}], but was {value}." - ) - return True - - -UINTEGER_MIN_VALUE = 0 -UINTEGER_MAX_VALUE = 2**31 - 1 - - -def uinteger_validator( - instance: Any, - attribute: "attrs.Attribute[int]", - value: Any, -) -> bool: - """Validates that unsigned integer value belongs in the range expected by LSP.""" - if not isinstance(value, int) or not ( - UINTEGER_MIN_VALUE <= value <= UINTEGER_MAX_VALUE - ): - name = attribute.name if hasattr(attribute, "name") else str(attribute) - raise ValueError( - f"{instance.__class__.__qualname__}.{name} should be in range [{UINTEGER_MIN_VALUE}:{UINTEGER_MAX_VALUE}], but was {value}." - ) - return True diff --git a/server/libs/packaging-25.0.dist-info/INSTALLER b/server/libs/packaging-25.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/server/libs/packaging-25.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/server/libs/packaging-25.0.dist-info/METADATA b/server/libs/packaging-25.0.dist-info/METADATA deleted file mode 100644 index 10b290a..0000000 --- a/server/libs/packaging-25.0.dist-info/METADATA +++ /dev/null @@ -1,105 +0,0 @@ -Metadata-Version: 2.4 -Name: packaging -Version: 25.0 -Summary: Core utilities for Python packages -Author-email: Donald Stufft -Requires-Python: >=3.8 -Description-Content-Type: text/x-rst -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: License :: OSI Approved :: BSD License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Typing :: Typed -License-File: LICENSE -License-File: LICENSE.APACHE -License-File: LICENSE.BSD -Project-URL: Documentation, https://packaging.pypa.io/ -Project-URL: Source, https://github.com/pypa/packaging - -packaging -========= - -.. start-intro - -Reusable core utilities for various Python Packaging -`interoperability specifications `_. - -This library provides utilities that implement the interoperability -specifications which have clearly one correct behaviour (eg: :pep:`440`) -or benefit greatly from having a single shared implementation (eg: :pep:`425`). - -.. end-intro - -The ``packaging`` project includes the following: version handling, specifiers, -markers, requirements, tags, utilities. - -Documentation -------------- - -The `documentation`_ provides information and the API for the following: - -- Version Handling -- Specifiers -- Markers -- Requirements -- Tags -- Utilities - -Installation ------------- - -Use ``pip`` to install these utilities:: - - pip install packaging - -The ``packaging`` library uses calendar-based versioning (``YY.N``). - -Discussion ----------- - -If you run into bugs, you can file them in our `issue tracker`_. - -You can also join ``#pypa`` on Freenode to ask questions or get involved. - - -.. _`documentation`: https://packaging.pypa.io/ -.. _`issue tracker`: https://github.com/pypa/packaging/issues - - -Code of Conduct ---------------- - -Everyone interacting in the packaging project's codebases, issue trackers, chat -rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_. - -.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md - -Contributing ------------- - -The ``CONTRIBUTING.rst`` file outlines how to contribute to this project as -well as how to report a potential security issue. The documentation for this -project also covers information about `project development`_ and `security`_. - -.. _`project development`: https://packaging.pypa.io/en/latest/development/ -.. _`security`: https://packaging.pypa.io/en/latest/security/ - -Project History ---------------- - -Please review the ``CHANGELOG.rst`` file or the `Changelog documentation`_ for -recent changes and project history. - -.. _`Changelog documentation`: https://packaging.pypa.io/en/latest/changelog/ - diff --git a/server/libs/packaging-25.0.dist-info/RECORD b/server/libs/packaging-25.0.dist-info/RECORD deleted file mode 100644 index 9346bb4..0000000 --- a/server/libs/packaging-25.0.dist-info/RECORD +++ /dev/null @@ -1,41 +0,0 @@ -packaging-25.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -packaging-25.0.dist-info/METADATA,sha256=W2EaYJw4_vw9YWv0XSCuyY-31T8kXayp4sMPyFx6woI,3281 -packaging-25.0.dist-info/RECORD,, -packaging-25.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -packaging-25.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 -packaging-25.0.dist-info/licenses/LICENSE,sha256=ytHvW9NA1z4HS6YU0m996spceUDD2MNIUuZcSQlobEg,197 -packaging-25.0.dist-info/licenses/LICENSE.APACHE,sha256=DVQuDIgE45qn836wDaWnYhSdxoLXgpRRKH4RuTjpRZQ,10174 -packaging-25.0.dist-info/licenses/LICENSE.BSD,sha256=tw5-m3QvHMb5SLNMFqo5_-zpQZY2S8iP8NIYDwAo-sU,1344 -packaging/__init__.py,sha256=_0cDiPVf2S-bNfVmZguxxzmrIYWlyASxpqph4qsJWUc,494 -packaging/__pycache__/__init__.cpython-311.pyc,, -packaging/__pycache__/_elffile.cpython-311.pyc,, -packaging/__pycache__/_manylinux.cpython-311.pyc,, -packaging/__pycache__/_musllinux.cpython-311.pyc,, -packaging/__pycache__/_parser.cpython-311.pyc,, -packaging/__pycache__/_structures.cpython-311.pyc,, -packaging/__pycache__/_tokenizer.cpython-311.pyc,, -packaging/__pycache__/markers.cpython-311.pyc,, -packaging/__pycache__/metadata.cpython-311.pyc,, -packaging/__pycache__/requirements.cpython-311.pyc,, -packaging/__pycache__/specifiers.cpython-311.pyc,, -packaging/__pycache__/tags.cpython-311.pyc,, -packaging/__pycache__/utils.cpython-311.pyc,, -packaging/__pycache__/version.cpython-311.pyc,, -packaging/_elffile.py,sha256=UkrbDtW7aeq3qqoAfU16ojyHZ1xsTvGke_WqMTKAKd0,3286 -packaging/_manylinux.py,sha256=t4y_-dTOcfr36gLY-ztiOpxxJFGO2ikC11HgfysGxiM,9596 -packaging/_musllinux.py,sha256=p9ZqNYiOItGee8KcZFeHF_YcdhVwGHdK6r-8lgixvGQ,2694 -packaging/_parser.py,sha256=gYfnj0pRHflVc4RHZit13KNTyN9iiVcU2RUCGi22BwM,10221 -packaging/_structures.py,sha256=q3eVNmbWJGG_S0Dit_S3Ao8qQqz_5PYTXFAKBZe5yr4,1431 -packaging/_tokenizer.py,sha256=OYzt7qKxylOAJ-q0XyK1qAycyPRYLfMPdGQKRXkZWyI,5310 -packaging/licenses/__init__.py,sha256=VsK4o27CJXWfTi8r2ybJmsBoCdhpnBWuNrskaCVKP7U,5715 -packaging/licenses/__pycache__/__init__.cpython-311.pyc,, -packaging/licenses/__pycache__/_spdx.cpython-311.pyc,, -packaging/licenses/_spdx.py,sha256=oAm1ztPFwlsmCKe7lAAsv_OIOfS1cWDu9bNBkeu-2ns,48398 -packaging/markers.py,sha256=P0we27jm1xUzgGMJxBjtUFCIWeBxTsMeJTOJ6chZmAY,12049 -packaging/metadata.py,sha256=8IZErqQQnNm53dZZuYq4FGU4_dpyinMeH1QFBIWIkfE,34739 -packaging/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -packaging/requirements.py,sha256=gYyRSAdbrIyKDY66ugIDUQjRMvxkH2ALioTmX3tnL6o,2947 -packaging/specifiers.py,sha256=gtPu5DTc-F9baLq3FTGEK6dPhHGCuwwZetaY0PSV2gs,40055 -packaging/tags.py,sha256=41s97W9Zatrq2Ed7Rc3qeBDaHe8pKKvYq2mGjwahfXk,22745 -packaging/utils.py,sha256=0F3Hh9OFuRgrhTgGZUl5K22Fv1YP2tZl1z_2gO6kJiA,5050 -packaging/version.py,sha256=olfyuk_DPbflNkJ4wBWetXQ17c74x3DB501degUv7DY,16676 diff --git a/server/libs/packaging-25.0.dist-info/REQUESTED b/server/libs/packaging-25.0.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/server/libs/packaging-25.0.dist-info/WHEEL b/server/libs/packaging-25.0.dist-info/WHEEL deleted file mode 100644 index d8b9936..0000000 --- a/server/libs/packaging-25.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.12.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/server/libs/packaging-25.0.dist-info/licenses/LICENSE b/server/libs/packaging-25.0.dist-info/licenses/LICENSE deleted file mode 100644 index 6f62d44..0000000 --- a/server/libs/packaging-25.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,3 +0,0 @@ -This software is made available under the terms of *either* of the licenses -found in LICENSE.APACHE or LICENSE.BSD. Contributions to this software is made -under the terms of *both* these licenses. diff --git a/server/libs/packaging-25.0.dist-info/licenses/LICENSE.APACHE b/server/libs/packaging-25.0.dist-info/licenses/LICENSE.APACHE deleted file mode 100644 index f433b1a..0000000 --- a/server/libs/packaging-25.0.dist-info/licenses/LICENSE.APACHE +++ /dev/null @@ -1,177 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS diff --git a/server/libs/packaging-25.0.dist-info/licenses/LICENSE.BSD b/server/libs/packaging-25.0.dist-info/licenses/LICENSE.BSD deleted file mode 100644 index 42ce7b7..0000000 --- a/server/libs/packaging-25.0.dist-info/licenses/LICENSE.BSD +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) Donald Stufft and individual contributors. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/server/libs/packaging/__init__.py b/server/libs/packaging/__init__.py deleted file mode 100644 index d45c22c..0000000 --- a/server/libs/packaging/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -__title__ = "packaging" -__summary__ = "Core utilities for Python packages" -__uri__ = "https://github.com/pypa/packaging" - -__version__ = "25.0" - -__author__ = "Donald Stufft and individual contributors" -__email__ = "donald@stufft.io" - -__license__ = "BSD-2-Clause or Apache-2.0" -__copyright__ = f"2014 {__author__}" diff --git a/server/libs/packaging/_elffile.py b/server/libs/packaging/_elffile.py deleted file mode 100644 index 7a5afc3..0000000 --- a/server/libs/packaging/_elffile.py +++ /dev/null @@ -1,109 +0,0 @@ -""" -ELF file parser. - -This provides a class ``ELFFile`` that parses an ELF executable in a similar -interface to ``ZipFile``. Only the read interface is implemented. - -Based on: https://gist.github.com/lyssdod/f51579ae8d93c8657a5564aefc2ffbca -ELF header: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html -""" - -from __future__ import annotations - -import enum -import os -import struct -from typing import IO - - -class ELFInvalid(ValueError): - pass - - -class EIClass(enum.IntEnum): - C32 = 1 - C64 = 2 - - -class EIData(enum.IntEnum): - Lsb = 1 - Msb = 2 - - -class EMachine(enum.IntEnum): - I386 = 3 - S390 = 22 - Arm = 40 - X8664 = 62 - AArc64 = 183 - - -class ELFFile: - """ - Representation of an ELF executable. - """ - - def __init__(self, f: IO[bytes]) -> None: - self._f = f - - try: - ident = self._read("16B") - except struct.error as e: - raise ELFInvalid("unable to parse identification") from e - magic = bytes(ident[:4]) - if magic != b"\x7fELF": - raise ELFInvalid(f"invalid magic: {magic!r}") - - self.capacity = ident[4] # Format for program header (bitness). - self.encoding = ident[5] # Data structure encoding (endianness). - - try: - # e_fmt: Format for program header. - # p_fmt: Format for section header. - # p_idx: Indexes to find p_type, p_offset, and p_filesz. - e_fmt, self._p_fmt, self._p_idx = { - (1, 1): ("HHIIIIIHHH", ">IIIIIIII", (0, 1, 4)), # 32-bit MSB. - (2, 1): ("HHIQQQIHHH", ">IIQQQQQQ", (0, 2, 5)), # 64-bit MSB. - }[(self.capacity, self.encoding)] - except KeyError as e: - raise ELFInvalid( - f"unrecognized capacity ({self.capacity}) or encoding ({self.encoding})" - ) from e - - try: - ( - _, - self.machine, # Architecture type. - _, - _, - self._e_phoff, # Offset of program header. - _, - self.flags, # Processor-specific flags. - _, - self._e_phentsize, # Size of section. - self._e_phnum, # Number of sections. - ) = self._read(e_fmt) - except struct.error as e: - raise ELFInvalid("unable to parse machine and section information") from e - - def _read(self, fmt: str) -> tuple[int, ...]: - return struct.unpack(fmt, self._f.read(struct.calcsize(fmt))) - - @property - def interpreter(self) -> str | None: - """ - The path recorded in the ``PT_INTERP`` section header. - """ - for index in range(self._e_phnum): - self._f.seek(self._e_phoff + self._e_phentsize * index) - try: - data = self._read(self._p_fmt) - except struct.error: - continue - if data[self._p_idx[0]] != 3: # Not PT_INTERP. - continue - self._f.seek(data[self._p_idx[1]]) - return os.fsdecode(self._f.read(data[self._p_idx[2]])).strip("\0") - return None diff --git a/server/libs/packaging/_manylinux.py b/server/libs/packaging/_manylinux.py deleted file mode 100644 index 95f5576..0000000 --- a/server/libs/packaging/_manylinux.py +++ /dev/null @@ -1,262 +0,0 @@ -from __future__ import annotations - -import collections -import contextlib -import functools -import os -import re -import sys -import warnings -from typing import Generator, Iterator, NamedTuple, Sequence - -from ._elffile import EIClass, EIData, ELFFile, EMachine - -EF_ARM_ABIMASK = 0xFF000000 -EF_ARM_ABI_VER5 = 0x05000000 -EF_ARM_ABI_FLOAT_HARD = 0x00000400 - - -# `os.PathLike` not a generic type until Python 3.9, so sticking with `str` -# as the type for `path` until then. -@contextlib.contextmanager -def _parse_elf(path: str) -> Generator[ELFFile | None, None, None]: - try: - with open(path, "rb") as f: - yield ELFFile(f) - except (OSError, TypeError, ValueError): - yield None - - -def _is_linux_armhf(executable: str) -> bool: - # hard-float ABI can be detected from the ELF header of the running - # process - # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf - with _parse_elf(executable) as f: - return ( - f is not None - and f.capacity == EIClass.C32 - and f.encoding == EIData.Lsb - and f.machine == EMachine.Arm - and f.flags & EF_ARM_ABIMASK == EF_ARM_ABI_VER5 - and f.flags & EF_ARM_ABI_FLOAT_HARD == EF_ARM_ABI_FLOAT_HARD - ) - - -def _is_linux_i686(executable: str) -> bool: - with _parse_elf(executable) as f: - return ( - f is not None - and f.capacity == EIClass.C32 - and f.encoding == EIData.Lsb - and f.machine == EMachine.I386 - ) - - -def _have_compatible_abi(executable: str, archs: Sequence[str]) -> bool: - if "armv7l" in archs: - return _is_linux_armhf(executable) - if "i686" in archs: - return _is_linux_i686(executable) - allowed_archs = { - "x86_64", - "aarch64", - "ppc64", - "ppc64le", - "s390x", - "loongarch64", - "riscv64", - } - return any(arch in allowed_archs for arch in archs) - - -# If glibc ever changes its major version, we need to know what the last -# minor version was, so we can build the complete list of all versions. -# For now, guess what the highest minor version might be, assume it will -# be 50 for testing. Once this actually happens, update the dictionary -# with the actual value. -_LAST_GLIBC_MINOR: dict[int, int] = collections.defaultdict(lambda: 50) - - -class _GLibCVersion(NamedTuple): - major: int - minor: int - - -def _glibc_version_string_confstr() -> str | None: - """ - Primary implementation of glibc_version_string using os.confstr. - """ - # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely - # to be broken or missing. This strategy is used in the standard library - # platform module. - # https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183 - try: - # Should be a string like "glibc 2.17". - version_string: str | None = os.confstr("CS_GNU_LIBC_VERSION") - assert version_string is not None - _, version = version_string.rsplit() - except (AssertionError, AttributeError, OSError, ValueError): - # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... - return None - return version - - -def _glibc_version_string_ctypes() -> str | None: - """ - Fallback implementation of glibc_version_string using ctypes. - """ - try: - import ctypes - except ImportError: - return None - - # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen - # manpage says, "If filename is NULL, then the returned handle is for the - # main program". This way we can let the linker do the work to figure out - # which libc our process is actually using. - # - # We must also handle the special case where the executable is not a - # dynamically linked executable. This can occur when using musl libc, - # for example. In this situation, dlopen() will error, leading to an - # OSError. Interestingly, at least in the case of musl, there is no - # errno set on the OSError. The single string argument used to construct - # OSError comes from libc itself and is therefore not portable to - # hard code here. In any case, failure to call dlopen() means we - # can proceed, so we bail on our attempt. - try: - process_namespace = ctypes.CDLL(None) - except OSError: - return None - - try: - gnu_get_libc_version = process_namespace.gnu_get_libc_version - except AttributeError: - # Symbol doesn't exist -> therefore, we are not linked to - # glibc. - return None - - # Call gnu_get_libc_version, which returns a string like "2.5" - gnu_get_libc_version.restype = ctypes.c_char_p - version_str: str = gnu_get_libc_version() - # py2 / py3 compatibility: - if not isinstance(version_str, str): - version_str = version_str.decode("ascii") - - return version_str - - -def _glibc_version_string() -> str | None: - """Returns glibc version string, or None if not using glibc.""" - return _glibc_version_string_confstr() or _glibc_version_string_ctypes() - - -def _parse_glibc_version(version_str: str) -> tuple[int, int]: - """Parse glibc version. - - We use a regexp instead of str.split because we want to discard any - random junk that might come after the minor version -- this might happen - in patched/forked versions of glibc (e.g. Linaro's version of glibc - uses version strings like "2.20-2014.11"). See gh-3588. - """ - m = re.match(r"(?P[0-9]+)\.(?P[0-9]+)", version_str) - if not m: - warnings.warn( - f"Expected glibc version with 2 components major.minor, got: {version_str}", - RuntimeWarning, - stacklevel=2, - ) - return -1, -1 - return int(m.group("major")), int(m.group("minor")) - - -@functools.lru_cache -def _get_glibc_version() -> tuple[int, int]: - version_str = _glibc_version_string() - if version_str is None: - return (-1, -1) - return _parse_glibc_version(version_str) - - -# From PEP 513, PEP 600 -def _is_compatible(arch: str, version: _GLibCVersion) -> bool: - sys_glibc = _get_glibc_version() - if sys_glibc < version: - return False - # Check for presence of _manylinux module. - try: - import _manylinux - except ImportError: - return True - if hasattr(_manylinux, "manylinux_compatible"): - result = _manylinux.manylinux_compatible(version[0], version[1], arch) - if result is not None: - return bool(result) - return True - if version == _GLibCVersion(2, 5): - if hasattr(_manylinux, "manylinux1_compatible"): - return bool(_manylinux.manylinux1_compatible) - if version == _GLibCVersion(2, 12): - if hasattr(_manylinux, "manylinux2010_compatible"): - return bool(_manylinux.manylinux2010_compatible) - if version == _GLibCVersion(2, 17): - if hasattr(_manylinux, "manylinux2014_compatible"): - return bool(_manylinux.manylinux2014_compatible) - return True - - -_LEGACY_MANYLINUX_MAP = { - # CentOS 7 w/ glibc 2.17 (PEP 599) - (2, 17): "manylinux2014", - # CentOS 6 w/ glibc 2.12 (PEP 571) - (2, 12): "manylinux2010", - # CentOS 5 w/ glibc 2.5 (PEP 513) - (2, 5): "manylinux1", -} - - -def platform_tags(archs: Sequence[str]) -> Iterator[str]: - """Generate manylinux tags compatible to the current platform. - - :param archs: Sequence of compatible architectures. - The first one shall be the closest to the actual architecture and be the part of - platform tag after the ``linux_`` prefix, e.g. ``x86_64``. - The ``linux_`` prefix is assumed as a prerequisite for the current platform to - be manylinux-compatible. - - :returns: An iterator of compatible manylinux tags. - """ - if not _have_compatible_abi(sys.executable, archs): - return - # Oldest glibc to be supported regardless of architecture is (2, 17). - too_old_glibc2 = _GLibCVersion(2, 16) - if set(archs) & {"x86_64", "i686"}: - # On x86/i686 also oldest glibc to be supported is (2, 5). - too_old_glibc2 = _GLibCVersion(2, 4) - current_glibc = _GLibCVersion(*_get_glibc_version()) - glibc_max_list = [current_glibc] - # We can assume compatibility across glibc major versions. - # https://sourceware.org/bugzilla/show_bug.cgi?id=24636 - # - # Build a list of maximum glibc versions so that we can - # output the canonical list of all glibc from current_glibc - # down to too_old_glibc2, including all intermediary versions. - for glibc_major in range(current_glibc.major - 1, 1, -1): - glibc_minor = _LAST_GLIBC_MINOR[glibc_major] - glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor)) - for arch in archs: - for glibc_max in glibc_max_list: - if glibc_max.major == too_old_glibc2.major: - min_minor = too_old_glibc2.minor - else: - # For other glibc major versions oldest supported is (x, 0). - min_minor = -1 - for glibc_minor in range(glibc_max.minor, min_minor, -1): - glibc_version = _GLibCVersion(glibc_max.major, glibc_minor) - tag = "manylinux_{}_{}".format(*glibc_version) - if _is_compatible(arch, glibc_version): - yield f"{tag}_{arch}" - # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags. - if glibc_version in _LEGACY_MANYLINUX_MAP: - legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version] - if _is_compatible(arch, glibc_version): - yield f"{legacy_tag}_{arch}" diff --git a/server/libs/packaging/_musllinux.py b/server/libs/packaging/_musllinux.py deleted file mode 100644 index d2bf30b..0000000 --- a/server/libs/packaging/_musllinux.py +++ /dev/null @@ -1,85 +0,0 @@ -"""PEP 656 support. - -This module implements logic to detect if the currently running Python is -linked against musl, and what musl version is used. -""" - -from __future__ import annotations - -import functools -import re -import subprocess -import sys -from typing import Iterator, NamedTuple, Sequence - -from ._elffile import ELFFile - - -class _MuslVersion(NamedTuple): - major: int - minor: int - - -def _parse_musl_version(output: str) -> _MuslVersion | None: - lines = [n for n in (n.strip() for n in output.splitlines()) if n] - if len(lines) < 2 or lines[0][:4] != "musl": - return None - m = re.match(r"Version (\d+)\.(\d+)", lines[1]) - if not m: - return None - return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2))) - - -@functools.lru_cache -def _get_musl_version(executable: str) -> _MuslVersion | None: - """Detect currently-running musl runtime version. - - This is done by checking the specified executable's dynamic linking - information, and invoking the loader to parse its output for a version - string. If the loader is musl, the output would be something like:: - - musl libc (x86_64) - Version 1.2.2 - Dynamic Program Loader - """ - try: - with open(executable, "rb") as f: - ld = ELFFile(f).interpreter - except (OSError, TypeError, ValueError): - return None - if ld is None or "musl" not in ld: - return None - proc = subprocess.run([ld], stderr=subprocess.PIPE, text=True) - return _parse_musl_version(proc.stderr) - - -def platform_tags(archs: Sequence[str]) -> Iterator[str]: - """Generate musllinux tags compatible to the current platform. - - :param archs: Sequence of compatible architectures. - The first one shall be the closest to the actual architecture and be the part of - platform tag after the ``linux_`` prefix, e.g. ``x86_64``. - The ``linux_`` prefix is assumed as a prerequisite for the current platform to - be musllinux-compatible. - - :returns: An iterator of compatible musllinux tags. - """ - sys_musl = _get_musl_version(sys.executable) - if sys_musl is None: # Python not dynamically linked against musl. - return - for arch in archs: - for minor in range(sys_musl.minor, -1, -1): - yield f"musllinux_{sys_musl.major}_{minor}_{arch}" - - -if __name__ == "__main__": # pragma: no cover - import sysconfig - - plat = sysconfig.get_platform() - assert plat.startswith("linux-"), "not linux" - - print("plat:", plat) - print("musl:", _get_musl_version(sys.executable)) - print("tags:", end=" ") - for t in platform_tags(re.sub(r"[.-]", "_", plat.split("-", 1)[-1])): - print(t, end="\n ") diff --git a/server/libs/packaging/_parser.py b/server/libs/packaging/_parser.py deleted file mode 100644 index 0007c0a..0000000 --- a/server/libs/packaging/_parser.py +++ /dev/null @@ -1,353 +0,0 @@ -"""Handwritten parser of dependency specifiers. - -The docstring for each __parse_* function contains EBNF-inspired grammar representing -the implementation. -""" - -from __future__ import annotations - -import ast -from typing import NamedTuple, Sequence, Tuple, Union - -from ._tokenizer import DEFAULT_RULES, Tokenizer - - -class Node: - def __init__(self, value: str) -> None: - self.value = value - - def __str__(self) -> str: - return self.value - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}('{self}')>" - - def serialize(self) -> str: - raise NotImplementedError - - -class Variable(Node): - def serialize(self) -> str: - return str(self) - - -class Value(Node): - def serialize(self) -> str: - return f'"{self}"' - - -class Op(Node): - def serialize(self) -> str: - return str(self) - - -MarkerVar = Union[Variable, Value] -MarkerItem = Tuple[MarkerVar, Op, MarkerVar] -MarkerAtom = Union[MarkerItem, Sequence["MarkerAtom"]] -MarkerList = Sequence[Union["MarkerList", MarkerAtom, str]] - - -class ParsedRequirement(NamedTuple): - name: str - url: str - extras: list[str] - specifier: str - marker: MarkerList | None - - -# -------------------------------------------------------------------------------------- -# Recursive descent parser for dependency specifier -# -------------------------------------------------------------------------------------- -def parse_requirement(source: str) -> ParsedRequirement: - return _parse_requirement(Tokenizer(source, rules=DEFAULT_RULES)) - - -def _parse_requirement(tokenizer: Tokenizer) -> ParsedRequirement: - """ - requirement = WS? IDENTIFIER WS? extras WS? requirement_details - """ - tokenizer.consume("WS") - - name_token = tokenizer.expect( - "IDENTIFIER", expected="package name at the start of dependency specifier" - ) - name = name_token.text - tokenizer.consume("WS") - - extras = _parse_extras(tokenizer) - tokenizer.consume("WS") - - url, specifier, marker = _parse_requirement_details(tokenizer) - tokenizer.expect("END", expected="end of dependency specifier") - - return ParsedRequirement(name, url, extras, specifier, marker) - - -def _parse_requirement_details( - tokenizer: Tokenizer, -) -> tuple[str, str, MarkerList | None]: - """ - requirement_details = AT URL (WS requirement_marker?)? - | specifier WS? (requirement_marker)? - """ - - specifier = "" - url = "" - marker = None - - if tokenizer.check("AT"): - tokenizer.read() - tokenizer.consume("WS") - - url_start = tokenizer.position - url = tokenizer.expect("URL", expected="URL after @").text - if tokenizer.check("END", peek=True): - return (url, specifier, marker) - - tokenizer.expect("WS", expected="whitespace after URL") - - # The input might end after whitespace. - if tokenizer.check("END", peek=True): - return (url, specifier, marker) - - marker = _parse_requirement_marker( - tokenizer, span_start=url_start, after="URL and whitespace" - ) - else: - specifier_start = tokenizer.position - specifier = _parse_specifier(tokenizer) - tokenizer.consume("WS") - - if tokenizer.check("END", peek=True): - return (url, specifier, marker) - - marker = _parse_requirement_marker( - tokenizer, - span_start=specifier_start, - after=( - "version specifier" - if specifier - else "name and no valid version specifier" - ), - ) - - return (url, specifier, marker) - - -def _parse_requirement_marker( - tokenizer: Tokenizer, *, span_start: int, after: str -) -> MarkerList: - """ - requirement_marker = SEMICOLON marker WS? - """ - - if not tokenizer.check("SEMICOLON"): - tokenizer.raise_syntax_error( - f"Expected end or semicolon (after {after})", - span_start=span_start, - ) - tokenizer.read() - - marker = _parse_marker(tokenizer) - tokenizer.consume("WS") - - return marker - - -def _parse_extras(tokenizer: Tokenizer) -> list[str]: - """ - extras = (LEFT_BRACKET wsp* extras_list? wsp* RIGHT_BRACKET)? - """ - if not tokenizer.check("LEFT_BRACKET", peek=True): - return [] - - with tokenizer.enclosing_tokens( - "LEFT_BRACKET", - "RIGHT_BRACKET", - around="extras", - ): - tokenizer.consume("WS") - extras = _parse_extras_list(tokenizer) - tokenizer.consume("WS") - - return extras - - -def _parse_extras_list(tokenizer: Tokenizer) -> list[str]: - """ - extras_list = identifier (wsp* ',' wsp* identifier)* - """ - extras: list[str] = [] - - if not tokenizer.check("IDENTIFIER"): - return extras - - extras.append(tokenizer.read().text) - - while True: - tokenizer.consume("WS") - if tokenizer.check("IDENTIFIER", peek=True): - tokenizer.raise_syntax_error("Expected comma between extra names") - elif not tokenizer.check("COMMA"): - break - - tokenizer.read() - tokenizer.consume("WS") - - extra_token = tokenizer.expect("IDENTIFIER", expected="extra name after comma") - extras.append(extra_token.text) - - return extras - - -def _parse_specifier(tokenizer: Tokenizer) -> str: - """ - specifier = LEFT_PARENTHESIS WS? version_many WS? RIGHT_PARENTHESIS - | WS? version_many WS? - """ - with tokenizer.enclosing_tokens( - "LEFT_PARENTHESIS", - "RIGHT_PARENTHESIS", - around="version specifier", - ): - tokenizer.consume("WS") - parsed_specifiers = _parse_version_many(tokenizer) - tokenizer.consume("WS") - - return parsed_specifiers - - -def _parse_version_many(tokenizer: Tokenizer) -> str: - """ - version_many = (SPECIFIER (WS? COMMA WS? SPECIFIER)*)? - """ - parsed_specifiers = "" - while tokenizer.check("SPECIFIER"): - span_start = tokenizer.position - parsed_specifiers += tokenizer.read().text - if tokenizer.check("VERSION_PREFIX_TRAIL", peek=True): - tokenizer.raise_syntax_error( - ".* suffix can only be used with `==` or `!=` operators", - span_start=span_start, - span_end=tokenizer.position + 1, - ) - if tokenizer.check("VERSION_LOCAL_LABEL_TRAIL", peek=True): - tokenizer.raise_syntax_error( - "Local version label can only be used with `==` or `!=` operators", - span_start=span_start, - span_end=tokenizer.position, - ) - tokenizer.consume("WS") - if not tokenizer.check("COMMA"): - break - parsed_specifiers += tokenizer.read().text - tokenizer.consume("WS") - - return parsed_specifiers - - -# -------------------------------------------------------------------------------------- -# Recursive descent parser for marker expression -# -------------------------------------------------------------------------------------- -def parse_marker(source: str) -> MarkerList: - return _parse_full_marker(Tokenizer(source, rules=DEFAULT_RULES)) - - -def _parse_full_marker(tokenizer: Tokenizer) -> MarkerList: - retval = _parse_marker(tokenizer) - tokenizer.expect("END", expected="end of marker expression") - return retval - - -def _parse_marker(tokenizer: Tokenizer) -> MarkerList: - """ - marker = marker_atom (BOOLOP marker_atom)+ - """ - expression = [_parse_marker_atom(tokenizer)] - while tokenizer.check("BOOLOP"): - token = tokenizer.read() - expr_right = _parse_marker_atom(tokenizer) - expression.extend((token.text, expr_right)) - return expression - - -def _parse_marker_atom(tokenizer: Tokenizer) -> MarkerAtom: - """ - marker_atom = WS? LEFT_PARENTHESIS WS? marker WS? RIGHT_PARENTHESIS WS? - | WS? marker_item WS? - """ - - tokenizer.consume("WS") - if tokenizer.check("LEFT_PARENTHESIS", peek=True): - with tokenizer.enclosing_tokens( - "LEFT_PARENTHESIS", - "RIGHT_PARENTHESIS", - around="marker expression", - ): - tokenizer.consume("WS") - marker: MarkerAtom = _parse_marker(tokenizer) - tokenizer.consume("WS") - else: - marker = _parse_marker_item(tokenizer) - tokenizer.consume("WS") - return marker - - -def _parse_marker_item(tokenizer: Tokenizer) -> MarkerItem: - """ - marker_item = WS? marker_var WS? marker_op WS? marker_var WS? - """ - tokenizer.consume("WS") - marker_var_left = _parse_marker_var(tokenizer) - tokenizer.consume("WS") - marker_op = _parse_marker_op(tokenizer) - tokenizer.consume("WS") - marker_var_right = _parse_marker_var(tokenizer) - tokenizer.consume("WS") - return (marker_var_left, marker_op, marker_var_right) - - -def _parse_marker_var(tokenizer: Tokenizer) -> MarkerVar: - """ - marker_var = VARIABLE | QUOTED_STRING - """ - if tokenizer.check("VARIABLE"): - return process_env_var(tokenizer.read().text.replace(".", "_")) - elif tokenizer.check("QUOTED_STRING"): - return process_python_str(tokenizer.read().text) - else: - tokenizer.raise_syntax_error( - message="Expected a marker variable or quoted string" - ) - - -def process_env_var(env_var: str) -> Variable: - if env_var in ("platform_python_implementation", "python_implementation"): - return Variable("platform_python_implementation") - else: - return Variable(env_var) - - -def process_python_str(python_str: str) -> Value: - value = ast.literal_eval(python_str) - return Value(str(value)) - - -def _parse_marker_op(tokenizer: Tokenizer) -> Op: - """ - marker_op = IN | NOT IN | OP - """ - if tokenizer.check("IN"): - tokenizer.read() - return Op("in") - elif tokenizer.check("NOT"): - tokenizer.read() - tokenizer.expect("WS", expected="whitespace after 'not'") - tokenizer.expect("IN", expected="'in' after 'not'") - return Op("not in") - elif tokenizer.check("OP"): - return Op(tokenizer.read().text) - else: - return tokenizer.raise_syntax_error( - "Expected marker operator, one of <=, <, !=, ==, >=, >, ~=, ===, in, not in" - ) diff --git a/server/libs/packaging/_structures.py b/server/libs/packaging/_structures.py deleted file mode 100644 index 90a6465..0000000 --- a/server/libs/packaging/_structures.py +++ /dev/null @@ -1,61 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - - -class InfinityType: - def __repr__(self) -> str: - return "Infinity" - - def __hash__(self) -> int: - return hash(repr(self)) - - def __lt__(self, other: object) -> bool: - return False - - def __le__(self, other: object) -> bool: - return False - - def __eq__(self, other: object) -> bool: - return isinstance(other, self.__class__) - - def __gt__(self, other: object) -> bool: - return True - - def __ge__(self, other: object) -> bool: - return True - - def __neg__(self: object) -> "NegativeInfinityType": - return NegativeInfinity - - -Infinity = InfinityType() - - -class NegativeInfinityType: - def __repr__(self) -> str: - return "-Infinity" - - def __hash__(self) -> int: - return hash(repr(self)) - - def __lt__(self, other: object) -> bool: - return True - - def __le__(self, other: object) -> bool: - return True - - def __eq__(self, other: object) -> bool: - return isinstance(other, self.__class__) - - def __gt__(self, other: object) -> bool: - return False - - def __ge__(self, other: object) -> bool: - return False - - def __neg__(self: object) -> InfinityType: - return Infinity - - -NegativeInfinity = NegativeInfinityType() diff --git a/server/libs/packaging/_tokenizer.py b/server/libs/packaging/_tokenizer.py deleted file mode 100644 index d28a9b6..0000000 --- a/server/libs/packaging/_tokenizer.py +++ /dev/null @@ -1,195 +0,0 @@ -from __future__ import annotations - -import contextlib -import re -from dataclasses import dataclass -from typing import Iterator, NoReturn - -from .specifiers import Specifier - - -@dataclass -class Token: - name: str - text: str - position: int - - -class ParserSyntaxError(Exception): - """The provided source text could not be parsed correctly.""" - - def __init__( - self, - message: str, - *, - source: str, - span: tuple[int, int], - ) -> None: - self.span = span - self.message = message - self.source = source - - super().__init__() - - def __str__(self) -> str: - marker = " " * self.span[0] + "~" * (self.span[1] - self.span[0]) + "^" - return "\n ".join([self.message, self.source, marker]) - - -DEFAULT_RULES: dict[str, str | re.Pattern[str]] = { - "LEFT_PARENTHESIS": r"\(", - "RIGHT_PARENTHESIS": r"\)", - "LEFT_BRACKET": r"\[", - "RIGHT_BRACKET": r"\]", - "SEMICOLON": r";", - "COMMA": r",", - "QUOTED_STRING": re.compile( - r""" - ( - ('[^']*') - | - ("[^"]*") - ) - """, - re.VERBOSE, - ), - "OP": r"(===|==|~=|!=|<=|>=|<|>)", - "BOOLOP": r"\b(or|and)\b", - "IN": r"\bin\b", - "NOT": r"\bnot\b", - "VARIABLE": re.compile( - r""" - \b( - python_version - |python_full_version - |os[._]name - |sys[._]platform - |platform_(release|system) - |platform[._](version|machine|python_implementation) - |python_implementation - |implementation_(name|version) - |extras? - |dependency_groups - )\b - """, - re.VERBOSE, - ), - "SPECIFIER": re.compile( - Specifier._operator_regex_str + Specifier._version_regex_str, - re.VERBOSE | re.IGNORECASE, - ), - "AT": r"\@", - "URL": r"[^ \t]+", - "IDENTIFIER": r"\b[a-zA-Z0-9][a-zA-Z0-9._-]*\b", - "VERSION_PREFIX_TRAIL": r"\.\*", - "VERSION_LOCAL_LABEL_TRAIL": r"\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*", - "WS": r"[ \t]+", - "END": r"$", -} - - -class Tokenizer: - """Context-sensitive token parsing. - - Provides methods to examine the input stream to check whether the next token - matches. - """ - - def __init__( - self, - source: str, - *, - rules: dict[str, str | re.Pattern[str]], - ) -> None: - self.source = source - self.rules: dict[str, re.Pattern[str]] = { - name: re.compile(pattern) for name, pattern in rules.items() - } - self.next_token: Token | None = None - self.position = 0 - - def consume(self, name: str) -> None: - """Move beyond provided token name, if at current position.""" - if self.check(name): - self.read() - - def check(self, name: str, *, peek: bool = False) -> bool: - """Check whether the next token has the provided name. - - By default, if the check succeeds, the token *must* be read before - another check. If `peek` is set to `True`, the token is not loaded and - would need to be checked again. - """ - assert self.next_token is None, ( - f"Cannot check for {name!r}, already have {self.next_token!r}" - ) - assert name in self.rules, f"Unknown token name: {name!r}" - - expression = self.rules[name] - - match = expression.match(self.source, self.position) - if match is None: - return False - if not peek: - self.next_token = Token(name, match[0], self.position) - return True - - def expect(self, name: str, *, expected: str) -> Token: - """Expect a certain token name next, failing with a syntax error otherwise. - - The token is *not* read. - """ - if not self.check(name): - raise self.raise_syntax_error(f"Expected {expected}") - return self.read() - - def read(self) -> Token: - """Consume the next token and return it.""" - token = self.next_token - assert token is not None - - self.position += len(token.text) - self.next_token = None - - return token - - def raise_syntax_error( - self, - message: str, - *, - span_start: int | None = None, - span_end: int | None = None, - ) -> NoReturn: - """Raise ParserSyntaxError at the given position.""" - span = ( - self.position if span_start is None else span_start, - self.position if span_end is None else span_end, - ) - raise ParserSyntaxError( - message, - source=self.source, - span=span, - ) - - @contextlib.contextmanager - def enclosing_tokens( - self, open_token: str, close_token: str, *, around: str - ) -> Iterator[None]: - if self.check(open_token): - open_position = self.position - self.read() - else: - open_position = None - - yield - - if open_position is None: - return - - if not self.check(close_token): - self.raise_syntax_error( - f"Expected matching {close_token} for {open_token}, after {around}", - span_start=open_position, - ) - - self.read() diff --git a/server/libs/packaging/licenses/__init__.py b/server/libs/packaging/licenses/__init__.py deleted file mode 100644 index 6f7f9e6..0000000 --- a/server/libs/packaging/licenses/__init__.py +++ /dev/null @@ -1,145 +0,0 @@ -####################################################################################### -# -# Adapted from: -# https://github.com/pypa/hatch/blob/5352e44/backend/src/hatchling/licenses/parse.py -# -# MIT License -# -# Copyright (c) 2017-present Ofek Lev -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of this -# software and associated documentation files (the "Software"), to deal in the Software -# without restriction, including without limitation the rights to use, copy, modify, -# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to the following -# conditions: -# -# The above copyright notice and this permission notice shall be included in all copies -# or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# -# With additional allowance of arbitrary `LicenseRef-` identifiers, not just -# `LicenseRef-Public-Domain` and `LicenseRef-Proprietary`. -# -####################################################################################### -from __future__ import annotations - -import re -from typing import NewType, cast - -from packaging.licenses._spdx import EXCEPTIONS, LICENSES - -__all__ = [ - "InvalidLicenseExpression", - "NormalizedLicenseExpression", - "canonicalize_license_expression", -] - -license_ref_allowed = re.compile("^[A-Za-z0-9.-]*$") - -NormalizedLicenseExpression = NewType("NormalizedLicenseExpression", str) - - -class InvalidLicenseExpression(ValueError): - """Raised when a license-expression string is invalid - - >>> canonicalize_license_expression("invalid") - Traceback (most recent call last): - ... - packaging.licenses.InvalidLicenseExpression: Invalid license expression: 'invalid' - """ - - -def canonicalize_license_expression( - raw_license_expression: str, -) -> NormalizedLicenseExpression: - if not raw_license_expression: - message = f"Invalid license expression: {raw_license_expression!r}" - raise InvalidLicenseExpression(message) - - # Pad any parentheses so tokenization can be achieved by merely splitting on - # whitespace. - license_expression = raw_license_expression.replace("(", " ( ").replace(")", " ) ") - licenseref_prefix = "LicenseRef-" - license_refs = { - ref.lower(): "LicenseRef-" + ref[len(licenseref_prefix) :] - for ref in license_expression.split() - if ref.lower().startswith(licenseref_prefix.lower()) - } - - # Normalize to lower case so we can look up licenses/exceptions - # and so boolean operators are Python-compatible. - license_expression = license_expression.lower() - - tokens = license_expression.split() - - # Rather than implementing boolean logic, we create an expression that Python can - # parse. Everything that is not involved with the grammar itself is treated as - # `False` and the expression should evaluate as such. - python_tokens = [] - for token in tokens: - if token not in {"or", "and", "with", "(", ")"}: - python_tokens.append("False") - elif token == "with": - python_tokens.append("or") - elif token == "(" and python_tokens and python_tokens[-1] not in {"or", "and"}: - message = f"Invalid license expression: {raw_license_expression!r}" - raise InvalidLicenseExpression(message) - else: - python_tokens.append(token) - - python_expression = " ".join(python_tokens) - try: - invalid = eval(python_expression, globals(), locals()) - except Exception: - invalid = True - - if invalid is not False: - message = f"Invalid license expression: {raw_license_expression!r}" - raise InvalidLicenseExpression(message) from None - - # Take a final pass to check for unknown licenses/exceptions. - normalized_tokens = [] - for token in tokens: - if token in {"or", "and", "with", "(", ")"}: - normalized_tokens.append(token.upper()) - continue - - if normalized_tokens and normalized_tokens[-1] == "WITH": - if token not in EXCEPTIONS: - message = f"Unknown license exception: {token!r}" - raise InvalidLicenseExpression(message) - - normalized_tokens.append(EXCEPTIONS[token]["id"]) - else: - if token.endswith("+"): - final_token = token[:-1] - suffix = "+" - else: - final_token = token - suffix = "" - - if final_token.startswith("licenseref-"): - if not license_ref_allowed.match(final_token): - message = f"Invalid licenseref: {final_token!r}" - raise InvalidLicenseExpression(message) - normalized_tokens.append(license_refs[final_token] + suffix) - else: - if final_token not in LICENSES: - message = f"Unknown license: {final_token!r}" - raise InvalidLicenseExpression(message) - normalized_tokens.append(LICENSES[final_token]["id"] + suffix) - - normalized_expression = " ".join(normalized_tokens) - - return cast( - NormalizedLicenseExpression, - normalized_expression.replace("( ", "(").replace(" )", ")"), - ) diff --git a/server/libs/packaging/licenses/_spdx.py b/server/libs/packaging/licenses/_spdx.py deleted file mode 100644 index eac2227..0000000 --- a/server/libs/packaging/licenses/_spdx.py +++ /dev/null @@ -1,759 +0,0 @@ - -from __future__ import annotations - -from typing import TypedDict - -class SPDXLicense(TypedDict): - id: str - deprecated: bool - -class SPDXException(TypedDict): - id: str - deprecated: bool - - -VERSION = '3.25.0' - -LICENSES: dict[str, SPDXLicense] = { - '0bsd': {'id': '0BSD', 'deprecated': False}, - '3d-slicer-1.0': {'id': '3D-Slicer-1.0', 'deprecated': False}, - 'aal': {'id': 'AAL', 'deprecated': False}, - 'abstyles': {'id': 'Abstyles', 'deprecated': False}, - 'adacore-doc': {'id': 'AdaCore-doc', 'deprecated': False}, - 'adobe-2006': {'id': 'Adobe-2006', 'deprecated': False}, - 'adobe-display-postscript': {'id': 'Adobe-Display-PostScript', 'deprecated': False}, - 'adobe-glyph': {'id': 'Adobe-Glyph', 'deprecated': False}, - 'adobe-utopia': {'id': 'Adobe-Utopia', 'deprecated': False}, - 'adsl': {'id': 'ADSL', 'deprecated': False}, - 'afl-1.1': {'id': 'AFL-1.1', 'deprecated': False}, - 'afl-1.2': {'id': 'AFL-1.2', 'deprecated': False}, - 'afl-2.0': {'id': 'AFL-2.0', 'deprecated': False}, - 'afl-2.1': {'id': 'AFL-2.1', 'deprecated': False}, - 'afl-3.0': {'id': 'AFL-3.0', 'deprecated': False}, - 'afmparse': {'id': 'Afmparse', 'deprecated': False}, - 'agpl-1.0': {'id': 'AGPL-1.0', 'deprecated': True}, - 'agpl-1.0-only': {'id': 'AGPL-1.0-only', 'deprecated': False}, - 'agpl-1.0-or-later': {'id': 'AGPL-1.0-or-later', 'deprecated': False}, - 'agpl-3.0': {'id': 'AGPL-3.0', 'deprecated': True}, - 'agpl-3.0-only': {'id': 'AGPL-3.0-only', 'deprecated': False}, - 'agpl-3.0-or-later': {'id': 'AGPL-3.0-or-later', 'deprecated': False}, - 'aladdin': {'id': 'Aladdin', 'deprecated': False}, - 'amd-newlib': {'id': 'AMD-newlib', 'deprecated': False}, - 'amdplpa': {'id': 'AMDPLPA', 'deprecated': False}, - 'aml': {'id': 'AML', 'deprecated': False}, - 'aml-glslang': {'id': 'AML-glslang', 'deprecated': False}, - 'ampas': {'id': 'AMPAS', 'deprecated': False}, - 'antlr-pd': {'id': 'ANTLR-PD', 'deprecated': False}, - 'antlr-pd-fallback': {'id': 'ANTLR-PD-fallback', 'deprecated': False}, - 'any-osi': {'id': 'any-OSI', 'deprecated': False}, - 'apache-1.0': {'id': 'Apache-1.0', 'deprecated': False}, - 'apache-1.1': {'id': 'Apache-1.1', 'deprecated': False}, - 'apache-2.0': {'id': 'Apache-2.0', 'deprecated': False}, - 'apafml': {'id': 'APAFML', 'deprecated': False}, - 'apl-1.0': {'id': 'APL-1.0', 'deprecated': False}, - 'app-s2p': {'id': 'App-s2p', 'deprecated': False}, - 'apsl-1.0': {'id': 'APSL-1.0', 'deprecated': False}, - 'apsl-1.1': {'id': 'APSL-1.1', 'deprecated': False}, - 'apsl-1.2': {'id': 'APSL-1.2', 'deprecated': False}, - 'apsl-2.0': {'id': 'APSL-2.0', 'deprecated': False}, - 'arphic-1999': {'id': 'Arphic-1999', 'deprecated': False}, - 'artistic-1.0': {'id': 'Artistic-1.0', 'deprecated': False}, - 'artistic-1.0-cl8': {'id': 'Artistic-1.0-cl8', 'deprecated': False}, - 'artistic-1.0-perl': {'id': 'Artistic-1.0-Perl', 'deprecated': False}, - 'artistic-2.0': {'id': 'Artistic-2.0', 'deprecated': False}, - 'aswf-digital-assets-1.0': {'id': 'ASWF-Digital-Assets-1.0', 'deprecated': False}, - 'aswf-digital-assets-1.1': {'id': 'ASWF-Digital-Assets-1.1', 'deprecated': False}, - 'baekmuk': {'id': 'Baekmuk', 'deprecated': False}, - 'bahyph': {'id': 'Bahyph', 'deprecated': False}, - 'barr': {'id': 'Barr', 'deprecated': False}, - 'bcrypt-solar-designer': {'id': 'bcrypt-Solar-Designer', 'deprecated': False}, - 'beerware': {'id': 'Beerware', 'deprecated': False}, - 'bitstream-charter': {'id': 'Bitstream-Charter', 'deprecated': False}, - 'bitstream-vera': {'id': 'Bitstream-Vera', 'deprecated': False}, - 'bittorrent-1.0': {'id': 'BitTorrent-1.0', 'deprecated': False}, - 'bittorrent-1.1': {'id': 'BitTorrent-1.1', 'deprecated': False}, - 'blessing': {'id': 'blessing', 'deprecated': False}, - 'blueoak-1.0.0': {'id': 'BlueOak-1.0.0', 'deprecated': False}, - 'boehm-gc': {'id': 'Boehm-GC', 'deprecated': False}, - 'borceux': {'id': 'Borceux', 'deprecated': False}, - 'brian-gladman-2-clause': {'id': 'Brian-Gladman-2-Clause', 'deprecated': False}, - 'brian-gladman-3-clause': {'id': 'Brian-Gladman-3-Clause', 'deprecated': False}, - 'bsd-1-clause': {'id': 'BSD-1-Clause', 'deprecated': False}, - 'bsd-2-clause': {'id': 'BSD-2-Clause', 'deprecated': False}, - 'bsd-2-clause-darwin': {'id': 'BSD-2-Clause-Darwin', 'deprecated': False}, - 'bsd-2-clause-first-lines': {'id': 'BSD-2-Clause-first-lines', 'deprecated': False}, - 'bsd-2-clause-freebsd': {'id': 'BSD-2-Clause-FreeBSD', 'deprecated': True}, - 'bsd-2-clause-netbsd': {'id': 'BSD-2-Clause-NetBSD', 'deprecated': True}, - 'bsd-2-clause-patent': {'id': 'BSD-2-Clause-Patent', 'deprecated': False}, - 'bsd-2-clause-views': {'id': 'BSD-2-Clause-Views', 'deprecated': False}, - 'bsd-3-clause': {'id': 'BSD-3-Clause', 'deprecated': False}, - 'bsd-3-clause-acpica': {'id': 'BSD-3-Clause-acpica', 'deprecated': False}, - 'bsd-3-clause-attribution': {'id': 'BSD-3-Clause-Attribution', 'deprecated': False}, - 'bsd-3-clause-clear': {'id': 'BSD-3-Clause-Clear', 'deprecated': False}, - 'bsd-3-clause-flex': {'id': 'BSD-3-Clause-flex', 'deprecated': False}, - 'bsd-3-clause-hp': {'id': 'BSD-3-Clause-HP', 'deprecated': False}, - 'bsd-3-clause-lbnl': {'id': 'BSD-3-Clause-LBNL', 'deprecated': False}, - 'bsd-3-clause-modification': {'id': 'BSD-3-Clause-Modification', 'deprecated': False}, - 'bsd-3-clause-no-military-license': {'id': 'BSD-3-Clause-No-Military-License', 'deprecated': False}, - 'bsd-3-clause-no-nuclear-license': {'id': 'BSD-3-Clause-No-Nuclear-License', 'deprecated': False}, - 'bsd-3-clause-no-nuclear-license-2014': {'id': 'BSD-3-Clause-No-Nuclear-License-2014', 'deprecated': False}, - 'bsd-3-clause-no-nuclear-warranty': {'id': 'BSD-3-Clause-No-Nuclear-Warranty', 'deprecated': False}, - 'bsd-3-clause-open-mpi': {'id': 'BSD-3-Clause-Open-MPI', 'deprecated': False}, - 'bsd-3-clause-sun': {'id': 'BSD-3-Clause-Sun', 'deprecated': False}, - 'bsd-4-clause': {'id': 'BSD-4-Clause', 'deprecated': False}, - 'bsd-4-clause-shortened': {'id': 'BSD-4-Clause-Shortened', 'deprecated': False}, - 'bsd-4-clause-uc': {'id': 'BSD-4-Clause-UC', 'deprecated': False}, - 'bsd-4.3reno': {'id': 'BSD-4.3RENO', 'deprecated': False}, - 'bsd-4.3tahoe': {'id': 'BSD-4.3TAHOE', 'deprecated': False}, - 'bsd-advertising-acknowledgement': {'id': 'BSD-Advertising-Acknowledgement', 'deprecated': False}, - 'bsd-attribution-hpnd-disclaimer': {'id': 'BSD-Attribution-HPND-disclaimer', 'deprecated': False}, - 'bsd-inferno-nettverk': {'id': 'BSD-Inferno-Nettverk', 'deprecated': False}, - 'bsd-protection': {'id': 'BSD-Protection', 'deprecated': False}, - 'bsd-source-beginning-file': {'id': 'BSD-Source-beginning-file', 'deprecated': False}, - 'bsd-source-code': {'id': 'BSD-Source-Code', 'deprecated': False}, - 'bsd-systemics': {'id': 'BSD-Systemics', 'deprecated': False}, - 'bsd-systemics-w3works': {'id': 'BSD-Systemics-W3Works', 'deprecated': False}, - 'bsl-1.0': {'id': 'BSL-1.0', 'deprecated': False}, - 'busl-1.1': {'id': 'BUSL-1.1', 'deprecated': False}, - 'bzip2-1.0.5': {'id': 'bzip2-1.0.5', 'deprecated': True}, - 'bzip2-1.0.6': {'id': 'bzip2-1.0.6', 'deprecated': False}, - 'c-uda-1.0': {'id': 'C-UDA-1.0', 'deprecated': False}, - 'cal-1.0': {'id': 'CAL-1.0', 'deprecated': False}, - 'cal-1.0-combined-work-exception': {'id': 'CAL-1.0-Combined-Work-Exception', 'deprecated': False}, - 'caldera': {'id': 'Caldera', 'deprecated': False}, - 'caldera-no-preamble': {'id': 'Caldera-no-preamble', 'deprecated': False}, - 'catharon': {'id': 'Catharon', 'deprecated': False}, - 'catosl-1.1': {'id': 'CATOSL-1.1', 'deprecated': False}, - 'cc-by-1.0': {'id': 'CC-BY-1.0', 'deprecated': False}, - 'cc-by-2.0': {'id': 'CC-BY-2.0', 'deprecated': False}, - 'cc-by-2.5': {'id': 'CC-BY-2.5', 'deprecated': False}, - 'cc-by-2.5-au': {'id': 'CC-BY-2.5-AU', 'deprecated': False}, - 'cc-by-3.0': {'id': 'CC-BY-3.0', 'deprecated': False}, - 'cc-by-3.0-at': {'id': 'CC-BY-3.0-AT', 'deprecated': False}, - 'cc-by-3.0-au': {'id': 'CC-BY-3.0-AU', 'deprecated': False}, - 'cc-by-3.0-de': {'id': 'CC-BY-3.0-DE', 'deprecated': False}, - 'cc-by-3.0-igo': {'id': 'CC-BY-3.0-IGO', 'deprecated': False}, - 'cc-by-3.0-nl': {'id': 'CC-BY-3.0-NL', 'deprecated': False}, - 'cc-by-3.0-us': {'id': 'CC-BY-3.0-US', 'deprecated': False}, - 'cc-by-4.0': {'id': 'CC-BY-4.0', 'deprecated': False}, - 'cc-by-nc-1.0': {'id': 'CC-BY-NC-1.0', 'deprecated': False}, - 'cc-by-nc-2.0': {'id': 'CC-BY-NC-2.0', 'deprecated': False}, - 'cc-by-nc-2.5': {'id': 'CC-BY-NC-2.5', 'deprecated': False}, - 'cc-by-nc-3.0': {'id': 'CC-BY-NC-3.0', 'deprecated': False}, - 'cc-by-nc-3.0-de': {'id': 'CC-BY-NC-3.0-DE', 'deprecated': False}, - 'cc-by-nc-4.0': {'id': 'CC-BY-NC-4.0', 'deprecated': False}, - 'cc-by-nc-nd-1.0': {'id': 'CC-BY-NC-ND-1.0', 'deprecated': False}, - 'cc-by-nc-nd-2.0': {'id': 'CC-BY-NC-ND-2.0', 'deprecated': False}, - 'cc-by-nc-nd-2.5': {'id': 'CC-BY-NC-ND-2.5', 'deprecated': False}, - 'cc-by-nc-nd-3.0': {'id': 'CC-BY-NC-ND-3.0', 'deprecated': False}, - 'cc-by-nc-nd-3.0-de': {'id': 'CC-BY-NC-ND-3.0-DE', 'deprecated': False}, - 'cc-by-nc-nd-3.0-igo': {'id': 'CC-BY-NC-ND-3.0-IGO', 'deprecated': False}, - 'cc-by-nc-nd-4.0': {'id': 'CC-BY-NC-ND-4.0', 'deprecated': False}, - 'cc-by-nc-sa-1.0': {'id': 'CC-BY-NC-SA-1.0', 'deprecated': False}, - 'cc-by-nc-sa-2.0': {'id': 'CC-BY-NC-SA-2.0', 'deprecated': False}, - 'cc-by-nc-sa-2.0-de': {'id': 'CC-BY-NC-SA-2.0-DE', 'deprecated': False}, - 'cc-by-nc-sa-2.0-fr': {'id': 'CC-BY-NC-SA-2.0-FR', 'deprecated': False}, - 'cc-by-nc-sa-2.0-uk': {'id': 'CC-BY-NC-SA-2.0-UK', 'deprecated': False}, - 'cc-by-nc-sa-2.5': {'id': 'CC-BY-NC-SA-2.5', 'deprecated': False}, - 'cc-by-nc-sa-3.0': {'id': 'CC-BY-NC-SA-3.0', 'deprecated': False}, - 'cc-by-nc-sa-3.0-de': {'id': 'CC-BY-NC-SA-3.0-DE', 'deprecated': False}, - 'cc-by-nc-sa-3.0-igo': {'id': 'CC-BY-NC-SA-3.0-IGO', 'deprecated': False}, - 'cc-by-nc-sa-4.0': {'id': 'CC-BY-NC-SA-4.0', 'deprecated': False}, - 'cc-by-nd-1.0': {'id': 'CC-BY-ND-1.0', 'deprecated': False}, - 'cc-by-nd-2.0': {'id': 'CC-BY-ND-2.0', 'deprecated': False}, - 'cc-by-nd-2.5': {'id': 'CC-BY-ND-2.5', 'deprecated': False}, - 'cc-by-nd-3.0': {'id': 'CC-BY-ND-3.0', 'deprecated': False}, - 'cc-by-nd-3.0-de': {'id': 'CC-BY-ND-3.0-DE', 'deprecated': False}, - 'cc-by-nd-4.0': {'id': 'CC-BY-ND-4.0', 'deprecated': False}, - 'cc-by-sa-1.0': {'id': 'CC-BY-SA-1.0', 'deprecated': False}, - 'cc-by-sa-2.0': {'id': 'CC-BY-SA-2.0', 'deprecated': False}, - 'cc-by-sa-2.0-uk': {'id': 'CC-BY-SA-2.0-UK', 'deprecated': False}, - 'cc-by-sa-2.1-jp': {'id': 'CC-BY-SA-2.1-JP', 'deprecated': False}, - 'cc-by-sa-2.5': {'id': 'CC-BY-SA-2.5', 'deprecated': False}, - 'cc-by-sa-3.0': {'id': 'CC-BY-SA-3.0', 'deprecated': False}, - 'cc-by-sa-3.0-at': {'id': 'CC-BY-SA-3.0-AT', 'deprecated': False}, - 'cc-by-sa-3.0-de': {'id': 'CC-BY-SA-3.0-DE', 'deprecated': False}, - 'cc-by-sa-3.0-igo': {'id': 'CC-BY-SA-3.0-IGO', 'deprecated': False}, - 'cc-by-sa-4.0': {'id': 'CC-BY-SA-4.0', 'deprecated': False}, - 'cc-pddc': {'id': 'CC-PDDC', 'deprecated': False}, - 'cc0-1.0': {'id': 'CC0-1.0', 'deprecated': False}, - 'cddl-1.0': {'id': 'CDDL-1.0', 'deprecated': False}, - 'cddl-1.1': {'id': 'CDDL-1.1', 'deprecated': False}, - 'cdl-1.0': {'id': 'CDL-1.0', 'deprecated': False}, - 'cdla-permissive-1.0': {'id': 'CDLA-Permissive-1.0', 'deprecated': False}, - 'cdla-permissive-2.0': {'id': 'CDLA-Permissive-2.0', 'deprecated': False}, - 'cdla-sharing-1.0': {'id': 'CDLA-Sharing-1.0', 'deprecated': False}, - 'cecill-1.0': {'id': 'CECILL-1.0', 'deprecated': False}, - 'cecill-1.1': {'id': 'CECILL-1.1', 'deprecated': False}, - 'cecill-2.0': {'id': 'CECILL-2.0', 'deprecated': False}, - 'cecill-2.1': {'id': 'CECILL-2.1', 'deprecated': False}, - 'cecill-b': {'id': 'CECILL-B', 'deprecated': False}, - 'cecill-c': {'id': 'CECILL-C', 'deprecated': False}, - 'cern-ohl-1.1': {'id': 'CERN-OHL-1.1', 'deprecated': False}, - 'cern-ohl-1.2': {'id': 'CERN-OHL-1.2', 'deprecated': False}, - 'cern-ohl-p-2.0': {'id': 'CERN-OHL-P-2.0', 'deprecated': False}, - 'cern-ohl-s-2.0': {'id': 'CERN-OHL-S-2.0', 'deprecated': False}, - 'cern-ohl-w-2.0': {'id': 'CERN-OHL-W-2.0', 'deprecated': False}, - 'cfitsio': {'id': 'CFITSIO', 'deprecated': False}, - 'check-cvs': {'id': 'check-cvs', 'deprecated': False}, - 'checkmk': {'id': 'checkmk', 'deprecated': False}, - 'clartistic': {'id': 'ClArtistic', 'deprecated': False}, - 'clips': {'id': 'Clips', 'deprecated': False}, - 'cmu-mach': {'id': 'CMU-Mach', 'deprecated': False}, - 'cmu-mach-nodoc': {'id': 'CMU-Mach-nodoc', 'deprecated': False}, - 'cnri-jython': {'id': 'CNRI-Jython', 'deprecated': False}, - 'cnri-python': {'id': 'CNRI-Python', 'deprecated': False}, - 'cnri-python-gpl-compatible': {'id': 'CNRI-Python-GPL-Compatible', 'deprecated': False}, - 'coil-1.0': {'id': 'COIL-1.0', 'deprecated': False}, - 'community-spec-1.0': {'id': 'Community-Spec-1.0', 'deprecated': False}, - 'condor-1.1': {'id': 'Condor-1.1', 'deprecated': False}, - 'copyleft-next-0.3.0': {'id': 'copyleft-next-0.3.0', 'deprecated': False}, - 'copyleft-next-0.3.1': {'id': 'copyleft-next-0.3.1', 'deprecated': False}, - 'cornell-lossless-jpeg': {'id': 'Cornell-Lossless-JPEG', 'deprecated': False}, - 'cpal-1.0': {'id': 'CPAL-1.0', 'deprecated': False}, - 'cpl-1.0': {'id': 'CPL-1.0', 'deprecated': False}, - 'cpol-1.02': {'id': 'CPOL-1.02', 'deprecated': False}, - 'cronyx': {'id': 'Cronyx', 'deprecated': False}, - 'crossword': {'id': 'Crossword', 'deprecated': False}, - 'crystalstacker': {'id': 'CrystalStacker', 'deprecated': False}, - 'cua-opl-1.0': {'id': 'CUA-OPL-1.0', 'deprecated': False}, - 'cube': {'id': 'Cube', 'deprecated': False}, - 'curl': {'id': 'curl', 'deprecated': False}, - 'cve-tou': {'id': 'cve-tou', 'deprecated': False}, - 'd-fsl-1.0': {'id': 'D-FSL-1.0', 'deprecated': False}, - 'dec-3-clause': {'id': 'DEC-3-Clause', 'deprecated': False}, - 'diffmark': {'id': 'diffmark', 'deprecated': False}, - 'dl-de-by-2.0': {'id': 'DL-DE-BY-2.0', 'deprecated': False}, - 'dl-de-zero-2.0': {'id': 'DL-DE-ZERO-2.0', 'deprecated': False}, - 'doc': {'id': 'DOC', 'deprecated': False}, - 'docbook-schema': {'id': 'DocBook-Schema', 'deprecated': False}, - 'docbook-xml': {'id': 'DocBook-XML', 'deprecated': False}, - 'dotseqn': {'id': 'Dotseqn', 'deprecated': False}, - 'drl-1.0': {'id': 'DRL-1.0', 'deprecated': False}, - 'drl-1.1': {'id': 'DRL-1.1', 'deprecated': False}, - 'dsdp': {'id': 'DSDP', 'deprecated': False}, - 'dtoa': {'id': 'dtoa', 'deprecated': False}, - 'dvipdfm': {'id': 'dvipdfm', 'deprecated': False}, - 'ecl-1.0': {'id': 'ECL-1.0', 'deprecated': False}, - 'ecl-2.0': {'id': 'ECL-2.0', 'deprecated': False}, - 'ecos-2.0': {'id': 'eCos-2.0', 'deprecated': True}, - 'efl-1.0': {'id': 'EFL-1.0', 'deprecated': False}, - 'efl-2.0': {'id': 'EFL-2.0', 'deprecated': False}, - 'egenix': {'id': 'eGenix', 'deprecated': False}, - 'elastic-2.0': {'id': 'Elastic-2.0', 'deprecated': False}, - 'entessa': {'id': 'Entessa', 'deprecated': False}, - 'epics': {'id': 'EPICS', 'deprecated': False}, - 'epl-1.0': {'id': 'EPL-1.0', 'deprecated': False}, - 'epl-2.0': {'id': 'EPL-2.0', 'deprecated': False}, - 'erlpl-1.1': {'id': 'ErlPL-1.1', 'deprecated': False}, - 'etalab-2.0': {'id': 'etalab-2.0', 'deprecated': False}, - 'eudatagrid': {'id': 'EUDatagrid', 'deprecated': False}, - 'eupl-1.0': {'id': 'EUPL-1.0', 'deprecated': False}, - 'eupl-1.1': {'id': 'EUPL-1.1', 'deprecated': False}, - 'eupl-1.2': {'id': 'EUPL-1.2', 'deprecated': False}, - 'eurosym': {'id': 'Eurosym', 'deprecated': False}, - 'fair': {'id': 'Fair', 'deprecated': False}, - 'fbm': {'id': 'FBM', 'deprecated': False}, - 'fdk-aac': {'id': 'FDK-AAC', 'deprecated': False}, - 'ferguson-twofish': {'id': 'Ferguson-Twofish', 'deprecated': False}, - 'frameworx-1.0': {'id': 'Frameworx-1.0', 'deprecated': False}, - 'freebsd-doc': {'id': 'FreeBSD-DOC', 'deprecated': False}, - 'freeimage': {'id': 'FreeImage', 'deprecated': False}, - 'fsfap': {'id': 'FSFAP', 'deprecated': False}, - 'fsfap-no-warranty-disclaimer': {'id': 'FSFAP-no-warranty-disclaimer', 'deprecated': False}, - 'fsful': {'id': 'FSFUL', 'deprecated': False}, - 'fsfullr': {'id': 'FSFULLR', 'deprecated': False}, - 'fsfullrwd': {'id': 'FSFULLRWD', 'deprecated': False}, - 'ftl': {'id': 'FTL', 'deprecated': False}, - 'furuseth': {'id': 'Furuseth', 'deprecated': False}, - 'fwlw': {'id': 'fwlw', 'deprecated': False}, - 'gcr-docs': {'id': 'GCR-docs', 'deprecated': False}, - 'gd': {'id': 'GD', 'deprecated': False}, - 'gfdl-1.1': {'id': 'GFDL-1.1', 'deprecated': True}, - 'gfdl-1.1-invariants-only': {'id': 'GFDL-1.1-invariants-only', 'deprecated': False}, - 'gfdl-1.1-invariants-or-later': {'id': 'GFDL-1.1-invariants-or-later', 'deprecated': False}, - 'gfdl-1.1-no-invariants-only': {'id': 'GFDL-1.1-no-invariants-only', 'deprecated': False}, - 'gfdl-1.1-no-invariants-or-later': {'id': 'GFDL-1.1-no-invariants-or-later', 'deprecated': False}, - 'gfdl-1.1-only': {'id': 'GFDL-1.1-only', 'deprecated': False}, - 'gfdl-1.1-or-later': {'id': 'GFDL-1.1-or-later', 'deprecated': False}, - 'gfdl-1.2': {'id': 'GFDL-1.2', 'deprecated': True}, - 'gfdl-1.2-invariants-only': {'id': 'GFDL-1.2-invariants-only', 'deprecated': False}, - 'gfdl-1.2-invariants-or-later': {'id': 'GFDL-1.2-invariants-or-later', 'deprecated': False}, - 'gfdl-1.2-no-invariants-only': {'id': 'GFDL-1.2-no-invariants-only', 'deprecated': False}, - 'gfdl-1.2-no-invariants-or-later': {'id': 'GFDL-1.2-no-invariants-or-later', 'deprecated': False}, - 'gfdl-1.2-only': {'id': 'GFDL-1.2-only', 'deprecated': False}, - 'gfdl-1.2-or-later': {'id': 'GFDL-1.2-or-later', 'deprecated': False}, - 'gfdl-1.3': {'id': 'GFDL-1.3', 'deprecated': True}, - 'gfdl-1.3-invariants-only': {'id': 'GFDL-1.3-invariants-only', 'deprecated': False}, - 'gfdl-1.3-invariants-or-later': {'id': 'GFDL-1.3-invariants-or-later', 'deprecated': False}, - 'gfdl-1.3-no-invariants-only': {'id': 'GFDL-1.3-no-invariants-only', 'deprecated': False}, - 'gfdl-1.3-no-invariants-or-later': {'id': 'GFDL-1.3-no-invariants-or-later', 'deprecated': False}, - 'gfdl-1.3-only': {'id': 'GFDL-1.3-only', 'deprecated': False}, - 'gfdl-1.3-or-later': {'id': 'GFDL-1.3-or-later', 'deprecated': False}, - 'giftware': {'id': 'Giftware', 'deprecated': False}, - 'gl2ps': {'id': 'GL2PS', 'deprecated': False}, - 'glide': {'id': 'Glide', 'deprecated': False}, - 'glulxe': {'id': 'Glulxe', 'deprecated': False}, - 'glwtpl': {'id': 'GLWTPL', 'deprecated': False}, - 'gnuplot': {'id': 'gnuplot', 'deprecated': False}, - 'gpl-1.0': {'id': 'GPL-1.0', 'deprecated': True}, - 'gpl-1.0+': {'id': 'GPL-1.0+', 'deprecated': True}, - 'gpl-1.0-only': {'id': 'GPL-1.0-only', 'deprecated': False}, - 'gpl-1.0-or-later': {'id': 'GPL-1.0-or-later', 'deprecated': False}, - 'gpl-2.0': {'id': 'GPL-2.0', 'deprecated': True}, - 'gpl-2.0+': {'id': 'GPL-2.0+', 'deprecated': True}, - 'gpl-2.0-only': {'id': 'GPL-2.0-only', 'deprecated': False}, - 'gpl-2.0-or-later': {'id': 'GPL-2.0-or-later', 'deprecated': False}, - 'gpl-2.0-with-autoconf-exception': {'id': 'GPL-2.0-with-autoconf-exception', 'deprecated': True}, - 'gpl-2.0-with-bison-exception': {'id': 'GPL-2.0-with-bison-exception', 'deprecated': True}, - 'gpl-2.0-with-classpath-exception': {'id': 'GPL-2.0-with-classpath-exception', 'deprecated': True}, - 'gpl-2.0-with-font-exception': {'id': 'GPL-2.0-with-font-exception', 'deprecated': True}, - 'gpl-2.0-with-gcc-exception': {'id': 'GPL-2.0-with-GCC-exception', 'deprecated': True}, - 'gpl-3.0': {'id': 'GPL-3.0', 'deprecated': True}, - 'gpl-3.0+': {'id': 'GPL-3.0+', 'deprecated': True}, - 'gpl-3.0-only': {'id': 'GPL-3.0-only', 'deprecated': False}, - 'gpl-3.0-or-later': {'id': 'GPL-3.0-or-later', 'deprecated': False}, - 'gpl-3.0-with-autoconf-exception': {'id': 'GPL-3.0-with-autoconf-exception', 'deprecated': True}, - 'gpl-3.0-with-gcc-exception': {'id': 'GPL-3.0-with-GCC-exception', 'deprecated': True}, - 'graphics-gems': {'id': 'Graphics-Gems', 'deprecated': False}, - 'gsoap-1.3b': {'id': 'gSOAP-1.3b', 'deprecated': False}, - 'gtkbook': {'id': 'gtkbook', 'deprecated': False}, - 'gutmann': {'id': 'Gutmann', 'deprecated': False}, - 'haskellreport': {'id': 'HaskellReport', 'deprecated': False}, - 'hdparm': {'id': 'hdparm', 'deprecated': False}, - 'hidapi': {'id': 'HIDAPI', 'deprecated': False}, - 'hippocratic-2.1': {'id': 'Hippocratic-2.1', 'deprecated': False}, - 'hp-1986': {'id': 'HP-1986', 'deprecated': False}, - 'hp-1989': {'id': 'HP-1989', 'deprecated': False}, - 'hpnd': {'id': 'HPND', 'deprecated': False}, - 'hpnd-dec': {'id': 'HPND-DEC', 'deprecated': False}, - 'hpnd-doc': {'id': 'HPND-doc', 'deprecated': False}, - 'hpnd-doc-sell': {'id': 'HPND-doc-sell', 'deprecated': False}, - 'hpnd-export-us': {'id': 'HPND-export-US', 'deprecated': False}, - 'hpnd-export-us-acknowledgement': {'id': 'HPND-export-US-acknowledgement', 'deprecated': False}, - 'hpnd-export-us-modify': {'id': 'HPND-export-US-modify', 'deprecated': False}, - 'hpnd-export2-us': {'id': 'HPND-export2-US', 'deprecated': False}, - 'hpnd-fenneberg-livingston': {'id': 'HPND-Fenneberg-Livingston', 'deprecated': False}, - 'hpnd-inria-imag': {'id': 'HPND-INRIA-IMAG', 'deprecated': False}, - 'hpnd-intel': {'id': 'HPND-Intel', 'deprecated': False}, - 'hpnd-kevlin-henney': {'id': 'HPND-Kevlin-Henney', 'deprecated': False}, - 'hpnd-markus-kuhn': {'id': 'HPND-Markus-Kuhn', 'deprecated': False}, - 'hpnd-merchantability-variant': {'id': 'HPND-merchantability-variant', 'deprecated': False}, - 'hpnd-mit-disclaimer': {'id': 'HPND-MIT-disclaimer', 'deprecated': False}, - 'hpnd-netrek': {'id': 'HPND-Netrek', 'deprecated': False}, - 'hpnd-pbmplus': {'id': 'HPND-Pbmplus', 'deprecated': False}, - 'hpnd-sell-mit-disclaimer-xserver': {'id': 'HPND-sell-MIT-disclaimer-xserver', 'deprecated': False}, - 'hpnd-sell-regexpr': {'id': 'HPND-sell-regexpr', 'deprecated': False}, - 'hpnd-sell-variant': {'id': 'HPND-sell-variant', 'deprecated': False}, - 'hpnd-sell-variant-mit-disclaimer': {'id': 'HPND-sell-variant-MIT-disclaimer', 'deprecated': False}, - 'hpnd-sell-variant-mit-disclaimer-rev': {'id': 'HPND-sell-variant-MIT-disclaimer-rev', 'deprecated': False}, - 'hpnd-uc': {'id': 'HPND-UC', 'deprecated': False}, - 'hpnd-uc-export-us': {'id': 'HPND-UC-export-US', 'deprecated': False}, - 'htmltidy': {'id': 'HTMLTIDY', 'deprecated': False}, - 'ibm-pibs': {'id': 'IBM-pibs', 'deprecated': False}, - 'icu': {'id': 'ICU', 'deprecated': False}, - 'iec-code-components-eula': {'id': 'IEC-Code-Components-EULA', 'deprecated': False}, - 'ijg': {'id': 'IJG', 'deprecated': False}, - 'ijg-short': {'id': 'IJG-short', 'deprecated': False}, - 'imagemagick': {'id': 'ImageMagick', 'deprecated': False}, - 'imatix': {'id': 'iMatix', 'deprecated': False}, - 'imlib2': {'id': 'Imlib2', 'deprecated': False}, - 'info-zip': {'id': 'Info-ZIP', 'deprecated': False}, - 'inner-net-2.0': {'id': 'Inner-Net-2.0', 'deprecated': False}, - 'intel': {'id': 'Intel', 'deprecated': False}, - 'intel-acpi': {'id': 'Intel-ACPI', 'deprecated': False}, - 'interbase-1.0': {'id': 'Interbase-1.0', 'deprecated': False}, - 'ipa': {'id': 'IPA', 'deprecated': False}, - 'ipl-1.0': {'id': 'IPL-1.0', 'deprecated': False}, - 'isc': {'id': 'ISC', 'deprecated': False}, - 'isc-veillard': {'id': 'ISC-Veillard', 'deprecated': False}, - 'jam': {'id': 'Jam', 'deprecated': False}, - 'jasper-2.0': {'id': 'JasPer-2.0', 'deprecated': False}, - 'jpl-image': {'id': 'JPL-image', 'deprecated': False}, - 'jpnic': {'id': 'JPNIC', 'deprecated': False}, - 'json': {'id': 'JSON', 'deprecated': False}, - 'kastrup': {'id': 'Kastrup', 'deprecated': False}, - 'kazlib': {'id': 'Kazlib', 'deprecated': False}, - 'knuth-ctan': {'id': 'Knuth-CTAN', 'deprecated': False}, - 'lal-1.2': {'id': 'LAL-1.2', 'deprecated': False}, - 'lal-1.3': {'id': 'LAL-1.3', 'deprecated': False}, - 'latex2e': {'id': 'Latex2e', 'deprecated': False}, - 'latex2e-translated-notice': {'id': 'Latex2e-translated-notice', 'deprecated': False}, - 'leptonica': {'id': 'Leptonica', 'deprecated': False}, - 'lgpl-2.0': {'id': 'LGPL-2.0', 'deprecated': True}, - 'lgpl-2.0+': {'id': 'LGPL-2.0+', 'deprecated': True}, - 'lgpl-2.0-only': {'id': 'LGPL-2.0-only', 'deprecated': False}, - 'lgpl-2.0-or-later': {'id': 'LGPL-2.0-or-later', 'deprecated': False}, - 'lgpl-2.1': {'id': 'LGPL-2.1', 'deprecated': True}, - 'lgpl-2.1+': {'id': 'LGPL-2.1+', 'deprecated': True}, - 'lgpl-2.1-only': {'id': 'LGPL-2.1-only', 'deprecated': False}, - 'lgpl-2.1-or-later': {'id': 'LGPL-2.1-or-later', 'deprecated': False}, - 'lgpl-3.0': {'id': 'LGPL-3.0', 'deprecated': True}, - 'lgpl-3.0+': {'id': 'LGPL-3.0+', 'deprecated': True}, - 'lgpl-3.0-only': {'id': 'LGPL-3.0-only', 'deprecated': False}, - 'lgpl-3.0-or-later': {'id': 'LGPL-3.0-or-later', 'deprecated': False}, - 'lgpllr': {'id': 'LGPLLR', 'deprecated': False}, - 'libpng': {'id': 'Libpng', 'deprecated': False}, - 'libpng-2.0': {'id': 'libpng-2.0', 'deprecated': False}, - 'libselinux-1.0': {'id': 'libselinux-1.0', 'deprecated': False}, - 'libtiff': {'id': 'libtiff', 'deprecated': False}, - 'libutil-david-nugent': {'id': 'libutil-David-Nugent', 'deprecated': False}, - 'liliq-p-1.1': {'id': 'LiLiQ-P-1.1', 'deprecated': False}, - 'liliq-r-1.1': {'id': 'LiLiQ-R-1.1', 'deprecated': False}, - 'liliq-rplus-1.1': {'id': 'LiLiQ-Rplus-1.1', 'deprecated': False}, - 'linux-man-pages-1-para': {'id': 'Linux-man-pages-1-para', 'deprecated': False}, - 'linux-man-pages-copyleft': {'id': 'Linux-man-pages-copyleft', 'deprecated': False}, - 'linux-man-pages-copyleft-2-para': {'id': 'Linux-man-pages-copyleft-2-para', 'deprecated': False}, - 'linux-man-pages-copyleft-var': {'id': 'Linux-man-pages-copyleft-var', 'deprecated': False}, - 'linux-openib': {'id': 'Linux-OpenIB', 'deprecated': False}, - 'loop': {'id': 'LOOP', 'deprecated': False}, - 'lpd-document': {'id': 'LPD-document', 'deprecated': False}, - 'lpl-1.0': {'id': 'LPL-1.0', 'deprecated': False}, - 'lpl-1.02': {'id': 'LPL-1.02', 'deprecated': False}, - 'lppl-1.0': {'id': 'LPPL-1.0', 'deprecated': False}, - 'lppl-1.1': {'id': 'LPPL-1.1', 'deprecated': False}, - 'lppl-1.2': {'id': 'LPPL-1.2', 'deprecated': False}, - 'lppl-1.3a': {'id': 'LPPL-1.3a', 'deprecated': False}, - 'lppl-1.3c': {'id': 'LPPL-1.3c', 'deprecated': False}, - 'lsof': {'id': 'lsof', 'deprecated': False}, - 'lucida-bitmap-fonts': {'id': 'Lucida-Bitmap-Fonts', 'deprecated': False}, - 'lzma-sdk-9.11-to-9.20': {'id': 'LZMA-SDK-9.11-to-9.20', 'deprecated': False}, - 'lzma-sdk-9.22': {'id': 'LZMA-SDK-9.22', 'deprecated': False}, - 'mackerras-3-clause': {'id': 'Mackerras-3-Clause', 'deprecated': False}, - 'mackerras-3-clause-acknowledgment': {'id': 'Mackerras-3-Clause-acknowledgment', 'deprecated': False}, - 'magaz': {'id': 'magaz', 'deprecated': False}, - 'mailprio': {'id': 'mailprio', 'deprecated': False}, - 'makeindex': {'id': 'MakeIndex', 'deprecated': False}, - 'martin-birgmeier': {'id': 'Martin-Birgmeier', 'deprecated': False}, - 'mcphee-slideshow': {'id': 'McPhee-slideshow', 'deprecated': False}, - 'metamail': {'id': 'metamail', 'deprecated': False}, - 'minpack': {'id': 'Minpack', 'deprecated': False}, - 'miros': {'id': 'MirOS', 'deprecated': False}, - 'mit': {'id': 'MIT', 'deprecated': False}, - 'mit-0': {'id': 'MIT-0', 'deprecated': False}, - 'mit-advertising': {'id': 'MIT-advertising', 'deprecated': False}, - 'mit-cmu': {'id': 'MIT-CMU', 'deprecated': False}, - 'mit-enna': {'id': 'MIT-enna', 'deprecated': False}, - 'mit-feh': {'id': 'MIT-feh', 'deprecated': False}, - 'mit-festival': {'id': 'MIT-Festival', 'deprecated': False}, - 'mit-khronos-old': {'id': 'MIT-Khronos-old', 'deprecated': False}, - 'mit-modern-variant': {'id': 'MIT-Modern-Variant', 'deprecated': False}, - 'mit-open-group': {'id': 'MIT-open-group', 'deprecated': False}, - 'mit-testregex': {'id': 'MIT-testregex', 'deprecated': False}, - 'mit-wu': {'id': 'MIT-Wu', 'deprecated': False}, - 'mitnfa': {'id': 'MITNFA', 'deprecated': False}, - 'mmixware': {'id': 'MMIXware', 'deprecated': False}, - 'motosoto': {'id': 'Motosoto', 'deprecated': False}, - 'mpeg-ssg': {'id': 'MPEG-SSG', 'deprecated': False}, - 'mpi-permissive': {'id': 'mpi-permissive', 'deprecated': False}, - 'mpich2': {'id': 'mpich2', 'deprecated': False}, - 'mpl-1.0': {'id': 'MPL-1.0', 'deprecated': False}, - 'mpl-1.1': {'id': 'MPL-1.1', 'deprecated': False}, - 'mpl-2.0': {'id': 'MPL-2.0', 'deprecated': False}, - 'mpl-2.0-no-copyleft-exception': {'id': 'MPL-2.0-no-copyleft-exception', 'deprecated': False}, - 'mplus': {'id': 'mplus', 'deprecated': False}, - 'ms-lpl': {'id': 'MS-LPL', 'deprecated': False}, - 'ms-pl': {'id': 'MS-PL', 'deprecated': False}, - 'ms-rl': {'id': 'MS-RL', 'deprecated': False}, - 'mtll': {'id': 'MTLL', 'deprecated': False}, - 'mulanpsl-1.0': {'id': 'MulanPSL-1.0', 'deprecated': False}, - 'mulanpsl-2.0': {'id': 'MulanPSL-2.0', 'deprecated': False}, - 'multics': {'id': 'Multics', 'deprecated': False}, - 'mup': {'id': 'Mup', 'deprecated': False}, - 'naist-2003': {'id': 'NAIST-2003', 'deprecated': False}, - 'nasa-1.3': {'id': 'NASA-1.3', 'deprecated': False}, - 'naumen': {'id': 'Naumen', 'deprecated': False}, - 'nbpl-1.0': {'id': 'NBPL-1.0', 'deprecated': False}, - 'ncbi-pd': {'id': 'NCBI-PD', 'deprecated': False}, - 'ncgl-uk-2.0': {'id': 'NCGL-UK-2.0', 'deprecated': False}, - 'ncl': {'id': 'NCL', 'deprecated': False}, - 'ncsa': {'id': 'NCSA', 'deprecated': False}, - 'net-snmp': {'id': 'Net-SNMP', 'deprecated': True}, - 'netcdf': {'id': 'NetCDF', 'deprecated': False}, - 'newsletr': {'id': 'Newsletr', 'deprecated': False}, - 'ngpl': {'id': 'NGPL', 'deprecated': False}, - 'nicta-1.0': {'id': 'NICTA-1.0', 'deprecated': False}, - 'nist-pd': {'id': 'NIST-PD', 'deprecated': False}, - 'nist-pd-fallback': {'id': 'NIST-PD-fallback', 'deprecated': False}, - 'nist-software': {'id': 'NIST-Software', 'deprecated': False}, - 'nlod-1.0': {'id': 'NLOD-1.0', 'deprecated': False}, - 'nlod-2.0': {'id': 'NLOD-2.0', 'deprecated': False}, - 'nlpl': {'id': 'NLPL', 'deprecated': False}, - 'nokia': {'id': 'Nokia', 'deprecated': False}, - 'nosl': {'id': 'NOSL', 'deprecated': False}, - 'noweb': {'id': 'Noweb', 'deprecated': False}, - 'npl-1.0': {'id': 'NPL-1.0', 'deprecated': False}, - 'npl-1.1': {'id': 'NPL-1.1', 'deprecated': False}, - 'nposl-3.0': {'id': 'NPOSL-3.0', 'deprecated': False}, - 'nrl': {'id': 'NRL', 'deprecated': False}, - 'ntp': {'id': 'NTP', 'deprecated': False}, - 'ntp-0': {'id': 'NTP-0', 'deprecated': False}, - 'nunit': {'id': 'Nunit', 'deprecated': True}, - 'o-uda-1.0': {'id': 'O-UDA-1.0', 'deprecated': False}, - 'oar': {'id': 'OAR', 'deprecated': False}, - 'occt-pl': {'id': 'OCCT-PL', 'deprecated': False}, - 'oclc-2.0': {'id': 'OCLC-2.0', 'deprecated': False}, - 'odbl-1.0': {'id': 'ODbL-1.0', 'deprecated': False}, - 'odc-by-1.0': {'id': 'ODC-By-1.0', 'deprecated': False}, - 'offis': {'id': 'OFFIS', 'deprecated': False}, - 'ofl-1.0': {'id': 'OFL-1.0', 'deprecated': False}, - 'ofl-1.0-no-rfn': {'id': 'OFL-1.0-no-RFN', 'deprecated': False}, - 'ofl-1.0-rfn': {'id': 'OFL-1.0-RFN', 'deprecated': False}, - 'ofl-1.1': {'id': 'OFL-1.1', 'deprecated': False}, - 'ofl-1.1-no-rfn': {'id': 'OFL-1.1-no-RFN', 'deprecated': False}, - 'ofl-1.1-rfn': {'id': 'OFL-1.1-RFN', 'deprecated': False}, - 'ogc-1.0': {'id': 'OGC-1.0', 'deprecated': False}, - 'ogdl-taiwan-1.0': {'id': 'OGDL-Taiwan-1.0', 'deprecated': False}, - 'ogl-canada-2.0': {'id': 'OGL-Canada-2.0', 'deprecated': False}, - 'ogl-uk-1.0': {'id': 'OGL-UK-1.0', 'deprecated': False}, - 'ogl-uk-2.0': {'id': 'OGL-UK-2.0', 'deprecated': False}, - 'ogl-uk-3.0': {'id': 'OGL-UK-3.0', 'deprecated': False}, - 'ogtsl': {'id': 'OGTSL', 'deprecated': False}, - 'oldap-1.1': {'id': 'OLDAP-1.1', 'deprecated': False}, - 'oldap-1.2': {'id': 'OLDAP-1.2', 'deprecated': False}, - 'oldap-1.3': {'id': 'OLDAP-1.3', 'deprecated': False}, - 'oldap-1.4': {'id': 'OLDAP-1.4', 'deprecated': False}, - 'oldap-2.0': {'id': 'OLDAP-2.0', 'deprecated': False}, - 'oldap-2.0.1': {'id': 'OLDAP-2.0.1', 'deprecated': False}, - 'oldap-2.1': {'id': 'OLDAP-2.1', 'deprecated': False}, - 'oldap-2.2': {'id': 'OLDAP-2.2', 'deprecated': False}, - 'oldap-2.2.1': {'id': 'OLDAP-2.2.1', 'deprecated': False}, - 'oldap-2.2.2': {'id': 'OLDAP-2.2.2', 'deprecated': False}, - 'oldap-2.3': {'id': 'OLDAP-2.3', 'deprecated': False}, - 'oldap-2.4': {'id': 'OLDAP-2.4', 'deprecated': False}, - 'oldap-2.5': {'id': 'OLDAP-2.5', 'deprecated': False}, - 'oldap-2.6': {'id': 'OLDAP-2.6', 'deprecated': False}, - 'oldap-2.7': {'id': 'OLDAP-2.7', 'deprecated': False}, - 'oldap-2.8': {'id': 'OLDAP-2.8', 'deprecated': False}, - 'olfl-1.3': {'id': 'OLFL-1.3', 'deprecated': False}, - 'oml': {'id': 'OML', 'deprecated': False}, - 'openpbs-2.3': {'id': 'OpenPBS-2.3', 'deprecated': False}, - 'openssl': {'id': 'OpenSSL', 'deprecated': False}, - 'openssl-standalone': {'id': 'OpenSSL-standalone', 'deprecated': False}, - 'openvision': {'id': 'OpenVision', 'deprecated': False}, - 'opl-1.0': {'id': 'OPL-1.0', 'deprecated': False}, - 'opl-uk-3.0': {'id': 'OPL-UK-3.0', 'deprecated': False}, - 'opubl-1.0': {'id': 'OPUBL-1.0', 'deprecated': False}, - 'oset-pl-2.1': {'id': 'OSET-PL-2.1', 'deprecated': False}, - 'osl-1.0': {'id': 'OSL-1.0', 'deprecated': False}, - 'osl-1.1': {'id': 'OSL-1.1', 'deprecated': False}, - 'osl-2.0': {'id': 'OSL-2.0', 'deprecated': False}, - 'osl-2.1': {'id': 'OSL-2.1', 'deprecated': False}, - 'osl-3.0': {'id': 'OSL-3.0', 'deprecated': False}, - 'padl': {'id': 'PADL', 'deprecated': False}, - 'parity-6.0.0': {'id': 'Parity-6.0.0', 'deprecated': False}, - 'parity-7.0.0': {'id': 'Parity-7.0.0', 'deprecated': False}, - 'pddl-1.0': {'id': 'PDDL-1.0', 'deprecated': False}, - 'php-3.0': {'id': 'PHP-3.0', 'deprecated': False}, - 'php-3.01': {'id': 'PHP-3.01', 'deprecated': False}, - 'pixar': {'id': 'Pixar', 'deprecated': False}, - 'pkgconf': {'id': 'pkgconf', 'deprecated': False}, - 'plexus': {'id': 'Plexus', 'deprecated': False}, - 'pnmstitch': {'id': 'pnmstitch', 'deprecated': False}, - 'polyform-noncommercial-1.0.0': {'id': 'PolyForm-Noncommercial-1.0.0', 'deprecated': False}, - 'polyform-small-business-1.0.0': {'id': 'PolyForm-Small-Business-1.0.0', 'deprecated': False}, - 'postgresql': {'id': 'PostgreSQL', 'deprecated': False}, - 'ppl': {'id': 'PPL', 'deprecated': False}, - 'psf-2.0': {'id': 'PSF-2.0', 'deprecated': False}, - 'psfrag': {'id': 'psfrag', 'deprecated': False}, - 'psutils': {'id': 'psutils', 'deprecated': False}, - 'python-2.0': {'id': 'Python-2.0', 'deprecated': False}, - 'python-2.0.1': {'id': 'Python-2.0.1', 'deprecated': False}, - 'python-ldap': {'id': 'python-ldap', 'deprecated': False}, - 'qhull': {'id': 'Qhull', 'deprecated': False}, - 'qpl-1.0': {'id': 'QPL-1.0', 'deprecated': False}, - 'qpl-1.0-inria-2004': {'id': 'QPL-1.0-INRIA-2004', 'deprecated': False}, - 'radvd': {'id': 'radvd', 'deprecated': False}, - 'rdisc': {'id': 'Rdisc', 'deprecated': False}, - 'rhecos-1.1': {'id': 'RHeCos-1.1', 'deprecated': False}, - 'rpl-1.1': {'id': 'RPL-1.1', 'deprecated': False}, - 'rpl-1.5': {'id': 'RPL-1.5', 'deprecated': False}, - 'rpsl-1.0': {'id': 'RPSL-1.0', 'deprecated': False}, - 'rsa-md': {'id': 'RSA-MD', 'deprecated': False}, - 'rscpl': {'id': 'RSCPL', 'deprecated': False}, - 'ruby': {'id': 'Ruby', 'deprecated': False}, - 'ruby-pty': {'id': 'Ruby-pty', 'deprecated': False}, - 'sax-pd': {'id': 'SAX-PD', 'deprecated': False}, - 'sax-pd-2.0': {'id': 'SAX-PD-2.0', 'deprecated': False}, - 'saxpath': {'id': 'Saxpath', 'deprecated': False}, - 'scea': {'id': 'SCEA', 'deprecated': False}, - 'schemereport': {'id': 'SchemeReport', 'deprecated': False}, - 'sendmail': {'id': 'Sendmail', 'deprecated': False}, - 'sendmail-8.23': {'id': 'Sendmail-8.23', 'deprecated': False}, - 'sgi-b-1.0': {'id': 'SGI-B-1.0', 'deprecated': False}, - 'sgi-b-1.1': {'id': 'SGI-B-1.1', 'deprecated': False}, - 'sgi-b-2.0': {'id': 'SGI-B-2.0', 'deprecated': False}, - 'sgi-opengl': {'id': 'SGI-OpenGL', 'deprecated': False}, - 'sgp4': {'id': 'SGP4', 'deprecated': False}, - 'shl-0.5': {'id': 'SHL-0.5', 'deprecated': False}, - 'shl-0.51': {'id': 'SHL-0.51', 'deprecated': False}, - 'simpl-2.0': {'id': 'SimPL-2.0', 'deprecated': False}, - 'sissl': {'id': 'SISSL', 'deprecated': False}, - 'sissl-1.2': {'id': 'SISSL-1.2', 'deprecated': False}, - 'sl': {'id': 'SL', 'deprecated': False}, - 'sleepycat': {'id': 'Sleepycat', 'deprecated': False}, - 'smlnj': {'id': 'SMLNJ', 'deprecated': False}, - 'smppl': {'id': 'SMPPL', 'deprecated': False}, - 'snia': {'id': 'SNIA', 'deprecated': False}, - 'snprintf': {'id': 'snprintf', 'deprecated': False}, - 'softsurfer': {'id': 'softSurfer', 'deprecated': False}, - 'soundex': {'id': 'Soundex', 'deprecated': False}, - 'spencer-86': {'id': 'Spencer-86', 'deprecated': False}, - 'spencer-94': {'id': 'Spencer-94', 'deprecated': False}, - 'spencer-99': {'id': 'Spencer-99', 'deprecated': False}, - 'spl-1.0': {'id': 'SPL-1.0', 'deprecated': False}, - 'ssh-keyscan': {'id': 'ssh-keyscan', 'deprecated': False}, - 'ssh-openssh': {'id': 'SSH-OpenSSH', 'deprecated': False}, - 'ssh-short': {'id': 'SSH-short', 'deprecated': False}, - 'ssleay-standalone': {'id': 'SSLeay-standalone', 'deprecated': False}, - 'sspl-1.0': {'id': 'SSPL-1.0', 'deprecated': False}, - 'standardml-nj': {'id': 'StandardML-NJ', 'deprecated': True}, - 'sugarcrm-1.1.3': {'id': 'SugarCRM-1.1.3', 'deprecated': False}, - 'sun-ppp': {'id': 'Sun-PPP', 'deprecated': False}, - 'sun-ppp-2000': {'id': 'Sun-PPP-2000', 'deprecated': False}, - 'sunpro': {'id': 'SunPro', 'deprecated': False}, - 'swl': {'id': 'SWL', 'deprecated': False}, - 'swrule': {'id': 'swrule', 'deprecated': False}, - 'symlinks': {'id': 'Symlinks', 'deprecated': False}, - 'tapr-ohl-1.0': {'id': 'TAPR-OHL-1.0', 'deprecated': False}, - 'tcl': {'id': 'TCL', 'deprecated': False}, - 'tcp-wrappers': {'id': 'TCP-wrappers', 'deprecated': False}, - 'termreadkey': {'id': 'TermReadKey', 'deprecated': False}, - 'tgppl-1.0': {'id': 'TGPPL-1.0', 'deprecated': False}, - 'threeparttable': {'id': 'threeparttable', 'deprecated': False}, - 'tmate': {'id': 'TMate', 'deprecated': False}, - 'torque-1.1': {'id': 'TORQUE-1.1', 'deprecated': False}, - 'tosl': {'id': 'TOSL', 'deprecated': False}, - 'tpdl': {'id': 'TPDL', 'deprecated': False}, - 'tpl-1.0': {'id': 'TPL-1.0', 'deprecated': False}, - 'ttwl': {'id': 'TTWL', 'deprecated': False}, - 'ttyp0': {'id': 'TTYP0', 'deprecated': False}, - 'tu-berlin-1.0': {'id': 'TU-Berlin-1.0', 'deprecated': False}, - 'tu-berlin-2.0': {'id': 'TU-Berlin-2.0', 'deprecated': False}, - 'ubuntu-font-1.0': {'id': 'Ubuntu-font-1.0', 'deprecated': False}, - 'ucar': {'id': 'UCAR', 'deprecated': False}, - 'ucl-1.0': {'id': 'UCL-1.0', 'deprecated': False}, - 'ulem': {'id': 'ulem', 'deprecated': False}, - 'umich-merit': {'id': 'UMich-Merit', 'deprecated': False}, - 'unicode-3.0': {'id': 'Unicode-3.0', 'deprecated': False}, - 'unicode-dfs-2015': {'id': 'Unicode-DFS-2015', 'deprecated': False}, - 'unicode-dfs-2016': {'id': 'Unicode-DFS-2016', 'deprecated': False}, - 'unicode-tou': {'id': 'Unicode-TOU', 'deprecated': False}, - 'unixcrypt': {'id': 'UnixCrypt', 'deprecated': False}, - 'unlicense': {'id': 'Unlicense', 'deprecated': False}, - 'upl-1.0': {'id': 'UPL-1.0', 'deprecated': False}, - 'urt-rle': {'id': 'URT-RLE', 'deprecated': False}, - 'vim': {'id': 'Vim', 'deprecated': False}, - 'vostrom': {'id': 'VOSTROM', 'deprecated': False}, - 'vsl-1.0': {'id': 'VSL-1.0', 'deprecated': False}, - 'w3c': {'id': 'W3C', 'deprecated': False}, - 'w3c-19980720': {'id': 'W3C-19980720', 'deprecated': False}, - 'w3c-20150513': {'id': 'W3C-20150513', 'deprecated': False}, - 'w3m': {'id': 'w3m', 'deprecated': False}, - 'watcom-1.0': {'id': 'Watcom-1.0', 'deprecated': False}, - 'widget-workshop': {'id': 'Widget-Workshop', 'deprecated': False}, - 'wsuipa': {'id': 'Wsuipa', 'deprecated': False}, - 'wtfpl': {'id': 'WTFPL', 'deprecated': False}, - 'wxwindows': {'id': 'wxWindows', 'deprecated': True}, - 'x11': {'id': 'X11', 'deprecated': False}, - 'x11-distribute-modifications-variant': {'id': 'X11-distribute-modifications-variant', 'deprecated': False}, - 'x11-swapped': {'id': 'X11-swapped', 'deprecated': False}, - 'xdebug-1.03': {'id': 'Xdebug-1.03', 'deprecated': False}, - 'xerox': {'id': 'Xerox', 'deprecated': False}, - 'xfig': {'id': 'Xfig', 'deprecated': False}, - 'xfree86-1.1': {'id': 'XFree86-1.1', 'deprecated': False}, - 'xinetd': {'id': 'xinetd', 'deprecated': False}, - 'xkeyboard-config-zinoviev': {'id': 'xkeyboard-config-Zinoviev', 'deprecated': False}, - 'xlock': {'id': 'xlock', 'deprecated': False}, - 'xnet': {'id': 'Xnet', 'deprecated': False}, - 'xpp': {'id': 'xpp', 'deprecated': False}, - 'xskat': {'id': 'XSkat', 'deprecated': False}, - 'xzoom': {'id': 'xzoom', 'deprecated': False}, - 'ypl-1.0': {'id': 'YPL-1.0', 'deprecated': False}, - 'ypl-1.1': {'id': 'YPL-1.1', 'deprecated': False}, - 'zed': {'id': 'Zed', 'deprecated': False}, - 'zeeff': {'id': 'Zeeff', 'deprecated': False}, - 'zend-2.0': {'id': 'Zend-2.0', 'deprecated': False}, - 'zimbra-1.3': {'id': 'Zimbra-1.3', 'deprecated': False}, - 'zimbra-1.4': {'id': 'Zimbra-1.4', 'deprecated': False}, - 'zlib': {'id': 'Zlib', 'deprecated': False}, - 'zlib-acknowledgement': {'id': 'zlib-acknowledgement', 'deprecated': False}, - 'zpl-1.1': {'id': 'ZPL-1.1', 'deprecated': False}, - 'zpl-2.0': {'id': 'ZPL-2.0', 'deprecated': False}, - 'zpl-2.1': {'id': 'ZPL-2.1', 'deprecated': False}, -} - -EXCEPTIONS: dict[str, SPDXException] = { - '389-exception': {'id': '389-exception', 'deprecated': False}, - 'asterisk-exception': {'id': 'Asterisk-exception', 'deprecated': False}, - 'asterisk-linking-protocols-exception': {'id': 'Asterisk-linking-protocols-exception', 'deprecated': False}, - 'autoconf-exception-2.0': {'id': 'Autoconf-exception-2.0', 'deprecated': False}, - 'autoconf-exception-3.0': {'id': 'Autoconf-exception-3.0', 'deprecated': False}, - 'autoconf-exception-generic': {'id': 'Autoconf-exception-generic', 'deprecated': False}, - 'autoconf-exception-generic-3.0': {'id': 'Autoconf-exception-generic-3.0', 'deprecated': False}, - 'autoconf-exception-macro': {'id': 'Autoconf-exception-macro', 'deprecated': False}, - 'bison-exception-1.24': {'id': 'Bison-exception-1.24', 'deprecated': False}, - 'bison-exception-2.2': {'id': 'Bison-exception-2.2', 'deprecated': False}, - 'bootloader-exception': {'id': 'Bootloader-exception', 'deprecated': False}, - 'classpath-exception-2.0': {'id': 'Classpath-exception-2.0', 'deprecated': False}, - 'clisp-exception-2.0': {'id': 'CLISP-exception-2.0', 'deprecated': False}, - 'cryptsetup-openssl-exception': {'id': 'cryptsetup-OpenSSL-exception', 'deprecated': False}, - 'digirule-foss-exception': {'id': 'DigiRule-FOSS-exception', 'deprecated': False}, - 'ecos-exception-2.0': {'id': 'eCos-exception-2.0', 'deprecated': False}, - 'erlang-otp-linking-exception': {'id': 'erlang-otp-linking-exception', 'deprecated': False}, - 'fawkes-runtime-exception': {'id': 'Fawkes-Runtime-exception', 'deprecated': False}, - 'fltk-exception': {'id': 'FLTK-exception', 'deprecated': False}, - 'fmt-exception': {'id': 'fmt-exception', 'deprecated': False}, - 'font-exception-2.0': {'id': 'Font-exception-2.0', 'deprecated': False}, - 'freertos-exception-2.0': {'id': 'freertos-exception-2.0', 'deprecated': False}, - 'gcc-exception-2.0': {'id': 'GCC-exception-2.0', 'deprecated': False}, - 'gcc-exception-2.0-note': {'id': 'GCC-exception-2.0-note', 'deprecated': False}, - 'gcc-exception-3.1': {'id': 'GCC-exception-3.1', 'deprecated': False}, - 'gmsh-exception': {'id': 'Gmsh-exception', 'deprecated': False}, - 'gnat-exception': {'id': 'GNAT-exception', 'deprecated': False}, - 'gnome-examples-exception': {'id': 'GNOME-examples-exception', 'deprecated': False}, - 'gnu-compiler-exception': {'id': 'GNU-compiler-exception', 'deprecated': False}, - 'gnu-javamail-exception': {'id': 'gnu-javamail-exception', 'deprecated': False}, - 'gpl-3.0-interface-exception': {'id': 'GPL-3.0-interface-exception', 'deprecated': False}, - 'gpl-3.0-linking-exception': {'id': 'GPL-3.0-linking-exception', 'deprecated': False}, - 'gpl-3.0-linking-source-exception': {'id': 'GPL-3.0-linking-source-exception', 'deprecated': False}, - 'gpl-cc-1.0': {'id': 'GPL-CC-1.0', 'deprecated': False}, - 'gstreamer-exception-2005': {'id': 'GStreamer-exception-2005', 'deprecated': False}, - 'gstreamer-exception-2008': {'id': 'GStreamer-exception-2008', 'deprecated': False}, - 'i2p-gpl-java-exception': {'id': 'i2p-gpl-java-exception', 'deprecated': False}, - 'kicad-libraries-exception': {'id': 'KiCad-libraries-exception', 'deprecated': False}, - 'lgpl-3.0-linking-exception': {'id': 'LGPL-3.0-linking-exception', 'deprecated': False}, - 'libpri-openh323-exception': {'id': 'libpri-OpenH323-exception', 'deprecated': False}, - 'libtool-exception': {'id': 'Libtool-exception', 'deprecated': False}, - 'linux-syscall-note': {'id': 'Linux-syscall-note', 'deprecated': False}, - 'llgpl': {'id': 'LLGPL', 'deprecated': False}, - 'llvm-exception': {'id': 'LLVM-exception', 'deprecated': False}, - 'lzma-exception': {'id': 'LZMA-exception', 'deprecated': False}, - 'mif-exception': {'id': 'mif-exception', 'deprecated': False}, - 'nokia-qt-exception-1.1': {'id': 'Nokia-Qt-exception-1.1', 'deprecated': True}, - 'ocaml-lgpl-linking-exception': {'id': 'OCaml-LGPL-linking-exception', 'deprecated': False}, - 'occt-exception-1.0': {'id': 'OCCT-exception-1.0', 'deprecated': False}, - 'openjdk-assembly-exception-1.0': {'id': 'OpenJDK-assembly-exception-1.0', 'deprecated': False}, - 'openvpn-openssl-exception': {'id': 'openvpn-openssl-exception', 'deprecated': False}, - 'pcre2-exception': {'id': 'PCRE2-exception', 'deprecated': False}, - 'ps-or-pdf-font-exception-20170817': {'id': 'PS-or-PDF-font-exception-20170817', 'deprecated': False}, - 'qpl-1.0-inria-2004-exception': {'id': 'QPL-1.0-INRIA-2004-exception', 'deprecated': False}, - 'qt-gpl-exception-1.0': {'id': 'Qt-GPL-exception-1.0', 'deprecated': False}, - 'qt-lgpl-exception-1.1': {'id': 'Qt-LGPL-exception-1.1', 'deprecated': False}, - 'qwt-exception-1.0': {'id': 'Qwt-exception-1.0', 'deprecated': False}, - 'romic-exception': {'id': 'romic-exception', 'deprecated': False}, - 'rrdtool-floss-exception-2.0': {'id': 'RRDtool-FLOSS-exception-2.0', 'deprecated': False}, - 'sane-exception': {'id': 'SANE-exception', 'deprecated': False}, - 'shl-2.0': {'id': 'SHL-2.0', 'deprecated': False}, - 'shl-2.1': {'id': 'SHL-2.1', 'deprecated': False}, - 'stunnel-exception': {'id': 'stunnel-exception', 'deprecated': False}, - 'swi-exception': {'id': 'SWI-exception', 'deprecated': False}, - 'swift-exception': {'id': 'Swift-exception', 'deprecated': False}, - 'texinfo-exception': {'id': 'Texinfo-exception', 'deprecated': False}, - 'u-boot-exception-2.0': {'id': 'u-boot-exception-2.0', 'deprecated': False}, - 'ubdl-exception': {'id': 'UBDL-exception', 'deprecated': False}, - 'universal-foss-exception-1.0': {'id': 'Universal-FOSS-exception-1.0', 'deprecated': False}, - 'vsftpd-openssl-exception': {'id': 'vsftpd-openssl-exception', 'deprecated': False}, - 'wxwindows-exception-3.1': {'id': 'WxWindows-exception-3.1', 'deprecated': False}, - 'x11vnc-openssl-exception': {'id': 'x11vnc-openssl-exception', 'deprecated': False}, -} diff --git a/server/libs/packaging/markers.py b/server/libs/packaging/markers.py deleted file mode 100644 index e7cea57..0000000 --- a/server/libs/packaging/markers.py +++ /dev/null @@ -1,362 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import operator -import os -import platform -import sys -from typing import AbstractSet, Any, Callable, Literal, TypedDict, Union, cast - -from ._parser import MarkerAtom, MarkerList, Op, Value, Variable -from ._parser import parse_marker as _parse_marker -from ._tokenizer import ParserSyntaxError -from .specifiers import InvalidSpecifier, Specifier -from .utils import canonicalize_name - -__all__ = [ - "EvaluateContext", - "InvalidMarker", - "Marker", - "UndefinedComparison", - "UndefinedEnvironmentName", - "default_environment", -] - -Operator = Callable[[str, Union[str, AbstractSet[str]]], bool] -EvaluateContext = Literal["metadata", "lock_file", "requirement"] -MARKERS_ALLOWING_SET = {"extras", "dependency_groups"} - - -class InvalidMarker(ValueError): - """ - An invalid marker was found, users should refer to PEP 508. - """ - - -class UndefinedComparison(ValueError): - """ - An invalid operation was attempted on a value that doesn't support it. - """ - - -class UndefinedEnvironmentName(ValueError): - """ - A name was attempted to be used that does not exist inside of the - environment. - """ - - -class Environment(TypedDict): - implementation_name: str - """The implementation's identifier, e.g. ``'cpython'``.""" - - implementation_version: str - """ - The implementation's version, e.g. ``'3.13.0a2'`` for CPython 3.13.0a2, or - ``'7.3.13'`` for PyPy3.10 v7.3.13. - """ - - os_name: str - """ - The value of :py:data:`os.name`. The name of the operating system dependent module - imported, e.g. ``'posix'``. - """ - - platform_machine: str - """ - Returns the machine type, e.g. ``'i386'``. - - An empty string if the value cannot be determined. - """ - - platform_release: str - """ - The system's release, e.g. ``'2.2.0'`` or ``'NT'``. - - An empty string if the value cannot be determined. - """ - - platform_system: str - """ - The system/OS name, e.g. ``'Linux'``, ``'Windows'`` or ``'Java'``. - - An empty string if the value cannot be determined. - """ - - platform_version: str - """ - The system's release version, e.g. ``'#3 on degas'``. - - An empty string if the value cannot be determined. - """ - - python_full_version: str - """ - The Python version as string ``'major.minor.patchlevel'``. - - Note that unlike the Python :py:data:`sys.version`, this value will always include - the patchlevel (it defaults to 0). - """ - - platform_python_implementation: str - """ - A string identifying the Python implementation, e.g. ``'CPython'``. - """ - - python_version: str - """The Python version as string ``'major.minor'``.""" - - sys_platform: str - """ - This string contains a platform identifier that can be used to append - platform-specific components to :py:data:`sys.path`, for instance. - - For Unix systems, except on Linux and AIX, this is the lowercased OS name as - returned by ``uname -s`` with the first part of the version as returned by - ``uname -r`` appended, e.g. ``'sunos5'`` or ``'freebsd8'``, at the time when Python - was built. - """ - - -def _normalize_extra_values(results: Any) -> Any: - """ - Normalize extra values. - """ - if isinstance(results[0], tuple): - lhs, op, rhs = results[0] - if isinstance(lhs, Variable) and lhs.value == "extra": - normalized_extra = canonicalize_name(rhs.value) - rhs = Value(normalized_extra) - elif isinstance(rhs, Variable) and rhs.value == "extra": - normalized_extra = canonicalize_name(lhs.value) - lhs = Value(normalized_extra) - results[0] = lhs, op, rhs - return results - - -def _format_marker( - marker: list[str] | MarkerAtom | str, first: bool | None = True -) -> str: - assert isinstance(marker, (list, tuple, str)) - - # Sometimes we have a structure like [[...]] which is a single item list - # where the single item is itself it's own list. In that case we want skip - # the rest of this function so that we don't get extraneous () on the - # outside. - if ( - isinstance(marker, list) - and len(marker) == 1 - and isinstance(marker[0], (list, tuple)) - ): - return _format_marker(marker[0]) - - if isinstance(marker, list): - inner = (_format_marker(m, first=False) for m in marker) - if first: - return " ".join(inner) - else: - return "(" + " ".join(inner) + ")" - elif isinstance(marker, tuple): - return " ".join([m.serialize() for m in marker]) - else: - return marker - - -_operators: dict[str, Operator] = { - "in": lambda lhs, rhs: lhs in rhs, - "not in": lambda lhs, rhs: lhs not in rhs, - "<": operator.lt, - "<=": operator.le, - "==": operator.eq, - "!=": operator.ne, - ">=": operator.ge, - ">": operator.gt, -} - - -def _eval_op(lhs: str, op: Op, rhs: str | AbstractSet[str]) -> bool: - if isinstance(rhs, str): - try: - spec = Specifier("".join([op.serialize(), rhs])) - except InvalidSpecifier: - pass - else: - return spec.contains(lhs, prereleases=True) - - oper: Operator | None = _operators.get(op.serialize()) - if oper is None: - raise UndefinedComparison(f"Undefined {op!r} on {lhs!r} and {rhs!r}.") - - return oper(lhs, rhs) - - -def _normalize( - lhs: str, rhs: str | AbstractSet[str], key: str -) -> tuple[str, str | AbstractSet[str]]: - # PEP 685 – Comparison of extra names for optional distribution dependencies - # https://peps.python.org/pep-0685/ - # > When comparing extra names, tools MUST normalize the names being - # > compared using the semantics outlined in PEP 503 for names - if key == "extra": - assert isinstance(rhs, str), "extra value must be a string" - return (canonicalize_name(lhs), canonicalize_name(rhs)) - if key in MARKERS_ALLOWING_SET: - if isinstance(rhs, str): # pragma: no cover - return (canonicalize_name(lhs), canonicalize_name(rhs)) - else: - return (canonicalize_name(lhs), {canonicalize_name(v) for v in rhs}) - - # other environment markers don't have such standards - return lhs, rhs - - -def _evaluate_markers( - markers: MarkerList, environment: dict[str, str | AbstractSet[str]] -) -> bool: - groups: list[list[bool]] = [[]] - - for marker in markers: - assert isinstance(marker, (list, tuple, str)) - - if isinstance(marker, list): - groups[-1].append(_evaluate_markers(marker, environment)) - elif isinstance(marker, tuple): - lhs, op, rhs = marker - - if isinstance(lhs, Variable): - environment_key = lhs.value - lhs_value = environment[environment_key] - rhs_value = rhs.value - else: - lhs_value = lhs.value - environment_key = rhs.value - rhs_value = environment[environment_key] - assert isinstance(lhs_value, str), "lhs must be a string" - lhs_value, rhs_value = _normalize(lhs_value, rhs_value, key=environment_key) - groups[-1].append(_eval_op(lhs_value, op, rhs_value)) - else: - assert marker in ["and", "or"] - if marker == "or": - groups.append([]) - - return any(all(item) for item in groups) - - -def format_full_version(info: sys._version_info) -> str: - version = f"{info.major}.{info.minor}.{info.micro}" - kind = info.releaselevel - if kind != "final": - version += kind[0] + str(info.serial) - return version - - -def default_environment() -> Environment: - iver = format_full_version(sys.implementation.version) - implementation_name = sys.implementation.name - return { - "implementation_name": implementation_name, - "implementation_version": iver, - "os_name": os.name, - "platform_machine": platform.machine(), - "platform_release": platform.release(), - "platform_system": platform.system(), - "platform_version": platform.version(), - "python_full_version": platform.python_version(), - "platform_python_implementation": platform.python_implementation(), - "python_version": ".".join(platform.python_version_tuple()[:2]), - "sys_platform": sys.platform, - } - - -class Marker: - def __init__(self, marker: str) -> None: - # Note: We create a Marker object without calling this constructor in - # packaging.requirements.Requirement. If any additional logic is - # added here, make sure to mirror/adapt Requirement. - try: - self._markers = _normalize_extra_values(_parse_marker(marker)) - # The attribute `_markers` can be described in terms of a recursive type: - # MarkerList = List[Union[Tuple[Node, ...], str, MarkerList]] - # - # For example, the following expression: - # python_version > "3.6" or (python_version == "3.6" and os_name == "unix") - # - # is parsed into: - # [ - # (, ')>, ), - # 'and', - # [ - # (, , ), - # 'or', - # (, , ) - # ] - # ] - except ParserSyntaxError as e: - raise InvalidMarker(str(e)) from e - - def __str__(self) -> str: - return _format_marker(self._markers) - - def __repr__(self) -> str: - return f"" - - def __hash__(self) -> int: - return hash((self.__class__.__name__, str(self))) - - def __eq__(self, other: Any) -> bool: - if not isinstance(other, Marker): - return NotImplemented - - return str(self) == str(other) - - def evaluate( - self, - environment: dict[str, str] | None = None, - context: EvaluateContext = "metadata", - ) -> bool: - """Evaluate a marker. - - Return the boolean from evaluating the given marker against the - environment. environment is an optional argument to override all or - part of the determined environment. The *context* parameter specifies what - context the markers are being evaluated for, which influences what markers - are considered valid. Acceptable values are "metadata" (for core metadata; - default), "lock_file", and "requirement" (i.e. all other situations). - - The environment is determined from the current Python process. - """ - current_environment = cast( - "dict[str, str | AbstractSet[str]]", default_environment() - ) - if context == "lock_file": - current_environment.update( - extras=frozenset(), dependency_groups=frozenset() - ) - elif context == "metadata": - current_environment["extra"] = "" - if environment is not None: - current_environment.update(environment) - # The API used to allow setting extra to None. We need to handle this - # case for backwards compatibility. - if "extra" in current_environment and current_environment["extra"] is None: - current_environment["extra"] = "" - - return _evaluate_markers( - self._markers, _repair_python_full_version(current_environment) - ) - - -def _repair_python_full_version( - env: dict[str, str | AbstractSet[str]], -) -> dict[str, str | AbstractSet[str]]: - """ - Work around platform.python_version() returning something that is not PEP 440 - compliant for non-tagged Python builds. - """ - python_full_version = cast(str, env["python_full_version"]) - if python_full_version.endswith("+"): - env["python_full_version"] = f"{python_full_version}local" - return env diff --git a/server/libs/packaging/metadata.py b/server/libs/packaging/metadata.py deleted file mode 100644 index 3bd8602..0000000 --- a/server/libs/packaging/metadata.py +++ /dev/null @@ -1,862 +0,0 @@ -from __future__ import annotations - -import email.feedparser -import email.header -import email.message -import email.parser -import email.policy -import pathlib -import sys -import typing -from typing import ( - Any, - Callable, - Generic, - Literal, - TypedDict, - cast, -) - -from . import licenses, requirements, specifiers, utils -from . import version as version_module -from .licenses import NormalizedLicenseExpression - -T = typing.TypeVar("T") - - -if sys.version_info >= (3, 11): # pragma: no cover - ExceptionGroup = ExceptionGroup -else: # pragma: no cover - - class ExceptionGroup(Exception): - """A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11. - - If :external:exc:`ExceptionGroup` is already defined by Python itself, - that version is used instead. - """ - - message: str - exceptions: list[Exception] - - def __init__(self, message: str, exceptions: list[Exception]) -> None: - self.message = message - self.exceptions = exceptions - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.message!r}, {self.exceptions!r})" - - -class InvalidMetadata(ValueError): - """A metadata field contains invalid data.""" - - field: str - """The name of the field that contains invalid data.""" - - def __init__(self, field: str, message: str) -> None: - self.field = field - super().__init__(message) - - -# The RawMetadata class attempts to make as few assumptions about the underlying -# serialization formats as possible. The idea is that as long as a serialization -# formats offer some very basic primitives in *some* way then we can support -# serializing to and from that format. -class RawMetadata(TypedDict, total=False): - """A dictionary of raw core metadata. - - Each field in core metadata maps to a key of this dictionary (when data is - provided). The key is lower-case and underscores are used instead of dashes - compared to the equivalent core metadata field. Any core metadata field that - can be specified multiple times or can hold multiple values in a single - field have a key with a plural name. See :class:`Metadata` whose attributes - match the keys of this dictionary. - - Core metadata fields that can be specified multiple times are stored as a - list or dict depending on which is appropriate for the field. Any fields - which hold multiple values in a single field are stored as a list. - - """ - - # Metadata 1.0 - PEP 241 - metadata_version: str - name: str - version: str - platforms: list[str] - summary: str - description: str - keywords: list[str] - home_page: str - author: str - author_email: str - license: str - - # Metadata 1.1 - PEP 314 - supported_platforms: list[str] - download_url: str - classifiers: list[str] - requires: list[str] - provides: list[str] - obsoletes: list[str] - - # Metadata 1.2 - PEP 345 - maintainer: str - maintainer_email: str - requires_dist: list[str] - provides_dist: list[str] - obsoletes_dist: list[str] - requires_python: str - requires_external: list[str] - project_urls: dict[str, str] - - # Metadata 2.0 - # PEP 426 attempted to completely revamp the metadata format - # but got stuck without ever being able to build consensus on - # it and ultimately ended up withdrawn. - # - # However, a number of tools had started emitting METADATA with - # `2.0` Metadata-Version, so for historical reasons, this version - # was skipped. - - # Metadata 2.1 - PEP 566 - description_content_type: str - provides_extra: list[str] - - # Metadata 2.2 - PEP 643 - dynamic: list[str] - - # Metadata 2.3 - PEP 685 - # No new fields were added in PEP 685, just some edge case were - # tightened up to provide better interoptability. - - # Metadata 2.4 - PEP 639 - license_expression: str - license_files: list[str] - - -_STRING_FIELDS = { - "author", - "author_email", - "description", - "description_content_type", - "download_url", - "home_page", - "license", - "license_expression", - "maintainer", - "maintainer_email", - "metadata_version", - "name", - "requires_python", - "summary", - "version", -} - -_LIST_FIELDS = { - "classifiers", - "dynamic", - "license_files", - "obsoletes", - "obsoletes_dist", - "platforms", - "provides", - "provides_dist", - "provides_extra", - "requires", - "requires_dist", - "requires_external", - "supported_platforms", -} - -_DICT_FIELDS = { - "project_urls", -} - - -def _parse_keywords(data: str) -> list[str]: - """Split a string of comma-separated keywords into a list of keywords.""" - return [k.strip() for k in data.split(",")] - - -def _parse_project_urls(data: list[str]) -> dict[str, str]: - """Parse a list of label/URL string pairings separated by a comma.""" - urls = {} - for pair in data: - # Our logic is slightly tricky here as we want to try and do - # *something* reasonable with malformed data. - # - # The main thing that we have to worry about, is data that does - # not have a ',' at all to split the label from the Value. There - # isn't a singular right answer here, and we will fail validation - # later on (if the caller is validating) so it doesn't *really* - # matter, but since the missing value has to be an empty str - # and our return value is dict[str, str], if we let the key - # be the missing value, then they'd have multiple '' values that - # overwrite each other in a accumulating dict. - # - # The other potentional issue is that it's possible to have the - # same label multiple times in the metadata, with no solid "right" - # answer with what to do in that case. As such, we'll do the only - # thing we can, which is treat the field as unparseable and add it - # to our list of unparsed fields. - parts = [p.strip() for p in pair.split(",", 1)] - parts.extend([""] * (max(0, 2 - len(parts)))) # Ensure 2 items - - # TODO: The spec doesn't say anything about if the keys should be - # considered case sensitive or not... logically they should - # be case-preserving and case-insensitive, but doing that - # would open up more cases where we might have duplicate - # entries. - label, url = parts - if label in urls: - # The label already exists in our set of urls, so this field - # is unparseable, and we can just add the whole thing to our - # unparseable data and stop processing it. - raise KeyError("duplicate labels in project urls") - urls[label] = url - - return urls - - -def _get_payload(msg: email.message.Message, source: bytes | str) -> str: - """Get the body of the message.""" - # If our source is a str, then our caller has managed encodings for us, - # and we don't need to deal with it. - if isinstance(source, str): - payload = msg.get_payload() - assert isinstance(payload, str) - return payload - # If our source is a bytes, then we're managing the encoding and we need - # to deal with it. - else: - bpayload = msg.get_payload(decode=True) - assert isinstance(bpayload, bytes) - try: - return bpayload.decode("utf8", "strict") - except UnicodeDecodeError as exc: - raise ValueError("payload in an invalid encoding") from exc - - -# The various parse_FORMAT functions here are intended to be as lenient as -# possible in their parsing, while still returning a correctly typed -# RawMetadata. -# -# To aid in this, we also generally want to do as little touching of the -# data as possible, except where there are possibly some historic holdovers -# that make valid data awkward to work with. -# -# While this is a lower level, intermediate format than our ``Metadata`` -# class, some light touch ups can make a massive difference in usability. - -# Map METADATA fields to RawMetadata. -_EMAIL_TO_RAW_MAPPING = { - "author": "author", - "author-email": "author_email", - "classifier": "classifiers", - "description": "description", - "description-content-type": "description_content_type", - "download-url": "download_url", - "dynamic": "dynamic", - "home-page": "home_page", - "keywords": "keywords", - "license": "license", - "license-expression": "license_expression", - "license-file": "license_files", - "maintainer": "maintainer", - "maintainer-email": "maintainer_email", - "metadata-version": "metadata_version", - "name": "name", - "obsoletes": "obsoletes", - "obsoletes-dist": "obsoletes_dist", - "platform": "platforms", - "project-url": "project_urls", - "provides": "provides", - "provides-dist": "provides_dist", - "provides-extra": "provides_extra", - "requires": "requires", - "requires-dist": "requires_dist", - "requires-external": "requires_external", - "requires-python": "requires_python", - "summary": "summary", - "supported-platform": "supported_platforms", - "version": "version", -} -_RAW_TO_EMAIL_MAPPING = {raw: email for email, raw in _EMAIL_TO_RAW_MAPPING.items()} - - -def parse_email(data: bytes | str) -> tuple[RawMetadata, dict[str, list[str]]]: - """Parse a distribution's metadata stored as email headers (e.g. from ``METADATA``). - - This function returns a two-item tuple of dicts. The first dict is of - recognized fields from the core metadata specification. Fields that can be - parsed and translated into Python's built-in types are converted - appropriately. All other fields are left as-is. Fields that are allowed to - appear multiple times are stored as lists. - - The second dict contains all other fields from the metadata. This includes - any unrecognized fields. It also includes any fields which are expected to - be parsed into a built-in type but were not formatted appropriately. Finally, - any fields that are expected to appear only once but are repeated are - included in this dict. - - """ - raw: dict[str, str | list[str] | dict[str, str]] = {} - unparsed: dict[str, list[str]] = {} - - if isinstance(data, str): - parsed = email.parser.Parser(policy=email.policy.compat32).parsestr(data) - else: - parsed = email.parser.BytesParser(policy=email.policy.compat32).parsebytes(data) - - # We have to wrap parsed.keys() in a set, because in the case of multiple - # values for a key (a list), the key will appear multiple times in the - # list of keys, but we're avoiding that by using get_all(). - for name in frozenset(parsed.keys()): - # Header names in RFC are case insensitive, so we'll normalize to all - # lower case to make comparisons easier. - name = name.lower() - - # We use get_all() here, even for fields that aren't multiple use, - # because otherwise someone could have e.g. two Name fields, and we - # would just silently ignore it rather than doing something about it. - headers = parsed.get_all(name) or [] - - # The way the email module works when parsing bytes is that it - # unconditionally decodes the bytes as ascii using the surrogateescape - # handler. When you pull that data back out (such as with get_all() ), - # it looks to see if the str has any surrogate escapes, and if it does - # it wraps it in a Header object instead of returning the string. - # - # As such, we'll look for those Header objects, and fix up the encoding. - value = [] - # Flag if we have run into any issues processing the headers, thus - # signalling that the data belongs in 'unparsed'. - valid_encoding = True - for h in headers: - # It's unclear if this can return more types than just a Header or - # a str, so we'll just assert here to make sure. - assert isinstance(h, (email.header.Header, str)) - - # If it's a header object, we need to do our little dance to get - # the real data out of it. In cases where there is invalid data - # we're going to end up with mojibake, but there's no obvious, good - # way around that without reimplementing parts of the Header object - # ourselves. - # - # That should be fine since, if mojibacked happens, this key is - # going into the unparsed dict anyways. - if isinstance(h, email.header.Header): - # The Header object stores it's data as chunks, and each chunk - # can be independently encoded, so we'll need to check each - # of them. - chunks: list[tuple[bytes, str | None]] = [] - for bin, encoding in email.header.decode_header(h): - try: - bin.decode("utf8", "strict") - except UnicodeDecodeError: - # Enable mojibake. - encoding = "latin1" - valid_encoding = False - else: - encoding = "utf8" - chunks.append((bin, encoding)) - - # Turn our chunks back into a Header object, then let that - # Header object do the right thing to turn them into a - # string for us. - value.append(str(email.header.make_header(chunks))) - # This is already a string, so just add it. - else: - value.append(h) - - # We've processed all of our values to get them into a list of str, - # but we may have mojibake data, in which case this is an unparsed - # field. - if not valid_encoding: - unparsed[name] = value - continue - - raw_name = _EMAIL_TO_RAW_MAPPING.get(name) - if raw_name is None: - # This is a bit of a weird situation, we've encountered a key that - # we don't know what it means, so we don't know whether it's meant - # to be a list or not. - # - # Since we can't really tell one way or another, we'll just leave it - # as a list, even though it may be a single item list, because that's - # what makes the most sense for email headers. - unparsed[name] = value - continue - - # If this is one of our string fields, then we'll check to see if our - # value is a list of a single item. If it is then we'll assume that - # it was emitted as a single string, and unwrap the str from inside - # the list. - # - # If it's any other kind of data, then we haven't the faintest clue - # what we should parse it as, and we have to just add it to our list - # of unparsed stuff. - if raw_name in _STRING_FIELDS and len(value) == 1: - raw[raw_name] = value[0] - # If this is one of our list of string fields, then we can just assign - # the value, since email *only* has strings, and our get_all() call - # above ensures that this is a list. - elif raw_name in _LIST_FIELDS: - raw[raw_name] = value - # Special Case: Keywords - # The keywords field is implemented in the metadata spec as a str, - # but it conceptually is a list of strings, and is serialized using - # ", ".join(keywords), so we'll do some light data massaging to turn - # this into what it logically is. - elif raw_name == "keywords" and len(value) == 1: - raw[raw_name] = _parse_keywords(value[0]) - # Special Case: Project-URL - # The project urls is implemented in the metadata spec as a list of - # specially-formatted strings that represent a key and a value, which - # is fundamentally a mapping, however the email format doesn't support - # mappings in a sane way, so it was crammed into a list of strings - # instead. - # - # We will do a little light data massaging to turn this into a map as - # it logically should be. - elif raw_name == "project_urls": - try: - raw[raw_name] = _parse_project_urls(value) - except KeyError: - unparsed[name] = value - # Nothing that we've done has managed to parse this, so it'll just - # throw it in our unparseable data and move on. - else: - unparsed[name] = value - - # We need to support getting the Description from the message payload in - # addition to getting it from the the headers. This does mean, though, there - # is the possibility of it being set both ways, in which case we put both - # in 'unparsed' since we don't know which is right. - try: - payload = _get_payload(parsed, data) - except ValueError: - unparsed.setdefault("description", []).append( - parsed.get_payload(decode=isinstance(data, bytes)) # type: ignore[call-overload] - ) - else: - if payload: - # Check to see if we've already got a description, if so then both - # it, and this body move to unparseable. - if "description" in raw: - description_header = cast(str, raw.pop("description")) - unparsed.setdefault("description", []).extend( - [description_header, payload] - ) - elif "description" in unparsed: - unparsed["description"].append(payload) - else: - raw["description"] = payload - - # We need to cast our `raw` to a metadata, because a TypedDict only support - # literal key names, but we're computing our key names on purpose, but the - # way this function is implemented, our `TypedDict` can only have valid key - # names. - return cast(RawMetadata, raw), unparsed - - -_NOT_FOUND = object() - - -# Keep the two values in sync. -_VALID_METADATA_VERSIONS = ["1.0", "1.1", "1.2", "2.1", "2.2", "2.3", "2.4"] -_MetadataVersion = Literal["1.0", "1.1", "1.2", "2.1", "2.2", "2.3", "2.4"] - -_REQUIRED_ATTRS = frozenset(["metadata_version", "name", "version"]) - - -class _Validator(Generic[T]): - """Validate a metadata field. - - All _process_*() methods correspond to a core metadata field. The method is - called with the field's raw value. If the raw value is valid it is returned - in its "enriched" form (e.g. ``version.Version`` for the ``Version`` field). - If the raw value is invalid, :exc:`InvalidMetadata` is raised (with a cause - as appropriate). - """ - - name: str - raw_name: str - added: _MetadataVersion - - def __init__( - self, - *, - added: _MetadataVersion = "1.0", - ) -> None: - self.added = added - - def __set_name__(self, _owner: Metadata, name: str) -> None: - self.name = name - self.raw_name = _RAW_TO_EMAIL_MAPPING[name] - - def __get__(self, instance: Metadata, _owner: type[Metadata]) -> T: - # With Python 3.8, the caching can be replaced with functools.cached_property(). - # No need to check the cache as attribute lookup will resolve into the - # instance's __dict__ before __get__ is called. - cache = instance.__dict__ - value = instance._raw.get(self.name) - - # To make the _process_* methods easier, we'll check if the value is None - # and if this field is NOT a required attribute, and if both of those - # things are true, we'll skip the the converter. This will mean that the - # converters never have to deal with the None union. - if self.name in _REQUIRED_ATTRS or value is not None: - try: - converter: Callable[[Any], T] = getattr(self, f"_process_{self.name}") - except AttributeError: - pass - else: - value = converter(value) - - cache[self.name] = value - try: - del instance._raw[self.name] # type: ignore[misc] - except KeyError: - pass - - return cast(T, value) - - def _invalid_metadata( - self, msg: str, cause: Exception | None = None - ) -> InvalidMetadata: - exc = InvalidMetadata( - self.raw_name, msg.format_map({"field": repr(self.raw_name)}) - ) - exc.__cause__ = cause - return exc - - def _process_metadata_version(self, value: str) -> _MetadataVersion: - # Implicitly makes Metadata-Version required. - if value not in _VALID_METADATA_VERSIONS: - raise self._invalid_metadata(f"{value!r} is not a valid metadata version") - return cast(_MetadataVersion, value) - - def _process_name(self, value: str) -> str: - if not value: - raise self._invalid_metadata("{field} is a required field") - # Validate the name as a side-effect. - try: - utils.canonicalize_name(value, validate=True) - except utils.InvalidName as exc: - raise self._invalid_metadata( - f"{value!r} is invalid for {{field}}", cause=exc - ) from exc - else: - return value - - def _process_version(self, value: str) -> version_module.Version: - if not value: - raise self._invalid_metadata("{field} is a required field") - try: - return version_module.parse(value) - except version_module.InvalidVersion as exc: - raise self._invalid_metadata( - f"{value!r} is invalid for {{field}}", cause=exc - ) from exc - - def _process_summary(self, value: str) -> str: - """Check the field contains no newlines.""" - if "\n" in value: - raise self._invalid_metadata("{field} must be a single line") - return value - - def _process_description_content_type(self, value: str) -> str: - content_types = {"text/plain", "text/x-rst", "text/markdown"} - message = email.message.EmailMessage() - message["content-type"] = value - - content_type, parameters = ( - # Defaults to `text/plain` if parsing failed. - message.get_content_type().lower(), - message["content-type"].params, - ) - # Check if content-type is valid or defaulted to `text/plain` and thus was - # not parseable. - if content_type not in content_types or content_type not in value.lower(): - raise self._invalid_metadata( - f"{{field}} must be one of {list(content_types)}, not {value!r}" - ) - - charset = parameters.get("charset", "UTF-8") - if charset != "UTF-8": - raise self._invalid_metadata( - f"{{field}} can only specify the UTF-8 charset, not {list(charset)}" - ) - - markdown_variants = {"GFM", "CommonMark"} - variant = parameters.get("variant", "GFM") # Use an acceptable default. - if content_type == "text/markdown" and variant not in markdown_variants: - raise self._invalid_metadata( - f"valid Markdown variants for {{field}} are {list(markdown_variants)}, " - f"not {variant!r}", - ) - return value - - def _process_dynamic(self, value: list[str]) -> list[str]: - for dynamic_field in map(str.lower, value): - if dynamic_field in {"name", "version", "metadata-version"}: - raise self._invalid_metadata( - f"{dynamic_field!r} is not allowed as a dynamic field" - ) - elif dynamic_field not in _EMAIL_TO_RAW_MAPPING: - raise self._invalid_metadata( - f"{dynamic_field!r} is not a valid dynamic field" - ) - return list(map(str.lower, value)) - - def _process_provides_extra( - self, - value: list[str], - ) -> list[utils.NormalizedName]: - normalized_names = [] - try: - for name in value: - normalized_names.append(utils.canonicalize_name(name, validate=True)) - except utils.InvalidName as exc: - raise self._invalid_metadata( - f"{name!r} is invalid for {{field}}", cause=exc - ) from exc - else: - return normalized_names - - def _process_requires_python(self, value: str) -> specifiers.SpecifierSet: - try: - return specifiers.SpecifierSet(value) - except specifiers.InvalidSpecifier as exc: - raise self._invalid_metadata( - f"{value!r} is invalid for {{field}}", cause=exc - ) from exc - - def _process_requires_dist( - self, - value: list[str], - ) -> list[requirements.Requirement]: - reqs = [] - try: - for req in value: - reqs.append(requirements.Requirement(req)) - except requirements.InvalidRequirement as exc: - raise self._invalid_metadata( - f"{req!r} is invalid for {{field}}", cause=exc - ) from exc - else: - return reqs - - def _process_license_expression( - self, value: str - ) -> NormalizedLicenseExpression | None: - try: - return licenses.canonicalize_license_expression(value) - except ValueError as exc: - raise self._invalid_metadata( - f"{value!r} is invalid for {{field}}", cause=exc - ) from exc - - def _process_license_files(self, value: list[str]) -> list[str]: - paths = [] - for path in value: - if ".." in path: - raise self._invalid_metadata( - f"{path!r} is invalid for {{field}}, " - "parent directory indicators are not allowed" - ) - if "*" in path: - raise self._invalid_metadata( - f"{path!r} is invalid for {{field}}, paths must be resolved" - ) - if ( - pathlib.PurePosixPath(path).is_absolute() - or pathlib.PureWindowsPath(path).is_absolute() - ): - raise self._invalid_metadata( - f"{path!r} is invalid for {{field}}, paths must be relative" - ) - if pathlib.PureWindowsPath(path).as_posix() != path: - raise self._invalid_metadata( - f"{path!r} is invalid for {{field}}, paths must use '/' delimiter" - ) - paths.append(path) - return paths - - -class Metadata: - """Representation of distribution metadata. - - Compared to :class:`RawMetadata`, this class provides objects representing - metadata fields instead of only using built-in types. Any invalid metadata - will cause :exc:`InvalidMetadata` to be raised (with a - :py:attr:`~BaseException.__cause__` attribute as appropriate). - """ - - _raw: RawMetadata - - @classmethod - def from_raw(cls, data: RawMetadata, *, validate: bool = True) -> Metadata: - """Create an instance from :class:`RawMetadata`. - - If *validate* is true, all metadata will be validated. All exceptions - related to validation will be gathered and raised as an :class:`ExceptionGroup`. - """ - ins = cls() - ins._raw = data.copy() # Mutations occur due to caching enriched values. - - if validate: - exceptions: list[Exception] = [] - try: - metadata_version = ins.metadata_version - metadata_age = _VALID_METADATA_VERSIONS.index(metadata_version) - except InvalidMetadata as metadata_version_exc: - exceptions.append(metadata_version_exc) - metadata_version = None - - # Make sure to check for the fields that are present, the required - # fields (so their absence can be reported). - fields_to_check = frozenset(ins._raw) | _REQUIRED_ATTRS - # Remove fields that have already been checked. - fields_to_check -= {"metadata_version"} - - for key in fields_to_check: - try: - if metadata_version: - # Can't use getattr() as that triggers descriptor protocol which - # will fail due to no value for the instance argument. - try: - field_metadata_version = cls.__dict__[key].added - except KeyError: - exc = InvalidMetadata(key, f"unrecognized field: {key!r}") - exceptions.append(exc) - continue - field_age = _VALID_METADATA_VERSIONS.index( - field_metadata_version - ) - if field_age > metadata_age: - field = _RAW_TO_EMAIL_MAPPING[key] - exc = InvalidMetadata( - field, - f"{field} introduced in metadata version " - f"{field_metadata_version}, not {metadata_version}", - ) - exceptions.append(exc) - continue - getattr(ins, key) - except InvalidMetadata as exc: - exceptions.append(exc) - - if exceptions: - raise ExceptionGroup("invalid metadata", exceptions) - - return ins - - @classmethod - def from_email(cls, data: bytes | str, *, validate: bool = True) -> Metadata: - """Parse metadata from email headers. - - If *validate* is true, the metadata will be validated. All exceptions - related to validation will be gathered and raised as an :class:`ExceptionGroup`. - """ - raw, unparsed = parse_email(data) - - if validate: - exceptions: list[Exception] = [] - for unparsed_key in unparsed: - if unparsed_key in _EMAIL_TO_RAW_MAPPING: - message = f"{unparsed_key!r} has invalid data" - else: - message = f"unrecognized field: {unparsed_key!r}" - exceptions.append(InvalidMetadata(unparsed_key, message)) - - if exceptions: - raise ExceptionGroup("unparsed", exceptions) - - try: - return cls.from_raw(raw, validate=validate) - except ExceptionGroup as exc_group: - raise ExceptionGroup( - "invalid or unparsed metadata", exc_group.exceptions - ) from None - - metadata_version: _Validator[_MetadataVersion] = _Validator() - """:external:ref:`core-metadata-metadata-version` - (required; validated to be a valid metadata version)""" - # `name` is not normalized/typed to NormalizedName so as to provide access to - # the original/raw name. - name: _Validator[str] = _Validator() - """:external:ref:`core-metadata-name` - (required; validated using :func:`~packaging.utils.canonicalize_name` and its - *validate* parameter)""" - version: _Validator[version_module.Version] = _Validator() - """:external:ref:`core-metadata-version` (required)""" - dynamic: _Validator[list[str] | None] = _Validator( - added="2.2", - ) - """:external:ref:`core-metadata-dynamic` - (validated against core metadata field names and lowercased)""" - platforms: _Validator[list[str] | None] = _Validator() - """:external:ref:`core-metadata-platform`""" - supported_platforms: _Validator[list[str] | None] = _Validator(added="1.1") - """:external:ref:`core-metadata-supported-platform`""" - summary: _Validator[str | None] = _Validator() - """:external:ref:`core-metadata-summary` (validated to contain no newlines)""" - description: _Validator[str | None] = _Validator() # TODO 2.1: can be in body - """:external:ref:`core-metadata-description`""" - description_content_type: _Validator[str | None] = _Validator(added="2.1") - """:external:ref:`core-metadata-description-content-type` (validated)""" - keywords: _Validator[list[str] | None] = _Validator() - """:external:ref:`core-metadata-keywords`""" - home_page: _Validator[str | None] = _Validator() - """:external:ref:`core-metadata-home-page`""" - download_url: _Validator[str | None] = _Validator(added="1.1") - """:external:ref:`core-metadata-download-url`""" - author: _Validator[str | None] = _Validator() - """:external:ref:`core-metadata-author`""" - author_email: _Validator[str | None] = _Validator() - """:external:ref:`core-metadata-author-email`""" - maintainer: _Validator[str | None] = _Validator(added="1.2") - """:external:ref:`core-metadata-maintainer`""" - maintainer_email: _Validator[str | None] = _Validator(added="1.2") - """:external:ref:`core-metadata-maintainer-email`""" - license: _Validator[str | None] = _Validator() - """:external:ref:`core-metadata-license`""" - license_expression: _Validator[NormalizedLicenseExpression | None] = _Validator( - added="2.4" - ) - """:external:ref:`core-metadata-license-expression`""" - license_files: _Validator[list[str] | None] = _Validator(added="2.4") - """:external:ref:`core-metadata-license-file`""" - classifiers: _Validator[list[str] | None] = _Validator(added="1.1") - """:external:ref:`core-metadata-classifier`""" - requires_dist: _Validator[list[requirements.Requirement] | None] = _Validator( - added="1.2" - ) - """:external:ref:`core-metadata-requires-dist`""" - requires_python: _Validator[specifiers.SpecifierSet | None] = _Validator( - added="1.2" - ) - """:external:ref:`core-metadata-requires-python`""" - # Because `Requires-External` allows for non-PEP 440 version specifiers, we - # don't do any processing on the values. - requires_external: _Validator[list[str] | None] = _Validator(added="1.2") - """:external:ref:`core-metadata-requires-external`""" - project_urls: _Validator[dict[str, str] | None] = _Validator(added="1.2") - """:external:ref:`core-metadata-project-url`""" - # PEP 685 lets us raise an error if an extra doesn't pass `Name` validation - # regardless of metadata version. - provides_extra: _Validator[list[utils.NormalizedName] | None] = _Validator( - added="2.1", - ) - """:external:ref:`core-metadata-provides-extra`""" - provides_dist: _Validator[list[str] | None] = _Validator(added="1.2") - """:external:ref:`core-metadata-provides-dist`""" - obsoletes_dist: _Validator[list[str] | None] = _Validator(added="1.2") - """:external:ref:`core-metadata-obsoletes-dist`""" - requires: _Validator[list[str] | None] = _Validator(added="1.1") - """``Requires`` (deprecated)""" - provides: _Validator[list[str] | None] = _Validator(added="1.1") - """``Provides`` (deprecated)""" - obsoletes: _Validator[list[str] | None] = _Validator(added="1.1") - """``Obsoletes`` (deprecated)""" diff --git a/server/libs/packaging/py.typed b/server/libs/packaging/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/server/libs/packaging/requirements.py b/server/libs/packaging/requirements.py deleted file mode 100644 index 4e068c9..0000000 --- a/server/libs/packaging/requirements.py +++ /dev/null @@ -1,91 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. -from __future__ import annotations - -from typing import Any, Iterator - -from ._parser import parse_requirement as _parse_requirement -from ._tokenizer import ParserSyntaxError -from .markers import Marker, _normalize_extra_values -from .specifiers import SpecifierSet -from .utils import canonicalize_name - - -class InvalidRequirement(ValueError): - """ - An invalid requirement was found, users should refer to PEP 508. - """ - - -class Requirement: - """Parse a requirement. - - Parse a given requirement string into its parts, such as name, specifier, - URL, and extras. Raises InvalidRequirement on a badly-formed requirement - string. - """ - - # TODO: Can we test whether something is contained within a requirement? - # If so how do we do that? Do we need to test against the _name_ of - # the thing as well as the version? What about the markers? - # TODO: Can we normalize the name and extra name? - - def __init__(self, requirement_string: str) -> None: - try: - parsed = _parse_requirement(requirement_string) - except ParserSyntaxError as e: - raise InvalidRequirement(str(e)) from e - - self.name: str = parsed.name - self.url: str | None = parsed.url or None - self.extras: set[str] = set(parsed.extras or []) - self.specifier: SpecifierSet = SpecifierSet(parsed.specifier) - self.marker: Marker | None = None - if parsed.marker is not None: - self.marker = Marker.__new__(Marker) - self.marker._markers = _normalize_extra_values(parsed.marker) - - def _iter_parts(self, name: str) -> Iterator[str]: - yield name - - if self.extras: - formatted_extras = ",".join(sorted(self.extras)) - yield f"[{formatted_extras}]" - - if self.specifier: - yield str(self.specifier) - - if self.url: - yield f"@ {self.url}" - if self.marker: - yield " " - - if self.marker: - yield f"; {self.marker}" - - def __str__(self) -> str: - return "".join(self._iter_parts(self.name)) - - def __repr__(self) -> str: - return f"" - - def __hash__(self) -> int: - return hash( - ( - self.__class__.__name__, - *self._iter_parts(canonicalize_name(self.name)), - ) - ) - - def __eq__(self, other: Any) -> bool: - if not isinstance(other, Requirement): - return NotImplemented - - return ( - canonicalize_name(self.name) == canonicalize_name(other.name) - and self.extras == other.extras - and self.specifier == other.specifier - and self.url == other.url - and self.marker == other.marker - ) diff --git a/server/libs/packaging/specifiers.py b/server/libs/packaging/specifiers.py deleted file mode 100644 index c844804..0000000 --- a/server/libs/packaging/specifiers.py +++ /dev/null @@ -1,1019 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. -""" -.. testsetup:: - - from packaging.specifiers import Specifier, SpecifierSet, InvalidSpecifier - from packaging.version import Version -""" - -from __future__ import annotations - -import abc -import itertools -import re -from typing import Callable, Iterable, Iterator, TypeVar, Union - -from .utils import canonicalize_version -from .version import Version - -UnparsedVersion = Union[Version, str] -UnparsedVersionVar = TypeVar("UnparsedVersionVar", bound=UnparsedVersion) -CallableOperator = Callable[[Version, str], bool] - - -def _coerce_version(version: UnparsedVersion) -> Version: - if not isinstance(version, Version): - version = Version(version) - return version - - -class InvalidSpecifier(ValueError): - """ - Raised when attempting to create a :class:`Specifier` with a specifier - string that is invalid. - - >>> Specifier("lolwat") - Traceback (most recent call last): - ... - packaging.specifiers.InvalidSpecifier: Invalid specifier: 'lolwat' - """ - - -class BaseSpecifier(metaclass=abc.ABCMeta): - @abc.abstractmethod - def __str__(self) -> str: - """ - Returns the str representation of this Specifier-like object. This - should be representative of the Specifier itself. - """ - - @abc.abstractmethod - def __hash__(self) -> int: - """ - Returns a hash value for this Specifier-like object. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Returns a boolean representing whether or not the two Specifier-like - objects are equal. - - :param other: The other object to check against. - """ - - @property - @abc.abstractmethod - def prereleases(self) -> bool | None: - """Whether or not pre-releases as a whole are allowed. - - This can be set to either ``True`` or ``False`` to explicitly enable or disable - prereleases or it can be set to ``None`` (the default) to use default semantics. - """ - - @prereleases.setter - def prereleases(self, value: bool) -> None: - """Setter for :attr:`prereleases`. - - :param value: The value to set. - """ - - @abc.abstractmethod - def contains(self, item: str, prereleases: bool | None = None) -> bool: - """ - Determines if the given item is contained within this specifier. - """ - - @abc.abstractmethod - def filter( - self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None - ) -> Iterator[UnparsedVersionVar]: - """ - Takes an iterable of items and filters them so that only items which - are contained within this specifier are allowed in it. - """ - - -class Specifier(BaseSpecifier): - """This class abstracts handling of version specifiers. - - .. tip:: - - It is generally not required to instantiate this manually. You should instead - prefer to work with :class:`SpecifierSet` instead, which can parse - comma-separated version specifiers (which is what package metadata contains). - """ - - _operator_regex_str = r""" - (?P(~=|==|!=|<=|>=|<|>|===)) - """ - _version_regex_str = r""" - (?P - (?: - # The identity operators allow for an escape hatch that will - # do an exact string match of the version you wish to install. - # This will not be parsed by PEP 440 and we cannot determine - # any semantic meaning from it. This operator is discouraged - # but included entirely as an escape hatch. - (?<====) # Only match for the identity operator - \s* - [^\s;)]* # The arbitrary version can be just about anything, - # we match everything except for whitespace, a - # semi-colon for marker support, and a closing paren - # since versions can be enclosed in them. - ) - | - (?: - # The (non)equality operators allow for wild card and local - # versions to be specified so we have to define these two - # operators separately to enable that. - (?<===|!=) # Only match for equals and not equals - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)* # release - - # You cannot use a wild card and a pre-release, post-release, a dev or - # local version together so group them with a | and make them optional. - (?: - \.\* # Wild card syntax of .* - | - (?: # pre release - [-_\.]? - (alpha|beta|preview|pre|a|b|c|rc) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local - )? - ) - | - (?: - # The compatible operator requires at least two digits in the - # release segment. - (?<=~=) # Only match for the compatible operator - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) - (?: # pre release - [-_\.]? - (alpha|beta|preview|pre|a|b|c|rc) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - ) - | - (?: - # All other operators only allow a sub set of what the - # (non)equality operators do. Specifically they do not allow - # local versions to be specified nor do they allow the prefix - # matching wild cards. - (?=": "greater_than_equal", - "<": "less_than", - ">": "greater_than", - "===": "arbitrary", - } - - def __init__(self, spec: str = "", prereleases: bool | None = None) -> None: - """Initialize a Specifier instance. - - :param spec: - The string representation of a specifier which will be parsed and - normalized before use. - :param prereleases: - This tells the specifier if it should accept prerelease versions if - applicable or not. The default of ``None`` will autodetect it from the - given specifiers. - :raises InvalidSpecifier: - If the given specifier is invalid (i.e. bad syntax). - """ - match = self._regex.search(spec) - if not match: - raise InvalidSpecifier(f"Invalid specifier: {spec!r}") - - self._spec: tuple[str, str] = ( - match.group("operator").strip(), - match.group("version").strip(), - ) - - # Store whether or not this Specifier should accept prereleases - self._prereleases = prereleases - - # https://github.com/python/mypy/pull/13475#pullrequestreview-1079784515 - @property # type: ignore[override] - def prereleases(self) -> bool: - # If there is an explicit prereleases set for this, then we'll just - # blindly use that. - if self._prereleases is not None: - return self._prereleases - - # Look at all of our specifiers and determine if they are inclusive - # operators, and if they are if they are including an explicit - # prerelease. - operator, version = self._spec - if operator in ["==", ">=", "<=", "~=", "===", ">", "<"]: - # The == specifier can include a trailing .*, if it does we - # want to remove before parsing. - if operator == "==" and version.endswith(".*"): - version = version[:-2] - - # Parse the version, and if it is a pre-release than this - # specifier allows pre-releases. - if Version(version).is_prerelease: - return True - - return False - - @prereleases.setter - def prereleases(self, value: bool) -> None: - self._prereleases = value - - @property - def operator(self) -> str: - """The operator of this specifier. - - >>> Specifier("==1.2.3").operator - '==' - """ - return self._spec[0] - - @property - def version(self) -> str: - """The version of this specifier. - - >>> Specifier("==1.2.3").version - '1.2.3' - """ - return self._spec[1] - - def __repr__(self) -> str: - """A representation of the Specifier that shows all internal state. - - >>> Specifier('>=1.0.0') - =1.0.0')> - >>> Specifier('>=1.0.0', prereleases=False) - =1.0.0', prereleases=False)> - >>> Specifier('>=1.0.0', prereleases=True) - =1.0.0', prereleases=True)> - """ - pre = ( - f", prereleases={self.prereleases!r}" - if self._prereleases is not None - else "" - ) - - return f"<{self.__class__.__name__}({str(self)!r}{pre})>" - - def __str__(self) -> str: - """A string representation of the Specifier that can be round-tripped. - - >>> str(Specifier('>=1.0.0')) - '>=1.0.0' - >>> str(Specifier('>=1.0.0', prereleases=False)) - '>=1.0.0' - """ - return "{}{}".format(*self._spec) - - @property - def _canonical_spec(self) -> tuple[str, str]: - canonical_version = canonicalize_version( - self._spec[1], - strip_trailing_zero=(self._spec[0] != "~="), - ) - return self._spec[0], canonical_version - - def __hash__(self) -> int: - return hash(self._canonical_spec) - - def __eq__(self, other: object) -> bool: - """Whether or not the two Specifier-like objects are equal. - - :param other: The other object to check against. - - The value of :attr:`prereleases` is ignored. - - >>> Specifier("==1.2.3") == Specifier("== 1.2.3.0") - True - >>> (Specifier("==1.2.3", prereleases=False) == - ... Specifier("==1.2.3", prereleases=True)) - True - >>> Specifier("==1.2.3") == "==1.2.3" - True - >>> Specifier("==1.2.3") == Specifier("==1.2.4") - False - >>> Specifier("==1.2.3") == Specifier("~=1.2.3") - False - """ - if isinstance(other, str): - try: - other = self.__class__(str(other)) - except InvalidSpecifier: - return NotImplemented - elif not isinstance(other, self.__class__): - return NotImplemented - - return self._canonical_spec == other._canonical_spec - - def _get_operator(self, op: str) -> CallableOperator: - operator_callable: CallableOperator = getattr( - self, f"_compare_{self._operators[op]}" - ) - return operator_callable - - def _compare_compatible(self, prospective: Version, spec: str) -> bool: - # Compatible releases have an equivalent combination of >= and ==. That - # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to - # implement this in terms of the other specifiers instead of - # implementing it ourselves. The only thing we need to do is construct - # the other specifiers. - - # We want everything but the last item in the version, but we want to - # ignore suffix segments. - prefix = _version_join( - list(itertools.takewhile(_is_not_suffix, _version_split(spec)))[:-1] - ) - - # Add the prefix notation to the end of our string - prefix += ".*" - - return self._get_operator(">=")(prospective, spec) and self._get_operator("==")( - prospective, prefix - ) - - def _compare_equal(self, prospective: Version, spec: str) -> bool: - # We need special logic to handle prefix matching - if spec.endswith(".*"): - # In the case of prefix matching we want to ignore local segment. - normalized_prospective = canonicalize_version( - prospective.public, strip_trailing_zero=False - ) - # Get the normalized version string ignoring the trailing .* - normalized_spec = canonicalize_version(spec[:-2], strip_trailing_zero=False) - # Split the spec out by bangs and dots, and pretend that there is - # an implicit dot in between a release segment and a pre-release segment. - split_spec = _version_split(normalized_spec) - - # Split the prospective version out by bangs and dots, and pretend - # that there is an implicit dot in between a release segment and - # a pre-release segment. - split_prospective = _version_split(normalized_prospective) - - # 0-pad the prospective version before shortening it to get the correct - # shortened version. - padded_prospective, _ = _pad_version(split_prospective, split_spec) - - # Shorten the prospective version to be the same length as the spec - # so that we can determine if the specifier is a prefix of the - # prospective version or not. - shortened_prospective = padded_prospective[: len(split_spec)] - - return shortened_prospective == split_spec - else: - # Convert our spec string into a Version - spec_version = Version(spec) - - # If the specifier does not have a local segment, then we want to - # act as if the prospective version also does not have a local - # segment. - if not spec_version.local: - prospective = Version(prospective.public) - - return prospective == spec_version - - def _compare_not_equal(self, prospective: Version, spec: str) -> bool: - return not self._compare_equal(prospective, spec) - - def _compare_less_than_equal(self, prospective: Version, spec: str) -> bool: - # NB: Local version identifiers are NOT permitted in the version - # specifier, so local version labels can be universally removed from - # the prospective version. - return Version(prospective.public) <= Version(spec) - - def _compare_greater_than_equal(self, prospective: Version, spec: str) -> bool: - # NB: Local version identifiers are NOT permitted in the version - # specifier, so local version labels can be universally removed from - # the prospective version. - return Version(prospective.public) >= Version(spec) - - def _compare_less_than(self, prospective: Version, spec_str: str) -> bool: - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec_str) - - # Check to see if the prospective version is less than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective < spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a pre-release version, that we do not accept pre-release - # versions for the version mentioned in the specifier (e.g. <3.1 should - # not match 3.1.dev0, but should match 3.0.dev0). - if not spec.is_prerelease and prospective.is_prerelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # less than the spec version *and* it's not a pre-release of the same - # version in the spec. - return True - - def _compare_greater_than(self, prospective: Version, spec_str: str) -> bool: - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec_str) - - # Check to see if the prospective version is greater than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective > spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a post-release version, that we do not accept - # post-release versions for the version mentioned in the specifier - # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). - if not spec.is_postrelease and prospective.is_postrelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # Ensure that we do not allow a local version of the version mentioned - # in the specifier, which is technically greater than, to match. - if prospective.local is not None: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # greater than the spec version *and* it's not a pre-release of the - # same version in the spec. - return True - - def _compare_arbitrary(self, prospective: Version, spec: str) -> bool: - return str(prospective).lower() == str(spec).lower() - - def __contains__(self, item: str | Version) -> bool: - """Return whether or not the item is contained in this specifier. - - :param item: The item to check for. - - This is used for the ``in`` operator and behaves the same as - :meth:`contains` with no ``prereleases`` argument passed. - - >>> "1.2.3" in Specifier(">=1.2.3") - True - >>> Version("1.2.3") in Specifier(">=1.2.3") - True - >>> "1.0.0" in Specifier(">=1.2.3") - False - >>> "1.3.0a1" in Specifier(">=1.2.3") - False - >>> "1.3.0a1" in Specifier(">=1.2.3", prereleases=True) - True - """ - return self.contains(item) - - def contains(self, item: UnparsedVersion, prereleases: bool | None = None) -> bool: - """Return whether or not the item is contained in this specifier. - - :param item: - The item to check for, which can be a version string or a - :class:`Version` instance. - :param prereleases: - Whether or not to match prereleases with this Specifier. If set to - ``None`` (the default), it uses :attr:`prereleases` to determine - whether or not prereleases are allowed. - - >>> Specifier(">=1.2.3").contains("1.2.3") - True - >>> Specifier(">=1.2.3").contains(Version("1.2.3")) - True - >>> Specifier(">=1.2.3").contains("1.0.0") - False - >>> Specifier(">=1.2.3").contains("1.3.0a1") - False - >>> Specifier(">=1.2.3", prereleases=True).contains("1.3.0a1") - True - >>> Specifier(">=1.2.3").contains("1.3.0a1", prereleases=True) - True - """ - - # Determine if prereleases are to be allowed or not. - if prereleases is None: - prereleases = self.prereleases - - # Normalize item to a Version, this allows us to have a shortcut for - # "2.0" in Specifier(">=2") - normalized_item = _coerce_version(item) - - # Determine if we should be supporting prereleases in this specifier - # or not, if we do not support prereleases than we can short circuit - # logic if this version is a prereleases. - if normalized_item.is_prerelease and not prereleases: - return False - - # Actually do the comparison to determine if this item is contained - # within this Specifier or not. - operator_callable: CallableOperator = self._get_operator(self.operator) - return operator_callable(normalized_item, self.version) - - def filter( - self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None - ) -> Iterator[UnparsedVersionVar]: - """Filter items in the given iterable, that match the specifier. - - :param iterable: - An iterable that can contain version strings and :class:`Version` instances. - The items in the iterable will be filtered according to the specifier. - :param prereleases: - Whether or not to allow prereleases in the returned iterator. If set to - ``None`` (the default), it will be intelligently decide whether to allow - prereleases or not (based on the :attr:`prereleases` attribute, and - whether the only versions matching are prereleases). - - This method is smarter than just ``filter(Specifier().contains, [...])`` - because it implements the rule from :pep:`440` that a prerelease item - SHOULD be accepted if no other versions match the given specifier. - - >>> list(Specifier(">=1.2.3").filter(["1.2", "1.3", "1.5a1"])) - ['1.3'] - >>> list(Specifier(">=1.2.3").filter(["1.2", "1.2.3", "1.3", Version("1.4")])) - ['1.2.3', '1.3', ] - >>> list(Specifier(">=1.2.3").filter(["1.2", "1.5a1"])) - ['1.5a1'] - >>> list(Specifier(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True)) - ['1.3', '1.5a1'] - >>> list(Specifier(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"])) - ['1.3', '1.5a1'] - """ - - yielded = False - found_prereleases = [] - - kw = {"prereleases": prereleases if prereleases is not None else True} - - # Attempt to iterate over all the values in the iterable and if any of - # them match, yield them. - for version in iterable: - parsed_version = _coerce_version(version) - - if self.contains(parsed_version, **kw): - # If our version is a prerelease, and we were not set to allow - # prereleases, then we'll store it for later in case nothing - # else matches this specifier. - if parsed_version.is_prerelease and not ( - prereleases or self.prereleases - ): - found_prereleases.append(version) - # Either this is not a prerelease, or we should have been - # accepting prereleases from the beginning. - else: - yielded = True - yield version - - # Now that we've iterated over everything, determine if we've yielded - # any values, and if we have not and we have any prereleases stored up - # then we will go ahead and yield the prereleases. - if not yielded and found_prereleases: - for version in found_prereleases: - yield version - - -_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") - - -def _version_split(version: str) -> list[str]: - """Split version into components. - - The split components are intended for version comparison. The logic does - not attempt to retain the original version string, so joining the - components back with :func:`_version_join` may not produce the original - version string. - """ - result: list[str] = [] - - epoch, _, rest = version.rpartition("!") - result.append(epoch or "0") - - for item in rest.split("."): - match = _prefix_regex.search(item) - if match: - result.extend(match.groups()) - else: - result.append(item) - return result - - -def _version_join(components: list[str]) -> str: - """Join split version components into a version string. - - This function assumes the input came from :func:`_version_split`, where the - first component must be the epoch (either empty or numeric), and all other - components numeric. - """ - epoch, *rest = components - return f"{epoch}!{'.'.join(rest)}" - - -def _is_not_suffix(segment: str) -> bool: - return not any( - segment.startswith(prefix) for prefix in ("dev", "a", "b", "rc", "post") - ) - - -def _pad_version(left: list[str], right: list[str]) -> tuple[list[str], list[str]]: - left_split, right_split = [], [] - - # Get the release segment of our versions - left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) - right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) - - # Get the rest of our versions - left_split.append(left[len(left_split[0]) :]) - right_split.append(right[len(right_split[0]) :]) - - # Insert our padding - left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0]))) - right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0]))) - - return ( - list(itertools.chain.from_iterable(left_split)), - list(itertools.chain.from_iterable(right_split)), - ) - - -class SpecifierSet(BaseSpecifier): - """This class abstracts handling of a set of version specifiers. - - It can be passed a single specifier (``>=3.0``), a comma-separated list of - specifiers (``>=3.0,!=3.1``), or no specifier at all. - """ - - def __init__( - self, - specifiers: str | Iterable[Specifier] = "", - prereleases: bool | None = None, - ) -> None: - """Initialize a SpecifierSet instance. - - :param specifiers: - The string representation of a specifier or a comma-separated list of - specifiers which will be parsed and normalized before use. - May also be an iterable of ``Specifier`` instances, which will be used - as is. - :param prereleases: - This tells the SpecifierSet if it should accept prerelease versions if - applicable or not. The default of ``None`` will autodetect it from the - given specifiers. - - :raises InvalidSpecifier: - If the given ``specifiers`` are not parseable than this exception will be - raised. - """ - - if isinstance(specifiers, str): - # Split on `,` to break each individual specifier into its own item, and - # strip each item to remove leading/trailing whitespace. - split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] - - # Make each individual specifier a Specifier and save in a frozen set - # for later. - self._specs = frozenset(map(Specifier, split_specifiers)) - else: - # Save the supplied specifiers in a frozen set. - self._specs = frozenset(specifiers) - - # Store our prereleases value so we can use it later to determine if - # we accept prereleases or not. - self._prereleases = prereleases - - @property - def prereleases(self) -> bool | None: - # If we have been given an explicit prerelease modifier, then we'll - # pass that through here. - if self._prereleases is not None: - return self._prereleases - - # If we don't have any specifiers, and we don't have a forced value, - # then we'll just return None since we don't know if this should have - # pre-releases or not. - if not self._specs: - return None - - # Otherwise we'll see if any of the given specifiers accept - # prereleases, if any of them do we'll return True, otherwise False. - return any(s.prereleases for s in self._specs) - - @prereleases.setter - def prereleases(self, value: bool) -> None: - self._prereleases = value - - def __repr__(self) -> str: - """A representation of the specifier set that shows all internal state. - - Note that the ordering of the individual specifiers within the set may not - match the input string. - - >>> SpecifierSet('>=1.0.0,!=2.0.0') - =1.0.0')> - >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=False) - =1.0.0', prereleases=False)> - >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=True) - =1.0.0', prereleases=True)> - """ - pre = ( - f", prereleases={self.prereleases!r}" - if self._prereleases is not None - else "" - ) - - return f"" - - def __str__(self) -> str: - """A string representation of the specifier set that can be round-tripped. - - Note that the ordering of the individual specifiers within the set may not - match the input string. - - >>> str(SpecifierSet(">=1.0.0,!=1.0.1")) - '!=1.0.1,>=1.0.0' - >>> str(SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False)) - '!=1.0.1,>=1.0.0' - """ - return ",".join(sorted(str(s) for s in self._specs)) - - def __hash__(self) -> int: - return hash(self._specs) - - def __and__(self, other: SpecifierSet | str) -> SpecifierSet: - """Return a SpecifierSet which is a combination of the two sets. - - :param other: The other object to combine with. - - >>> SpecifierSet(">=1.0.0,!=1.0.1") & '<=2.0.0,!=2.0.1' - =1.0.0')> - >>> SpecifierSet(">=1.0.0,!=1.0.1") & SpecifierSet('<=2.0.0,!=2.0.1') - =1.0.0')> - """ - if isinstance(other, str): - other = SpecifierSet(other) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - specifier = SpecifierSet() - specifier._specs = frozenset(self._specs | other._specs) - - if self._prereleases is None and other._prereleases is not None: - specifier._prereleases = other._prereleases - elif self._prereleases is not None and other._prereleases is None: - specifier._prereleases = self._prereleases - elif self._prereleases == other._prereleases: - specifier._prereleases = self._prereleases - else: - raise ValueError( - "Cannot combine SpecifierSets with True and False prerelease overrides." - ) - - return specifier - - def __eq__(self, other: object) -> bool: - """Whether or not the two SpecifierSet-like objects are equal. - - :param other: The other object to check against. - - The value of :attr:`prereleases` is ignored. - - >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.1") - True - >>> (SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False) == - ... SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True)) - True - >>> SpecifierSet(">=1.0.0,!=1.0.1") == ">=1.0.0,!=1.0.1" - True - >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0") - False - >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.2") - False - """ - if isinstance(other, (str, Specifier)): - other = SpecifierSet(str(other)) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - return self._specs == other._specs - - def __len__(self) -> int: - """Returns the number of specifiers in this specifier set.""" - return len(self._specs) - - def __iter__(self) -> Iterator[Specifier]: - """ - Returns an iterator over all the underlying :class:`Specifier` instances - in this specifier set. - - >>> sorted(SpecifierSet(">=1.0.0,!=1.0.1"), key=str) - [, =1.0.0')>] - """ - return iter(self._specs) - - def __contains__(self, item: UnparsedVersion) -> bool: - """Return whether or not the item is contained in this specifier. - - :param item: The item to check for. - - This is used for the ``in`` operator and behaves the same as - :meth:`contains` with no ``prereleases`` argument passed. - - >>> "1.2.3" in SpecifierSet(">=1.0.0,!=1.0.1") - True - >>> Version("1.2.3") in SpecifierSet(">=1.0.0,!=1.0.1") - True - >>> "1.0.1" in SpecifierSet(">=1.0.0,!=1.0.1") - False - >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1") - False - >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True) - True - """ - return self.contains(item) - - def contains( - self, - item: UnparsedVersion, - prereleases: bool | None = None, - installed: bool | None = None, - ) -> bool: - """Return whether or not the item is contained in this SpecifierSet. - - :param item: - The item to check for, which can be a version string or a - :class:`Version` instance. - :param prereleases: - Whether or not to match prereleases with this SpecifierSet. If set to - ``None`` (the default), it uses :attr:`prereleases` to determine - whether or not prereleases are allowed. - - >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.2.3") - True - >>> SpecifierSet(">=1.0.0,!=1.0.1").contains(Version("1.2.3")) - True - >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.0.1") - False - >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1") - False - >>> SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True).contains("1.3.0a1") - True - >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1", prereleases=True) - True - """ - # Ensure that our item is a Version instance. - if not isinstance(item, Version): - item = Version(item) - - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # We can determine if we're going to allow pre-releases by looking to - # see if any of the underlying items supports them. If none of them do - # and this item is a pre-release then we do not allow it and we can - # short circuit that here. - # Note: This means that 1.0.dev1 would not be contained in something - # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 - if not prereleases and item.is_prerelease: - return False - - if installed and item.is_prerelease: - item = Version(item.base_version) - - # We simply dispatch to the underlying specs here to make sure that the - # given version is contained within all of them. - # Note: This use of all() here means that an empty set of specifiers - # will always return True, this is an explicit design decision. - return all(s.contains(item, prereleases=prereleases) for s in self._specs) - - def filter( - self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None - ) -> Iterator[UnparsedVersionVar]: - """Filter items in the given iterable, that match the specifiers in this set. - - :param iterable: - An iterable that can contain version strings and :class:`Version` instances. - The items in the iterable will be filtered according to the specifier. - :param prereleases: - Whether or not to allow prereleases in the returned iterator. If set to - ``None`` (the default), it will be intelligently decide whether to allow - prereleases or not (based on the :attr:`prereleases` attribute, and - whether the only versions matching are prereleases). - - This method is smarter than just ``filter(SpecifierSet(...).contains, [...])`` - because it implements the rule from :pep:`440` that a prerelease item - SHOULD be accepted if no other versions match the given specifier. - - >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", "1.5a1"])) - ['1.3'] - >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", Version("1.4")])) - ['1.3', ] - >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.5a1"])) - [] - >>> list(SpecifierSet(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True)) - ['1.3', '1.5a1'] - >>> list(SpecifierSet(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"])) - ['1.3', '1.5a1'] - - An "empty" SpecifierSet will filter items based on the presence of prerelease - versions in the set. - - >>> list(SpecifierSet("").filter(["1.3", "1.5a1"])) - ['1.3'] - >>> list(SpecifierSet("").filter(["1.5a1"])) - ['1.5a1'] - >>> list(SpecifierSet("", prereleases=True).filter(["1.3", "1.5a1"])) - ['1.3', '1.5a1'] - >>> list(SpecifierSet("").filter(["1.3", "1.5a1"], prereleases=True)) - ['1.3', '1.5a1'] - """ - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # If we have any specifiers, then we want to wrap our iterable in the - # filter method for each one, this will act as a logical AND amongst - # each specifier. - if self._specs: - for spec in self._specs: - iterable = spec.filter(iterable, prereleases=bool(prereleases)) - return iter(iterable) - # If we do not have any specifiers, then we need to have a rough filter - # which will filter out any pre-releases, unless there are no final - # releases. - else: - filtered: list[UnparsedVersionVar] = [] - found_prereleases: list[UnparsedVersionVar] = [] - - for item in iterable: - parsed_version = _coerce_version(item) - - # Store any item which is a pre-release for later unless we've - # already found a final version or we are accepting prereleases - if parsed_version.is_prerelease and not prereleases: - if not filtered: - found_prereleases.append(item) - else: - filtered.append(item) - - # If we've found no items except for pre-releases, then we'll go - # ahead and use the pre-releases - if not filtered and found_prereleases and prereleases is None: - return iter(found_prereleases) - - return iter(filtered) diff --git a/server/libs/packaging/tags.py b/server/libs/packaging/tags.py deleted file mode 100644 index 8522f59..0000000 --- a/server/libs/packaging/tags.py +++ /dev/null @@ -1,656 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import logging -import platform -import re -import struct -import subprocess -import sys -import sysconfig -from importlib.machinery import EXTENSION_SUFFIXES -from typing import ( - Iterable, - Iterator, - Sequence, - Tuple, - cast, -) - -from . import _manylinux, _musllinux - -logger = logging.getLogger(__name__) - -PythonVersion = Sequence[int] -AppleVersion = Tuple[int, int] - -INTERPRETER_SHORT_NAMES: dict[str, str] = { - "python": "py", # Generic. - "cpython": "cp", - "pypy": "pp", - "ironpython": "ip", - "jython": "jy", -} - - -_32_BIT_INTERPRETER = struct.calcsize("P") == 4 - - -class Tag: - """ - A representation of the tag triple for a wheel. - - Instances are considered immutable and thus are hashable. Equality checking - is also supported. - """ - - __slots__ = ["_abi", "_hash", "_interpreter", "_platform"] - - def __init__(self, interpreter: str, abi: str, platform: str) -> None: - self._interpreter = interpreter.lower() - self._abi = abi.lower() - self._platform = platform.lower() - # The __hash__ of every single element in a Set[Tag] will be evaluated each time - # that a set calls its `.disjoint()` method, which may be called hundreds of - # times when scanning a page of links for packages with tags matching that - # Set[Tag]. Pre-computing the value here produces significant speedups for - # downstream consumers. - self._hash = hash((self._interpreter, self._abi, self._platform)) - - @property - def interpreter(self) -> str: - return self._interpreter - - @property - def abi(self) -> str: - return self._abi - - @property - def platform(self) -> str: - return self._platform - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Tag): - return NotImplemented - - return ( - (self._hash == other._hash) # Short-circuit ASAP for perf reasons. - and (self._platform == other._platform) - and (self._abi == other._abi) - and (self._interpreter == other._interpreter) - ) - - def __hash__(self) -> int: - return self._hash - - def __str__(self) -> str: - return f"{self._interpreter}-{self._abi}-{self._platform}" - - def __repr__(self) -> str: - return f"<{self} @ {id(self)}>" - - -def parse_tag(tag: str) -> frozenset[Tag]: - """ - Parses the provided tag (e.g. `py3-none-any`) into a frozenset of Tag instances. - - Returning a set is required due to the possibility that the tag is a - compressed tag set. - """ - tags = set() - interpreters, abis, platforms = tag.split("-") - for interpreter in interpreters.split("."): - for abi in abis.split("."): - for platform_ in platforms.split("."): - tags.add(Tag(interpreter, abi, platform_)) - return frozenset(tags) - - -def _get_config_var(name: str, warn: bool = False) -> int | str | None: - value: int | str | None = sysconfig.get_config_var(name) - if value is None and warn: - logger.debug( - "Config variable '%s' is unset, Python ABI tag may be incorrect", name - ) - return value - - -def _normalize_string(string: str) -> str: - return string.replace(".", "_").replace("-", "_").replace(" ", "_") - - -def _is_threaded_cpython(abis: list[str]) -> bool: - """ - Determine if the ABI corresponds to a threaded (`--disable-gil`) build. - - The threaded builds are indicated by a "t" in the abiflags. - """ - if len(abis) == 0: - return False - # expect e.g., cp313 - m = re.match(r"cp\d+(.*)", abis[0]) - if not m: - return False - abiflags = m.group(1) - return "t" in abiflags - - -def _abi3_applies(python_version: PythonVersion, threading: bool) -> bool: - """ - Determine if the Python version supports abi3. - - PEP 384 was first implemented in Python 3.2. The threaded (`--disable-gil`) - builds do not support abi3. - """ - return len(python_version) > 1 and tuple(python_version) >= (3, 2) and not threading - - -def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> list[str]: - py_version = tuple(py_version) # To allow for version comparison. - abis = [] - version = _version_nodot(py_version[:2]) - threading = debug = pymalloc = ucs4 = "" - with_debug = _get_config_var("Py_DEBUG", warn) - has_refcount = hasattr(sys, "gettotalrefcount") - # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled - # extension modules is the best option. - # https://github.com/pypa/pip/issues/3383#issuecomment-173267692 - has_ext = "_d.pyd" in EXTENSION_SUFFIXES - if with_debug or (with_debug is None and (has_refcount or has_ext)): - debug = "d" - if py_version >= (3, 13) and _get_config_var("Py_GIL_DISABLED", warn): - threading = "t" - if py_version < (3, 8): - with_pymalloc = _get_config_var("WITH_PYMALLOC", warn) - if with_pymalloc or with_pymalloc is None: - pymalloc = "m" - if py_version < (3, 3): - unicode_size = _get_config_var("Py_UNICODE_SIZE", warn) - if unicode_size == 4 or ( - unicode_size is None and sys.maxunicode == 0x10FFFF - ): - ucs4 = "u" - elif debug: - # Debug builds can also load "normal" extension modules. - # We can also assume no UCS-4 or pymalloc requirement. - abis.append(f"cp{version}{threading}") - abis.insert(0, f"cp{version}{threading}{debug}{pymalloc}{ucs4}") - return abis - - -def cpython_tags( - python_version: PythonVersion | None = None, - abis: Iterable[str] | None = None, - platforms: Iterable[str] | None = None, - *, - warn: bool = False, -) -> Iterator[Tag]: - """ - Yields the tags for a CPython interpreter. - - The tags consist of: - - cp-- - - cp-abi3- - - cp-none- - - cp-abi3- # Older Python versions down to 3.2. - - If python_version only specifies a major version then user-provided ABIs and - the 'none' ABItag will be used. - - If 'abi3' or 'none' are specified in 'abis' then they will be yielded at - their normal position and not at the beginning. - """ - if not python_version: - python_version = sys.version_info[:2] - - interpreter = f"cp{_version_nodot(python_version[:2])}" - - if abis is None: - if len(python_version) > 1: - abis = _cpython_abis(python_version, warn) - else: - abis = [] - abis = list(abis) - # 'abi3' and 'none' are explicitly handled later. - for explicit_abi in ("abi3", "none"): - try: - abis.remove(explicit_abi) - except ValueError: - pass - - platforms = list(platforms or platform_tags()) - for abi in abis: - for platform_ in platforms: - yield Tag(interpreter, abi, platform_) - - threading = _is_threaded_cpython(abis) - use_abi3 = _abi3_applies(python_version, threading) - if use_abi3: - yield from (Tag(interpreter, "abi3", platform_) for platform_ in platforms) - yield from (Tag(interpreter, "none", platform_) for platform_ in platforms) - - if use_abi3: - for minor_version in range(python_version[1] - 1, 1, -1): - for platform_ in platforms: - version = _version_nodot((python_version[0], minor_version)) - interpreter = f"cp{version}" - yield Tag(interpreter, "abi3", platform_) - - -def _generic_abi() -> list[str]: - """ - Return the ABI tag based on EXT_SUFFIX. - """ - # The following are examples of `EXT_SUFFIX`. - # We want to keep the parts which are related to the ABI and remove the - # parts which are related to the platform: - # - linux: '.cpython-310-x86_64-linux-gnu.so' => cp310 - # - mac: '.cpython-310-darwin.so' => cp310 - # - win: '.cp310-win_amd64.pyd' => cp310 - # - win: '.pyd' => cp37 (uses _cpython_abis()) - # - pypy: '.pypy38-pp73-x86_64-linux-gnu.so' => pypy38_pp73 - # - graalpy: '.graalpy-38-native-x86_64-darwin.dylib' - # => graalpy_38_native - - ext_suffix = _get_config_var("EXT_SUFFIX", warn=True) - if not isinstance(ext_suffix, str) or ext_suffix[0] != ".": - raise SystemError("invalid sysconfig.get_config_var('EXT_SUFFIX')") - parts = ext_suffix.split(".") - if len(parts) < 3: - # CPython3.7 and earlier uses ".pyd" on Windows. - return _cpython_abis(sys.version_info[:2]) - soabi = parts[1] - if soabi.startswith("cpython"): - # non-windows - abi = "cp" + soabi.split("-")[1] - elif soabi.startswith("cp"): - # windows - abi = soabi.split("-")[0] - elif soabi.startswith("pypy"): - abi = "-".join(soabi.split("-")[:2]) - elif soabi.startswith("graalpy"): - abi = "-".join(soabi.split("-")[:3]) - elif soabi: - # pyston, ironpython, others? - abi = soabi - else: - return [] - return [_normalize_string(abi)] - - -def generic_tags( - interpreter: str | None = None, - abis: Iterable[str] | None = None, - platforms: Iterable[str] | None = None, - *, - warn: bool = False, -) -> Iterator[Tag]: - """ - Yields the tags for a generic interpreter. - - The tags consist of: - - -- - - The "none" ABI will be added if it was not explicitly provided. - """ - if not interpreter: - interp_name = interpreter_name() - interp_version = interpreter_version(warn=warn) - interpreter = "".join([interp_name, interp_version]) - if abis is None: - abis = _generic_abi() - else: - abis = list(abis) - platforms = list(platforms or platform_tags()) - if "none" not in abis: - abis.append("none") - for abi in abis: - for platform_ in platforms: - yield Tag(interpreter, abi, platform_) - - -def _py_interpreter_range(py_version: PythonVersion) -> Iterator[str]: - """ - Yields Python versions in descending order. - - After the latest version, the major-only version will be yielded, and then - all previous versions of that major version. - """ - if len(py_version) > 1: - yield f"py{_version_nodot(py_version[:2])}" - yield f"py{py_version[0]}" - if len(py_version) > 1: - for minor in range(py_version[1] - 1, -1, -1): - yield f"py{_version_nodot((py_version[0], minor))}" - - -def compatible_tags( - python_version: PythonVersion | None = None, - interpreter: str | None = None, - platforms: Iterable[str] | None = None, -) -> Iterator[Tag]: - """ - Yields the sequence of tags that are compatible with a specific version of Python. - - The tags consist of: - - py*-none- - - -none-any # ... if `interpreter` is provided. - - py*-none-any - """ - if not python_version: - python_version = sys.version_info[:2] - platforms = list(platforms or platform_tags()) - for version in _py_interpreter_range(python_version): - for platform_ in platforms: - yield Tag(version, "none", platform_) - if interpreter: - yield Tag(interpreter, "none", "any") - for version in _py_interpreter_range(python_version): - yield Tag(version, "none", "any") - - -def _mac_arch(arch: str, is_32bit: bool = _32_BIT_INTERPRETER) -> str: - if not is_32bit: - return arch - - if arch.startswith("ppc"): - return "ppc" - - return "i386" - - -def _mac_binary_formats(version: AppleVersion, cpu_arch: str) -> list[str]: - formats = [cpu_arch] - if cpu_arch == "x86_64": - if version < (10, 4): - return [] - formats.extend(["intel", "fat64", "fat32"]) - - elif cpu_arch == "i386": - if version < (10, 4): - return [] - formats.extend(["intel", "fat32", "fat"]) - - elif cpu_arch == "ppc64": - # TODO: Need to care about 32-bit PPC for ppc64 through 10.2? - if version > (10, 5) or version < (10, 4): - return [] - formats.append("fat64") - - elif cpu_arch == "ppc": - if version > (10, 6): - return [] - formats.extend(["fat32", "fat"]) - - if cpu_arch in {"arm64", "x86_64"}: - formats.append("universal2") - - if cpu_arch in {"x86_64", "i386", "ppc64", "ppc", "intel"}: - formats.append("universal") - - return formats - - -def mac_platforms( - version: AppleVersion | None = None, arch: str | None = None -) -> Iterator[str]: - """ - Yields the platform tags for a macOS system. - - The `version` parameter is a two-item tuple specifying the macOS version to - generate platform tags for. The `arch` parameter is the CPU architecture to - generate platform tags for. Both parameters default to the appropriate value - for the current system. - """ - version_str, _, cpu_arch = platform.mac_ver() - if version is None: - version = cast("AppleVersion", tuple(map(int, version_str.split(".")[:2]))) - if version == (10, 16): - # When built against an older macOS SDK, Python will report macOS 10.16 - # instead of the real version. - version_str = subprocess.run( - [ - sys.executable, - "-sS", - "-c", - "import platform; print(platform.mac_ver()[0])", - ], - check=True, - env={"SYSTEM_VERSION_COMPAT": "0"}, - stdout=subprocess.PIPE, - text=True, - ).stdout - version = cast("AppleVersion", tuple(map(int, version_str.split(".")[:2]))) - else: - version = version - if arch is None: - arch = _mac_arch(cpu_arch) - else: - arch = arch - - if (10, 0) <= version and version < (11, 0): - # Prior to Mac OS 11, each yearly release of Mac OS bumped the - # "minor" version number. The major version was always 10. - major_version = 10 - for minor_version in range(version[1], -1, -1): - compat_version = major_version, minor_version - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield f"macosx_{major_version}_{minor_version}_{binary_format}" - - if version >= (11, 0): - # Starting with Mac OS 11, each yearly release bumps the major version - # number. The minor versions are now the midyear updates. - minor_version = 0 - for major_version in range(version[0], 10, -1): - compat_version = major_version, minor_version - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield f"macosx_{major_version}_{minor_version}_{binary_format}" - - if version >= (11, 0): - # Mac OS 11 on x86_64 is compatible with binaries from previous releases. - # Arm64 support was introduced in 11.0, so no Arm binaries from previous - # releases exist. - # - # However, the "universal2" binary format can have a - # macOS version earlier than 11.0 when the x86_64 part of the binary supports - # that version of macOS. - major_version = 10 - if arch == "x86_64": - for minor_version in range(16, 3, -1): - compat_version = major_version, minor_version - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield f"macosx_{major_version}_{minor_version}_{binary_format}" - else: - for minor_version in range(16, 3, -1): - compat_version = major_version, minor_version - binary_format = "universal2" - yield f"macosx_{major_version}_{minor_version}_{binary_format}" - - -def ios_platforms( - version: AppleVersion | None = None, multiarch: str | None = None -) -> Iterator[str]: - """ - Yields the platform tags for an iOS system. - - :param version: A two-item tuple specifying the iOS version to generate - platform tags for. Defaults to the current iOS version. - :param multiarch: The CPU architecture+ABI to generate platform tags for - - (the value used by `sys.implementation._multiarch` e.g., - `arm64_iphoneos` or `x84_64_iphonesimulator`). Defaults to the current - multiarch value. - """ - if version is None: - # if iOS is the current platform, ios_ver *must* be defined. However, - # it won't exist for CPython versions before 3.13, which causes a mypy - # error. - _, release, _, _ = platform.ios_ver() # type: ignore[attr-defined, unused-ignore] - version = cast("AppleVersion", tuple(map(int, release.split(".")[:2]))) - - if multiarch is None: - multiarch = sys.implementation._multiarch - multiarch = multiarch.replace("-", "_") - - ios_platform_template = "ios_{major}_{minor}_{multiarch}" - - # Consider any iOS major.minor version from the version requested, down to - # 12.0. 12.0 is the first iOS version that is known to have enough features - # to support CPython. Consider every possible minor release up to X.9. There - # highest the minor has ever gone is 8 (14.8 and 15.8) but having some extra - # candidates that won't ever match doesn't really hurt, and it saves us from - # having to keep an explicit list of known iOS versions in the code. Return - # the results descending order of version number. - - # If the requested major version is less than 12, there won't be any matches. - if version[0] < 12: - return - - # Consider the actual X.Y version that was requested. - yield ios_platform_template.format( - major=version[0], minor=version[1], multiarch=multiarch - ) - - # Consider every minor version from X.0 to the minor version prior to the - # version requested by the platform. - for minor in range(version[1] - 1, -1, -1): - yield ios_platform_template.format( - major=version[0], minor=minor, multiarch=multiarch - ) - - for major in range(version[0] - 1, 11, -1): - for minor in range(9, -1, -1): - yield ios_platform_template.format( - major=major, minor=minor, multiarch=multiarch - ) - - -def android_platforms( - api_level: int | None = None, abi: str | None = None -) -> Iterator[str]: - """ - Yields the :attr:`~Tag.platform` tags for Android. If this function is invoked on - non-Android platforms, the ``api_level`` and ``abi`` arguments are required. - - :param int api_level: The maximum `API level - `__ to return. Defaults - to the current system's version, as returned by ``platform.android_ver``. - :param str abi: The `Android ABI `__, - e.g. ``arm64_v8a``. Defaults to the current system's ABI , as returned by - ``sysconfig.get_platform``. Hyphens and periods will be replaced with - underscores. - """ - if platform.system() != "Android" and (api_level is None or abi is None): - raise TypeError( - "on non-Android platforms, the api_level and abi arguments are required" - ) - - if api_level is None: - # Python 3.13 was the first version to return platform.system() == "Android", - # and also the first version to define platform.android_ver(). - api_level = platform.android_ver().api_level # type: ignore[attr-defined] - - if abi is None: - abi = sysconfig.get_platform().split("-")[-1] - abi = _normalize_string(abi) - - # 16 is the minimum API level known to have enough features to support CPython - # without major patching. Yield every API level from the maximum down to the - # minimum, inclusive. - min_api_level = 16 - for ver in range(api_level, min_api_level - 1, -1): - yield f"android_{ver}_{abi}" - - -def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]: - linux = _normalize_string(sysconfig.get_platform()) - if not linux.startswith("linux_"): - # we should never be here, just yield the sysconfig one and return - yield linux - return - if is_32bit: - if linux == "linux_x86_64": - linux = "linux_i686" - elif linux == "linux_aarch64": - linux = "linux_armv8l" - _, arch = linux.split("_", 1) - archs = {"armv8l": ["armv8l", "armv7l"]}.get(arch, [arch]) - yield from _manylinux.platform_tags(archs) - yield from _musllinux.platform_tags(archs) - for arch in archs: - yield f"linux_{arch}" - - -def _generic_platforms() -> Iterator[str]: - yield _normalize_string(sysconfig.get_platform()) - - -def platform_tags() -> Iterator[str]: - """ - Provides the platform tags for this installation. - """ - if platform.system() == "Darwin": - return mac_platforms() - elif platform.system() == "iOS": - return ios_platforms() - elif platform.system() == "Android": - return android_platforms() - elif platform.system() == "Linux": - return _linux_platforms() - else: - return _generic_platforms() - - -def interpreter_name() -> str: - """ - Returns the name of the running interpreter. - - Some implementations have a reserved, two-letter abbreviation which will - be returned when appropriate. - """ - name = sys.implementation.name - return INTERPRETER_SHORT_NAMES.get(name) or name - - -def interpreter_version(*, warn: bool = False) -> str: - """ - Returns the version of the running interpreter. - """ - version = _get_config_var("py_version_nodot", warn=warn) - if version: - version = str(version) - else: - version = _version_nodot(sys.version_info[:2]) - return version - - -def _version_nodot(version: PythonVersion) -> str: - return "".join(map(str, version)) - - -def sys_tags(*, warn: bool = False) -> Iterator[Tag]: - """ - Returns the sequence of tag triples for the running interpreter. - - The order of the sequence corresponds to priority order for the - interpreter, from most to least important. - """ - - interp_name = interpreter_name() - if interp_name == "cp": - yield from cpython_tags(warn=warn) - else: - yield from generic_tags() - - if interp_name == "pp": - interp = "pp3" - elif interp_name == "cp": - interp = "cp" + interpreter_version(warn=warn) - else: - interp = None - yield from compatible_tags(interpreter=interp) diff --git a/server/libs/packaging/utils.py b/server/libs/packaging/utils.py deleted file mode 100644 index 2345095..0000000 --- a/server/libs/packaging/utils.py +++ /dev/null @@ -1,163 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import functools -import re -from typing import NewType, Tuple, Union, cast - -from .tags import Tag, parse_tag -from .version import InvalidVersion, Version, _TrimmedRelease - -BuildTag = Union[Tuple[()], Tuple[int, str]] -NormalizedName = NewType("NormalizedName", str) - - -class InvalidName(ValueError): - """ - An invalid distribution name; users should refer to the packaging user guide. - """ - - -class InvalidWheelFilename(ValueError): - """ - An invalid wheel filename was found, users should refer to PEP 427. - """ - - -class InvalidSdistFilename(ValueError): - """ - An invalid sdist filename was found, users should refer to the packaging user guide. - """ - - -# Core metadata spec for `Name` -_validate_regex = re.compile( - r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", re.IGNORECASE -) -_canonicalize_regex = re.compile(r"[-_.]+") -_normalized_regex = re.compile(r"^([a-z0-9]|[a-z0-9]([a-z0-9-](?!--))*[a-z0-9])$") -# PEP 427: The build number must start with a digit. -_build_tag_regex = re.compile(r"(\d+)(.*)") - - -def canonicalize_name(name: str, *, validate: bool = False) -> NormalizedName: - if validate and not _validate_regex.match(name): - raise InvalidName(f"name is invalid: {name!r}") - # This is taken from PEP 503. - value = _canonicalize_regex.sub("-", name).lower() - return cast(NormalizedName, value) - - -def is_normalized_name(name: str) -> bool: - return _normalized_regex.match(name) is not None - - -@functools.singledispatch -def canonicalize_version( - version: Version | str, *, strip_trailing_zero: bool = True -) -> str: - """ - Return a canonical form of a version as a string. - - >>> canonicalize_version('1.0.1') - '1.0.1' - - Per PEP 625, versions may have multiple canonical forms, differing - only by trailing zeros. - - >>> canonicalize_version('1.0.0') - '1' - >>> canonicalize_version('1.0.0', strip_trailing_zero=False) - '1.0.0' - - Invalid versions are returned unaltered. - - >>> canonicalize_version('foo bar baz') - 'foo bar baz' - """ - return str(_TrimmedRelease(str(version)) if strip_trailing_zero else version) - - -@canonicalize_version.register -def _(version: str, *, strip_trailing_zero: bool = True) -> str: - try: - parsed = Version(version) - except InvalidVersion: - # Legacy versions cannot be normalized - return version - return canonicalize_version(parsed, strip_trailing_zero=strip_trailing_zero) - - -def parse_wheel_filename( - filename: str, -) -> tuple[NormalizedName, Version, BuildTag, frozenset[Tag]]: - if not filename.endswith(".whl"): - raise InvalidWheelFilename( - f"Invalid wheel filename (extension must be '.whl'): {filename!r}" - ) - - filename = filename[:-4] - dashes = filename.count("-") - if dashes not in (4, 5): - raise InvalidWheelFilename( - f"Invalid wheel filename (wrong number of parts): {filename!r}" - ) - - parts = filename.split("-", dashes - 2) - name_part = parts[0] - # See PEP 427 for the rules on escaping the project name. - if "__" in name_part or re.match(r"^[\w\d._]*$", name_part, re.UNICODE) is None: - raise InvalidWheelFilename(f"Invalid project name: {filename!r}") - name = canonicalize_name(name_part) - - try: - version = Version(parts[1]) - except InvalidVersion as e: - raise InvalidWheelFilename( - f"Invalid wheel filename (invalid version): {filename!r}" - ) from e - - if dashes == 5: - build_part = parts[2] - build_match = _build_tag_regex.match(build_part) - if build_match is None: - raise InvalidWheelFilename( - f"Invalid build number: {build_part} in {filename!r}" - ) - build = cast(BuildTag, (int(build_match.group(1)), build_match.group(2))) - else: - build = () - tags = parse_tag(parts[-1]) - return (name, version, build, tags) - - -def parse_sdist_filename(filename: str) -> tuple[NormalizedName, Version]: - if filename.endswith(".tar.gz"): - file_stem = filename[: -len(".tar.gz")] - elif filename.endswith(".zip"): - file_stem = filename[: -len(".zip")] - else: - raise InvalidSdistFilename( - f"Invalid sdist filename (extension must be '.tar.gz' or '.zip'):" - f" {filename!r}" - ) - - # We are requiring a PEP 440 version, which cannot contain dashes, - # so we split on the last dash. - name_part, sep, version_part = file_stem.rpartition("-") - if not sep: - raise InvalidSdistFilename(f"Invalid sdist filename: {filename!r}") - - name = canonicalize_name(name_part) - - try: - version = Version(version_part) - except InvalidVersion as e: - raise InvalidSdistFilename( - f"Invalid sdist filename (invalid version): {filename!r}" - ) from e - - return (name, version) diff --git a/server/libs/packaging/version.py b/server/libs/packaging/version.py deleted file mode 100644 index c9bbda2..0000000 --- a/server/libs/packaging/version.py +++ /dev/null @@ -1,582 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. -""" -.. testsetup:: - - from packaging.version import parse, Version -""" - -from __future__ import annotations - -import itertools -import re -from typing import Any, Callable, NamedTuple, SupportsInt, Tuple, Union - -from ._structures import Infinity, InfinityType, NegativeInfinity, NegativeInfinityType - -__all__ = ["VERSION_PATTERN", "InvalidVersion", "Version", "parse"] - -LocalType = Tuple[Union[int, str], ...] - -CmpPrePostDevType = Union[InfinityType, NegativeInfinityType, Tuple[str, int]] -CmpLocalType = Union[ - NegativeInfinityType, - Tuple[Union[Tuple[int, str], Tuple[NegativeInfinityType, Union[int, str]]], ...], -] -CmpKey = Tuple[ - int, - Tuple[int, ...], - CmpPrePostDevType, - CmpPrePostDevType, - CmpPrePostDevType, - CmpLocalType, -] -VersionComparisonMethod = Callable[[CmpKey, CmpKey], bool] - - -class _Version(NamedTuple): - epoch: int - release: tuple[int, ...] - dev: tuple[str, int] | None - pre: tuple[str, int] | None - post: tuple[str, int] | None - local: LocalType | None - - -def parse(version: str) -> Version: - """Parse the given version string. - - >>> parse('1.0.dev1') - - - :param version: The version string to parse. - :raises InvalidVersion: When the version string is not a valid version. - """ - return Version(version) - - -class InvalidVersion(ValueError): - """Raised when a version string is not a valid version. - - >>> Version("invalid") - Traceback (most recent call last): - ... - packaging.version.InvalidVersion: Invalid version: 'invalid' - """ - - -class _BaseVersion: - _key: tuple[Any, ...] - - def __hash__(self) -> int: - return hash(self._key) - - # Please keep the duplicated `isinstance` check - # in the six comparisons hereunder - # unless you find a way to avoid adding overhead function calls. - def __lt__(self, other: _BaseVersion) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key < other._key - - def __le__(self, other: _BaseVersion) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key <= other._key - - def __eq__(self, other: object) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key == other._key - - def __ge__(self, other: _BaseVersion) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key >= other._key - - def __gt__(self, other: _BaseVersion) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key > other._key - - def __ne__(self, other: object) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key != other._key - - -# Deliberately not anchored to the start and end of the string, to make it -# easier for 3rd party code to reuse -_VERSION_PATTERN = r""" - v? - (?: - (?:(?P[0-9]+)!)? # epoch - (?P[0-9]+(?:\.[0-9]+)*) # release segment - (?P
                                          # pre-release
-            [-_\.]?
-            (?Palpha|a|beta|b|preview|pre|c|rc)
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-        (?P                                         # post release
-            (?:-(?P[0-9]+))
-            |
-            (?:
-                [-_\.]?
-                (?Ppost|rev|r)
-                [-_\.]?
-                (?P[0-9]+)?
-            )
-        )?
-        (?P                                          # dev release
-            [-_\.]?
-            (?Pdev)
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-    )
-    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
-"""
-
-VERSION_PATTERN = _VERSION_PATTERN
-"""
-A string containing the regular expression used to match a valid version.
-
-The pattern is not anchored at either end, and is intended for embedding in larger
-expressions (for example, matching a version number as part of a file name). The
-regular expression should be compiled with the ``re.VERBOSE`` and ``re.IGNORECASE``
-flags set.
-
-:meta hide-value:
-"""
-
-
-class Version(_BaseVersion):
-    """This class abstracts handling of a project's versions.
-
-    A :class:`Version` instance is comparison aware and can be compared and
-    sorted using the standard Python interfaces.
-
-    >>> v1 = Version("1.0a5")
-    >>> v2 = Version("1.0")
-    >>> v1
-    
-    >>> v2
-    
-    >>> v1 < v2
-    True
-    >>> v1 == v2
-    False
-    >>> v1 > v2
-    False
-    >>> v1 >= v2
-    False
-    >>> v1 <= v2
-    True
-    """
-
-    _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
-    _key: CmpKey
-
-    def __init__(self, version: str) -> None:
-        """Initialize a Version object.
-
-        :param version:
-            The string representation of a version which will be parsed and normalized
-            before use.
-        :raises InvalidVersion:
-            If the ``version`` does not conform to PEP 440 in any way then this
-            exception will be raised.
-        """
-
-        # Validate the version and parse it into pieces
-        match = self._regex.search(version)
-        if not match:
-            raise InvalidVersion(f"Invalid version: {version!r}")
-
-        # Store the parsed out pieces of the version
-        self._version = _Version(
-            epoch=int(match.group("epoch")) if match.group("epoch") else 0,
-            release=tuple(int(i) for i in match.group("release").split(".")),
-            pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
-            post=_parse_letter_version(
-                match.group("post_l"), match.group("post_n1") or match.group("post_n2")
-            ),
-            dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
-            local=_parse_local_version(match.group("local")),
-        )
-
-        # Generate a key which will be used for sorting
-        self._key = _cmpkey(
-            self._version.epoch,
-            self._version.release,
-            self._version.pre,
-            self._version.post,
-            self._version.dev,
-            self._version.local,
-        )
-
-    def __repr__(self) -> str:
-        """A representation of the Version that shows all internal state.
-
-        >>> Version('1.0.0')
-        
-        """
-        return f""
-
-    def __str__(self) -> str:
-        """A string representation of the version that can be round-tripped.
-
-        >>> str(Version("1.0a5"))
-        '1.0a5'
-        """
-        parts = []
-
-        # Epoch
-        if self.epoch != 0:
-            parts.append(f"{self.epoch}!")
-
-        # Release segment
-        parts.append(".".join(str(x) for x in self.release))
-
-        # Pre-release
-        if self.pre is not None:
-            parts.append("".join(str(x) for x in self.pre))
-
-        # Post-release
-        if self.post is not None:
-            parts.append(f".post{self.post}")
-
-        # Development release
-        if self.dev is not None:
-            parts.append(f".dev{self.dev}")
-
-        # Local version segment
-        if self.local is not None:
-            parts.append(f"+{self.local}")
-
-        return "".join(parts)
-
-    @property
-    def epoch(self) -> int:
-        """The epoch of the version.
-
-        >>> Version("2.0.0").epoch
-        0
-        >>> Version("1!2.0.0").epoch
-        1
-        """
-        return self._version.epoch
-
-    @property
-    def release(self) -> tuple[int, ...]:
-        """The components of the "release" segment of the version.
-
-        >>> Version("1.2.3").release
-        (1, 2, 3)
-        >>> Version("2.0.0").release
-        (2, 0, 0)
-        >>> Version("1!2.0.0.post0").release
-        (2, 0, 0)
-
-        Includes trailing zeroes but not the epoch or any pre-release / development /
-        post-release suffixes.
-        """
-        return self._version.release
-
-    @property
-    def pre(self) -> tuple[str, int] | None:
-        """The pre-release segment of the version.
-
-        >>> print(Version("1.2.3").pre)
-        None
-        >>> Version("1.2.3a1").pre
-        ('a', 1)
-        >>> Version("1.2.3b1").pre
-        ('b', 1)
-        >>> Version("1.2.3rc1").pre
-        ('rc', 1)
-        """
-        return self._version.pre
-
-    @property
-    def post(self) -> int | None:
-        """The post-release number of the version.
-
-        >>> print(Version("1.2.3").post)
-        None
-        >>> Version("1.2.3.post1").post
-        1
-        """
-        return self._version.post[1] if self._version.post else None
-
-    @property
-    def dev(self) -> int | None:
-        """The development number of the version.
-
-        >>> print(Version("1.2.3").dev)
-        None
-        >>> Version("1.2.3.dev1").dev
-        1
-        """
-        return self._version.dev[1] if self._version.dev else None
-
-    @property
-    def local(self) -> str | None:
-        """The local version segment of the version.
-
-        >>> print(Version("1.2.3").local)
-        None
-        >>> Version("1.2.3+abc").local
-        'abc'
-        """
-        if self._version.local:
-            return ".".join(str(x) for x in self._version.local)
-        else:
-            return None
-
-    @property
-    def public(self) -> str:
-        """The public portion of the version.
-
-        >>> Version("1.2.3").public
-        '1.2.3'
-        >>> Version("1.2.3+abc").public
-        '1.2.3'
-        >>> Version("1!1.2.3dev1+abc").public
-        '1!1.2.3.dev1'
-        """
-        return str(self).split("+", 1)[0]
-
-    @property
-    def base_version(self) -> str:
-        """The "base version" of the version.
-
-        >>> Version("1.2.3").base_version
-        '1.2.3'
-        >>> Version("1.2.3+abc").base_version
-        '1.2.3'
-        >>> Version("1!1.2.3dev1+abc").base_version
-        '1!1.2.3'
-
-        The "base version" is the public version of the project without any pre or post
-        release markers.
-        """
-        parts = []
-
-        # Epoch
-        if self.epoch != 0:
-            parts.append(f"{self.epoch}!")
-
-        # Release segment
-        parts.append(".".join(str(x) for x in self.release))
-
-        return "".join(parts)
-
-    @property
-    def is_prerelease(self) -> bool:
-        """Whether this version is a pre-release.
-
-        >>> Version("1.2.3").is_prerelease
-        False
-        >>> Version("1.2.3a1").is_prerelease
-        True
-        >>> Version("1.2.3b1").is_prerelease
-        True
-        >>> Version("1.2.3rc1").is_prerelease
-        True
-        >>> Version("1.2.3dev1").is_prerelease
-        True
-        """
-        return self.dev is not None or self.pre is not None
-
-    @property
-    def is_postrelease(self) -> bool:
-        """Whether this version is a post-release.
-
-        >>> Version("1.2.3").is_postrelease
-        False
-        >>> Version("1.2.3.post1").is_postrelease
-        True
-        """
-        return self.post is not None
-
-    @property
-    def is_devrelease(self) -> bool:
-        """Whether this version is a development release.
-
-        >>> Version("1.2.3").is_devrelease
-        False
-        >>> Version("1.2.3.dev1").is_devrelease
-        True
-        """
-        return self.dev is not None
-
-    @property
-    def major(self) -> int:
-        """The first item of :attr:`release` or ``0`` if unavailable.
-
-        >>> Version("1.2.3").major
-        1
-        """
-        return self.release[0] if len(self.release) >= 1 else 0
-
-    @property
-    def minor(self) -> int:
-        """The second item of :attr:`release` or ``0`` if unavailable.
-
-        >>> Version("1.2.3").minor
-        2
-        >>> Version("1").minor
-        0
-        """
-        return self.release[1] if len(self.release) >= 2 else 0
-
-    @property
-    def micro(self) -> int:
-        """The third item of :attr:`release` or ``0`` if unavailable.
-
-        >>> Version("1.2.3").micro
-        3
-        >>> Version("1").micro
-        0
-        """
-        return self.release[2] if len(self.release) >= 3 else 0
-
-
-class _TrimmedRelease(Version):
-    @property
-    def release(self) -> tuple[int, ...]:
-        """
-        Release segment without any trailing zeros.
-
-        >>> _TrimmedRelease('1.0.0').release
-        (1,)
-        >>> _TrimmedRelease('0.0').release
-        (0,)
-        """
-        rel = super().release
-        nonzeros = (index for index, val in enumerate(rel) if val)
-        last_nonzero = max(nonzeros, default=0)
-        return rel[: last_nonzero + 1]
-
-
-def _parse_letter_version(
-    letter: str | None, number: str | bytes | SupportsInt | None
-) -> tuple[str, int] | None:
-    if letter:
-        # We consider there to be an implicit 0 in a pre-release if there is
-        # not a numeral associated with it.
-        if number is None:
-            number = 0
-
-        # We normalize any letters to their lower case form
-        letter = letter.lower()
-
-        # We consider some words to be alternate spellings of other words and
-        # in those cases we want to normalize the spellings to our preferred
-        # spelling.
-        if letter == "alpha":
-            letter = "a"
-        elif letter == "beta":
-            letter = "b"
-        elif letter in ["c", "pre", "preview"]:
-            letter = "rc"
-        elif letter in ["rev", "r"]:
-            letter = "post"
-
-        return letter, int(number)
-
-    assert not letter
-    if number:
-        # We assume if we are given a number, but we are not given a letter
-        # then this is using the implicit post release syntax (e.g. 1.0-1)
-        letter = "post"
-
-        return letter, int(number)
-
-    return None
-
-
-_local_version_separators = re.compile(r"[\._-]")
-
-
-def _parse_local_version(local: str | None) -> LocalType | None:
-    """
-    Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
-    """
-    if local is not None:
-        return tuple(
-            part.lower() if not part.isdigit() else int(part)
-            for part in _local_version_separators.split(local)
-        )
-    return None
-
-
-def _cmpkey(
-    epoch: int,
-    release: tuple[int, ...],
-    pre: tuple[str, int] | None,
-    post: tuple[str, int] | None,
-    dev: tuple[str, int] | None,
-    local: LocalType | None,
-) -> CmpKey:
-    # When we compare a release version, we want to compare it with all of the
-    # trailing zeros removed. So we'll use a reverse the list, drop all the now
-    # leading zeros until we come to something non zero, then take the rest
-    # re-reverse it back into the correct order and make it a tuple and use
-    # that for our sorting key.
-    _release = tuple(
-        reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
-    )
-
-    # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
-    # We'll do this by abusing the pre segment, but we _only_ want to do this
-    # if there is not a pre or a post segment. If we have one of those then
-    # the normal sorting rules will handle this case correctly.
-    if pre is None and post is None and dev is not None:
-        _pre: CmpPrePostDevType = NegativeInfinity
-    # Versions without a pre-release (except as noted above) should sort after
-    # those with one.
-    elif pre is None:
-        _pre = Infinity
-    else:
-        _pre = pre
-
-    # Versions without a post segment should sort before those with one.
-    if post is None:
-        _post: CmpPrePostDevType = NegativeInfinity
-
-    else:
-        _post = post
-
-    # Versions without a development segment should sort after those with one.
-    if dev is None:
-        _dev: CmpPrePostDevType = Infinity
-
-    else:
-        _dev = dev
-
-    if local is None:
-        # Versions without a local segment should sort before those with one.
-        _local: CmpLocalType = NegativeInfinity
-    else:
-        # Versions with a local segment need that segment parsed to implement
-        # the sorting rules in PEP440.
-        # - Alpha numeric segments sort before numeric segments
-        # - Alpha numeric segments sort lexicographically
-        # - Numeric segments sort numerically
-        # - Shorter versions sort before longer versions when the prefixes
-        #   match exactly
-        _local = tuple(
-            (i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local
-        )
-
-    return epoch, _release, _pre, _post, _dev, _local
diff --git a/server/libs/pathspec-0.11.2.dist-info/INSTALLER b/server/libs/pathspec-0.11.2.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/server/libs/pathspec-0.11.2.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/server/libs/pathspec-0.11.2.dist-info/LICENSE b/server/libs/pathspec-0.11.2.dist-info/LICENSE
deleted file mode 100644
index 14e2f77..0000000
--- a/server/libs/pathspec-0.11.2.dist-info/LICENSE
+++ /dev/null
@@ -1,373 +0,0 @@
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
-    means each individual or legal entity that creates, contributes to
-    the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-    means the combination of the Contributions of others (if any) used
-    by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-    means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-    means Source Code Form to which the initial Contributor has attached
-    the notice in Exhibit A, the Executable Form of such Source Code
-    Form, and Modifications of such Source Code Form, in each case
-    including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
-    means
-
-    (a) that the initial Contributor has attached the notice described
-        in Exhibit B to the Covered Software; or
-
-    (b) that the Covered Software was made available under the terms of
-        version 1.1 or earlier of the License, but not also under the
-        terms of a Secondary License.
-
-1.6. "Executable Form"
-    means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-    means a work that combines Covered Software with other material, in 
-    a separate file or files, that is not Covered Software.
-
-1.8. "License"
-    means this document.
-
-1.9. "Licensable"
-    means having the right to grant, to the maximum extent possible,
-    whether at the time of the initial grant or subsequently, any and
-    all of the rights conveyed by this License.
-
-1.10. "Modifications"
-    means any of the following:
-
-    (a) any file in Source Code Form that results from an addition to,
-        deletion from, or modification of the contents of Covered
-        Software; or
-
-    (b) any new file in Source Code Form that contains any Covered
-        Software.
-
-1.11. "Patent Claims" of a Contributor
-    means any patent claim(s), including without limitation, method,
-    process, and apparatus claims, in any patent Licensable by such
-    Contributor that would be infringed, but for the grant of the
-    License, by the making, using, selling, offering for sale, having
-    made, import, or transfer of either its Contributions or its
-    Contributor Version.
-
-1.12. "Secondary License"
-    means either the GNU General Public License, Version 2.0, the GNU
-    Lesser General Public License, Version 2.1, the GNU Affero General
-    Public License, Version 3.0, or any later versions of those
-    licenses.
-
-1.13. "Source Code Form"
-    means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-    means an individual or a legal entity exercising rights under this
-    License. For legal entities, "You" includes any entity that
-    controls, is controlled by, or is under common control with You. For
-    purposes of this definition, "control" means (a) the power, direct
-    or indirect, to cause the direction or management of such entity,
-    whether by contract or otherwise, or (b) ownership of more than
-    fifty percent (50%) of the outstanding shares or beneficial
-    ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
-    Licensable by such Contributor to use, reproduce, make available,
-    modify, display, perform, distribute, and otherwise exploit its
-    Contributions, either on an unmodified basis, with Modifications, or
-    as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
-    for sale, have made, import, and otherwise transfer either its
-    Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
-    or
-
-(b) for infringements caused by: (i) Your and any other third party's
-    modifications of Covered Software, or (ii) the combination of its
-    Contributions with other software (except as part of its Contributor
-    Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
-    its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
-    Form, as described in Section 3.1, and You must inform recipients of
-    the Executable Form how they can obtain a copy of such Source Code
-    Form by reasonable means in a timely manner, at a charge no more
-    than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
-    License, or sublicense it under different terms, provided that the
-    license for the Executable Form does not attempt to limit or alter
-    the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-*                                                                      *
-*  6. Disclaimer of Warranty                                           *
-*  -------------------------                                           *
-*                                                                      *
-*  Covered Software is provided under this License on an "as is"       *
-*  basis, without warranty of any kind, either expressed, implied, or  *
-*  statutory, including, without limitation, warranties that the       *
-*  Covered Software is free of defects, merchantable, fit for a        *
-*  particular purpose or non-infringing. The entire risk as to the     *
-*  quality and performance of the Covered Software is with You.        *
-*  Should any Covered Software prove defective in any respect, You     *
-*  (not any Contributor) assume the cost of any necessary servicing,   *
-*  repair, or correction. This disclaimer of warranty constitutes an   *
-*  essential part of this License. No use of any Covered Software is   *
-*  authorized under this License except under this disclaimer.         *
-*                                                                      *
-************************************************************************
-
-************************************************************************
-*                                                                      *
-*  7. Limitation of Liability                                          *
-*  --------------------------                                          *
-*                                                                      *
-*  Under no circumstances and under no legal theory, whether tort      *
-*  (including negligence), contract, or otherwise, shall any           *
-*  Contributor, or anyone who distributes Covered Software as          *
-*  permitted above, be liable to You for any direct, indirect,         *
-*  special, incidental, or consequential damages of any character      *
-*  including, without limitation, damages for lost profits, loss of    *
-*  goodwill, work stoppage, computer failure or malfunction, or any    *
-*  and all other commercial damages or losses, even if such party      *
-*  shall have been informed of the possibility of such damages. This   *
-*  limitation of liability shall not apply to liability for death or   *
-*  personal injury resulting from such party's negligence to the       *
-*  extent applicable law prohibits such limitation. Some               *
-*  jurisdictions do not allow the exclusion or limitation of           *
-*  incidental or consequential damages, so this exclusion and          *
-*  limitation may not apply to You.                                    *
-*                                                                      *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
-  This Source Code Form is subject to the terms of the Mozilla Public
-  License, v. 2.0. If a copy of the MPL was not distributed with this
-  file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
-  This Source Code Form is "Incompatible With Secondary Licenses", as
-  defined by the Mozilla Public License, v. 2.0.
diff --git a/server/libs/pathspec-0.11.2.dist-info/METADATA b/server/libs/pathspec-0.11.2.dist-info/METADATA
deleted file mode 100644
index 5652f2e..0000000
--- a/server/libs/pathspec-0.11.2.dist-info/METADATA
+++ /dev/null
@@ -1,601 +0,0 @@
-Metadata-Version: 2.1
-Name: pathspec
-Version: 0.11.2
-Summary: Utility library for gitignore style pattern matching of file paths.
-Author-email: "Caleb P. Burns" 
-Requires-Python: >=3.7
-Description-Content-Type: text/x-rst
-Classifier: Development Status :: 4 - Beta
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: Implementation :: CPython
-Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: Topic :: Utilities
-Project-URL: Documentation, https://python-path-specification.readthedocs.io/en/latest/index.html
-Project-URL: Issue Tracker, https://github.com/cpburnz/python-pathspec/issues
-Project-URL: Source Code, https://github.com/cpburnz/python-pathspec
-
-
-PathSpec
-========
-
-*pathspec* is a utility library for pattern matching of file paths. So
-far this only includes Git's wildmatch pattern matching which itself is
-derived from Rsync's wildmatch. Git uses wildmatch for its `gitignore`_
-files.
-
-.. _`gitignore`: http://git-scm.com/docs/gitignore
-
-
-Tutorial
---------
-
-Say you have a "Projects" directory and you want to back it up, but only
-certain files, and ignore others depending on certain conditions::
-
-	>>> import pathspec
-	>>> # The gitignore-style patterns for files to select, but we're including
-	>>> # instead of ignoring.
-	>>> spec_text = """
-	...
-	... # This is a comment because the line begins with a hash: "#"
-	...
-	... # Include several project directories (and all descendants) relative to
-	... # the current directory. To reference a directory you must end with a
-	... # slash: "/"
-	... /project-a/
-	... /project-b/
-	... /project-c/
-	...
-	... # Patterns can be negated by prefixing with exclamation mark: "!"
-	...
-	... # Ignore temporary files beginning or ending with "~" and ending with
-	... # ".swp".
-	... !~*
-	... !*~
-	... !*.swp
-	...
-	... # These are python projects so ignore compiled python files from
-	... # testing.
-	... !*.pyc
-	...
-	... # Ignore the build directories but only directly under the project
-	... # directories.
-	... !/*/build/
-	...
-	... """
-
-We want to use the ``GitWildMatchPattern`` class to compile our patterns. The
-``PathSpec`` class provides an interface around pattern implementations::
-
-	>>> spec = pathspec.PathSpec.from_lines(pathspec.patterns.GitWildMatchPattern, spec_text.splitlines())
-
-That may be a mouthful but it allows for additional patterns to be implemented
-in the future without them having to deal with anything but matching the paths
-sent to them. ``GitWildMatchPattern`` is the implementation of the actual
-pattern which internally gets converted into a regular expression. ``PathSpec``
-is a simple wrapper around a list of compiled patterns.
-
-To make things simpler, we can use the registered name for a pattern class
-instead of always having to provide a reference to the class itself. The
-``GitWildMatchPattern`` class is registered as **gitwildmatch**::
-
-	>>> spec = pathspec.PathSpec.from_lines('gitwildmatch', spec_text.splitlines())
-
-If we wanted to manually compile the patterns we can just do the following::
-
-	>>> patterns = map(pathspec.patterns.GitWildMatchPattern, spec_text.splitlines())
-	>>> spec = PathSpec(patterns)
-
-``PathSpec.from_lines()`` is simply a class method which does just that.
-
-If you want to load the patterns from file, you can pass the file instance
-directly as well::
-
-	>>> with open('patterns.list', 'r') as fh:
-	>>>     spec = pathspec.PathSpec.from_lines('gitwildmatch', fh)
-
-You can perform matching on a whole directory tree with::
-
-	>>> matches = spec.match_tree('path/to/directory')
-
-Or you can perform matching on a specific set of file paths with::
-
-	>>> matches = spec.match_files(file_paths)
-
-Or check to see if an individual file matches::
-
-	>>> is_matched = spec.match_file(file_path)
-
-There is a specialized class, ``pathspec.GitIgnoreSpec``, which more closely
-implements the behavior of **gitignore**. This uses ``GitWildMatchPattern``
-pattern by default and handles some edge cases differently from the generic
-``PathSpec`` class. ``GitIgnoreSpec`` can be used without specifying the pattern
-factory::
-
-	>>> spec = pathspec.GitIgnoreSpec.from_lines(spec_text.splitlines())
-
-
-License
--------
-
-*pathspec* is licensed under the `Mozilla Public License Version 2.0`_. See
-`LICENSE`_ or the `FAQ`_ for more information.
-
-In summary, you may use *pathspec* with any closed or open source project
-without affecting the license of the larger work so long as you:
-
-- give credit where credit is due,
-
-- and release any custom changes made to *pathspec*.
-
-.. _`Mozilla Public License Version 2.0`: http://www.mozilla.org/MPL/2.0
-.. _`LICENSE`: LICENSE
-.. _`FAQ`: http://www.mozilla.org/MPL/2.0/FAQ.html
-
-
-Source
-------
-
-The source code for *pathspec* is available from the GitHub repo
-`cpburnz/python-pathspec`_.
-
-.. _`cpburnz/python-pathspec`: https://github.com/cpburnz/python-pathspec
-
-
-Installation
-------------
-
-*pathspec* is available for install through `PyPI`_::
-
-	pip install pathspec
-
-*pathspec* can also be built from source. The following packages will be
-required:
-
-- `build`_ (>=0.6.0)
-
-*pathspec* can then be built and installed with::
-
-	python -m build
-	pip install dist/pathspec-*-py3-none-any.whl
-
-.. _`PyPI`: http://pypi.python.org/pypi/pathspec
-.. _`build`: https://pypi.org/project/build/
-
-
-Documentation
--------------
-
-Documentation for *pathspec* is available on `Read the Docs`_.
-
-.. _`Read the Docs`: https://python-path-specification.readthedocs.io
-
-
-Other Languages
----------------
-
-The related project `pathspec-ruby`_ (by *highb*) provides a similar library as
-a `Ruby gem`_.
-
-.. _`pathspec-ruby`: https://github.com/highb/pathspec-ruby
-.. _`Ruby gem`: https://rubygems.org/gems/pathspec
-
-
-
-Change History
-==============
-
-
-0.11.2 (2023-07-28)
--------------------
-
-New features:
-
-- `Issue #80`_: match_files with negated path spec. `pathspec.PathSpec.match_*()` now have a `negate` parameter to make using *.gitignore* logic easier and more efficient.
-
-Bug fixes:
-
-- `Pull #76`_: Add edge case: patterns that end with an escaped space
-- `Issue #77`_/`Pull #78`_: Negate with caret symbol as with the exclamation mark.
-
-
-.. _`Pull #76`: https://github.com/cpburnz/python-pathspec/pull/76
-.. _`Issue #77`: https://github.com/cpburnz/python-pathspec/issues/77
-.. _`Pull #78`: https://github.com/cpburnz/python-pathspec/pull/78/
-.. _`Issue #80`: https://github.com/cpburnz/python-pathspec/issues/80
-
-
-0.11.1 (2023-03-14)
--------------------
-
-Bug fixes:
-
-- `Issue #74`_: Include directory should override exclude file.
-
-Improvements:
-
-- `Pull #75`_: Fix partially unknown PathLike type.
-- Convert `os.PathLike` to a string properly using `os.fspath`.
-
-
-.. _`Issue #74`: https://github.com/cpburnz/python-pathspec/issues/74
-.. _`Pull #75`: https://github.com/cpburnz/python-pathspec/pull/75
-
-
-0.11.0 (2023-01-24)
--------------------
-
-Major changes:
-
-- Changed build backend to `flit_core.buildapi`_ from `setuptools.build_meta`_. Building with `setuptools` through `setup.py` is still supported for distributions that need it. See `Issue #72`_.
-
-Improvements:
-
-- `Issue #72`_/`Pull #73`_: Please consider switching the build-system to flit_core to ease setuptools bootstrap.
-
-
-.. _`flit_core.buildapi`: https://flit.pypa.io/en/latest/index.html
-.. _`Issue #72`: https://github.com/cpburnz/python-pathspec/issues/72
-.. _`Pull #73`: https://github.com/cpburnz/python-pathspec/pull/73
-
-
-0.10.3 (2022-12-09)
--------------------
-
-New features:
-
-- Added utility function `pathspec.util.append_dir_sep()` to aid in distinguishing between directories and files on the file-system. See `Issue #65`_.
-
-Bug fixes:
-
-- `Issue #66`_/`Pull #67`_: Package not marked as py.typed.
-- `Issue #68`_: Exports are considered private.
-- `Issue #70`_/`Pull #71`_: 'Self' string literal type is Unknown in pyright.
-
-Improvements:
-
-- `Issue #65`_: Checking directories via match_file() does not work on Path objects.
-
-
-.. _`Issue #65`: https://github.com/cpburnz/python-pathspec/issues/65
-.. _`Issue #66`: https://github.com/cpburnz/python-pathspec/issues/66
-.. _`Pull #67`: https://github.com/cpburnz/python-pathspec/pull/67
-.. _`Issue #68`: https://github.com/cpburnz/python-pathspec/issues/68
-.. _`Issue #70`: https://github.com/cpburnz/python-pathspec/issues/70
-.. _`Pull #71`: https://github.com/cpburnz/python-pathspec/pull/71
-
-
-0.10.2 (2022-11-12)
--------------------
-
-Bug fixes:
-
-- Fix failing tests on Windows.
-- Type hint on *root* parameter on `pathspec.pathspec.PathSpec.match_tree_entries()`.
-- Type hint on *root* parameter on `pathspec.pathspec.PathSpec.match_tree_files()`.
-- Type hint on *root* parameter on `pathspec.util.iter_tree_entries()`.
-- Type hint on *root* parameter on `pathspec.util.iter_tree_files()`.
-- `Issue #64`_: IndexError with my .gitignore file when trying to build a Python package.
-
-Improvements:
-
-- `Pull #58`_: CI: add GitHub Actions test workflow.
-
-
-.. _`Pull #58`: https://github.com/cpburnz/python-pathspec/pull/58
-.. _`Issue #64`: https://github.com/cpburnz/python-pathspec/issues/64
-
-
-0.10.1 (2022-09-02)
--------------------
-
-Bug fixes:
-
-- Fix documentation on `pathspec.pattern.RegexPattern.match_file()`.
-- `Pull #60`_: Remove redundant wheel dep from pyproject.toml.
-- `Issue #61`_: Dist failure for Fedora, CentOS, EPEL.
-- `Issue #62`_: Since version 0.10.0 pure wildcard does not work in some cases.
-
-Improvements:
-
-- Restore support for legacy installations using `setup.py`. See `Issue #61`_.
-
-
-.. _`Pull #60`: https://github.com/cpburnz/python-pathspec/pull/60
-.. _`Issue #61`: https://github.com/cpburnz/python-pathspec/issues/61
-.. _`Issue #62`: https://github.com/cpburnz/python-pathspec/issues/62
-
-
-0.10.0 (2022-08-30)
--------------------
-
-Major changes:
-
-- Dropped support of EOL Python 2.7, 3.5, 3.6. See `Issue #47`_.
-- The *gitwildmatch* pattern `dir/*` is now handled the same as `dir/`. This means `dir/*` will now match all descendants rather than only direct children. See `Issue #19`_.
-- Added `pathspec.GitIgnoreSpec` class (see new features).
-- Changed build system to `pyproject.toml`_ and build backend to `setuptools.build_meta`_ which may have unforeseen consequences.
-- Renamed GitHub project from `python-path-specification`_ to `python-pathspec`_. See `Issue #35`_.
-
-API changes:
-
-- Deprecated: `pathspec.util.match_files()` is an old function no longer used.
-- Deprecated: `pathspec.match_files()` is an old function no longer used.
-- Deprecated: `pathspec.util.normalize_files()` is no longer used.
-- Deprecated: `pathspec.util.iter_tree()` is an alias for `pathspec.util.iter_tree_files()`.
-- Deprecated: `pathspec.iter_tree()` is an alias for `pathspec.util.iter_tree_files()`.
--	Deprecated: `pathspec.pattern.Pattern.match()` is no longer used. Use or implement
-	`pathspec.pattern.Pattern.match_file()`.
-
-New features:
-
-- Added class `pathspec.gitignore.GitIgnoreSpec` (with alias `pathspec.GitIgnoreSpec`) to implement *gitignore* behavior not possible with standard `PathSpec` class. The particular *gitignore* behavior implemented is prioritizing patterns matching the file directly over matching an ancestor directory.
-
-Bug fixes:
-
-- `Issue #19`_: Files inside an ignored sub-directory are not matched.
-- `Issue #41`_: Incorrectly (?) matches files inside directories that do match.
-- `Pull #51`_: Refactor deprecated unittest aliases for Python 3.11 compatibility.
-- `Issue #53`_: Symlink pathspec_meta.py breaks Windows.
-- `Issue #54`_: test_util.py uses os.symlink which can fail on Windows.
-- `Issue #55`_: Backslashes at start of pattern not handled correctly.
-- `Pull #56`_: pyproject.toml: include subpackages in setuptools config
-- `Issue #57`_: `!` doesn't exclude files in directories if the pattern doesn't have a trailing slash.
-
-Improvements:
-
-- Support Python 3.10, 3.11.
-- Modernize code to Python 3.7.
-- `Issue #52`_: match_files() is not a pure generator function, and it impacts tree_*() gravely.
-
-
-.. _`python-path-specification`: https://github.com/cpburnz/python-path-specification
-.. _`python-pathspec`: https://github.com/cpburnz/python-pathspec
-.. _`pyproject.toml`: https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/
-.. _`setuptools.build_meta`: https://setuptools.pypa.io/en/latest/build_meta.html
-.. _`Issue #19`: https://github.com/cpburnz/python-pathspec/issues/19
-.. _`Issue #35`: https://github.com/cpburnz/python-pathspec/issues/35
-.. _`Issue #41`: https://github.com/cpburnz/python-pathspec/issues/41
-.. _`Issue #47`: https://github.com/cpburnz/python-pathspec/issues/47
-.. _`Pull #51`: https://github.com/cpburnz/python-pathspec/pull/51
-.. _`Issue #52`: https://github.com/cpburnz/python-pathspec/issues/52
-.. _`Issue #53`: https://github.com/cpburnz/python-pathspec/issues/53
-.. _`Issue #54`: https://github.com/cpburnz/python-pathspec/issues/54
-.. _`Issue #55`: https://github.com/cpburnz/python-pathspec/issues/55
-.. _`Pull #56`: https://github.com/cpburnz/python-pathspec/pull/56
-.. _`Issue #57`: https://github.com/cpburnz/python-pathspec/issues/57
-
-
-0.9.0 (2021-07-17)
-------------------
-
-- `Issue #44`_/`Pull #50`_: Raise `GitWildMatchPatternError` for invalid git patterns.
-- `Pull #45`_: Fix for duplicate leading double-asterisk, and edge cases.
-- `Issue #46`_: Fix matching absolute paths.
-- API change: `util.normalize_files()` now returns a `Dict[str, List[pathlike]]` instead of a `Dict[str, pathlike]`.
-- Added type hinting.
-
-.. _`Issue #44`: https://github.com/cpburnz/python-pathspec/issues/44
-.. _`Pull #45`: https://github.com/cpburnz/python-pathspec/pull/45
-.. _`Issue #46`: https://github.com/cpburnz/python-pathspec/issues/46
-.. _`Pull #50`: https://github.com/cpburnz/python-pathspec/pull/50
-
-
-0.8.1 (2020-11-07)
-------------------
-
-- `Pull #43`_: Add support for addition operator.
-
-.. _`Pull #43`: https://github.com/cpburnz/python-pathspec/pull/43
-
-
-0.8.0 (2020-04-09)
-------------------
-
-- `Issue #30`_: Expose what patterns matched paths. Added `util.detailed_match_files()`.
-- `Issue #31`_: `match_tree()` doesn't return symlinks.
-- `Issue #34`_: Support `pathlib.Path`\ s.
-- Add `PathSpec.match_tree_entries` and `util.iter_tree_entries()` to support directories and symlinks.
-- API change: `match_tree()` has been renamed to `match_tree_files()`. The old name `match_tree()` is still available as an alias.
-- API change: `match_tree_files()` now returns symlinks. This is a bug fix but it will change the returned results.
-
-.. _`Issue #30`: https://github.com/cpburnz/python-pathspec/issues/30
-.. _`Issue #31`: https://github.com/cpburnz/python-pathspec/issues/31
-.. _`Issue #34`: https://github.com/cpburnz/python-pathspec/issues/34
-
-
-0.7.0 (2019-12-27)
-------------------
-
-- `Pull #28`_: Add support for Python 3.8, and drop Python 3.4.
-- `Pull #29`_: Publish bdist wheel.
-
-.. _`Pull #28`: https://github.com/cpburnz/python-pathspec/pull/28
-.. _`Pull #29`: https://github.com/cpburnz/python-pathspec/pull/29
-
-
-0.6.0 (2019-10-03)
-------------------
-
-- `Pull #24`_: Drop support for Python 2.6, 3.2, and 3.3.
-- `Pull #25`_: Update README.rst.
-- `Pull #26`_: Method to escape gitwildmatch.
-
-.. _`Pull #24`: https://github.com/cpburnz/python-pathspec/pull/24
-.. _`Pull #25`: https://github.com/cpburnz/python-pathspec/pull/25
-.. _`Pull #26`: https://github.com/cpburnz/python-pathspec/pull/26
-
-
-0.5.9 (2018-09-15)
-------------------
-
-- Fixed file system error handling.
-
-
-0.5.8 (2018-09-15)
-------------------
-
-- Improved type checking.
-- Created scripts to test Python 2.6 because Tox removed support for it.
-- Improved byte string handling in Python 3.
-- `Issue #22`_: Handle dangling symlinks.
-
-.. _`Issue #22`: https://github.com/cpburnz/python-pathspec/issues/22
-
-
-0.5.7 (2018-08-14)
-------------------
-
-- `Issue #21`_: Fix collections deprecation warning.
-
-.. _`Issue #21`: https://github.com/cpburnz/python-pathspec/issues/21
-
-
-0.5.6 (2018-04-06)
-------------------
-
-- Improved unit tests.
-- Improved type checking.
-- `Issue #20`_: Support current directory prefix.
-
-.. _`Issue #20`: https://github.com/cpburnz/python-pathspec/issues/20
-
-
-0.5.5 (2017-09-09)
-------------------
-
-- Add documentation link to README.
-
-
-0.5.4 (2017-09-09)
-------------------
-
-- `Pull #17`_: Add link to Ruby implementation of *pathspec*.
-- Add sphinx documentation.
-
-.. _`Pull #17`: https://github.com/cpburnz/python-pathspec/pull/17
-
-
-0.5.3 (2017-07-01)
-------------------
-
-- `Issue #14`_: Fix byte strings for Python 3.
-- `Pull #15`_: Include "LICENSE" in source package.
-- `Issue #16`_: Support Python 2.6.
-
-.. _`Issue #14`: https://github.com/cpburnz/python-pathspec/issues/14
-.. _`Pull #15`: https://github.com/cpburnz/python-pathspec/pull/15
-.. _`Issue #16`: https://github.com/cpburnz/python-pathspec/issues/16
-
-
-0.5.2 (2017-04-04)
-------------------
-
-- Fixed change log.
-
-
-0.5.1 (2017-04-04)
-------------------
-
-- `Pull #13`_: Add equality methods to `PathSpec` and `RegexPattern`.
-
-.. _`Pull #13`: https://github.com/cpburnz/python-pathspec/pull/13
-
-
-0.5.0 (2016-08-22)
-------------------
-
-- `Issue #12`_: Add `PathSpec.match_file()`.
-- Renamed `gitignore.GitIgnorePattern` to `patterns.gitwildmatch.GitWildMatchPattern`.
-- Deprecated `gitignore.GitIgnorePattern`.
-
-.. _`Issue #12`: https://github.com/cpburnz/python-pathspec/issues/12
-
-
-0.4.0 (2016-07-15)
-------------------
-
-- `Issue #11`_: Support converting patterns into regular expressions without compiling them.
-- API change: Subclasses of `RegexPattern` should implement `pattern_to_regex()`.
-
-.. _`Issue #11`: https://github.com/cpburnz/python-pathspec/issues/11
-
-
-0.3.4 (2015-08-24)
-------------------
-
-- `Pull #7`_: Fixed non-recursive links.
-- `Pull #8`_: Fixed edge cases in gitignore patterns.
-- `Pull #9`_: Fixed minor usage documentation.
-- Fixed recursion detection.
-- Fixed trivial incompatibility with Python 3.2.
-
-.. _`Pull #7`: https://github.com/cpburnz/python-pathspec/pull/7
-.. _`Pull #8`: https://github.com/cpburnz/python-pathspec/pull/8
-.. _`Pull #9`: https://github.com/cpburnz/python-pathspec/pull/9
-
-
-0.3.3 (2014-11-21)
-------------------
-
-- Improved documentation.
-
-
-0.3.2 (2014-11-08)
-------------------
-
-- `Pull #5`_: Use tox for testing.
-- `Issue #6`_: Fixed matching Windows paths.
-- Improved documentation.
-- API change: `spec.match_tree()` and `spec.match_files()` now return iterators instead of sets.
-
-.. _`Pull #5`: https://github.com/cpburnz/python-pathspec/pull/5
-.. _`Issue #6`: https://github.com/cpburnz/python-pathspec/issues/6
-
-
-0.3.1 (2014-09-17)
-------------------
-
-- Updated README.
-
-
-0.3.0 (2014-09-17)
-------------------
-
-- `Pull #3`_: Fixed trailing slash in gitignore patterns.
-- `Pull #4`_: Fixed test for trailing slash in gitignore patterns.
-- Added registered patterns.
-
-.. _`Pull #3`: https://github.com/cpburnz/python-pathspec/pull/3
-.. _`Pull #4`: https://github.com/cpburnz/python-pathspec/pull/4
-
-
-0.2.2 (2013-12-17)
-------------------
-
-- Fixed setup.py.
-
-
-0.2.1 (2013-12-17)
-------------------
-
-- Added tests.
-- Fixed comment gitignore patterns.
-- Fixed relative path gitignore patterns.
-
-
-0.2.0 (2013-12-07)
-------------------
-
-- Initial release.
-
diff --git a/server/libs/pathspec-0.11.2.dist-info/RECORD b/server/libs/pathspec-0.11.2.dist-info/RECORD
deleted file mode 100644
index 65483bf..0000000
--- a/server/libs/pathspec-0.11.2.dist-info/RECORD
+++ /dev/null
@@ -1,23 +0,0 @@
-pathspec-0.11.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-pathspec-0.11.2.dist-info/LICENSE,sha256=-rPda9qyJvHAhjCx3ZF-Efy07F4eAg4sFvg6ChOGPoU,16726
-pathspec-0.11.2.dist-info/METADATA,sha256=SxnZo-5WRH5npmxwSmYWT1DThQTSIfanQM8_-j8ye1g,19563
-pathspec-0.11.2.dist-info/RECORD,,
-pathspec-0.11.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pathspec-0.11.2.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
-pathspec/__init__.py,sha256=7SXysmS-FbGnfonqXtaSm6aUKdepQCXdvd4ArWAMJak,1630
-pathspec/__pycache__/__init__.cpython-311.pyc,,
-pathspec/__pycache__/_meta.cpython-311.pyc,,
-pathspec/__pycache__/gitignore.cpython-311.pyc,,
-pathspec/__pycache__/pathspec.cpython-311.pyc,,
-pathspec/__pycache__/pattern.cpython-311.pyc,,
-pathspec/__pycache__/util.cpython-311.pyc,,
-pathspec/_meta.py,sha256=KkXyQhYw9KfMMlZeEuw6TV5Ar7qn_Y9yF4jTBeiJ-pQ,2223
-pathspec/gitignore.py,sha256=nHZA92AltTIfCLf1i4uwvvXeEdfvbNBjetogn0ueGJM,3895
-pathspec/pathspec.py,sha256=O8oFAbo71uvwFWZZm7c2iFy0nzClyEcxOFJHg_EL8WQ,9530
-pathspec/pattern.py,sha256=HVpwUuGMAW7WOtgPOkZUmJY-lg84BtWVvkVXcc_ha28,5784
-pathspec/patterns/__init__.py,sha256=vAzIEqBc2KsvWsiszsLCeYQwQVWXIHzbHNgq5TNrPdk,302
-pathspec/patterns/__pycache__/__init__.cpython-311.pyc,,
-pathspec/patterns/__pycache__/gitwildmatch.cpython-311.pyc,,
-pathspec/patterns/gitwildmatch.py,sha256=7f8zEBMvySzznrm7oo_geFV0NnmxUucZaYQxtsnMBQ8,12438
-pathspec/py.typed,sha256=wq7wwDeyBungK6DsiV4O-IujgKzARwHz94uQshdpdEU,68
-pathspec/util.py,sha256=8w65a_vDtw3eCyIY5LVQ8EgUGekLwdIBne5yORdIoOQ,20273
diff --git a/server/libs/pathspec-0.11.2.dist-info/REQUESTED b/server/libs/pathspec-0.11.2.dist-info/REQUESTED
deleted file mode 100644
index e69de29..0000000
diff --git a/server/libs/pathspec-0.11.2.dist-info/WHEEL b/server/libs/pathspec-0.11.2.dist-info/WHEEL
deleted file mode 100644
index 3b5e64b..0000000
--- a/server/libs/pathspec-0.11.2.dist-info/WHEEL
+++ /dev/null
@@ -1,4 +0,0 @@
-Wheel-Version: 1.0
-Generator: flit 3.9.0
-Root-Is-Purelib: true
-Tag: py3-none-any
diff --git a/server/libs/pathspec/__init__.py b/server/libs/pathspec/__init__.py
deleted file mode 100644
index 32e03f7..0000000
--- a/server/libs/pathspec/__init__.py
+++ /dev/null
@@ -1,76 +0,0 @@
-"""
-The *pathspec* package provides pattern matching for file paths. So far
-this only includes Git's wildmatch pattern matching (the style used for
-".gitignore" files).
-
-The following classes are imported and made available from the root of
-the `pathspec` package:
-
--	:class:`pathspec.gitignore.GitIgnoreSpec`
-
--	:class:`pathspec.pathspec.PathSpec`
-
--	:class:`pathspec.pattern.Pattern`
-
--	:class:`pathspec.pattern.RegexPattern`
-
--	:class:`pathspec.util.RecursionError`
-
-The following functions are also imported:
-
--	:func:`pathspec.util.lookup_pattern`
-
-The following deprecated functions are also imported to maintain
-backward compatibility:
-
--	:func:`pathspec.util.iter_tree` which is an alias for
-	:func:`pathspec.util.iter_tree_files`.
-
--	:func:`pathspec.util.match_files`
-"""
-
-from .gitignore import (
-	GitIgnoreSpec)
-from .pathspec import (
-	PathSpec)
-from .pattern import (
-	Pattern,
-	RegexPattern)
-from .util import (
-	RecursionError,
-	iter_tree,
-	lookup_pattern,
-	match_files)
-
-from ._meta import (
-	__author__,
-	__copyright__,
-	__credits__,
-	__license__,
-	__version__,
-)
-
-# Load pattern implementations.
-from . import patterns
-
-# DEPRECATED: Expose the `GitIgnorePattern` class in the root module for
-# backward compatibility with v0.4.
-from .patterns.gitwildmatch import GitIgnorePattern
-
-# Declare private imports as part of the public interface. Deprecated
-# imports are deliberately excluded.
-__all__ = [
-	'GitIgnoreSpec',
-	'PathSpec',
-	'Pattern',
-	'RecursionError',
-	'RegexPattern',
-	'__author__',
-	'__copyright__',
-	'__credits__',
-	'__license__',
-	'__version__',
-	'iter_tree',
-	'lookup_pattern',
-	'match_files',
-]
diff --git a/server/libs/pathspec/_meta.py b/server/libs/pathspec/_meta.py
deleted file mode 100644
index 6cba91d..0000000
--- a/server/libs/pathspec/_meta.py
+++ /dev/null
@@ -1,57 +0,0 @@
-"""
-This module contains the project meta-data.
-"""
-
-__author__ = "Caleb P. Burns"
-__copyright__ = "Copyright © 2013-2023 Caleb P. Burns"
-__credits__ = [
-	"dahlia ",
-	"highb ",
-	"029xue ",
-	"mikexstudios ",
-	"nhumrich ",
-	"davidfraser ",
-	"demurgos ",
-	"ghickman ",
-	"nvie ",
-	"adrienverge ",
-	"AndersBlomdell ",
-	"thmxv ",
-	"wimglenn ",
-	"hugovk ",
-	"dcecile ",
-	"mroutis ",
-	"jdufresne ",
-	"groodt ",
-	"ftrofin ",
-	"pykong ",
-	"nhhollander ",
-	"KOLANICH ",
-	"JonjonHays ",
-	"Isaac0616 ",
-	"SebastiaanZ ",
-	"RoelAdriaans ",
-	"raviselker ",
-	"johanvergeer ",
-	"danjer ",
-	"jhbuhrman ",
-	"WPDOrdina ",
-	"tirkarthi ",
-	"jayvdb ",
-	"jwodder ",
-	"kloczek ",
-	"orens ",
-	"spMohanty ",
-	"ichard26 ",
-	"jack1142 ",
-	"mgorny ",
-	"bzakdd ",
-	"haimat ",
-	"Avasam ",
-	"yschroeder ",
-	"axesider ",
-	"tomruk ",
-	"oprypin ",
-]
-__license__ = "MPL 2.0"
-__version__ = "0.11.2"
diff --git a/server/libs/pathspec/gitignore.py b/server/libs/pathspec/gitignore.py
deleted file mode 100644
index a939225..0000000
--- a/server/libs/pathspec/gitignore.py
+++ /dev/null
@@ -1,138 +0,0 @@
-"""
-This module provides :class:`.GitIgnoreSpec` which replicates
-*.gitignore* behavior.
-"""
-
-from typing import (
-	AnyStr,
-	Callable,
-	Collection,
-	Iterable,
-	Type,
-	TypeVar,
-	Union)
-
-from .pathspec import (
-	PathSpec)
-from .pattern import (
-	Pattern)
-from .patterns.gitwildmatch import (
-	GitWildMatchPattern,
-	GitWildMatchPatternError,
-	_DIR_MARK)
-from .util import (
-	_is_iterable)
-
-Self = TypeVar("Self", bound="GitIgnoreSpec")
-"""
-:class:`GitIgnoreSpec` self type hint to support Python v<3.11 using PEP
-673 recommendation.
-"""
-
-
-class GitIgnoreSpec(PathSpec):
-	"""
-	The :class:`GitIgnoreSpec` class extends :class:`PathSpec` to
-	replicate *.gitignore* behavior.
-	"""
-
-	def __eq__(self, other: object) -> bool:
-		"""
-		Tests the equality of this gitignore-spec with *other*
-		(:class:`GitIgnoreSpec`) by comparing their :attr:`~PathSpec.patterns`
-		attributes. A non-:class:`GitIgnoreSpec` will not compare equal.
-		"""
-		if isinstance(other, GitIgnoreSpec):
-			return super().__eq__(other)
-		elif isinstance(other, PathSpec):
-			return False
-		else:
-			return NotImplemented
-
-	@classmethod
-	def from_lines(
-		cls: Type[Self],
-		lines: Iterable[AnyStr],
-		pattern_factory: Union[str, Callable[[AnyStr], Pattern], None] = None,
-	) -> Self:
-		"""
-		Compiles the pattern lines.
-
-		*lines* (:class:`~collections.abc.Iterable`) yields each uncompiled
-		pattern (:class:`str`). This simply has to yield each line so it can
-		be a :class:`io.TextIOBase` (e.g., from :func:`open` or
-		:class:`io.StringIO`) or the result from :meth:`str.splitlines`.
-
-		*pattern_factory* can be :data:`None`, the name of a registered
-		pattern factory (:class:`str`), or a :class:`~collections.abc.Callable`
-		used to compile patterns. The callable must accept an uncompiled
-		pattern (:class:`str`) and return the compiled pattern (:class:`.Pattern`).
-		Default is :data:`None` for :class:`.GitWildMatchPattern`).
-
-		Returns the :class:`GitIgnoreSpec` instance.
-		"""
-		if pattern_factory is None:
-			pattern_factory = GitWildMatchPattern
-
-		elif (isinstance(lines, str) or callable(lines)) and _is_iterable(pattern_factory):
-			# Support reversed order of arguments from PathSpec.
-			pattern_factory, lines = lines, pattern_factory
-
-		self = super().from_lines(pattern_factory, lines)
-		return self  # type: ignore
-
-	@staticmethod
-	def _match_file(
-		patterns: Collection[GitWildMatchPattern],
-		file: str,
-	) -> bool:
-		"""
-		Matches the file to the patterns.
-
-		.. NOTE:: Subclasses of :class:`.PathSpec` may override this
-		   method as an instance method. It does not have to be a static
-		   method.
-
-		*patterns* (:class:`~collections.abc.Iterable` of :class:`~pathspec.pattern.Pattern`)
-		contains the patterns to use.
-
-		*file* (:class:`str`) is the normalized file path to be matched
-		against *patterns*.
-
-		Returns :data:`True` if *file* matched; otherwise, :data:`False`.
-		"""
-		out_matched = False
-		out_priority = 0
-		for pattern in patterns:
-			if pattern.include is not None:
-				match = pattern.match_file(file)
-				if match is not None:
-					# Pattern matched.
-
-					# Check for directory marker.
-					try:
-						dir_mark = match.match.group(_DIR_MARK)
-					except IndexError as e:
-						# NOTICE: The exact content of this error message is subject
-						# to change.
-						raise GitWildMatchPatternError((
-							f"Invalid git pattern: directory marker regex group is missing. "
-							f"Debug: file={file!r} regex={pattern.regex!r} "
-							f"group={_DIR_MARK!r} match={match.match!r}."
-						)) from e
-
-					if dir_mark:
-						# Pattern matched by a directory pattern.
-						priority = 1
-					else:
-						# Pattern matched by a file pattern.
-						priority = 2
-
-					if pattern.include and dir_mark:
-						out_matched = pattern.include
-						out_priority = priority
-					elif priority >= out_priority:
-						out_matched = pattern.include
-						out_priority = priority
-
-		return out_matched
diff --git a/server/libs/pathspec/pathspec.py b/server/libs/pathspec/pathspec.py
deleted file mode 100644
index 93f2f60..0000000
--- a/server/libs/pathspec/pathspec.py
+++ /dev/null
@@ -1,304 +0,0 @@
-"""
-This module provides an object oriented interface for pattern matching of files.
-"""
-
-from collections.abc import (
-	Collection as CollectionType)
-from itertools import (
-	zip_longest)
-from typing import (
-	AnyStr,
-	Callable,
-	Collection,
-	Iterable,
-	Iterator,
-	Optional,
-	Type,
-	TypeVar,
-	Union)
-
-from . import util
-from .pattern import (
-	Pattern)
-from .util import (
-	StrPath,
-	TreeEntry,
-	_filter_patterns,
-	_is_iterable,
-	match_file,
-	normalize_file)
-
-Self = TypeVar("Self", bound="PathSpec")
-"""
-:class:`PathSpec` self type hint to support Python v<3.11 using PEP 673
-recommendation.
-"""
-
-
-class PathSpec(object):
-	"""
-	The :class:`PathSpec` class is a wrapper around a list of compiled
-	:class:`.Pattern` instances.
-	"""
-
-	def __init__(self, patterns: Iterable[Pattern]) -> None:
-		"""
-		Initializes the :class:`PathSpec` instance.
-
-		*patterns* (:class:`~collections.abc.Collection` or :class:`~collections.abc.Iterable`)
-		yields each compiled pattern (:class:`.Pattern`).
-		"""
-
-		self.patterns = patterns if isinstance(patterns, CollectionType) else list(patterns)
-		"""
-		*patterns* (:class:`~collections.abc.Collection` of :class:`.Pattern`)
-		contains the compiled patterns.
-		"""
-
-	def __eq__(self, other: object) -> bool:
-		"""
-		Tests the equality of this path-spec with *other* (:class:`PathSpec`)
-		by comparing their :attr:`~PathSpec.patterns` attributes.
-		"""
-		if isinstance(other, PathSpec):
-			paired_patterns = zip_longest(self.patterns, other.patterns)
-			return all(a == b for a, b in paired_patterns)
-		else:
-			return NotImplemented
-
-	def __len__(self) -> int:
-		"""
-		Returns the number of compiled patterns this path-spec contains
-		(:class:`int`).
-		"""
-		return len(self.patterns)
-
-	def __add__(self: Self, other: "PathSpec") -> Self:
-		"""
-		Combines the :attr:`Pathspec.patterns` patterns from two
-		:class:`PathSpec` instances.
-		"""
-		if isinstance(other, PathSpec):
-			return self.__class__(self.patterns + other.patterns)
-		else:
-			return NotImplemented
-
-	def __iadd__(self: Self, other: "PathSpec") -> Self:
-		"""
-		Adds the :attr:`Pathspec.patterns` patterns from one :class:`PathSpec`
-		instance to this instance.
-		"""
-		if isinstance(other, PathSpec):
-			self.patterns += other.patterns
-			return self
-		else:
-			return NotImplemented
-
-	@classmethod
-	def from_lines(
-		cls: Type[Self],
-		pattern_factory: Union[str, Callable[[AnyStr], Pattern]],
-		lines: Iterable[AnyStr],
-	) -> Self:
-		"""
-		Compiles the pattern lines.
-
-		*pattern_factory* can be either the name of a registered pattern factory
-		(:class:`str`), or a :class:`~collections.abc.Callable` used to compile
-		patterns. It must accept an uncompiled pattern (:class:`str`) and return the
-		compiled pattern (:class:`.Pattern`).
-
-		*lines* (:class:`~collections.abc.Iterable`) yields each uncompiled pattern
-		(:class:`str`). This simply has to yield each line so that it can be a
-		:class:`io.TextIOBase` (e.g., from :func:`open` or :class:`io.StringIO`) or
-		the result from :meth:`str.splitlines`.
-
-		Returns the :class:`PathSpec` instance.
-		"""
-		if isinstance(pattern_factory, str):
-			pattern_factory = util.lookup_pattern(pattern_factory)
-
-		if not callable(pattern_factory):
-			raise TypeError(f"pattern_factory:{pattern_factory!r} is not callable.")
-
-		if not _is_iterable(lines):
-			raise TypeError(f"lines:{lines!r} is not an iterable.")
-
-		patterns = [pattern_factory(line) for line in lines if line]
-		return cls(patterns)
-
-	def match_entries(
-		self,
-		entries: Iterable[TreeEntry],
-		separators: Optional[Collection[str]] = None,
-		*,
-		negate: Optional[bool] = None,
-	) -> Iterator[TreeEntry]:
-		"""
-		Matches the entries to this path-spec.
-
-		*entries* (:class:`~collections.abc.Iterable` of :class:`~util.TreeEntry`)
-		contains the entries to be matched against :attr:`self.patterns `.
-
-		*separators* (:class:`~collections.abc.Collection` of :class:`str`; or
-		:data:`None`) optionally contains the path separators to normalize. See
-		:func:`~pathspec.util.normalize_file` for more information.
-
-		*negate* (:class:`bool` or :data:`None`) is whether to negate the match
-		results of the patterns. If :data:`True`, a pattern matching a file will
-		exclude the file rather than include it. Default is :data:`None` for
-		:data:`False`.
-
-		Returns the matched entries (:class:`~collections.abc.Iterator` of
-		:class:`~util.TreeEntry`).
-		"""
-		if not _is_iterable(entries):
-			raise TypeError(f"entries:{entries!r} is not an iterable.")
-
-		use_patterns = _filter_patterns(self.patterns)
-		for entry in entries:
-			norm_file = normalize_file(entry.path, separators)
-			is_match = self._match_file(use_patterns, norm_file)
-
-			if negate:
-				is_match = not is_match
-
-			if is_match:
-				yield entry
-
-	# Match files using the `match_file()` utility function. Subclasses may
-	# override this method as an instance method. It does not have to be a static
-	# method.
-	_match_file = staticmethod(match_file)
-
-	def match_file(
-		self,
-		file: StrPath,
-		separators: Optional[Collection[str]] = None,
-	) -> bool:
-		"""
-		Matches the file to this path-spec.
-
-		*file* (:class:`str` or :class:`os.PathLike[str]`) is the file path to be
-		matched against :attr:`self.patterns `.
-
-		*separators* (:class:`~collections.abc.Collection` of :class:`str`)
-		optionally contains the path separators to normalize. See
-		:func:`~pathspec.util.normalize_file` for more information.
-
-		Returns :data:`True` if *file* matched; otherwise, :data:`False`.
-		"""
-		norm_file = util.normalize_file(file, separators=separators)
-		return self._match_file(self.patterns, norm_file)
-
-	def match_files(
-		self,
-		files: Iterable[StrPath],
-		separators: Optional[Collection[str]] = None,
-		*,
-		negate: Optional[bool] = None,
-	) -> Iterator[StrPath]:
-		"""
-		Matches the files to this path-spec.
-
-		*files* (:class:`~collections.abc.Iterable` of :class:`str` or
-		:class:`os.PathLike[str]`) contains the file paths to be matched against
-		:attr:`self.patterns `.
-
-		*separators* (:class:`~collections.abc.Collection` of :class:`str`; or
-		:data:`None`) optionally contains the path separators to normalize. See
-		:func:`~pathspec.util.normalize_file` for more information.
-
-		*negate* (:class:`bool` or :data:`None`) is whether to negate the match
-		results of the patterns. If :data:`True`, a pattern matching a file will
-		exclude the file rather than include it. Default is :data:`None` for
-		:data:`False`.
-
-		Returns the matched files (:class:`~collections.abc.Iterator` of
-		:class:`str` or :class:`os.PathLike[str]`).
-		"""
-		if not _is_iterable(files):
-			raise TypeError(f"files:{files!r} is not an iterable.")
-
-		use_patterns = _filter_patterns(self.patterns)
-		for orig_file in files:
-			norm_file = normalize_file(orig_file, separators)
-			is_match = self._match_file(use_patterns, norm_file)
-
-			if negate:
-				is_match = not is_match
-
-			if is_match:
-				yield orig_file
-
-	def match_tree_entries(
-		self,
-		root: StrPath,
-		on_error: Optional[Callable] = None,
-		follow_links: Optional[bool] = None,
-		*,
-		negate: Optional[bool] = None,
-	) -> Iterator[TreeEntry]:
-		"""
-		Walks the specified root path for all files and matches them to this
-		path-spec.
-
-		*root* (:class:`str` or :class:`os.PathLike[str]`) is the root directory to
-		search.
-
-		*on_error* (:class:`~collections.abc.Callable` or :data:`None`) optionally
-		is the error handler for file-system exceptions. See
-		:func:`~pathspec.util.iter_tree_entries` for more information.
-
-		*follow_links* (:class:`bool` or :data:`None`) optionally is whether to walk
-		symbolic links that resolve to directories. See
-		:func:`~pathspec.util.iter_tree_files` for more information.
-
-		*negate* (:class:`bool` or :data:`None`) is whether to negate the match
-		results of the patterns. If :data:`True`, a pattern matching a file will
-		exclude the file rather than include it. Default is :data:`None` for
-		:data:`False`.
-
-		Returns the matched files (:class:`~collections.abc.Iterator` of
-		:class:`.TreeEntry`).
-		"""
-		entries = util.iter_tree_entries(root, on_error=on_error, follow_links=follow_links)
-		yield from self.match_entries(entries, negate=negate)
-
-	def match_tree_files(
-		self,
-		root: StrPath,
-		on_error: Optional[Callable] = None,
-		follow_links: Optional[bool] = None,
-		*,
-		negate: Optional[bool] = None,
-	) -> Iterator[str]:
-		"""
-		Walks the specified root path for all files and matches them to this
-		path-spec.
-
-		*root* (:class:`str` or :class:`os.PathLike[str]`) is the root directory to
-		search for files.
-
-		*on_error* (:class:`~collections.abc.Callable` or :data:`None`) optionally
-		is the error handler for file-system exceptions. See
-		:func:`~pathspec.util.iter_tree_files` for more information.
-
-		*follow_links* (:class:`bool` or :data:`None`) optionally is whether to walk
-		symbolic links that resolve to directories. See
-		:func:`~pathspec.util.iter_tree_files` for more information.
-
-		*negate* (:class:`bool` or :data:`None`) is whether to negate the match
-		results of the patterns. If :data:`True`, a pattern matching a file will
-		exclude the file rather than include it. Default is :data:`None` for
-		:data:`False`.
-
-		Returns the matched files (:class:`~collections.abc.Iterable` of
-		:class:`str`).
-		"""
-		files = util.iter_tree_files(root, on_error=on_error, follow_links=follow_links)
-		yield from self.match_files(files, negate=negate)
-
-	# Alias `match_tree_files()` as `match_tree()` for backward compatibility
-	# before v0.3.2.
-	match_tree = match_tree_files
diff --git a/server/libs/pathspec/pattern.py b/server/libs/pathspec/pattern.py
deleted file mode 100644
index 5222ec0..0000000
--- a/server/libs/pathspec/pattern.py
+++ /dev/null
@@ -1,206 +0,0 @@
-"""
-This module provides the base definition for patterns.
-"""
-
-import dataclasses
-import re
-import warnings
-from typing import (
-	Any,
-	AnyStr,
-	Iterable,
-	Iterator,
-	Match as MatchHint,
-	Optional,
-	Pattern as PatternHint,
-	Tuple,
-	Union)
-
-
-class Pattern(object):
-	"""
-	The :class:`Pattern` class is the abstract definition of a pattern.
-	"""
-
-	# Make the class dict-less.
-	__slots__ = ('include',)
-
-	def __init__(self, include: Optional[bool]) -> None:
-		"""
-		Initializes the :class:`Pattern` instance.
-
-		*include* (:class:`bool` or :data:`None`) is whether the matched
-		files should be included (:data:`True`), excluded (:data:`False`),
-		or is a null-operation (:data:`None`).
-		"""
-
-		self.include = include
-		"""
-		*include* (:class:`bool` or :data:`None`) is whether the matched
-		files should be included (:data:`True`), excluded (:data:`False`),
-		or is a null-operation (:data:`None`).
-		"""
-
-	def match(self, files: Iterable[str]) -> Iterator[str]:
-		"""
-		DEPRECATED: This method is no longer used and has been replaced by
-		:meth:`.match_file`. Use the :meth:`.match_file` method with a loop
-		for similar results.
-
-		Matches this pattern against the specified files.
-
-		*files* (:class:`~collections.abc.Iterable` of :class:`str`)
-		contains each file relative to the root directory (e.g.,
-		:data:`"relative/path/to/file"`).
-
-		Returns an :class:`~collections.abc.Iterable` yielding each matched
-		file path (:class:`str`).
-		"""
-		warnings.warn((
-			"{0.__module__}.{0.__qualname__}.match() is deprecated. Use "
-			"{0.__module__}.{0.__qualname__}.match_file() with a loop for "
-			"similar results."
-		).format(self.__class__), DeprecationWarning, stacklevel=2)
-
-		for file in files:
-			if self.match_file(file) is not None:
-				yield file
-
-	def match_file(self, file: str) -> Optional[Any]:
-		"""
-		Matches this pattern against the specified file.
-
-		*file* (:class:`str`) is the normalized file path to match against.
-
-		Returns the match result if *file* matched; otherwise, :data:`None`.
-		"""
-		raise NotImplementedError((
-			"{0.__module__}.{0.__qualname__} must override match_file()."
-		).format(self.__class__))
-
-
-class RegexPattern(Pattern):
-	"""
-	The :class:`RegexPattern` class is an implementation of a pattern
-	using regular expressions.
-	"""
-
-	# Keep the class dict-less.
-	__slots__ = ('regex',)
-
-	def __init__(
-		self,
-		pattern: Union[AnyStr, PatternHint],
-		include: Optional[bool] = None,
-	) -> None:
-		"""
-		Initializes the :class:`RegexPattern` instance.
-
-		*pattern* (:class:`str`, :class:`bytes`, :class:`re.Pattern`, or
-		:data:`None`) is the pattern to compile into a regular expression.
-
-		*include* (:class:`bool` or :data:`None`) must be :data:`None`
-		unless *pattern* is a precompiled regular expression (:class:`re.Pattern`)
-		in which case it is whether matched files should be included
-		(:data:`True`), excluded (:data:`False`), or is a null operation
-		(:data:`None`).
-
-			.. NOTE:: Subclasses do not need to support the *include*
-			   parameter.
-		"""
-
-		if isinstance(pattern, (str, bytes)):
-			assert include is None, (
-				"include:{!r} must be null when pattern:{!r} is a string."
-			).format(include, pattern)
-			regex, include = self.pattern_to_regex(pattern)
-			# NOTE: Make sure to allow a null regular expression to be
-			# returned for a null-operation.
-			if include is not None:
-				regex = re.compile(regex)
-
-		elif pattern is not None and hasattr(pattern, 'match'):
-			# Assume pattern is a precompiled regular expression.
-			# - NOTE: Used specified *include*.
-			regex = pattern
-
-		elif pattern is None:
-			# NOTE: Make sure to allow a null pattern to be passed for a
-			# null-operation.
-			assert include is None, (
-				"include:{!r} must be null when pattern:{!r} is null."
-			).format(include, pattern)
-
-		else:
-			raise TypeError("pattern:{!r} is not a string, re.Pattern, or None.".format(pattern))
-
-		super(RegexPattern, self).__init__(include)
-
-		self.regex: PatternHint = regex
-		"""
-		*regex* (:class:`re.Pattern`) is the regular expression for the
-		pattern.
-		"""
-
-	def __eq__(self, other: 'RegexPattern') -> bool:
-		"""
-		Tests the equality of this regex pattern with *other* (:class:`RegexPattern`)
-		by comparing their :attr:`~Pattern.include` and :attr:`~RegexPattern.regex`
-		attributes.
-		"""
-		if isinstance(other, RegexPattern):
-			return self.include == other.include and self.regex == other.regex
-		else:
-			return NotImplemented
-
-	def match_file(self, file: str) -> Optional['RegexMatchResult']:
-		"""
-		Matches this pattern against the specified file.
-
-		*file* (:class:`str`)
-		contains each file relative to the root directory (e.g., "relative/path/to/file").
-
-		Returns the match result (:class:`RegexMatchResult`) if *file*
-		matched; otherwise, :data:`None`.
-		"""
-		if self.include is not None:
-			match = self.regex.match(file)
-			if match is not None:
-				return RegexMatchResult(match)
-
-		return None
-
-	@classmethod
-	def pattern_to_regex(cls, pattern: str) -> Tuple[str, bool]:
-		"""
-		Convert the pattern into an uncompiled regular expression.
-
-		*pattern* (:class:`str`) is the pattern to convert into a regular
-		expression.
-
-		Returns the uncompiled regular expression (:class:`str` or :data:`None`),
-		and whether matched files should be included (:data:`True`),
-		excluded (:data:`False`), or is a null-operation (:data:`None`).
-
-			.. NOTE:: The default implementation simply returns *pattern* and
-			   :data:`True`.
-		"""
-		return pattern, True
-
-
-@dataclasses.dataclass()
-class RegexMatchResult(object):
-	"""
-	The :class:`RegexMatchResult` data class is used to return information
-	about the matched regular expression.
-	"""
-
-	# Keep the class dict-less.
-	__slots__ = (
-		'match',
-	)
-
-	match: MatchHint
-	"""
-	*match* (:class:`re.Match`) is the regex match result.
-	"""
diff --git a/server/libs/pathspec/patterns/__init__.py b/server/libs/pathspec/patterns/__init__.py
deleted file mode 100644
index 7360e9c..0000000
--- a/server/libs/pathspec/patterns/__init__.py
+++ /dev/null
@@ -1,11 +0,0 @@
-"""
-The *pathspec.patterns* package contains the pattern matching
-implementations.
-"""
-
-# Load pattern implementations.
-from . import gitwildmatch
-
-# DEPRECATED: Expose the `GitWildMatchPattern` class in this module for
-# backward compatibility with v0.5.
-from .gitwildmatch import GitWildMatchPattern
diff --git a/server/libs/pathspec/patterns/gitwildmatch.py b/server/libs/pathspec/patterns/gitwildmatch.py
deleted file mode 100644
index 5c00086..0000000
--- a/server/libs/pathspec/patterns/gitwildmatch.py
+++ /dev/null
@@ -1,421 +0,0 @@
-"""
-This module implements Git's wildmatch pattern matching which itself is
-derived from Rsync's wildmatch. Git uses wildmatch for its ".gitignore"
-files.
-"""
-
-import re
-import warnings
-from typing import (
-	AnyStr,
-	Optional,
-	Tuple)
-
-from .. import util
-from ..pattern import RegexPattern
-
-_BYTES_ENCODING = 'latin1'
-"""
-The encoding to use when parsing a byte string pattern.
-"""
-
-_DIR_MARK = 'ps_d'
-"""
-The regex group name for the directory marker. This is only used by
-:class:`GitIgnoreSpec`.
-"""
-
-
-class GitWildMatchPatternError(ValueError):
-	"""
-	The :class:`GitWildMatchPatternError` indicates an invalid git wild match
-	pattern.
-	"""
-	pass
-
-
-class GitWildMatchPattern(RegexPattern):
-	"""
-	The :class:`GitWildMatchPattern` class represents a compiled Git
-	wildmatch pattern.
-	"""
-
-	# Keep the dict-less class hierarchy.
-	__slots__ = ()
-
-	@classmethod
-	def pattern_to_regex(
-		cls,
-		pattern: AnyStr,
-	) -> Tuple[Optional[AnyStr], Optional[bool]]:
-		"""
-		Convert the pattern into a regular expression.
-
-		*pattern* (:class:`str` or :class:`bytes`) is the pattern to convert
-		into a regular expression.
-
-		Returns the uncompiled regular expression (:class:`str`, :class:`bytes`,
-		or :data:`None`); and whether matched files should be included
-		(:data:`True`), excluded (:data:`False`), or if it is a
-		null-operation (:data:`None`).
-		"""
-		if isinstance(pattern, str):
-			return_type = str
-		elif isinstance(pattern, bytes):
-			return_type = bytes
-			pattern = pattern.decode(_BYTES_ENCODING)
-		else:
-			raise TypeError(f"pattern:{pattern!r} is not a unicode or byte string.")
-
-		original_pattern = pattern
-
-		if pattern.endswith('\\ '):
-			# EDGE CASE: Spaces can be escaped with backslash.
-			# If a pattern that ends with backslash followed by a space,
-			# only strip from left.
-			pattern = pattern.lstrip()
-		else:
-			pattern = pattern.strip()
-
-		if pattern.startswith('#'):
-			# A pattern starting with a hash ('#') serves as a comment
-			# (neither includes nor excludes files). Escape the hash with a
-			# back-slash to match a literal hash (i.e., '\#').
-			regex = None
-			include = None
-
-		elif pattern == '/':
-			# EDGE CASE: According to `git check-ignore` (v2.4.1), a single
-			# '/' does not match any file.
-			regex = None
-			include = None
-
-		elif pattern:
-			if pattern.startswith('!'):
-				# A pattern starting with an exclamation mark ('!') negates the
-				# pattern (exclude instead of include). Escape the exclamation
-				# mark with a back-slash to match a literal exclamation mark
-				# (i.e., '\!').
-				include = False
-				# Remove leading exclamation mark.
-				pattern = pattern[1:]
-			else:
-				include = True
-
-			# Allow a regex override for edge cases that cannot be handled
-			# through normalization.
-			override_regex = None
-
-			# Split pattern into segments.
-			pattern_segs = pattern.split('/')
-
-			# Normalize pattern to make processing easier.
-
-			# EDGE CASE: Deal with duplicate double-asterisk sequences.
-			# Collapse each sequence down to one double-asterisk. Iterate over
-			# the segments in reverse and remove the duplicate double
-			# asterisks as we go.
-			for i in range(len(pattern_segs) - 1, 0, -1):
-				prev = pattern_segs[i-1]
-				seg = pattern_segs[i]
-				if prev == '**' and seg == '**':
-					del pattern_segs[i]
-
-			if len(pattern_segs) == 2 and pattern_segs[0] == '**' and not pattern_segs[1]:
-				# EDGE CASE: The '**/' pattern should match everything except
-				# individual files in the root directory. This case cannot be
-				# adequately handled through normalization. Use the override.
-				override_regex = f'^.+(?P<{_DIR_MARK}>/).*$'
-
-			if not pattern_segs[0]:
-				# A pattern beginning with a slash ('/') will only match paths
-				# directly on the root directory instead of any descendant
-				# paths. So, remove empty first segment to make pattern relative
-				# to root.
-				del pattern_segs[0]
-
-			elif len(pattern_segs) == 1 or (len(pattern_segs) == 2 and not pattern_segs[1]):
-				# A single pattern without a beginning slash ('/') will match
-				# any descendant path. This is equivalent to "**/{pattern}". So,
-				# prepend with double-asterisks to make pattern relative to
-				# root.
-				# EDGE CASE: This also holds for a single pattern with a
-				# trailing slash (e.g. dir/).
-				if pattern_segs[0] != '**':
-					pattern_segs.insert(0, '**')
-
-			else:
-				# EDGE CASE: A pattern without a beginning slash ('/') but
-				# contains at least one prepended directory (e.g.
-				# "dir/{pattern}") should not match "**/dir/{pattern}",
-				# according to `git check-ignore` (v2.4.1).
-				pass
-
-			if not pattern_segs:
-				# After resolving the edge cases, we end up with no pattern at
-				# all. This must be because the pattern is invalid.
-				raise GitWildMatchPatternError(f"Invalid git pattern: {original_pattern!r}")
-
-			if not pattern_segs[-1] and len(pattern_segs) > 1:
-				# A pattern ending with a slash ('/') will match all descendant
-				# paths if it is a directory but not if it is a regular file.
-				# This is equivalent to "{pattern}/**". So, set last segment to
-				# a double-asterisk to include all descendants.
-				pattern_segs[-1] = '**'
-
-			if override_regex is None:
-				# Build regular expression from pattern.
-				output = ['^']
-				need_slash = False
-				end = len(pattern_segs) - 1
-				for i, seg in enumerate(pattern_segs):
-					if seg == '**':
-						if i == 0 and i == end:
-							# A pattern consisting solely of double-asterisks ('**')
-							# will match every path.
-							output.append(f'[^/]+(?:(?P<{_DIR_MARK}>/).*)?')
-						elif i == 0:
-							# A normalized pattern beginning with double-asterisks
-							# ('**') will match any leading path segments.
-							output.append('(?:.+/)?')
-							need_slash = False
-						elif i == end:
-							# A normalized pattern ending with double-asterisks ('**')
-							# will match any trailing path segments.
-							output.append(f'(?P<{_DIR_MARK}>/).*')
-						else:
-							# A pattern with inner double-asterisks ('**') will match
-							# multiple (or zero) inner path segments.
-							output.append('(?:/.+)?')
-							need_slash = True
-
-					elif seg == '*':
-						# Match single path segment.
-						if need_slash:
-							output.append('/')
-
-						output.append('[^/]+')
-
-						if i == end:
-							# A pattern ending without a slash ('/') will match a file
-							# or a directory (with paths underneath it). E.g., "foo"
-							# matches "foo", "foo/bar", "foo/bar/baz", etc.
-							output.append(f'(?:(?P<{_DIR_MARK}>/).*)?')
-
-						need_slash = True
-
-					else:
-						# Match segment glob pattern.
-						if need_slash:
-							output.append('/')
-
-						try:
-							output.append(cls._translate_segment_glob(seg))
-						except ValueError as e:
-							raise GitWildMatchPatternError(f"Invalid git pattern: {original_pattern!r}") from e
-
-						if i == end:
-							# A pattern ending without a slash ('/') will match a file
-							# or a directory (with paths underneath it). E.g., "foo"
-							# matches "foo", "foo/bar", "foo/bar/baz", etc.
-							output.append(f'(?:(?P<{_DIR_MARK}>/).*)?')
-
-						need_slash = True
-
-				output.append('$')
-				regex = ''.join(output)
-
-			else:
-				# Use regex override.
-				regex = override_regex
-
-		else:
-			# A blank pattern is a null-operation (neither includes nor
-			# excludes files).
-			regex = None
-			include = None
-
-		if regex is not None and return_type is bytes:
-			regex = regex.encode(_BYTES_ENCODING)
-
-		return regex, include
-
-	@staticmethod
-	def _translate_segment_glob(pattern: str) -> str:
-		"""
-		Translates the glob pattern to a regular expression. This is used in
-		the constructor to translate a path segment glob pattern to its
-		corresponding regular expression.
-
-		*pattern* (:class:`str`) is the glob pattern.
-
-		Returns the regular expression (:class:`str`).
-		"""
-		# NOTE: This is derived from `fnmatch.translate()` and is similar to
-		# the POSIX function `fnmatch()` with the `FNM_PATHNAME` flag set.
-
-		escape = False
-		regex = ''
-		i, end = 0, len(pattern)
-		while i < end:
-			# Get next character.
-			char = pattern[i]
-			i += 1
-
-			if escape:
-				# Escape the character.
-				escape = False
-				regex += re.escape(char)
-
-			elif char == '\\':
-				# Escape character, escape next character.
-				escape = True
-
-			elif char == '*':
-				# Multi-character wildcard. Match any string (except slashes),
-				# including an empty string.
-				regex += '[^/]*'
-
-			elif char == '?':
-				# Single-character wildcard. Match any single character (except
-				# a slash).
-				regex += '[^/]'
-
-			elif char == '[':
-				# Bracket expression wildcard. Except for the beginning
-				# exclamation mark, the whole bracket expression can be used
-				# directly as regex but we have to find where the expression
-				# ends.
-				# - "[][!]" matches ']', '[' and '!'.
-				# - "[]-]" matches ']' and '-'.
-				# - "[!]a-]" matches any character except ']', 'a' and '-'.
-				j = i
-        
-				# Pass bracket expression negation.
-				if j < end and (pattern[j] == '!' or pattern[j] == '^'):
-					j += 1
-          
-				# Pass first closing bracket if it is at the beginning of the
-				# expression.
-				if j < end and pattern[j] == ']':
-					j += 1
-          
-				# Find closing bracket. Stop once we reach the end or find it.
-				while j < end and pattern[j] != ']':
-					j += 1
-
-				if j < end:
-					# Found end of bracket expression. Increment j to be one past
-					# the closing bracket:
-					#
-					#  [...]
-					#   ^   ^
-					#   i   j
-					#
-					j += 1
-					expr = '['
-
-					if pattern[i] == '!':
-						# Bracket expression needs to be negated.
-						expr += '^'
-						i += 1
-					elif pattern[i] == '^':
-						# POSIX declares that the regex bracket expression negation
-						# "[^...]" is undefined in a glob pattern. Python's
-						# `fnmatch.translate()` escapes the caret ('^') as a
-						# literal. Git supports the using a caret for negation.
-						# Maintain consistency with Git because that is the expected
-						# behavior.
-						expr += '^'
-						i += 1
-
-					# Build regex bracket expression. Escape slashes so they are
-					# treated as literal slashes by regex as defined by POSIX.
-					expr += pattern[i:j].replace('\\', '\\\\')
-
-					# Add regex bracket expression to regex result.
-					regex += expr
-
-					# Set i to one past the closing bracket.
-					i = j
-
-				else:
-					# Failed to find closing bracket, treat opening bracket as a
-					# bracket literal instead of as an expression.
-					regex += '\\['
-
-			else:
-				# Regular character, escape it for regex.
-				regex += re.escape(char)
-
-		if escape:
-			raise ValueError(f"Escape character found with no next character to escape: {pattern!r}")
-
-		return regex
-
-	@staticmethod
-	def escape(s: AnyStr) -> AnyStr:
-		"""
-		Escape special characters in the given string.
-
-		*s* (:class:`str` or :class:`bytes`) a filename or a string that you
-		want to escape, usually before adding it to a ".gitignore".
-
-		Returns the escaped string (:class:`str` or :class:`bytes`).
-		"""
-		if isinstance(s, str):
-			return_type = str
-			string = s
-		elif isinstance(s, bytes):
-			return_type = bytes
-			string = s.decode(_BYTES_ENCODING)
-		else:
-			raise TypeError(f"s:{s!r} is not a unicode or byte string.")
-
-		# Reference: https://git-scm.com/docs/gitignore#_pattern_format
-		meta_characters = r"[]!*#?"
-
-		out_string = "".join("\\" + x if x in meta_characters else x for x in string)
-
-		if return_type is bytes:
-			return out_string.encode(_BYTES_ENCODING)
-		else:
-			return out_string
-
-util.register_pattern('gitwildmatch', GitWildMatchPattern)
-
-
-class GitIgnorePattern(GitWildMatchPattern):
-	"""
-	The :class:`GitIgnorePattern` class is deprecated by :class:`GitWildMatchPattern`.
-	This class only exists to maintain compatibility with v0.4.
-	"""
-
-	def __init__(self, *args, **kw) -> None:
-		"""
-		Warn about deprecation.
-		"""
-		self._deprecated()
-		super(GitIgnorePattern, self).__init__(*args, **kw)
-
-	@staticmethod
-	def _deprecated() -> None:
-		"""
-		Warn about deprecation.
-		"""
-		warnings.warn((
-			"GitIgnorePattern ('gitignore') is deprecated. Use "
-			"GitWildMatchPattern ('gitwildmatch') instead."
-		), DeprecationWarning, stacklevel=3)
-
-	@classmethod
-	def pattern_to_regex(cls, *args, **kw):
-		"""
-		Warn about deprecation.
-		"""
-		cls._deprecated()
-		return super(GitIgnorePattern, cls).pattern_to_regex(*args, **kw)
-
-# Register `GitIgnorePattern` as "gitignore" for backward compatibility
-# with v0.4.
-util.register_pattern('gitignore', GitIgnorePattern)
diff --git a/server/libs/pathspec/py.typed b/server/libs/pathspec/py.typed
deleted file mode 100644
index b01eaaf..0000000
--- a/server/libs/pathspec/py.typed
+++ /dev/null
@@ -1 +0,0 @@
-# Marker file for PEP 561.  The pathspec package uses inline types.
diff --git a/server/libs/pathspec/util.py b/server/libs/pathspec/util.py
deleted file mode 100644
index 969e3bc..0000000
--- a/server/libs/pathspec/util.py
+++ /dev/null
@@ -1,719 +0,0 @@
-"""
-This module provides utility methods for dealing with path-specs.
-"""
-
-import os
-import os.path
-import pathlib
-import posixpath
-import stat
-import sys
-import warnings
-from collections.abc import (
-	Collection as CollectionType,
-	Iterable as IterableType)
-from os import (
-	PathLike)
-from typing import (
-	Any,
-	AnyStr,
-	Callable,
-	Collection,
-	Dict,
-	Iterable,
-	Iterator,
-	List,
-	Optional,
-	Sequence,
-	Set,
-	Union)
-
-from .pattern import (
-	Pattern)
-
-if sys.version_info >= (3, 9):
-	StrPath = Union[str, PathLike[str]]
-else:
-	StrPath = Union[str, PathLike]
-
-NORMALIZE_PATH_SEPS = [
-	__sep
-	for __sep in [os.sep, os.altsep]
-	if __sep and __sep != posixpath.sep
-]
-"""
-*NORMALIZE_PATH_SEPS* (:class:`list` of :class:`str`) contains the path
-separators that need to be normalized to the POSIX separator for the
-current operating system. The separators are determined by examining
-:data:`os.sep` and :data:`os.altsep`.
-"""
-
-_registered_patterns = {}
-"""
-*_registered_patterns* (:class:`dict`) maps a name (:class:`str`) to the
-registered pattern factory (:class:`~collections.abc.Callable`).
-"""
-
-
-def append_dir_sep(path: pathlib.Path) -> str:
-	"""
-	Appends the path separator to the path if the path is a directory.
-	This can be used to aid in distinguishing between directories and
-	files on the file-system by relying on the presence of a trailing path
-	separator.
-
-	*path* (:class:`pathlib.path`) is the path to use.
-
-	Returns the path (:class:`str`).
-	"""
-	str_path = str(path)
-	if path.is_dir():
-		str_path += os.sep
-
-	return str_path
-
-
-def detailed_match_files(
-	patterns: Iterable[Pattern],
-	files: Iterable[str],
-	all_matches: Optional[bool] = None,
-) -> Dict[str, 'MatchDetail']:
-	"""
-	Matches the files to the patterns, and returns which patterns matched
-	the files.
-
-	*patterns* (:class:`~collections.abc.Iterable` of :class:`~pathspec.pattern.Pattern`)
-	contains the patterns to use.
-
-	*files* (:class:`~collections.abc.Iterable` of :class:`str`) contains
-	the normalized file paths to be matched against *patterns*.
-
-	*all_matches* (:class:`boot` or :data:`None`) is whether to return all
-	matches patterns (:data:`True`), or only the last matched pattern
-	(:data:`False`). Default is :data:`None` for :data:`False`.
-
-	Returns the matched files (:class:`dict`) which maps each matched file
-	(:class:`str`) to the patterns that matched in order (:class:`.MatchDetail`).
-	"""
-	all_files = files if isinstance(files, CollectionType) else list(files)
-	return_files = {}
-	for pattern in patterns:
-		if pattern.include is not None:
-			result_files = pattern.match(all_files)  # TODO: Replace with `.match_file()`.
-			if pattern.include:
-				# Add files and record pattern.
-				for result_file in result_files:
-					if result_file in return_files:
-						if all_matches:
-							return_files[result_file].patterns.append(pattern)
-						else:
-							return_files[result_file].patterns[0] = pattern
-					else:
-						return_files[result_file] = MatchDetail([pattern])
-
-			else:
-				# Remove files.
-				for file in result_files:
-					del return_files[file]
-
-	return return_files
-
-
-def _filter_patterns(patterns: Iterable[Pattern]) -> List[Pattern]:
-	"""
-	Filters out null-patterns.
-
-	*patterns* (:class:`Iterable` of :class:`.Pattern`) contains the
-	patterns.
-
-	Returns the patterns (:class:`list` of :class:`.Pattern`).
-	"""
-	return [
-		__pat
-		for __pat in patterns
-		if __pat.include is not None
-	]
-
-
-def _is_iterable(value: Any) -> bool:
-	"""
-	Check whether the value is an iterable (excludes strings).
-
-	*value* is the value to check,
-
-	Returns whether *value* is a iterable (:class:`bool`).
-	"""
-	return isinstance(value, IterableType) and not isinstance(value, (str, bytes))
-
-
-def iter_tree_entries(
-	root: StrPath,
-	on_error: Optional[Callable] = None,
-	follow_links: Optional[bool] = None,
-) -> Iterator['TreeEntry']:
-	"""
-	Walks the specified directory for all files and directories.
-
-	*root* (:class:`str` or :class:`os.PathLike[str]`) is the root directory to
-	search.
-
-	*on_error* (:class:`~collections.abc.Callable` or :data:`None`)
-	optionally is the error handler for file-system exceptions. It will be
-	called with the exception (:exc:`OSError`). Reraise the exception to
-	abort the walk. Default is :data:`None` to ignore file-system
-	exceptions.
-
-	*follow_links* (:class:`bool` or :data:`None`) optionally is whether
-	to walk symbolic links that resolve to directories. Default is
-	:data:`None` for :data:`True`.
-
-	Raises :exc:`RecursionError` if recursion is detected.
-
-	Returns an :class:`~collections.abc.Iterator` yielding each file or
-	directory entry (:class:`.TreeEntry`) relative to *root*.
-	"""
-	if on_error is not None and not callable(on_error):
-		raise TypeError(f"on_error:{on_error!r} is not callable.")
-
-	if follow_links is None:
-		follow_links = True
-
-	yield from _iter_tree_entries_next(os.path.abspath(root), '', {}, on_error, follow_links)
-
-
-def _iter_tree_entries_next(
-	root_full: str,
-	dir_rel: str,
-	memo: Dict[str, str],
-	on_error: Callable,
-	follow_links: bool,
-) -> Iterator['TreeEntry']:
-	"""
-	Scan the directory for all descendant files.
-
-	*root_full* (:class:`str`) the absolute path to the root directory.
-
-	*dir_rel* (:class:`str`) the path to the directory to scan relative to
-	*root_full*.
-
-	*memo* (:class:`dict`) keeps track of ancestor directories
-	encountered. Maps each ancestor real path (:class:`str`) to relative
-	path (:class:`str`).
-
-	*on_error* (:class:`~collections.abc.Callable` or :data:`None`)
-	optionally is the error handler for file-system exceptions.
-
-	*follow_links* (:class:`bool`) is whether to walk symbolic links that
-	resolve to directories.
-
-	Yields each entry (:class:`.TreeEntry`).
-	"""
-	dir_full = os.path.join(root_full, dir_rel)
-	dir_real = os.path.realpath(dir_full)
-
-	# Remember each encountered ancestor directory and its canonical
-	# (real) path. If a canonical path is encountered more than once,
-	# recursion has occurred.
-	if dir_real not in memo:
-		memo[dir_real] = dir_rel
-	else:
-		raise RecursionError(real_path=dir_real, first_path=memo[dir_real], second_path=dir_rel)
-
-	with os.scandir(dir_full) as scan_iter:
-		node_ent: os.DirEntry
-		for node_ent in scan_iter:
-			node_rel = os.path.join(dir_rel, node_ent.name)
-
-			# Inspect child node.
-			try:
-				node_lstat = node_ent.stat(follow_symlinks=False)
-			except OSError as e:
-				if on_error is not None:
-					on_error(e)
-				continue
-
-			if node_ent.is_symlink():
-				# Child node is a link, inspect the target node.
-				try:
-					node_stat = node_ent.stat()
-				except OSError as e:
-					if on_error is not None:
-						on_error(e)
-					continue
-			else:
-				node_stat = node_lstat
-
-			if node_ent.is_dir(follow_symlinks=follow_links):
-				# Child node is a directory, recurse into it and yield its
-				# descendant files.
-				yield TreeEntry(node_ent.name, node_rel, node_lstat, node_stat)
-
-				yield from _iter_tree_entries_next(root_full, node_rel, memo, on_error, follow_links)
-
-			elif node_ent.is_file() or node_ent.is_symlink():
-				# Child node is either a file or an unfollowed link, yield it.
-				yield TreeEntry(node_ent.name, node_rel, node_lstat, node_stat)
-
-	# NOTE: Make sure to remove the canonical (real) path of the directory
-	# from the ancestors memo once we are done with it. This allows the
-	# same directory to appear multiple times. If this is not done, the
-	# second occurrence of the directory will be incorrectly interpreted
-	# as a recursion. See .
-	del memo[dir_real]
-
-
-def iter_tree_files(
-	root: StrPath,
-	on_error: Optional[Callable] = None,
-	follow_links: Optional[bool] = None,
-) -> Iterator[str]:
-	"""
-	Walks the specified directory for all files.
-
-	*root* (:class:`str` or :class:`os.PathLike[str]`) is the root directory to
-	search for files.
-
-	*on_error* (:class:`~collections.abc.Callable` or :data:`None`)
-	optionally is the error handler for file-system exceptions. It will be
-	called with the exception (:exc:`OSError`). Reraise the exception to
-	abort the walk. Default is :data:`None` to ignore file-system
-	exceptions.
-
-	*follow_links* (:class:`bool` or :data:`None`) optionally is whether
-	to walk symbolic links that resolve to directories. Default is
-	:data:`None` for :data:`True`.
-
-	Raises :exc:`RecursionError` if recursion is detected.
-
-	Returns an :class:`~collections.abc.Iterator` yielding the path to
-	each file (:class:`str`) relative to *root*.
-	"""
-	for entry in iter_tree_entries(root, on_error=on_error, follow_links=follow_links):
-		if not entry.is_dir(follow_links):
-			yield entry.path
-
-
-def iter_tree(root, on_error=None, follow_links=None):
-	"""
-	DEPRECATED: The :func:`.iter_tree` function is an alias for the
-	:func:`.iter_tree_files` function.
-	"""
-	warnings.warn((
-		"util.iter_tree() is deprecated. Use util.iter_tree_files() instead."
-	), DeprecationWarning, stacklevel=2)
-	return iter_tree_files(root, on_error=on_error, follow_links=follow_links)
-
-
-def lookup_pattern(name: str) -> Callable[[AnyStr], Pattern]:
-	"""
-	Lookups a registered pattern factory by name.
-
-	*name* (:class:`str`) is the name of the pattern factory.
-
-	Returns the registered pattern factory (:class:`~collections.abc.Callable`).
-	If no pattern factory is registered, raises :exc:`KeyError`.
-	"""
-	return _registered_patterns[name]
-
-
-def match_file(patterns: Iterable[Pattern], file: str) -> bool:
-	"""
-	Matches the file to the patterns.
-
-	*patterns* (:class:`~collections.abc.Iterable` of :class:`~pathspec.pattern.Pattern`)
-	contains the patterns to use.
-
-	*file* (:class:`str`) is the normalized file path to be matched
-	against *patterns*.
-
-	Returns :data:`True` if *file* matched; otherwise, :data:`False`.
-	"""
-	matched = False
-	for pattern in patterns:
-		if pattern.include is not None:
-			if pattern.match_file(file) is not None:
-				matched = pattern.include
-
-	return matched
-
-
-def match_files(
-	patterns: Iterable[Pattern],
-	files: Iterable[str],
-) -> Set[str]:
-	"""
-	DEPRECATED: This is an old function no longer used. Use the :func:`.match_file`
-	function with a loop for better results.
-
-	Matches the files to the patterns.
-
-	*patterns* (:class:`~collections.abc.Iterable` of :class:`~pathspec.pattern.Pattern`)
-	contains the patterns to use.
-
-	*files* (:class:`~collections.abc.Iterable` of :class:`str`) contains
-	the normalized file paths to be matched against *patterns*.
-
-	Returns the matched files (:class:`set` of :class:`str`).
-	"""
-	warnings.warn((
-		"util.match_files() is deprecated. Use util.match_file() with a "
-		"loop for better results."
-	), DeprecationWarning, stacklevel=2)
-
-	use_patterns = _filter_patterns(patterns)
-
-	return_files = set()
-	for file in files:
-		if match_file(use_patterns, file):
-			return_files.add(file)
-
-	return return_files
-
-
-def normalize_file(
-	file: StrPath,
-	separators: Optional[Collection[str]] = None,
-) -> str:
-	"""
-	Normalizes the file path to use the POSIX path separator (i.e.,
-	:data:`'/'`), and make the paths relative (remove leading :data:`'/'`).
-
-	*file* (:class:`str` or :class:`os.PathLike[str]`) is the file path.
-
-	*separators* (:class:`~collections.abc.Collection` of :class:`str`; or
-	:data:`None`) optionally contains the path separators to normalize.
-	This does not need to include the POSIX path separator (:data:`'/'`),
-	but including it will not affect the results. Default is :data:`None`
-	for :data:`NORMALIZE_PATH_SEPS`. To prevent normalization, pass an
-	empty container (e.g., an empty tuple :data:`()`).
-
-	Returns the normalized file path (:class:`str`).
-	"""
-	# Normalize path separators.
-	if separators is None:
-		separators = NORMALIZE_PATH_SEPS
-
-	# Convert path object to string.
-	norm_file: str = os.fspath(file)
-
-	for sep in separators:
-		norm_file = norm_file.replace(sep, posixpath.sep)
-
-	if norm_file.startswith('/'):
-		# Make path relative.
-		norm_file = norm_file[1:]
-
-	elif norm_file.startswith('./'):
-		# Remove current directory prefix.
-		norm_file = norm_file[2:]
-
-	return norm_file
-
-
-def normalize_files(
-	files: Iterable[StrPath],
-	separators: Optional[Collection[str]] = None,
-) -> Dict[str, List[StrPath]]:
-	"""
-	DEPRECATED: This function is no longer used. Use the :func:`.normalize_file`
-	function with a loop for better results.
-
-	Normalizes the file paths to use the POSIX path separator.
-
-	*files* (:class:`~collections.abc.Iterable` of :class:`str` or
-	:class:`os.PathLike[str]`) contains the file paths to be normalized.
-
-	*separators* (:class:`~collections.abc.Collection` of :class:`str`; or
-	:data:`None`) optionally contains the path separators to normalize.
-	See :func:`normalize_file` for more information.
-
-	Returns a :class:`dict` mapping each normalized file path (:class:`str`)
-	to the original file paths (:class:`list` of :class:`str` or
-	:class:`os.PathLike[str]`).
-	"""
-	warnings.warn((
-		"util.normalize_files() is deprecated. Use util.normalize_file() "
-		"with a loop for better results."
-	), DeprecationWarning, stacklevel=2)
-
-	norm_files = {}
-	for path in files:
-		norm_file = normalize_file(path, separators=separators)
-		if norm_file in norm_files:
-			norm_files[norm_file].append(path)
-		else:
-			norm_files[norm_file] = [path]
-
-	return norm_files
-
-
-def register_pattern(
-	name: str,
-	pattern_factory: Callable[[AnyStr], Pattern],
-	override: Optional[bool] = None,
-) -> None:
-	"""
-	Registers the specified pattern factory.
-
-	*name* (:class:`str`) is the name to register the pattern factory
-	under.
-
-	*pattern_factory* (:class:`~collections.abc.Callable`) is used to
-	compile patterns. It must accept an uncompiled pattern (:class:`str`)
-	and return the compiled pattern (:class:`.Pattern`).
-
-	*override* (:class:`bool` or :data:`None`) optionally is whether to
-	allow overriding an already registered pattern under the same name
-	(:data:`True`), instead of raising an :exc:`AlreadyRegisteredError`
-	(:data:`False`). Default is :data:`None` for :data:`False`.
-	"""
-	if not isinstance(name, str):
-		raise TypeError(f"name:{name!r} is not a string.")
-
-	if not callable(pattern_factory):
-		raise TypeError(f"pattern_factory:{pattern_factory!r} is not callable.")
-
-	if name in _registered_patterns and not override:
-		raise AlreadyRegisteredError(name, _registered_patterns[name])
-
-	_registered_patterns[name] = pattern_factory
-
-
-class AlreadyRegisteredError(Exception):
-	"""
-	The :exc:`AlreadyRegisteredError` exception is raised when a pattern
-	factory is registered under a name already in use.
-	"""
-
-	def __init__(
-		self,
-		name: str,
-		pattern_factory: Callable[[AnyStr], Pattern],
-	) -> None:
-		"""
-		Initializes the :exc:`AlreadyRegisteredError` instance.
-
-		*name* (:class:`str`) is the name of the registered pattern.
-
-		*pattern_factory* (:class:`~collections.abc.Callable`) is the
-		registered pattern factory.
-		"""
-		super(AlreadyRegisteredError, self).__init__(name, pattern_factory)
-
-	@property
-	def message(self) -> str:
-		"""
-		*message* (:class:`str`) is the error message.
-		"""
-		return "{name!r} is already registered for pattern factory:{pattern_factory!r}.".format(
-			name=self.name,
-			pattern_factory=self.pattern_factory,
-		)
-
-	@property
-	def name(self) -> str:
-		"""
-		*name* (:class:`str`) is the name of the registered pattern.
-		"""
-		return self.args[0]
-
-	@property
-	def pattern_factory(self) -> Callable[[AnyStr], Pattern]:
-		"""
-		*pattern_factory* (:class:`~collections.abc.Callable`) is the
-		registered pattern factory.
-		"""
-		return self.args[1]
-
-
-class RecursionError(Exception):
-	"""
-	The :exc:`RecursionError` exception is raised when recursion is
-	detected.
-	"""
-
-	def __init__(
-		self,
-		real_path: str,
-		first_path: str,
-		second_path: str,
-	) -> None:
-		"""
-		Initializes the :exc:`RecursionError` instance.
-
-		*real_path* (:class:`str`) is the real path that recursion was
-		encountered on.
-
-		*first_path* (:class:`str`) is the first path encountered for
-		*real_path*.
-
-		*second_path* (:class:`str`) is the second path encountered for
-		*real_path*.
-		"""
-		super(RecursionError, self).__init__(real_path, first_path, second_path)
-
-	@property
-	def first_path(self) -> str:
-		"""
-		*first_path* (:class:`str`) is the first path encountered for
-		:attr:`self.real_path `.
-		"""
-		return self.args[1]
-
-	@property
-	def message(self) -> str:
-		"""
-		*message* (:class:`str`) is the error message.
-		"""
-		return "Real path {real!r} was encountered at {first!r} and then {second!r}.".format(
-			real=self.real_path,
-			first=self.first_path,
-			second=self.second_path,
-		)
-
-	@property
-	def real_path(self) -> str:
-		"""
-		*real_path* (:class:`str`) is the real path that recursion was
-		encountered on.
-		"""
-		return self.args[0]
-
-	@property
-	def second_path(self) -> str:
-		"""
-		*second_path* (:class:`str`) is the second path encountered for
-		:attr:`self.real_path `.
-		"""
-		return self.args[2]
-
-
-class MatchDetail(object):
-	"""
-	The :class:`.MatchDetail` class contains information about
-	"""
-
-	# Make the class dict-less.
-	__slots__ = ('patterns',)
-
-	def __init__(self, patterns: Sequence[Pattern]) -> None:
-		"""
-		Initialize the :class:`.MatchDetail` instance.
-
-		*patterns* (:class:`~collections.abc.Sequence` of :class:`~pathspec.pattern.Pattern`)
-		contains the patterns that matched the file in the order they were
-		encountered.
-		"""
-
-		self.patterns = patterns
-		"""
-		*patterns* (:class:`~collections.abc.Sequence` of :class:`~pathspec.pattern.Pattern`)
-		contains the patterns that matched the file in the order they were
-		encountered.
-		"""
-
-
-class TreeEntry(object):
-	"""
-	The :class:`.TreeEntry` class contains information about a file-system
-	entry.
-	"""
-
-	# Make the class dict-less.
-	__slots__ = ('_lstat', 'name', 'path', '_stat')
-
-	def __init__(
-		self,
-		name: str,
-		path: str,
-		lstat: os.stat_result,
-		stat: os.stat_result,
-	) -> None:
-		"""
-		Initialize the :class:`.TreeEntry` instance.
-
-		*name* (:class:`str`) is the base name of the entry.
-
-		*path* (:class:`str`) is the relative path of the entry.
-
-		*lstat* (:class:`os.stat_result`) is the stat result of the direct
-		entry.
-
-		*stat* (:class:`os.stat_result`) is the stat result of the entry,
-		potentially linked.
-		"""
-
-		self._lstat: os.stat_result = lstat
-		"""
-		*_lstat* (:class:`os.stat_result`) is the stat result of the direct
-		entry.
-		"""
-
-		self.name: str = name
-		"""
-		*name* (:class:`str`) is the base name of the entry.
-		"""
-
-		self.path: str = path
-		"""
-		*path* (:class:`str`) is the path of the entry.
-		"""
-
-		self._stat: os.stat_result = stat
-		"""
-		*_stat* (:class:`os.stat_result`) is the stat result of the linked
-		entry.
-		"""
-
-	def is_dir(self, follow_links: Optional[bool] = None) -> bool:
-		"""
-		Get whether the entry is a directory.
-
-		*follow_links* (:class:`bool` or :data:`None`) is whether to follow
-		symbolic links. If this is :data:`True`, a symlink to a directory
-		will result in :data:`True`. Default is :data:`None` for :data:`True`.
-
-		Returns whether the entry is a directory (:class:`bool`).
-		"""
-		if follow_links is None:
-			follow_links = True
-
-		node_stat = self._stat if follow_links else self._lstat
-		return stat.S_ISDIR(node_stat.st_mode)
-
-	def is_file(self, follow_links: Optional[bool] = None) -> bool:
-		"""
-		Get whether the entry is a regular file.
-
-		*follow_links* (:class:`bool` or :data:`None`) is whether to follow
-		symbolic links. If this is :data:`True`, a symlink to a regular file
-		will result in :data:`True`. Default is :data:`None` for :data:`True`.
-
-		Returns whether the entry is a regular file (:class:`bool`).
-		"""
-		if follow_links is None:
-			follow_links = True
-
-		node_stat = self._stat if follow_links else self._lstat
-		return stat.S_ISREG(node_stat.st_mode)
-
-	def is_symlink(self) -> bool:
-		"""
-		Returns whether the entry is a symbolic link (:class:`bool`).
-		"""
-		return stat.S_ISLNK(self._lstat.st_mode)
-
-	def stat(self, follow_links: Optional[bool] = None) -> os.stat_result:
-		"""
-		Get the cached stat result for the entry.
-
-		*follow_links* (:class:`bool` or :data:`None`) is whether to follow
-		symbolic links. If this is :data:`True`, the stat result of the
-		linked file will be returned. Default is :data:`None` for :data:`True`.
-
-		Returns that stat result (:class:`os.stat_result`).
-		"""
-		if follow_links is None:
-			follow_links = True
-
-		return self._stat if follow_links else self._lstat
diff --git a/server/libs/ply-3.11.dist-info/DESCRIPTION.rst b/server/libs/ply-3.11.dist-info/DESCRIPTION.rst
deleted file mode 100644
index 5e826bd..0000000
--- a/server/libs/ply-3.11.dist-info/DESCRIPTION.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-
-PLY is yet another implementation of lex and yacc for Python. Some notable
-features include the fact that its implemented entirely in Python and it
-uses LALR(1) parsing which is efficient and well suited for larger grammars.
-
-PLY provides most of the standard lex/yacc features including support for empty 
-productions, precedence rules, error recovery, and support for ambiguous grammars. 
-
-PLY is extremely easy to use and provides very extensive error checking. 
-It is compatible with both Python 2 and Python 3.
-
-
diff --git a/server/libs/ply-3.11.dist-info/INSTALLER b/server/libs/ply-3.11.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/server/libs/ply-3.11.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/server/libs/ply-3.11.dist-info/METADATA b/server/libs/ply-3.11.dist-info/METADATA
deleted file mode 100644
index 25ed5ab..0000000
--- a/server/libs/ply-3.11.dist-info/METADATA
+++ /dev/null
@@ -1,25 +0,0 @@
-Metadata-Version: 2.0
-Name: ply
-Version: 3.11
-Summary: Python Lex & Yacc
-Home-page: http://www.dabeaz.com/ply/
-Author: David Beazley
-Author-email: dave@dabeaz.com
-License: BSD
-Description-Content-Type: UNKNOWN
-Platform: UNKNOWN
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 2
-
-
-PLY is yet another implementation of lex and yacc for Python. Some notable
-features include the fact that its implemented entirely in Python and it
-uses LALR(1) parsing which is efficient and well suited for larger grammars.
-
-PLY provides most of the standard lex/yacc features including support for empty 
-productions, precedence rules, error recovery, and support for ambiguous grammars. 
-
-PLY is extremely easy to use and provides very extensive error checking. 
-It is compatible with both Python 2 and Python 3.
-
-
diff --git a/server/libs/ply-3.11.dist-info/RECORD b/server/libs/ply-3.11.dist-info/RECORD
deleted file mode 100644
index 5a76af5..0000000
--- a/server/libs/ply-3.11.dist-info/RECORD
+++ /dev/null
@@ -1,20 +0,0 @@
-ply-3.11.dist-info/DESCRIPTION.rst,sha256=nnBY1Nj_GhIsOFck7R2yGHobQVosxi2CPQkHgeSZ0Hg,519
-ply-3.11.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-ply-3.11.dist-info/METADATA,sha256=pYZ9p1TsWGQ8Kxp9yEJVyvs25PkR5h3gIDuTOCsvJGg,844
-ply-3.11.dist-info/RECORD,,
-ply-3.11.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-ply-3.11.dist-info/WHEEL,sha256=kdsN-5OJAZIiHN-iO4Rhl82KyS0bDWf4uBwMbkNafr8,110
-ply-3.11.dist-info/metadata.json,sha256=s7M7va9E25_7TRpzHfNCfN73Ieiy5iKogF0PzXtMxMI,515
-ply-3.11.dist-info/top_level.txt,sha256=gDYBHRQ7Vy0tY0AjXyJtadvU2LDaOsHqhhV70AGsisc,4
-ply/__init__.py,sha256=sx6iBIF__WKIeU0iw2WSoSqBhclHF5EhBTc0wDigTV8,103
-ply/__pycache__/__init__.cpython-311.pyc,,
-ply/__pycache__/cpp.cpython-311.pyc,,
-ply/__pycache__/ctokens.cpython-311.pyc,,
-ply/__pycache__/lex.cpython-311.pyc,,
-ply/__pycache__/yacc.cpython-311.pyc,,
-ply/__pycache__/ygen.cpython-311.pyc,,
-ply/cpp.py,sha256=KTg13R5SKeicwZm7bIPL44KcQBRcHsmeEGOwIBVvLko,33639
-ply/ctokens.py,sha256=GmyWYDY9nl6F1WJQ9rmcQFgh1FnADFlnp_TBjTcEsqU,3155
-ply/lex.py,sha256=babRISnIAfzHo7WqLYF2qGCSaH0btM8d3ztgHaK3SA0,42905
-ply/yacc.py,sha256=EF043rIHrXJYG6jcb15TI2SLwdCoNOQZXCN_1M3-I4k,137736
-ply/ygen.py,sha256=TRnkZgx5BBB43Qspu2J4gVtpeBut8xrTEZoLbNN0b6M,2246
diff --git a/server/libs/ply-3.11.dist-info/REQUESTED b/server/libs/ply-3.11.dist-info/REQUESTED
deleted file mode 100644
index e69de29..0000000
diff --git a/server/libs/ply-3.11.dist-info/WHEEL b/server/libs/ply-3.11.dist-info/WHEEL
deleted file mode 100644
index 7332a41..0000000
--- a/server/libs/ply-3.11.dist-info/WHEEL
+++ /dev/null
@@ -1,6 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.30.0)
-Root-Is-Purelib: true
-Tag: py2-none-any
-Tag: py3-none-any
-
diff --git a/server/libs/ply-3.11.dist-info/metadata.json b/server/libs/ply-3.11.dist-info/metadata.json
deleted file mode 100644
index 9f472a3..0000000
--- a/server/libs/ply-3.11.dist-info/metadata.json
+++ /dev/null
@@ -1 +0,0 @@
-{"classifiers": ["Programming Language :: Python :: 3", "Programming Language :: Python :: 2"], "description_content_type": "UNKNOWN", "extensions": {"python.details": {"contacts": [{"email": "dave@dabeaz.com", "name": "David Beazley", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://www.dabeaz.com/ply/"}}}, "generator": "bdist_wheel (0.30.0)", "license": "BSD", "metadata_version": "2.0", "name": "ply", "summary": "Python Lex & Yacc", "version": "3.11"}
\ No newline at end of file
diff --git a/server/libs/ply-3.11.dist-info/top_level.txt b/server/libs/ply-3.11.dist-info/top_level.txt
deleted file mode 100644
index 90412f0..0000000
--- a/server/libs/ply-3.11.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-ply
diff --git a/server/libs/ply/__init__.py b/server/libs/ply/__init__.py
deleted file mode 100644
index 23707c6..0000000
--- a/server/libs/ply/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# PLY package
-# Author: David Beazley (dave@dabeaz.com)
-
-__version__ = '3.11'
-__all__ = ['lex','yacc']
diff --git a/server/libs/ply/cpp.py b/server/libs/ply/cpp.py
deleted file mode 100644
index 2422916..0000000
--- a/server/libs/ply/cpp.py
+++ /dev/null
@@ -1,914 +0,0 @@
-# -----------------------------------------------------------------------------
-# cpp.py
-#
-# Author:  David Beazley (http://www.dabeaz.com)
-# Copyright (C) 2007
-# All rights reserved
-#
-# This module implements an ANSI-C style lexical preprocessor for PLY.
-# -----------------------------------------------------------------------------
-from __future__ import generators
-
-import sys
-
-# Some Python 3 compatibility shims
-if sys.version_info.major < 3:
-    STRING_TYPES = (str, unicode)
-else:
-    STRING_TYPES = str
-    xrange = range
-
-# -----------------------------------------------------------------------------
-# Default preprocessor lexer definitions.   These tokens are enough to get
-# a basic preprocessor working.   Other modules may import these if they want
-# -----------------------------------------------------------------------------
-
-tokens = (
-   'CPP_ID','CPP_INTEGER', 'CPP_FLOAT', 'CPP_STRING', 'CPP_CHAR', 'CPP_WS', 'CPP_COMMENT1', 'CPP_COMMENT2', 'CPP_POUND','CPP_DPOUND'
-)
-
-literals = "+-*/%|&~^<>=!?()[]{}.,;:\\\'\""
-
-# Whitespace
-def t_CPP_WS(t):
-    r'\s+'
-    t.lexer.lineno += t.value.count("\n")
-    return t
-
-t_CPP_POUND = r'\#'
-t_CPP_DPOUND = r'\#\#'
-
-# Identifier
-t_CPP_ID = r'[A-Za-z_][\w_]*'
-
-# Integer literal
-def CPP_INTEGER(t):
-    r'(((((0x)|(0X))[0-9a-fA-F]+)|(\d+))([uU][lL]|[lL][uU]|[uU]|[lL])?)'
-    return t
-
-t_CPP_INTEGER = CPP_INTEGER
-
-# Floating literal
-t_CPP_FLOAT = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?'
-
-# String literal
-def t_CPP_STRING(t):
-    r'\"([^\\\n]|(\\(.|\n)))*?\"'
-    t.lexer.lineno += t.value.count("\n")
-    return t
-
-# Character constant 'c' or L'c'
-def t_CPP_CHAR(t):
-    r'(L)?\'([^\\\n]|(\\(.|\n)))*?\''
-    t.lexer.lineno += t.value.count("\n")
-    return t
-
-# Comment
-def t_CPP_COMMENT1(t):
-    r'(/\*(.|\n)*?\*/)'
-    ncr = t.value.count("\n")
-    t.lexer.lineno += ncr
-    # replace with one space or a number of '\n'
-    t.type = 'CPP_WS'; t.value = '\n' * ncr if ncr else ' '
-    return t
-
-# Line comment
-def t_CPP_COMMENT2(t):
-    r'(//.*?(\n|$))'
-    # replace with '/n'
-    t.type = 'CPP_WS'; t.value = '\n'
-    return t
-
-def t_error(t):
-    t.type = t.value[0]
-    t.value = t.value[0]
-    t.lexer.skip(1)
-    return t
-
-import re
-import copy
-import time
-import os.path
-
-# -----------------------------------------------------------------------------
-# trigraph()
-#
-# Given an input string, this function replaces all trigraph sequences.
-# The following mapping is used:
-#
-#     ??=    #
-#     ??/    \
-#     ??'    ^
-#     ??(    [
-#     ??)    ]
-#     ??!    |
-#     ??<    {
-#     ??>    }
-#     ??-    ~
-# -----------------------------------------------------------------------------
-
-_trigraph_pat = re.compile(r'''\?\?[=/\'\(\)\!<>\-]''')
-_trigraph_rep = {
-    '=':'#',
-    '/':'\\',
-    "'":'^',
-    '(':'[',
-    ')':']',
-    '!':'|',
-    '<':'{',
-    '>':'}',
-    '-':'~'
-}
-
-def trigraph(input):
-    return _trigraph_pat.sub(lambda g: _trigraph_rep[g.group()[-1]],input)
-
-# ------------------------------------------------------------------
-# Macro object
-#
-# This object holds information about preprocessor macros
-#
-#    .name      - Macro name (string)
-#    .value     - Macro value (a list of tokens)
-#    .arglist   - List of argument names
-#    .variadic  - Boolean indicating whether or not variadic macro
-#    .vararg    - Name of the variadic parameter
-#
-# When a macro is created, the macro replacement token sequence is
-# pre-scanned and used to create patch lists that are later used
-# during macro expansion
-# ------------------------------------------------------------------
-
-class Macro(object):
-    def __init__(self,name,value,arglist=None,variadic=False):
-        self.name = name
-        self.value = value
-        self.arglist = arglist
-        self.variadic = variadic
-        if variadic:
-            self.vararg = arglist[-1]
-        self.source = None
-
-# ------------------------------------------------------------------
-# Preprocessor object
-#
-# Object representing a preprocessor.  Contains macro definitions,
-# include directories, and other information
-# ------------------------------------------------------------------
-
-class Preprocessor(object):
-    def __init__(self,lexer=None):
-        if lexer is None:
-            lexer = lex.lexer
-        self.lexer = lexer
-        self.macros = { }
-        self.path = []
-        self.temp_path = []
-
-        # Probe the lexer for selected tokens
-        self.lexprobe()
-
-        tm = time.localtime()
-        self.define("__DATE__ \"%s\"" % time.strftime("%b %d %Y",tm))
-        self.define("__TIME__ \"%s\"" % time.strftime("%H:%M:%S",tm))
-        self.parser = None
-
-    # -----------------------------------------------------------------------------
-    # tokenize()
-    #
-    # Utility function. Given a string of text, tokenize into a list of tokens
-    # -----------------------------------------------------------------------------
-
-    def tokenize(self,text):
-        tokens = []
-        self.lexer.input(text)
-        while True:
-            tok = self.lexer.token()
-            if not tok: break
-            tokens.append(tok)
-        return tokens
-
-    # ---------------------------------------------------------------------
-    # error()
-    #
-    # Report a preprocessor error/warning of some kind
-    # ----------------------------------------------------------------------
-
-    def error(self,file,line,msg):
-        print("%s:%d %s" % (file,line,msg))
-
-    # ----------------------------------------------------------------------
-    # lexprobe()
-    #
-    # This method probes the preprocessor lexer object to discover
-    # the token types of symbols that are important to the preprocessor.
-    # If this works right, the preprocessor will simply "work"
-    # with any suitable lexer regardless of how tokens have been named.
-    # ----------------------------------------------------------------------
-
-    def lexprobe(self):
-
-        # Determine the token type for identifiers
-        self.lexer.input("identifier")
-        tok = self.lexer.token()
-        if not tok or tok.value != "identifier":
-            print("Couldn't determine identifier type")
-        else:
-            self.t_ID = tok.type
-
-        # Determine the token type for integers
-        self.lexer.input("12345")
-        tok = self.lexer.token()
-        if not tok or int(tok.value) != 12345:
-            print("Couldn't determine integer type")
-        else:
-            self.t_INTEGER = tok.type
-            self.t_INTEGER_TYPE = type(tok.value)
-
-        # Determine the token type for strings enclosed in double quotes
-        self.lexer.input("\"filename\"")
-        tok = self.lexer.token()
-        if not tok or tok.value != "\"filename\"":
-            print("Couldn't determine string type")
-        else:
-            self.t_STRING = tok.type
-
-        # Determine the token type for whitespace--if any
-        self.lexer.input("  ")
-        tok = self.lexer.token()
-        if not tok or tok.value != "  ":
-            self.t_SPACE = None
-        else:
-            self.t_SPACE = tok.type
-
-        # Determine the token type for newlines
-        self.lexer.input("\n")
-        tok = self.lexer.token()
-        if not tok or tok.value != "\n":
-            self.t_NEWLINE = None
-            print("Couldn't determine token for newlines")
-        else:
-            self.t_NEWLINE = tok.type
-
-        self.t_WS = (self.t_SPACE, self.t_NEWLINE)
-
-        # Check for other characters used by the preprocessor
-        chars = [ '<','>','#','##','\\','(',')',',','.']
-        for c in chars:
-            self.lexer.input(c)
-            tok = self.lexer.token()
-            if not tok or tok.value != c:
-                print("Unable to lex '%s' required for preprocessor" % c)
-
-    # ----------------------------------------------------------------------
-    # add_path()
-    #
-    # Adds a search path to the preprocessor.
-    # ----------------------------------------------------------------------
-
-    def add_path(self,path):
-        self.path.append(path)
-
-    # ----------------------------------------------------------------------
-    # group_lines()
-    #
-    # Given an input string, this function splits it into lines.  Trailing whitespace
-    # is removed.   Any line ending with \ is grouped with the next line.  This
-    # function forms the lowest level of the preprocessor---grouping into text into
-    # a line-by-line format.
-    # ----------------------------------------------------------------------
-
-    def group_lines(self,input):
-        lex = self.lexer.clone()
-        lines = [x.rstrip() for x in input.splitlines()]
-        for i in xrange(len(lines)):
-            j = i+1
-            while lines[i].endswith('\\') and (j < len(lines)):
-                lines[i] = lines[i][:-1]+lines[j]
-                lines[j] = ""
-                j += 1
-
-        input = "\n".join(lines)
-        lex.input(input)
-        lex.lineno = 1
-
-        current_line = []
-        while True:
-            tok = lex.token()
-            if not tok:
-                break
-            current_line.append(tok)
-            if tok.type in self.t_WS and '\n' in tok.value:
-                yield current_line
-                current_line = []
-
-        if current_line:
-            yield current_line
-
-    # ----------------------------------------------------------------------
-    # tokenstrip()
-    #
-    # Remove leading/trailing whitespace tokens from a token list
-    # ----------------------------------------------------------------------
-
-    def tokenstrip(self,tokens):
-        i = 0
-        while i < len(tokens) and tokens[i].type in self.t_WS:
-            i += 1
-        del tokens[:i]
-        i = len(tokens)-1
-        while i >= 0 and tokens[i].type in self.t_WS:
-            i -= 1
-        del tokens[i+1:]
-        return tokens
-
-
-    # ----------------------------------------------------------------------
-    # collect_args()
-    #
-    # Collects comma separated arguments from a list of tokens.   The arguments
-    # must be enclosed in parenthesis.  Returns a tuple (tokencount,args,positions)
-    # where tokencount is the number of tokens consumed, args is a list of arguments,
-    # and positions is a list of integers containing the starting index of each
-    # argument.  Each argument is represented by a list of tokens.
-    #
-    # When collecting arguments, leading and trailing whitespace is removed
-    # from each argument.
-    #
-    # This function properly handles nested parenthesis and commas---these do not
-    # define new arguments.
-    # ----------------------------------------------------------------------
-
-    def collect_args(self,tokenlist):
-        args = []
-        positions = []
-        current_arg = []
-        nesting = 1
-        tokenlen = len(tokenlist)
-
-        # Search for the opening '('.
-        i = 0
-        while (i < tokenlen) and (tokenlist[i].type in self.t_WS):
-            i += 1
-
-        if (i < tokenlen) and (tokenlist[i].value == '('):
-            positions.append(i+1)
-        else:
-            self.error(self.source,tokenlist[0].lineno,"Missing '(' in macro arguments")
-            return 0, [], []
-
-        i += 1
-
-        while i < tokenlen:
-            t = tokenlist[i]
-            if t.value == '(':
-                current_arg.append(t)
-                nesting += 1
-            elif t.value == ')':
-                nesting -= 1
-                if nesting == 0:
-                    if current_arg:
-                        args.append(self.tokenstrip(current_arg))
-                        positions.append(i)
-                    return i+1,args,positions
-                current_arg.append(t)
-            elif t.value == ',' and nesting == 1:
-                args.append(self.tokenstrip(current_arg))
-                positions.append(i+1)
-                current_arg = []
-            else:
-                current_arg.append(t)
-            i += 1
-
-        # Missing end argument
-        self.error(self.source,tokenlist[-1].lineno,"Missing ')' in macro arguments")
-        return 0, [],[]
-
-    # ----------------------------------------------------------------------
-    # macro_prescan()
-    #
-    # Examine the macro value (token sequence) and identify patch points
-    # This is used to speed up macro expansion later on---we'll know
-    # right away where to apply patches to the value to form the expansion
-    # ----------------------------------------------------------------------
-
-    def macro_prescan(self,macro):
-        macro.patch     = []             # Standard macro arguments
-        macro.str_patch = []             # String conversion expansion
-        macro.var_comma_patch = []       # Variadic macro comma patch
-        i = 0
-        while i < len(macro.value):
-            if macro.value[i].type == self.t_ID and macro.value[i].value in macro.arglist:
-                argnum = macro.arglist.index(macro.value[i].value)
-                # Conversion of argument to a string
-                if i > 0 and macro.value[i-1].value == '#':
-                    macro.value[i] = copy.copy(macro.value[i])
-                    macro.value[i].type = self.t_STRING
-                    del macro.value[i-1]
-                    macro.str_patch.append((argnum,i-1))
-                    continue
-                # Concatenation
-                elif (i > 0 and macro.value[i-1].value == '##'):
-                    macro.patch.append(('c',argnum,i-1))
-                    del macro.value[i-1]
-                    i -= 1
-                    continue
-                elif ((i+1) < len(macro.value) and macro.value[i+1].value == '##'):
-                    macro.patch.append(('c',argnum,i))
-                    del macro.value[i + 1]
-                    continue
-                # Standard expansion
-                else:
-                    macro.patch.append(('e',argnum,i))
-            elif macro.value[i].value == '##':
-                if macro.variadic and (i > 0) and (macro.value[i-1].value == ',') and \
-                        ((i+1) < len(macro.value)) and (macro.value[i+1].type == self.t_ID) and \
-                        (macro.value[i+1].value == macro.vararg):
-                    macro.var_comma_patch.append(i-1)
-            i += 1
-        macro.patch.sort(key=lambda x: x[2],reverse=True)
-
-    # ----------------------------------------------------------------------
-    # macro_expand_args()
-    #
-    # Given a Macro and list of arguments (each a token list), this method
-    # returns an expanded version of a macro.  The return value is a token sequence
-    # representing the replacement macro tokens
-    # ----------------------------------------------------------------------
-
-    def macro_expand_args(self,macro,args):
-        # Make a copy of the macro token sequence
-        rep = [copy.copy(_x) for _x in macro.value]
-
-        # Make string expansion patches.  These do not alter the length of the replacement sequence
-
-        str_expansion = {}
-        for argnum, i in macro.str_patch:
-            if argnum not in str_expansion:
-                str_expansion[argnum] = ('"%s"' % "".join([x.value for x in args[argnum]])).replace("\\","\\\\")
-            rep[i] = copy.copy(rep[i])
-            rep[i].value = str_expansion[argnum]
-
-        # Make the variadic macro comma patch.  If the variadic macro argument is empty, we get rid
-        comma_patch = False
-        if macro.variadic and not args[-1]:
-            for i in macro.var_comma_patch:
-                rep[i] = None
-                comma_patch = True
-
-        # Make all other patches.   The order of these matters.  It is assumed that the patch list
-        # has been sorted in reverse order of patch location since replacements will cause the
-        # size of the replacement sequence to expand from the patch point.
-
-        expanded = { }
-        for ptype, argnum, i in macro.patch:
-            # Concatenation.   Argument is left unexpanded
-            if ptype == 'c':
-                rep[i:i+1] = args[argnum]
-            # Normal expansion.  Argument is macro expanded first
-            elif ptype == 'e':
-                if argnum not in expanded:
-                    expanded[argnum] = self.expand_macros(args[argnum])
-                rep[i:i+1] = expanded[argnum]
-
-        # Get rid of removed comma if necessary
-        if comma_patch:
-            rep = [_i for _i in rep if _i]
-
-        return rep
-
-
-    # ----------------------------------------------------------------------
-    # expand_macros()
-    #
-    # Given a list of tokens, this function performs macro expansion.
-    # The expanded argument is a dictionary that contains macros already
-    # expanded.  This is used to prevent infinite recursion.
-    # ----------------------------------------------------------------------
-
-    def expand_macros(self,tokens,expanded=None):
-        if expanded is None:
-            expanded = {}
-        i = 0
-        while i < len(tokens):
-            t = tokens[i]
-            if t.type == self.t_ID:
-                if t.value in self.macros and t.value not in expanded:
-                    # Yes, we found a macro match
-                    expanded[t.value] = True
-
-                    m = self.macros[t.value]
-                    if not m.arglist:
-                        # A simple macro
-                        ex = self.expand_macros([copy.copy(_x) for _x in m.value],expanded)
-                        for e in ex:
-                            e.lineno = t.lineno
-                        tokens[i:i+1] = ex
-                        i += len(ex)
-                    else:
-                        # A macro with arguments
-                        j = i + 1
-                        while j < len(tokens) and tokens[j].type in self.t_WS:
-                            j += 1
-                        if j < len(tokens) and tokens[j].value == '(':
-                            tokcount,args,positions = self.collect_args(tokens[j:])
-                            if not m.variadic and len(args) !=  len(m.arglist):
-                                self.error(self.source,t.lineno,"Macro %s requires %d arguments" % (t.value,len(m.arglist)))
-                                i = j + tokcount
-                            elif m.variadic and len(args) < len(m.arglist)-1:
-                                if len(m.arglist) > 2:
-                                    self.error(self.source,t.lineno,"Macro %s must have at least %d arguments" % (t.value, len(m.arglist)-1))
-                                else:
-                                    self.error(self.source,t.lineno,"Macro %s must have at least %d argument" % (t.value, len(m.arglist)-1))
-                                i = j + tokcount
-                            else:
-                                if m.variadic:
-                                    if len(args) == len(m.arglist)-1:
-                                        args.append([])
-                                    else:
-                                        args[len(m.arglist)-1] = tokens[j+positions[len(m.arglist)-1]:j+tokcount-1]
-                                        del args[len(m.arglist):]
-
-                                # Get macro replacement text
-                                rep = self.macro_expand_args(m,args)
-                                rep = self.expand_macros(rep,expanded)
-                                for r in rep:
-                                    r.lineno = t.lineno
-                                tokens[i:j+tokcount] = rep
-                                i += len(rep)
-                        else:
-                            # This is not a macro. It is just a word which
-                            # equals to name of the macro. Hence, go to the
-                            # next token.
-                            i += 1
-
-                    del expanded[t.value]
-                    continue
-                elif t.value == '__LINE__':
-                    t.type = self.t_INTEGER
-                    t.value = self.t_INTEGER_TYPE(t.lineno)
-
-            i += 1
-        return tokens
-
-    # ----------------------------------------------------------------------
-    # evalexpr()
-    #
-    # Evaluate an expression token sequence for the purposes of evaluating
-    # integral expressions.
-    # ----------------------------------------------------------------------
-
-    def evalexpr(self,tokens):
-        # tokens = tokenize(line)
-        # Search for defined macros
-        i = 0
-        while i < len(tokens):
-            if tokens[i].type == self.t_ID and tokens[i].value == 'defined':
-                j = i + 1
-                needparen = False
-                result = "0L"
-                while j < len(tokens):
-                    if tokens[j].type in self.t_WS:
-                        j += 1
-                        continue
-                    elif tokens[j].type == self.t_ID:
-                        if tokens[j].value in self.macros:
-                            result = "1L"
-                        else:
-                            result = "0L"
-                        if not needparen: break
-                    elif tokens[j].value == '(':
-                        needparen = True
-                    elif tokens[j].value == ')':
-                        break
-                    else:
-                        self.error(self.source,tokens[i].lineno,"Malformed defined()")
-                    j += 1
-                tokens[i].type = self.t_INTEGER
-                tokens[i].value = self.t_INTEGER_TYPE(result)
-                del tokens[i+1:j+1]
-            i += 1
-        tokens = self.expand_macros(tokens)
-        for i,t in enumerate(tokens):
-            if t.type == self.t_ID:
-                tokens[i] = copy.copy(t)
-                tokens[i].type = self.t_INTEGER
-                tokens[i].value = self.t_INTEGER_TYPE("0L")
-            elif t.type == self.t_INTEGER:
-                tokens[i] = copy.copy(t)
-                # Strip off any trailing suffixes
-                tokens[i].value = str(tokens[i].value)
-                while tokens[i].value[-1] not in "0123456789abcdefABCDEF":
-                    tokens[i].value = tokens[i].value[:-1]
-
-        expr = "".join([str(x.value) for x in tokens])
-        expr = expr.replace("&&"," and ")
-        expr = expr.replace("||"," or ")
-        expr = expr.replace("!"," not ")
-        try:
-            result = eval(expr)
-        except Exception:
-            self.error(self.source,tokens[0].lineno,"Couldn't evaluate expression")
-            result = 0
-        return result
-
-    # ----------------------------------------------------------------------
-    # parsegen()
-    #
-    # Parse an input string/
-    # ----------------------------------------------------------------------
-    def parsegen(self,input,source=None):
-
-        # Replace trigraph sequences
-        t = trigraph(input)
-        lines = self.group_lines(t)
-
-        if not source:
-            source = ""
-
-        self.define("__FILE__ \"%s\"" % source)
-
-        self.source = source
-        chunk = []
-        enable = True
-        iftrigger = False
-        ifstack = []
-
-        for x in lines:
-            for i,tok in enumerate(x):
-                if tok.type not in self.t_WS: break
-            if tok.value == '#':
-                # Preprocessor directive
-
-                # insert necessary whitespace instead of eaten tokens
-                for tok in x:
-                    if tok.type in self.t_WS and '\n' in tok.value:
-                        chunk.append(tok)
-
-                dirtokens = self.tokenstrip(x[i+1:])
-                if dirtokens:
-                    name = dirtokens[0].value
-                    args = self.tokenstrip(dirtokens[1:])
-                else:
-                    name = ""
-                    args = []
-
-                if name == 'define':
-                    if enable:
-                        for tok in self.expand_macros(chunk):
-                            yield tok
-                        chunk = []
-                        self.define(args)
-                elif name == 'include':
-                    if enable:
-                        for tok in self.expand_macros(chunk):
-                            yield tok
-                        chunk = []
-                        oldfile = self.macros['__FILE__']
-                        for tok in self.include(args):
-                            yield tok
-                        self.macros['__FILE__'] = oldfile
-                        self.source = source
-                elif name == 'undef':
-                    if enable:
-                        for tok in self.expand_macros(chunk):
-                            yield tok
-                        chunk = []
-                        self.undef(args)
-                elif name == 'ifdef':
-                    ifstack.append((enable,iftrigger))
-                    if enable:
-                        if not args[0].value in self.macros:
-                            enable = False
-                            iftrigger = False
-                        else:
-                            iftrigger = True
-                elif name == 'ifndef':
-                    ifstack.append((enable,iftrigger))
-                    if enable:
-                        if args[0].value in self.macros:
-                            enable = False
-                            iftrigger = False
-                        else:
-                            iftrigger = True
-                elif name == 'if':
-                    ifstack.append((enable,iftrigger))
-                    if enable:
-                        result = self.evalexpr(args)
-                        if not result:
-                            enable = False
-                            iftrigger = False
-                        else:
-                            iftrigger = True
-                elif name == 'elif':
-                    if ifstack:
-                        if ifstack[-1][0]:     # We only pay attention if outer "if" allows this
-                            if enable:         # If already true, we flip enable False
-                                enable = False
-                            elif not iftrigger:   # If False, but not triggered yet, we'll check expression
-                                result = self.evalexpr(args)
-                                if result:
-                                    enable  = True
-                                    iftrigger = True
-                    else:
-                        self.error(self.source,dirtokens[0].lineno,"Misplaced #elif")
-
-                elif name == 'else':
-                    if ifstack:
-                        if ifstack[-1][0]:
-                            if enable:
-                                enable = False
-                            elif not iftrigger:
-                                enable = True
-                                iftrigger = True
-                    else:
-                        self.error(self.source,dirtokens[0].lineno,"Misplaced #else")
-
-                elif name == 'endif':
-                    if ifstack:
-                        enable,iftrigger = ifstack.pop()
-                    else:
-                        self.error(self.source,dirtokens[0].lineno,"Misplaced #endif")
-                else:
-                    # Unknown preprocessor directive
-                    pass
-
-            else:
-                # Normal text
-                if enable:
-                    chunk.extend(x)
-
-        for tok in self.expand_macros(chunk):
-            yield tok
-        chunk = []
-
-    # ----------------------------------------------------------------------
-    # include()
-    #
-    # Implementation of file-inclusion
-    # ----------------------------------------------------------------------
-
-    def include(self,tokens):
-        # Try to extract the filename and then process an include file
-        if not tokens:
-            return
-        if tokens:
-            if tokens[0].value != '<' and tokens[0].type != self.t_STRING:
-                tokens = self.expand_macros(tokens)
-
-            if tokens[0].value == '<':
-                # Include <...>
-                i = 1
-                while i < len(tokens):
-                    if tokens[i].value == '>':
-                        break
-                    i += 1
-                else:
-                    print("Malformed #include <...>")
-                    return
-                filename = "".join([x.value for x in tokens[1:i]])
-                path = self.path + [""] + self.temp_path
-            elif tokens[0].type == self.t_STRING:
-                filename = tokens[0].value[1:-1]
-                path = self.temp_path + [""] + self.path
-            else:
-                print("Malformed #include statement")
-                return
-        for p in path:
-            iname = os.path.join(p,filename)
-            try:
-                data = open(iname,"r").read()
-                dname = os.path.dirname(iname)
-                if dname:
-                    self.temp_path.insert(0,dname)
-                for tok in self.parsegen(data,filename):
-                    yield tok
-                if dname:
-                    del self.temp_path[0]
-                break
-            except IOError:
-                pass
-        else:
-            print("Couldn't find '%s'" % filename)
-
-    # ----------------------------------------------------------------------
-    # define()
-    #
-    # Define a new macro
-    # ----------------------------------------------------------------------
-
-    def define(self,tokens):
-        if isinstance(tokens,STRING_TYPES):
-            tokens = self.tokenize(tokens)
-
-        linetok = tokens
-        try:
-            name = linetok[0]
-            if len(linetok) > 1:
-                mtype = linetok[1]
-            else:
-                mtype = None
-            if not mtype:
-                m = Macro(name.value,[])
-                self.macros[name.value] = m
-            elif mtype.type in self.t_WS:
-                # A normal macro
-                m = Macro(name.value,self.tokenstrip(linetok[2:]))
-                self.macros[name.value] = m
-            elif mtype.value == '(':
-                # A macro with arguments
-                tokcount, args, positions = self.collect_args(linetok[1:])
-                variadic = False
-                for a in args:
-                    if variadic:
-                        print("No more arguments may follow a variadic argument")
-                        break
-                    astr = "".join([str(_i.value) for _i in a])
-                    if astr == "...":
-                        variadic = True
-                        a[0].type = self.t_ID
-                        a[0].value = '__VA_ARGS__'
-                        variadic = True
-                        del a[1:]
-                        continue
-                    elif astr[-3:] == "..." and a[0].type == self.t_ID:
-                        variadic = True
-                        del a[1:]
-                        # If, for some reason, "." is part of the identifier, strip off the name for the purposes
-                        # of macro expansion
-                        if a[0].value[-3:] == '...':
-                            a[0].value = a[0].value[:-3]
-                        continue
-                    if len(a) > 1 or a[0].type != self.t_ID:
-                        print("Invalid macro argument")
-                        break
-                else:
-                    mvalue = self.tokenstrip(linetok[1+tokcount:])
-                    i = 0
-                    while i < len(mvalue):
-                        if i+1 < len(mvalue):
-                            if mvalue[i].type in self.t_WS and mvalue[i+1].value == '##':
-                                del mvalue[i]
-                                continue
-                            elif mvalue[i].value == '##' and mvalue[i+1].type in self.t_WS:
-                                del mvalue[i+1]
-                        i += 1
-                    m = Macro(name.value,mvalue,[x[0].value for x in args],variadic)
-                    self.macro_prescan(m)
-                    self.macros[name.value] = m
-            else:
-                print("Bad macro definition")
-        except LookupError:
-            print("Bad macro definition")
-
-    # ----------------------------------------------------------------------
-    # undef()
-    #
-    # Undefine a macro
-    # ----------------------------------------------------------------------
-
-    def undef(self,tokens):
-        id = tokens[0].value
-        try:
-            del self.macros[id]
-        except LookupError:
-            pass
-
-    # ----------------------------------------------------------------------
-    # parse()
-    #
-    # Parse input text.
-    # ----------------------------------------------------------------------
-    def parse(self,input,source=None,ignore={}):
-        self.ignore = ignore
-        self.parser = self.parsegen(input,source)
-
-    # ----------------------------------------------------------------------
-    # token()
-    #
-    # Method to return individual tokens
-    # ----------------------------------------------------------------------
-    def token(self):
-        try:
-            while True:
-                tok = next(self.parser)
-                if tok.type not in self.ignore: return tok
-        except StopIteration:
-            self.parser = None
-            return None
-
-if __name__ == '__main__':
-    import ply.lex as lex
-    lexer = lex.lex()
-
-    # Run a preprocessor
-    import sys
-    f = open(sys.argv[1])
-    input = f.read()
-
-    p = Preprocessor(lexer)
-    p.parse(input,sys.argv[1])
-    while True:
-        tok = p.token()
-        if not tok: break
-        print(p.source, tok)
diff --git a/server/libs/ply/ctokens.py b/server/libs/ply/ctokens.py
deleted file mode 100644
index b265e59..0000000
--- a/server/libs/ply/ctokens.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# ----------------------------------------------------------------------
-# ctokens.py
-#
-# Token specifications for symbols in ANSI C and C++.  This file is
-# meant to be used as a library in other tokenizers.
-# ----------------------------------------------------------------------
-
-# Reserved words
-
-tokens = [
-    # Literals (identifier, integer constant, float constant, string constant, char const)
-    'ID', 'TYPEID', 'INTEGER', 'FLOAT', 'STRING', 'CHARACTER',
-
-    # Operators (+,-,*,/,%,|,&,~,^,<<,>>, ||, &&, !, <, <=, >, >=, ==, !=)
-    'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MODULO',
-    'OR', 'AND', 'NOT', 'XOR', 'LSHIFT', 'RSHIFT',
-    'LOR', 'LAND', 'LNOT',
-    'LT', 'LE', 'GT', 'GE', 'EQ', 'NE',
-
-    # Assignment (=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=)
-    'EQUALS', 'TIMESEQUAL', 'DIVEQUAL', 'MODEQUAL', 'PLUSEQUAL', 'MINUSEQUAL',
-    'LSHIFTEQUAL','RSHIFTEQUAL', 'ANDEQUAL', 'XOREQUAL', 'OREQUAL',
-
-    # Increment/decrement (++,--)
-    'INCREMENT', 'DECREMENT',
-
-    # Structure dereference (->)
-    'ARROW',
-
-    # Ternary operator (?)
-    'TERNARY',
-
-    # Delimeters ( ) [ ] { } , . ; :
-    'LPAREN', 'RPAREN',
-    'LBRACKET', 'RBRACKET',
-    'LBRACE', 'RBRACE',
-    'COMMA', 'PERIOD', 'SEMI', 'COLON',
-
-    # Ellipsis (...)
-    'ELLIPSIS',
-]
-
-# Operators
-t_PLUS             = r'\+'
-t_MINUS            = r'-'
-t_TIMES            = r'\*'
-t_DIVIDE           = r'/'
-t_MODULO           = r'%'
-t_OR               = r'\|'
-t_AND              = r'&'
-t_NOT              = r'~'
-t_XOR              = r'\^'
-t_LSHIFT           = r'<<'
-t_RSHIFT           = r'>>'
-t_LOR              = r'\|\|'
-t_LAND             = r'&&'
-t_LNOT             = r'!'
-t_LT               = r'<'
-t_GT               = r'>'
-t_LE               = r'<='
-t_GE               = r'>='
-t_EQ               = r'=='
-t_NE               = r'!='
-
-# Assignment operators
-
-t_EQUALS           = r'='
-t_TIMESEQUAL       = r'\*='
-t_DIVEQUAL         = r'/='
-t_MODEQUAL         = r'%='
-t_PLUSEQUAL        = r'\+='
-t_MINUSEQUAL       = r'-='
-t_LSHIFTEQUAL      = r'<<='
-t_RSHIFTEQUAL      = r'>>='
-t_ANDEQUAL         = r'&='
-t_OREQUAL          = r'\|='
-t_XOREQUAL         = r'\^='
-
-# Increment/decrement
-t_INCREMENT        = r'\+\+'
-t_DECREMENT        = r'--'
-
-# ->
-t_ARROW            = r'->'
-
-# ?
-t_TERNARY          = r'\?'
-
-# Delimeters
-t_LPAREN           = r'\('
-t_RPAREN           = r'\)'
-t_LBRACKET         = r'\['
-t_RBRACKET         = r'\]'
-t_LBRACE           = r'\{'
-t_RBRACE           = r'\}'
-t_COMMA            = r','
-t_PERIOD           = r'\.'
-t_SEMI             = r';'
-t_COLON            = r':'
-t_ELLIPSIS         = r'\.\.\.'
-
-# Identifiers
-t_ID = r'[A-Za-z_][A-Za-z0-9_]*'
-
-# Integer literal
-t_INTEGER = r'\d+([uU]|[lL]|[uU][lL]|[lL][uU])?'
-
-# Floating literal
-t_FLOAT = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?'
-
-# String literal
-t_STRING = r'\"([^\\\n]|(\\.))*?\"'
-
-# Character constant 'c' or L'c'
-t_CHARACTER = r'(L)?\'([^\\\n]|(\\.))*?\''
-
-# Comment (C-Style)
-def t_COMMENT(t):
-    r'/\*(.|\n)*?\*/'
-    t.lexer.lineno += t.value.count('\n')
-    return t
-
-# Comment (C++-Style)
-def t_CPPCOMMENT(t):
-    r'//.*\n'
-    t.lexer.lineno += 1
-    return t
diff --git a/server/libs/ply/lex.py b/server/libs/ply/lex.py
deleted file mode 100644
index f95bcdb..0000000
--- a/server/libs/ply/lex.py
+++ /dev/null
@@ -1,1098 +0,0 @@
-# -----------------------------------------------------------------------------
-# ply: lex.py
-#
-# Copyright (C) 2001-2018
-# David M. Beazley (Dabeaz LLC)
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright notice,
-#   this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-#   this list of conditions and the following disclaimer in the documentation
-#   and/or other materials provided with the distribution.
-# * Neither the name of the David Beazley or Dabeaz LLC may be used to
-#   endorse or promote products derived from this software without
-#  specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# -----------------------------------------------------------------------------
-
-__version__    = '3.11'
-__tabversion__ = '3.10'
-
-import re
-import sys
-import types
-import copy
-import os
-import inspect
-
-# This tuple contains known string types
-try:
-    # Python 2.6
-    StringTypes = (types.StringType, types.UnicodeType)
-except AttributeError:
-    # Python 3.0
-    StringTypes = (str, bytes)
-
-# This regular expression is used to match valid token names
-_is_identifier = re.compile(r'^[a-zA-Z0-9_]+$')
-
-# Exception thrown when invalid token encountered and no default error
-# handler is defined.
-class LexError(Exception):
-    def __init__(self, message, s):
-        self.args = (message,)
-        self.text = s
-
-
-# Token class.  This class is used to represent the tokens produced.
-class LexToken(object):
-    def __str__(self):
-        return 'LexToken(%s,%r,%d,%d)' % (self.type, self.value, self.lineno, self.lexpos)
-
-    def __repr__(self):
-        return str(self)
-
-
-# This object is a stand-in for a logging object created by the
-# logging module.
-
-class PlyLogger(object):
-    def __init__(self, f):
-        self.f = f
-
-    def critical(self, msg, *args, **kwargs):
-        self.f.write((msg % args) + '\n')
-
-    def warning(self, msg, *args, **kwargs):
-        self.f.write('WARNING: ' + (msg % args) + '\n')
-
-    def error(self, msg, *args, **kwargs):
-        self.f.write('ERROR: ' + (msg % args) + '\n')
-
-    info = critical
-    debug = critical
-
-
-# Null logger is used when no output is generated. Does nothing.
-class NullLogger(object):
-    def __getattribute__(self, name):
-        return self
-
-    def __call__(self, *args, **kwargs):
-        return self
-
-
-# -----------------------------------------------------------------------------
-#                        === Lexing Engine ===
-#
-# The following Lexer class implements the lexer runtime.   There are only
-# a few public methods and attributes:
-#
-#    input()          -  Store a new string in the lexer
-#    token()          -  Get the next token
-#    clone()          -  Clone the lexer
-#
-#    lineno           -  Current line number
-#    lexpos           -  Current position in the input string
-# -----------------------------------------------------------------------------
-
-class Lexer:
-    def __init__(self):
-        self.lexre = None             # Master regular expression. This is a list of
-                                      # tuples (re, findex) where re is a compiled
-                                      # regular expression and findex is a list
-                                      # mapping regex group numbers to rules
-        self.lexretext = None         # Current regular expression strings
-        self.lexstatere = {}          # Dictionary mapping lexer states to master regexs
-        self.lexstateretext = {}      # Dictionary mapping lexer states to regex strings
-        self.lexstaterenames = {}     # Dictionary mapping lexer states to symbol names
-        self.lexstate = 'INITIAL'     # Current lexer state
-        self.lexstatestack = []       # Stack of lexer states
-        self.lexstateinfo = None      # State information
-        self.lexstateignore = {}      # Dictionary of ignored characters for each state
-        self.lexstateerrorf = {}      # Dictionary of error functions for each state
-        self.lexstateeoff = {}        # Dictionary of eof functions for each state
-        self.lexreflags = 0           # Optional re compile flags
-        self.lexdata = None           # Actual input data (as a string)
-        self.lexpos = 0               # Current position in input text
-        self.lexlen = 0               # Length of the input text
-        self.lexerrorf = None         # Error rule (if any)
-        self.lexeoff = None           # EOF rule (if any)
-        self.lextokens = None         # List of valid tokens
-        self.lexignore = ''           # Ignored characters
-        self.lexliterals = ''         # Literal characters that can be passed through
-        self.lexmodule = None         # Module
-        self.lineno = 1               # Current line number
-        self.lexoptimize = False      # Optimized mode
-
-    def clone(self, object=None):
-        c = copy.copy(self)
-
-        # If the object parameter has been supplied, it means we are attaching the
-        # lexer to a new object.  In this case, we have to rebind all methods in
-        # the lexstatere and lexstateerrorf tables.
-
-        if object:
-            newtab = {}
-            for key, ritem in self.lexstatere.items():
-                newre = []
-                for cre, findex in ritem:
-                    newfindex = []
-                    for f in findex:
-                        if not f or not f[0]:
-                            newfindex.append(f)
-                            continue
-                        newfindex.append((getattr(object, f[0].__name__), f[1]))
-                newre.append((cre, newfindex))
-                newtab[key] = newre
-            c.lexstatere = newtab
-            c.lexstateerrorf = {}
-            for key, ef in self.lexstateerrorf.items():
-                c.lexstateerrorf[key] = getattr(object, ef.__name__)
-            c.lexmodule = object
-        return c
-
-    # ------------------------------------------------------------
-    # writetab() - Write lexer information to a table file
-    # ------------------------------------------------------------
-    def writetab(self, lextab, outputdir=''):
-        if isinstance(lextab, types.ModuleType):
-            raise IOError("Won't overwrite existing lextab module")
-        basetabmodule = lextab.split('.')[-1]
-        filename = os.path.join(outputdir, basetabmodule) + '.py'
-        with open(filename, 'w') as tf:
-            tf.write('# %s.py. This file automatically created by PLY (version %s). Don\'t edit!\n' % (basetabmodule, __version__))
-            tf.write('_tabversion   = %s\n' % repr(__tabversion__))
-            tf.write('_lextokens    = set(%s)\n' % repr(tuple(sorted(self.lextokens))))
-            tf.write('_lexreflags   = %s\n' % repr(int(self.lexreflags)))
-            tf.write('_lexliterals  = %s\n' % repr(self.lexliterals))
-            tf.write('_lexstateinfo = %s\n' % repr(self.lexstateinfo))
-
-            # Rewrite the lexstatere table, replacing function objects with function names
-            tabre = {}
-            for statename, lre in self.lexstatere.items():
-                titem = []
-                for (pat, func), retext, renames in zip(lre, self.lexstateretext[statename], self.lexstaterenames[statename]):
-                    titem.append((retext, _funcs_to_names(func, renames)))
-                tabre[statename] = titem
-
-            tf.write('_lexstatere   = %s\n' % repr(tabre))
-            tf.write('_lexstateignore = %s\n' % repr(self.lexstateignore))
-
-            taberr = {}
-            for statename, ef in self.lexstateerrorf.items():
-                taberr[statename] = ef.__name__ if ef else None
-            tf.write('_lexstateerrorf = %s\n' % repr(taberr))
-
-            tabeof = {}
-            for statename, ef in self.lexstateeoff.items():
-                tabeof[statename] = ef.__name__ if ef else None
-            tf.write('_lexstateeoff = %s\n' % repr(tabeof))
-
-    # ------------------------------------------------------------
-    # readtab() - Read lexer information from a tab file
-    # ------------------------------------------------------------
-    def readtab(self, tabfile, fdict):
-        if isinstance(tabfile, types.ModuleType):
-            lextab = tabfile
-        else:
-            exec('import %s' % tabfile)
-            lextab = sys.modules[tabfile]
-
-        if getattr(lextab, '_tabversion', '0.0') != __tabversion__:
-            raise ImportError('Inconsistent PLY version')
-
-        self.lextokens      = lextab._lextokens
-        self.lexreflags     = lextab._lexreflags
-        self.lexliterals    = lextab._lexliterals
-        self.lextokens_all  = self.lextokens | set(self.lexliterals)
-        self.lexstateinfo   = lextab._lexstateinfo
-        self.lexstateignore = lextab._lexstateignore
-        self.lexstatere     = {}
-        self.lexstateretext = {}
-        for statename, lre in lextab._lexstatere.items():
-            titem = []
-            txtitem = []
-            for pat, func_name in lre:
-                titem.append((re.compile(pat, lextab._lexreflags), _names_to_funcs(func_name, fdict)))
-
-            self.lexstatere[statename] = titem
-            self.lexstateretext[statename] = txtitem
-
-        self.lexstateerrorf = {}
-        for statename, ef in lextab._lexstateerrorf.items():
-            self.lexstateerrorf[statename] = fdict[ef]
-
-        self.lexstateeoff = {}
-        for statename, ef in lextab._lexstateeoff.items():
-            self.lexstateeoff[statename] = fdict[ef]
-
-        self.begin('INITIAL')
-
-    # ------------------------------------------------------------
-    # input() - Push a new string into the lexer
-    # ------------------------------------------------------------
-    def input(self, s):
-        # Pull off the first character to see if s looks like a string
-        c = s[:1]
-        if not isinstance(c, StringTypes):
-            raise ValueError('Expected a string')
-        self.lexdata = s
-        self.lexpos = 0
-        self.lexlen = len(s)
-
-    # ------------------------------------------------------------
-    # begin() - Changes the lexing state
-    # ------------------------------------------------------------
-    def begin(self, state):
-        if state not in self.lexstatere:
-            raise ValueError('Undefined state')
-        self.lexre = self.lexstatere[state]
-        self.lexretext = self.lexstateretext[state]
-        self.lexignore = self.lexstateignore.get(state, '')
-        self.lexerrorf = self.lexstateerrorf.get(state, None)
-        self.lexeoff = self.lexstateeoff.get(state, None)
-        self.lexstate = state
-
-    # ------------------------------------------------------------
-    # push_state() - Changes the lexing state and saves old on stack
-    # ------------------------------------------------------------
-    def push_state(self, state):
-        self.lexstatestack.append(self.lexstate)
-        self.begin(state)
-
-    # ------------------------------------------------------------
-    # pop_state() - Restores the previous state
-    # ------------------------------------------------------------
-    def pop_state(self):
-        self.begin(self.lexstatestack.pop())
-
-    # ------------------------------------------------------------
-    # current_state() - Returns the current lexing state
-    # ------------------------------------------------------------
-    def current_state(self):
-        return self.lexstate
-
-    # ------------------------------------------------------------
-    # skip() - Skip ahead n characters
-    # ------------------------------------------------------------
-    def skip(self, n):
-        self.lexpos += n
-
-    # ------------------------------------------------------------
-    # opttoken() - Return the next token from the Lexer
-    #
-    # Note: This function has been carefully implemented to be as fast
-    # as possible.  Don't make changes unless you really know what
-    # you are doing
-    # ------------------------------------------------------------
-    def token(self):
-        # Make local copies of frequently referenced attributes
-        lexpos    = self.lexpos
-        lexlen    = self.lexlen
-        lexignore = self.lexignore
-        lexdata   = self.lexdata
-
-        while lexpos < lexlen:
-            # This code provides some short-circuit code for whitespace, tabs, and other ignored characters
-            if lexdata[lexpos] in lexignore:
-                lexpos += 1
-                continue
-
-            # Look for a regular expression match
-            for lexre, lexindexfunc in self.lexre:
-                m = lexre.match(lexdata, lexpos)
-                if not m:
-                    continue
-
-                # Create a token for return
-                tok = LexToken()
-                tok.value = m.group()
-                tok.lineno = self.lineno
-                tok.lexpos = lexpos
-
-                i = m.lastindex
-                func, tok.type = lexindexfunc[i]
-
-                if not func:
-                    # If no token type was set, it's an ignored token
-                    if tok.type:
-                        self.lexpos = m.end()
-                        return tok
-                    else:
-                        lexpos = m.end()
-                        break
-
-                lexpos = m.end()
-
-                # If token is processed by a function, call it
-
-                tok.lexer = self      # Set additional attributes useful in token rules
-                self.lexmatch = m
-                self.lexpos = lexpos
-
-                newtok = func(tok)
-
-                # Every function must return a token, if nothing, we just move to next token
-                if not newtok:
-                    lexpos    = self.lexpos         # This is here in case user has updated lexpos.
-                    lexignore = self.lexignore      # This is here in case there was a state change
-                    break
-
-                # Verify type of the token.  If not in the token map, raise an error
-                if not self.lexoptimize:
-                    if newtok.type not in self.lextokens_all:
-                        raise LexError("%s:%d: Rule '%s' returned an unknown token type '%s'" % (
-                            func.__code__.co_filename, func.__code__.co_firstlineno,
-                            func.__name__, newtok.type), lexdata[lexpos:])
-
-                return newtok
-            else:
-                # No match, see if in literals
-                if lexdata[lexpos] in self.lexliterals:
-                    tok = LexToken()
-                    tok.value = lexdata[lexpos]
-                    tok.lineno = self.lineno
-                    tok.type = tok.value
-                    tok.lexpos = lexpos
-                    self.lexpos = lexpos + 1
-                    return tok
-
-                # No match. Call t_error() if defined.
-                if self.lexerrorf:
-                    tok = LexToken()
-                    tok.value = self.lexdata[lexpos:]
-                    tok.lineno = self.lineno
-                    tok.type = 'error'
-                    tok.lexer = self
-                    tok.lexpos = lexpos
-                    self.lexpos = lexpos
-                    newtok = self.lexerrorf(tok)
-                    if lexpos == self.lexpos:
-                        # Error method didn't change text position at all. This is an error.
-                        raise LexError("Scanning error. Illegal character '%s'" % (lexdata[lexpos]), lexdata[lexpos:])
-                    lexpos = self.lexpos
-                    if not newtok:
-                        continue
-                    return newtok
-
-                self.lexpos = lexpos
-                raise LexError("Illegal character '%s' at index %d" % (lexdata[lexpos], lexpos), lexdata[lexpos:])
-
-        if self.lexeoff:
-            tok = LexToken()
-            tok.type = 'eof'
-            tok.value = ''
-            tok.lineno = self.lineno
-            tok.lexpos = lexpos
-            tok.lexer = self
-            self.lexpos = lexpos
-            newtok = self.lexeoff(tok)
-            return newtok
-
-        self.lexpos = lexpos + 1
-        if self.lexdata is None:
-            raise RuntimeError('No input string given with input()')
-        return None
-
-    # Iterator interface
-    def __iter__(self):
-        return self
-
-    def next(self):
-        t = self.token()
-        if t is None:
-            raise StopIteration
-        return t
-
-    __next__ = next
-
-# -----------------------------------------------------------------------------
-#                           ==== Lex Builder ===
-#
-# The functions and classes below are used to collect lexing information
-# and build a Lexer object from it.
-# -----------------------------------------------------------------------------
-
-# -----------------------------------------------------------------------------
-# _get_regex(func)
-#
-# Returns the regular expression assigned to a function either as a doc string
-# or as a .regex attribute attached by the @TOKEN decorator.
-# -----------------------------------------------------------------------------
-def _get_regex(func):
-    return getattr(func, 'regex', func.__doc__)
-
-# -----------------------------------------------------------------------------
-# get_caller_module_dict()
-#
-# This function returns a dictionary containing all of the symbols defined within
-# a caller further down the call stack.  This is used to get the environment
-# associated with the yacc() call if none was provided.
-# -----------------------------------------------------------------------------
-def get_caller_module_dict(levels):
-    f = sys._getframe(levels)
-    ldict = f.f_globals.copy()
-    if f.f_globals != f.f_locals:
-        ldict.update(f.f_locals)
-    return ldict
-
-# -----------------------------------------------------------------------------
-# _funcs_to_names()
-#
-# Given a list of regular expression functions, this converts it to a list
-# suitable for output to a table file
-# -----------------------------------------------------------------------------
-def _funcs_to_names(funclist, namelist):
-    result = []
-    for f, name in zip(funclist, namelist):
-        if f and f[0]:
-            result.append((name, f[1]))
-        else:
-            result.append(f)
-    return result
-
-# -----------------------------------------------------------------------------
-# _names_to_funcs()
-#
-# Given a list of regular expression function names, this converts it back to
-# functions.
-# -----------------------------------------------------------------------------
-def _names_to_funcs(namelist, fdict):
-    result = []
-    for n in namelist:
-        if n and n[0]:
-            result.append((fdict[n[0]], n[1]))
-        else:
-            result.append(n)
-    return result
-
-# -----------------------------------------------------------------------------
-# _form_master_re()
-#
-# This function takes a list of all of the regex components and attempts to
-# form the master regular expression.  Given limitations in the Python re
-# module, it may be necessary to break the master regex into separate expressions.
-# -----------------------------------------------------------------------------
-def _form_master_re(relist, reflags, ldict, toknames):
-    if not relist:
-        return []
-    regex = '|'.join(relist)
-    try:
-        lexre = re.compile(regex, reflags)
-
-        # Build the index to function map for the matching engine
-        lexindexfunc = [None] * (max(lexre.groupindex.values()) + 1)
-        lexindexnames = lexindexfunc[:]
-
-        for f, i in lexre.groupindex.items():
-            handle = ldict.get(f, None)
-            if type(handle) in (types.FunctionType, types.MethodType):
-                lexindexfunc[i] = (handle, toknames[f])
-                lexindexnames[i] = f
-            elif handle is not None:
-                lexindexnames[i] = f
-                if f.find('ignore_') > 0:
-                    lexindexfunc[i] = (None, None)
-                else:
-                    lexindexfunc[i] = (None, toknames[f])
-
-        return [(lexre, lexindexfunc)], [regex], [lexindexnames]
-    except Exception:
-        m = int(len(relist)/2)
-        if m == 0:
-            m = 1
-        llist, lre, lnames = _form_master_re(relist[:m], reflags, ldict, toknames)
-        rlist, rre, rnames = _form_master_re(relist[m:], reflags, ldict, toknames)
-        return (llist+rlist), (lre+rre), (lnames+rnames)
-
-# -----------------------------------------------------------------------------
-# def _statetoken(s,names)
-#
-# Given a declaration name s of the form "t_" and a dictionary whose keys are
-# state names, this function returns a tuple (states,tokenname) where states
-# is a tuple of state names and tokenname is the name of the token.  For example,
-# calling this with s = "t_foo_bar_SPAM" might return (('foo','bar'),'SPAM')
-# -----------------------------------------------------------------------------
-def _statetoken(s, names):
-    parts = s.split('_')
-    for i, part in enumerate(parts[1:], 1):
-        if part not in names and part != 'ANY':
-            break
-
-    if i > 1:
-        states = tuple(parts[1:i])
-    else:
-        states = ('INITIAL',)
-
-    if 'ANY' in states:
-        states = tuple(names)
-
-    tokenname = '_'.join(parts[i:])
-    return (states, tokenname)
-
-
-# -----------------------------------------------------------------------------
-# LexerReflect()
-#
-# This class represents information needed to build a lexer as extracted from a
-# user's input file.
-# -----------------------------------------------------------------------------
-class LexerReflect(object):
-    def __init__(self, ldict, log=None, reflags=0):
-        self.ldict      = ldict
-        self.error_func = None
-        self.tokens     = []
-        self.reflags    = reflags
-        self.stateinfo  = {'INITIAL': 'inclusive'}
-        self.modules    = set()
-        self.error      = False
-        self.log        = PlyLogger(sys.stderr) if log is None else log
-
-    # Get all of the basic information
-    def get_all(self):
-        self.get_tokens()
-        self.get_literals()
-        self.get_states()
-        self.get_rules()
-
-    # Validate all of the information
-    def validate_all(self):
-        self.validate_tokens()
-        self.validate_literals()
-        self.validate_rules()
-        return self.error
-
-    # Get the tokens map
-    def get_tokens(self):
-        tokens = self.ldict.get('tokens', None)
-        if not tokens:
-            self.log.error('No token list is defined')
-            self.error = True
-            return
-
-        if not isinstance(tokens, (list, tuple)):
-            self.log.error('tokens must be a list or tuple')
-            self.error = True
-            return
-
-        if not tokens:
-            self.log.error('tokens is empty')
-            self.error = True
-            return
-
-        self.tokens = tokens
-
-    # Validate the tokens
-    def validate_tokens(self):
-        terminals = {}
-        for n in self.tokens:
-            if not _is_identifier.match(n):
-                self.log.error("Bad token name '%s'", n)
-                self.error = True
-            if n in terminals:
-                self.log.warning("Token '%s' multiply defined", n)
-            terminals[n] = 1
-
-    # Get the literals specifier
-    def get_literals(self):
-        self.literals = self.ldict.get('literals', '')
-        if not self.literals:
-            self.literals = ''
-
-    # Validate literals
-    def validate_literals(self):
-        try:
-            for c in self.literals:
-                if not isinstance(c, StringTypes) or len(c) > 1:
-                    self.log.error('Invalid literal %s. Must be a single character', repr(c))
-                    self.error = True
-
-        except TypeError:
-            self.log.error('Invalid literals specification. literals must be a sequence of characters')
-            self.error = True
-
-    def get_states(self):
-        self.states = self.ldict.get('states', None)
-        # Build statemap
-        if self.states:
-            if not isinstance(self.states, (tuple, list)):
-                self.log.error('states must be defined as a tuple or list')
-                self.error = True
-            else:
-                for s in self.states:
-                    if not isinstance(s, tuple) or len(s) != 2:
-                        self.log.error("Invalid state specifier %s. Must be a tuple (statename,'exclusive|inclusive')", repr(s))
-                        self.error = True
-                        continue
-                    name, statetype = s
-                    if not isinstance(name, StringTypes):
-                        self.log.error('State name %s must be a string', repr(name))
-                        self.error = True
-                        continue
-                    if not (statetype == 'inclusive' or statetype == 'exclusive'):
-                        self.log.error("State type for state %s must be 'inclusive' or 'exclusive'", name)
-                        self.error = True
-                        continue
-                    if name in self.stateinfo:
-                        self.log.error("State '%s' already defined", name)
-                        self.error = True
-                        continue
-                    self.stateinfo[name] = statetype
-
-    # Get all of the symbols with a t_ prefix and sort them into various
-    # categories (functions, strings, error functions, and ignore characters)
-
-    def get_rules(self):
-        tsymbols = [f for f in self.ldict if f[:2] == 't_']
-
-        # Now build up a list of functions and a list of strings
-        self.toknames = {}        # Mapping of symbols to token names
-        self.funcsym  = {}        # Symbols defined as functions
-        self.strsym   = {}        # Symbols defined as strings
-        self.ignore   = {}        # Ignore strings by state
-        self.errorf   = {}        # Error functions by state
-        self.eoff     = {}        # EOF functions by state
-
-        for s in self.stateinfo:
-            self.funcsym[s] = []
-            self.strsym[s] = []
-
-        if len(tsymbols) == 0:
-            self.log.error('No rules of the form t_rulename are defined')
-            self.error = True
-            return
-
-        for f in tsymbols:
-            t = self.ldict[f]
-            states, tokname = _statetoken(f, self.stateinfo)
-            self.toknames[f] = tokname
-
-            if hasattr(t, '__call__'):
-                if tokname == 'error':
-                    for s in states:
-                        self.errorf[s] = t
-                elif tokname == 'eof':
-                    for s in states:
-                        self.eoff[s] = t
-                elif tokname == 'ignore':
-                    line = t.__code__.co_firstlineno
-                    file = t.__code__.co_filename
-                    self.log.error("%s:%d: Rule '%s' must be defined as a string", file, line, t.__name__)
-                    self.error = True
-                else:
-                    for s in states:
-                        self.funcsym[s].append((f, t))
-            elif isinstance(t, StringTypes):
-                if tokname == 'ignore':
-                    for s in states:
-                        self.ignore[s] = t
-                    if '\\' in t:
-                        self.log.warning("%s contains a literal backslash '\\'", f)
-
-                elif tokname == 'error':
-                    self.log.error("Rule '%s' must be defined as a function", f)
-                    self.error = True
-                else:
-                    for s in states:
-                        self.strsym[s].append((f, t))
-            else:
-                self.log.error('%s not defined as a function or string', f)
-                self.error = True
-
-        # Sort the functions by line number
-        for f in self.funcsym.values():
-            f.sort(key=lambda x: x[1].__code__.co_firstlineno)
-
-        # Sort the strings by regular expression length
-        for s in self.strsym.values():
-            s.sort(key=lambda x: len(x[1]), reverse=True)
-
-    # Validate all of the t_rules collected
-    def validate_rules(self):
-        for state in self.stateinfo:
-            # Validate all rules defined by functions
-
-            for fname, f in self.funcsym[state]:
-                line = f.__code__.co_firstlineno
-                file = f.__code__.co_filename
-                module = inspect.getmodule(f)
-                self.modules.add(module)
-
-                tokname = self.toknames[fname]
-                if isinstance(f, types.MethodType):
-                    reqargs = 2
-                else:
-                    reqargs = 1
-                nargs = f.__code__.co_argcount
-                if nargs > reqargs:
-                    self.log.error("%s:%d: Rule '%s' has too many arguments", file, line, f.__name__)
-                    self.error = True
-                    continue
-
-                if nargs < reqargs:
-                    self.log.error("%s:%d: Rule '%s' requires an argument", file, line, f.__name__)
-                    self.error = True
-                    continue
-
-                if not _get_regex(f):
-                    self.log.error("%s:%d: No regular expression defined for rule '%s'", file, line, f.__name__)
-                    self.error = True
-                    continue
-
-                try:
-                    c = re.compile('(?P<%s>%s)' % (fname, _get_regex(f)), self.reflags)
-                    if c.match(''):
-                        self.log.error("%s:%d: Regular expression for rule '%s' matches empty string", file, line, f.__name__)
-                        self.error = True
-                except re.error as e:
-                    self.log.error("%s:%d: Invalid regular expression for rule '%s'. %s", file, line, f.__name__, e)
-                    if '#' in _get_regex(f):
-                        self.log.error("%s:%d. Make sure '#' in rule '%s' is escaped with '\\#'", file, line, f.__name__)
-                    self.error = True
-
-            # Validate all rules defined by strings
-            for name, r in self.strsym[state]:
-                tokname = self.toknames[name]
-                if tokname == 'error':
-                    self.log.error("Rule '%s' must be defined as a function", name)
-                    self.error = True
-                    continue
-
-                if tokname not in self.tokens and tokname.find('ignore_') < 0:
-                    self.log.error("Rule '%s' defined for an unspecified token %s", name, tokname)
-                    self.error = True
-                    continue
-
-                try:
-                    c = re.compile('(?P<%s>%s)' % (name, r), self.reflags)
-                    if (c.match('')):
-                        self.log.error("Regular expression for rule '%s' matches empty string", name)
-                        self.error = True
-                except re.error as e:
-                    self.log.error("Invalid regular expression for rule '%s'. %s", name, e)
-                    if '#' in r:
-                        self.log.error("Make sure '#' in rule '%s' is escaped with '\\#'", name)
-                    self.error = True
-
-            if not self.funcsym[state] and not self.strsym[state]:
-                self.log.error("No rules defined for state '%s'", state)
-                self.error = True
-
-            # Validate the error function
-            efunc = self.errorf.get(state, None)
-            if efunc:
-                f = efunc
-                line = f.__code__.co_firstlineno
-                file = f.__code__.co_filename
-                module = inspect.getmodule(f)
-                self.modules.add(module)
-
-                if isinstance(f, types.MethodType):
-                    reqargs = 2
-                else:
-                    reqargs = 1
-                nargs = f.__code__.co_argcount
-                if nargs > reqargs:
-                    self.log.error("%s:%d: Rule '%s' has too many arguments", file, line, f.__name__)
-                    self.error = True
-
-                if nargs < reqargs:
-                    self.log.error("%s:%d: Rule '%s' requires an argument", file, line, f.__name__)
-                    self.error = True
-
-        for module in self.modules:
-            self.validate_module(module)
-
-    # -----------------------------------------------------------------------------
-    # validate_module()
-    #
-    # This checks to see if there are duplicated t_rulename() functions or strings
-    # in the parser input file.  This is done using a simple regular expression
-    # match on each line in the source code of the given module.
-    # -----------------------------------------------------------------------------
-
-    def validate_module(self, module):
-        try:
-            lines, linen = inspect.getsourcelines(module)
-        except IOError:
-            return
-
-        fre = re.compile(r'\s*def\s+(t_[a-zA-Z_0-9]*)\(')
-        sre = re.compile(r'\s*(t_[a-zA-Z_0-9]*)\s*=')
-
-        counthash = {}
-        linen += 1
-        for line in lines:
-            m = fre.match(line)
-            if not m:
-                m = sre.match(line)
-            if m:
-                name = m.group(1)
-                prev = counthash.get(name)
-                if not prev:
-                    counthash[name] = linen
-                else:
-                    filename = inspect.getsourcefile(module)
-                    self.log.error('%s:%d: Rule %s redefined. Previously defined on line %d', filename, linen, name, prev)
-                    self.error = True
-            linen += 1
-
-# -----------------------------------------------------------------------------
-# lex(module)
-#
-# Build all of the regular expression rules from definitions in the supplied module
-# -----------------------------------------------------------------------------
-def lex(module=None, object=None, debug=False, optimize=False, lextab='lextab',
-        reflags=int(re.VERBOSE), nowarn=False, outputdir=None, debuglog=None, errorlog=None):
-
-    if lextab is None:
-        lextab = 'lextab'
-
-    global lexer
-
-    ldict = None
-    stateinfo  = {'INITIAL': 'inclusive'}
-    lexobj = Lexer()
-    lexobj.lexoptimize = optimize
-    global token, input
-
-    if errorlog is None:
-        errorlog = PlyLogger(sys.stderr)
-
-    if debug:
-        if debuglog is None:
-            debuglog = PlyLogger(sys.stderr)
-
-    # Get the module dictionary used for the lexer
-    if object:
-        module = object
-
-    # Get the module dictionary used for the parser
-    if module:
-        _items = [(k, getattr(module, k)) for k in dir(module)]
-        ldict = dict(_items)
-        # If no __file__ attribute is available, try to obtain it from the __module__ instead
-        if '__file__' not in ldict:
-            ldict['__file__'] = sys.modules[ldict['__module__']].__file__
-    else:
-        ldict = get_caller_module_dict(2)
-
-    # Determine if the module is package of a package or not.
-    # If so, fix the tabmodule setting so that tables load correctly
-    pkg = ldict.get('__package__')
-    if pkg and isinstance(lextab, str):
-        if '.' not in lextab:
-            lextab = pkg + '.' + lextab
-
-    # Collect parser information from the dictionary
-    linfo = LexerReflect(ldict, log=errorlog, reflags=reflags)
-    linfo.get_all()
-    if not optimize:
-        if linfo.validate_all():
-            raise SyntaxError("Can't build lexer")
-
-    if optimize and lextab:
-        try:
-            lexobj.readtab(lextab, ldict)
-            token = lexobj.token
-            input = lexobj.input
-            lexer = lexobj
-            return lexobj
-
-        except ImportError:
-            pass
-
-    # Dump some basic debugging information
-    if debug:
-        debuglog.info('lex: tokens   = %r', linfo.tokens)
-        debuglog.info('lex: literals = %r', linfo.literals)
-        debuglog.info('lex: states   = %r', linfo.stateinfo)
-
-    # Build a dictionary of valid token names
-    lexobj.lextokens = set()
-    for n in linfo.tokens:
-        lexobj.lextokens.add(n)
-
-    # Get literals specification
-    if isinstance(linfo.literals, (list, tuple)):
-        lexobj.lexliterals = type(linfo.literals[0])().join(linfo.literals)
-    else:
-        lexobj.lexliterals = linfo.literals
-
-    lexobj.lextokens_all = lexobj.lextokens | set(lexobj.lexliterals)
-
-    # Get the stateinfo dictionary
-    stateinfo = linfo.stateinfo
-
-    regexs = {}
-    # Build the master regular expressions
-    for state in stateinfo:
-        regex_list = []
-
-        # Add rules defined by functions first
-        for fname, f in linfo.funcsym[state]:
-            regex_list.append('(?P<%s>%s)' % (fname, _get_regex(f)))
-            if debug:
-                debuglog.info("lex: Adding rule %s -> '%s' (state '%s')", fname, _get_regex(f), state)
-
-        # Now add all of the simple rules
-        for name, r in linfo.strsym[state]:
-            regex_list.append('(?P<%s>%s)' % (name, r))
-            if debug:
-                debuglog.info("lex: Adding rule %s -> '%s' (state '%s')", name, r, state)
-
-        regexs[state] = regex_list
-
-    # Build the master regular expressions
-
-    if debug:
-        debuglog.info('lex: ==== MASTER REGEXS FOLLOW ====')
-
-    for state in regexs:
-        lexre, re_text, re_names = _form_master_re(regexs[state], reflags, ldict, linfo.toknames)
-        lexobj.lexstatere[state] = lexre
-        lexobj.lexstateretext[state] = re_text
-        lexobj.lexstaterenames[state] = re_names
-        if debug:
-            for i, text in enumerate(re_text):
-                debuglog.info("lex: state '%s' : regex[%d] = '%s'", state, i, text)
-
-    # For inclusive states, we need to add the regular expressions from the INITIAL state
-    for state, stype in stateinfo.items():
-        if state != 'INITIAL' and stype == 'inclusive':
-            lexobj.lexstatere[state].extend(lexobj.lexstatere['INITIAL'])
-            lexobj.lexstateretext[state].extend(lexobj.lexstateretext['INITIAL'])
-            lexobj.lexstaterenames[state].extend(lexobj.lexstaterenames['INITIAL'])
-
-    lexobj.lexstateinfo = stateinfo
-    lexobj.lexre = lexobj.lexstatere['INITIAL']
-    lexobj.lexretext = lexobj.lexstateretext['INITIAL']
-    lexobj.lexreflags = reflags
-
-    # Set up ignore variables
-    lexobj.lexstateignore = linfo.ignore
-    lexobj.lexignore = lexobj.lexstateignore.get('INITIAL', '')
-
-    # Set up error functions
-    lexobj.lexstateerrorf = linfo.errorf
-    lexobj.lexerrorf = linfo.errorf.get('INITIAL', None)
-    if not lexobj.lexerrorf:
-        errorlog.warning('No t_error rule is defined')
-
-    # Set up eof functions
-    lexobj.lexstateeoff = linfo.eoff
-    lexobj.lexeoff = linfo.eoff.get('INITIAL', None)
-
-    # Check state information for ignore and error rules
-    for s, stype in stateinfo.items():
-        if stype == 'exclusive':
-            if s not in linfo.errorf:
-                errorlog.warning("No error rule is defined for exclusive state '%s'", s)
-            if s not in linfo.ignore and lexobj.lexignore:
-                errorlog.warning("No ignore rule is defined for exclusive state '%s'", s)
-        elif stype == 'inclusive':
-            if s not in linfo.errorf:
-                linfo.errorf[s] = linfo.errorf.get('INITIAL', None)
-            if s not in linfo.ignore:
-                linfo.ignore[s] = linfo.ignore.get('INITIAL', '')
-
-    # Create global versions of the token() and input() functions
-    token = lexobj.token
-    input = lexobj.input
-    lexer = lexobj
-
-    # If in optimize mode, we write the lextab
-    if lextab and optimize:
-        if outputdir is None:
-            # If no output directory is set, the location of the output files
-            # is determined according to the following rules:
-            #     - If lextab specifies a package, files go into that package directory
-            #     - Otherwise, files go in the same directory as the specifying module
-            if isinstance(lextab, types.ModuleType):
-                srcfile = lextab.__file__
-            else:
-                if '.' not in lextab:
-                    srcfile = ldict['__file__']
-                else:
-                    parts = lextab.split('.')
-                    pkgname = '.'.join(parts[:-1])
-                    exec('import %s' % pkgname)
-                    srcfile = getattr(sys.modules[pkgname], '__file__', '')
-            outputdir = os.path.dirname(srcfile)
-        try:
-            lexobj.writetab(lextab, outputdir)
-            if lextab in sys.modules:
-                del sys.modules[lextab]
-        except IOError as e:
-            errorlog.warning("Couldn't write lextab module %r. %s" % (lextab, e))
-
-    return lexobj
-
-# -----------------------------------------------------------------------------
-# runmain()
-#
-# This runs the lexer as a main program
-# -----------------------------------------------------------------------------
-
-def runmain(lexer=None, data=None):
-    if not data:
-        try:
-            filename = sys.argv[1]
-            f = open(filename)
-            data = f.read()
-            f.close()
-        except IndexError:
-            sys.stdout.write('Reading from standard input (type EOF to end):\n')
-            data = sys.stdin.read()
-
-    if lexer:
-        _input = lexer.input
-    else:
-        _input = input
-    _input(data)
-    if lexer:
-        _token = lexer.token
-    else:
-        _token = token
-
-    while True:
-        tok = _token()
-        if not tok:
-            break
-        sys.stdout.write('(%s,%r,%d,%d)\n' % (tok.type, tok.value, tok.lineno, tok.lexpos))
-
-# -----------------------------------------------------------------------------
-# @TOKEN(regex)
-#
-# This decorator function can be used to set the regex expression on a function
-# when its docstring might need to be set in an alternative way
-# -----------------------------------------------------------------------------
-
-def TOKEN(r):
-    def set_regex(f):
-        if hasattr(r, '__call__'):
-            f.regex = _get_regex(r)
-        else:
-            f.regex = r
-        return f
-    return set_regex
-
-# Alternative spelling of the TOKEN decorator
-Token = TOKEN
diff --git a/server/libs/ply/yacc.py b/server/libs/ply/yacc.py
deleted file mode 100644
index 88188a1..0000000
--- a/server/libs/ply/yacc.py
+++ /dev/null
@@ -1,3502 +0,0 @@
-# -----------------------------------------------------------------------------
-# ply: yacc.py
-#
-# Copyright (C) 2001-2018
-# David M. Beazley (Dabeaz LLC)
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright notice,
-#   this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-#   this list of conditions and the following disclaimer in the documentation
-#   and/or other materials provided with the distribution.
-# * Neither the name of the David Beazley or Dabeaz LLC may be used to
-#   endorse or promote products derived from this software without
-#  specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# -----------------------------------------------------------------------------
-#
-# This implements an LR parser that is constructed from grammar rules defined
-# as Python functions. The grammar is specified by supplying the BNF inside
-# Python documentation strings.  The inspiration for this technique was borrowed
-# from John Aycock's Spark parsing system.  PLY might be viewed as cross between
-# Spark and the GNU bison utility.
-#
-# The current implementation is only somewhat object-oriented. The
-# LR parser itself is defined in terms of an object (which allows multiple
-# parsers to co-exist).  However, most of the variables used during table
-# construction are defined in terms of global variables.  Users shouldn't
-# notice unless they are trying to define multiple parsers at the same
-# time using threads (in which case they should have their head examined).
-#
-# This implementation supports both SLR and LALR(1) parsing.  LALR(1)
-# support was originally implemented by Elias Ioup (ezioup@alumni.uchicago.edu),
-# using the algorithm found in Aho, Sethi, and Ullman "Compilers: Principles,
-# Techniques, and Tools" (The Dragon Book).  LALR(1) has since been replaced
-# by the more efficient DeRemer and Pennello algorithm.
-#
-# :::::::: WARNING :::::::
-#
-# Construction of LR parsing tables is fairly complicated and expensive.
-# To make this module run fast, a *LOT* of work has been put into
-# optimization---often at the expensive of readability and what might
-# consider to be good Python "coding style."   Modify the code at your
-# own risk!
-# ----------------------------------------------------------------------------
-
-import re
-import types
-import sys
-import os.path
-import inspect
-import warnings
-
-__version__    = '3.11'
-__tabversion__ = '3.10'
-
-#-----------------------------------------------------------------------------
-#                     === User configurable parameters ===
-#
-# Change these to modify the default behavior of yacc (if you wish)
-#-----------------------------------------------------------------------------
-
-yaccdebug   = True             # Debugging mode.  If set, yacc generates a
-                               # a 'parser.out' file in the current directory
-
-debug_file  = 'parser.out'     # Default name of the debugging file
-tab_module  = 'parsetab'       # Default name of the table module
-default_lr  = 'LALR'           # Default LR table generation method
-
-error_count = 3                # Number of symbols that must be shifted to leave recovery mode
-
-yaccdevel   = False            # Set to True if developing yacc.  This turns off optimized
-                               # implementations of certain functions.
-
-resultlimit = 40               # Size limit of results when running in debug mode.
-
-pickle_protocol = 0            # Protocol to use when writing pickle files
-
-# String type-checking compatibility
-if sys.version_info[0] < 3:
-    string_types = basestring
-else:
-    string_types = str
-
-MAXINT = sys.maxsize
-
-# This object is a stand-in for a logging object created by the
-# logging module.   PLY will use this by default to create things
-# such as the parser.out file.  If a user wants more detailed
-# information, they can create their own logging object and pass
-# it into PLY.
-
-class PlyLogger(object):
-    def __init__(self, f):
-        self.f = f
-
-    def debug(self, msg, *args, **kwargs):
-        self.f.write((msg % args) + '\n')
-
-    info = debug
-
-    def warning(self, msg, *args, **kwargs):
-        self.f.write('WARNING: ' + (msg % args) + '\n')
-
-    def error(self, msg, *args, **kwargs):
-        self.f.write('ERROR: ' + (msg % args) + '\n')
-
-    critical = debug
-
-# Null logger is used when no output is generated. Does nothing.
-class NullLogger(object):
-    def __getattribute__(self, name):
-        return self
-
-    def __call__(self, *args, **kwargs):
-        return self
-
-# Exception raised for yacc-related errors
-class YaccError(Exception):
-    pass
-
-# Format the result message that the parser produces when running in debug mode.
-def format_result(r):
-    repr_str = repr(r)
-    if '\n' in repr_str:
-        repr_str = repr(repr_str)
-    if len(repr_str) > resultlimit:
-        repr_str = repr_str[:resultlimit] + ' ...'
-    result = '<%s @ 0x%x> (%s)' % (type(r).__name__, id(r), repr_str)
-    return result
-
-# Format stack entries when the parser is running in debug mode
-def format_stack_entry(r):
-    repr_str = repr(r)
-    if '\n' in repr_str:
-        repr_str = repr(repr_str)
-    if len(repr_str) < 16:
-        return repr_str
-    else:
-        return '<%s @ 0x%x>' % (type(r).__name__, id(r))
-
-# Panic mode error recovery support.   This feature is being reworked--much of the
-# code here is to offer a deprecation/backwards compatible transition
-
-_errok = None
-_token = None
-_restart = None
-_warnmsg = '''PLY: Don't use global functions errok(), token(), and restart() in p_error().
-Instead, invoke the methods on the associated parser instance:
-
-    def p_error(p):
-        ...
-        # Use parser.errok(), parser.token(), parser.restart()
-        ...
-
-    parser = yacc.yacc()
-'''
-
-def errok():
-    warnings.warn(_warnmsg)
-    return _errok()
-
-def restart():
-    warnings.warn(_warnmsg)
-    return _restart()
-
-def token():
-    warnings.warn(_warnmsg)
-    return _token()
-
-# Utility function to call the p_error() function with some deprecation hacks
-def call_errorfunc(errorfunc, token, parser):
-    global _errok, _token, _restart
-    _errok = parser.errok
-    _token = parser.token
-    _restart = parser.restart
-    r = errorfunc(token)
-    try:
-        del _errok, _token, _restart
-    except NameError:
-        pass
-    return r
-
-#-----------------------------------------------------------------------------
-#                        ===  LR Parsing Engine ===
-#
-# The following classes are used for the LR parser itself.  These are not
-# used during table construction and are independent of the actual LR
-# table generation algorithm
-#-----------------------------------------------------------------------------
-
-# This class is used to hold non-terminal grammar symbols during parsing.
-# It normally has the following attributes set:
-#        .type       = Grammar symbol type
-#        .value      = Symbol value
-#        .lineno     = Starting line number
-#        .endlineno  = Ending line number (optional, set automatically)
-#        .lexpos     = Starting lex position
-#        .endlexpos  = Ending lex position (optional, set automatically)
-
-class YaccSymbol:
-    def __str__(self):
-        return self.type
-
-    def __repr__(self):
-        return str(self)
-
-# This class is a wrapper around the objects actually passed to each
-# grammar rule.   Index lookup and assignment actually assign the
-# .value attribute of the underlying YaccSymbol object.
-# The lineno() method returns the line number of a given
-# item (or 0 if not defined).   The linespan() method returns
-# a tuple of (startline,endline) representing the range of lines
-# for a symbol.  The lexspan() method returns a tuple (lexpos,endlexpos)
-# representing the range of positional information for a symbol.
-
-class YaccProduction:
-    def __init__(self, s, stack=None):
-        self.slice = s
-        self.stack = stack
-        self.lexer = None
-        self.parser = None
-
-    def __getitem__(self, n):
-        if isinstance(n, slice):
-            return [s.value for s in self.slice[n]]
-        elif n >= 0:
-            return self.slice[n].value
-        else:
-            return self.stack[n].value
-
-    def __setitem__(self, n, v):
-        self.slice[n].value = v
-
-    def __getslice__(self, i, j):
-        return [s.value for s in self.slice[i:j]]
-
-    def __len__(self):
-        return len(self.slice)
-
-    def lineno(self, n):
-        return getattr(self.slice[n], 'lineno', 0)
-
-    def set_lineno(self, n, lineno):
-        self.slice[n].lineno = lineno
-
-    def linespan(self, n):
-        startline = getattr(self.slice[n], 'lineno', 0)
-        endline = getattr(self.slice[n], 'endlineno', startline)
-        return startline, endline
-
-    def lexpos(self, n):
-        return getattr(self.slice[n], 'lexpos', 0)
-
-    def set_lexpos(self, n, lexpos):
-        self.slice[n].lexpos = lexpos
-
-    def lexspan(self, n):
-        startpos = getattr(self.slice[n], 'lexpos', 0)
-        endpos = getattr(self.slice[n], 'endlexpos', startpos)
-        return startpos, endpos
-
-    def error(self):
-        raise SyntaxError
-
-# -----------------------------------------------------------------------------
-#                               == LRParser ==
-#
-# The LR Parsing engine.
-# -----------------------------------------------------------------------------
-
-class LRParser:
-    def __init__(self, lrtab, errorf):
-        self.productions = lrtab.lr_productions
-        self.action = lrtab.lr_action
-        self.goto = lrtab.lr_goto
-        self.errorfunc = errorf
-        self.set_defaulted_states()
-        self.errorok = True
-
-    def errok(self):
-        self.errorok = True
-
-    def restart(self):
-        del self.statestack[:]
-        del self.symstack[:]
-        sym = YaccSymbol()
-        sym.type = '$end'
-        self.symstack.append(sym)
-        self.statestack.append(0)
-
-    # Defaulted state support.
-    # This method identifies parser states where there is only one possible reduction action.
-    # For such states, the parser can make a choose to make a rule reduction without consuming
-    # the next look-ahead token.  This delayed invocation of the tokenizer can be useful in
-    # certain kinds of advanced parsing situations where the lexer and parser interact with
-    # each other or change states (i.e., manipulation of scope, lexer states, etc.).
-    #
-    # See:  http://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html#Default-Reductions
-    def set_defaulted_states(self):
-        self.defaulted_states = {}
-        for state, actions in self.action.items():
-            rules = list(actions.values())
-            if len(rules) == 1 and rules[0] < 0:
-                self.defaulted_states[state] = rules[0]
-
-    def disable_defaulted_states(self):
-        self.defaulted_states = {}
-
-    def parse(self, input=None, lexer=None, debug=False, tracking=False, tokenfunc=None):
-        if debug or yaccdevel:
-            if isinstance(debug, int):
-                debug = PlyLogger(sys.stderr)
-            return self.parsedebug(input, lexer, debug, tracking, tokenfunc)
-        elif tracking:
-            return self.parseopt(input, lexer, debug, tracking, tokenfunc)
-        else:
-            return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
-
-
-    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-    # parsedebug().
-    #
-    # This is the debugging enabled version of parse().  All changes made to the
-    # parsing engine should be made here.   Optimized versions of this function
-    # are automatically created by the ply/ygen.py script.  This script cuts out
-    # sections enclosed in markers such as this:
-    #
-    #      #--! DEBUG
-    #      statements
-    #      #--! DEBUG
-    #
-    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-    def parsedebug(self, input=None, lexer=None, debug=False, tracking=False, tokenfunc=None):
-        #--! parsedebug-start
-        lookahead = None                         # Current lookahead symbol
-        lookaheadstack = []                      # Stack of lookahead symbols
-        actions = self.action                    # Local reference to action table (to avoid lookup on self.)
-        goto    = self.goto                      # Local reference to goto table (to avoid lookup on self.)
-        prod    = self.productions               # Local reference to production list (to avoid lookup on self.)
-        defaulted_states = self.defaulted_states # Local reference to defaulted states
-        pslice  = YaccProduction(None)           # Production object passed to grammar rules
-        errorcount = 0                           # Used during error recovery
-
-        #--! DEBUG
-        debug.info('PLY: PARSE DEBUG START')
-        #--! DEBUG
-
-        # If no lexer was given, we will try to use the lex module
-        if not lexer:
-            from . import lex
-            lexer = lex.lexer
-
-        # Set up the lexer and parser objects on pslice
-        pslice.lexer = lexer
-        pslice.parser = self
-
-        # If input was supplied, pass to lexer
-        if input is not None:
-            lexer.input(input)
-
-        if tokenfunc is None:
-            # Tokenize function
-            get_token = lexer.token
-        else:
-            get_token = tokenfunc
-
-        # Set the parser() token method (sometimes used in error recovery)
-        self.token = get_token
-
-        # Set up the state and symbol stacks
-
-        statestack = []                # Stack of parsing states
-        self.statestack = statestack
-        symstack   = []                # Stack of grammar symbols
-        self.symstack = symstack
-
-        pslice.stack = symstack         # Put in the production
-        errtoken   = None               # Err token
-
-        # The start state is assumed to be (0,$end)
-
-        statestack.append(0)
-        sym = YaccSymbol()
-        sym.type = '$end'
-        symstack.append(sym)
-        state = 0
-        while True:
-            # Get the next symbol on the input.  If a lookahead symbol
-            # is already set, we just use that. Otherwise, we'll pull
-            # the next token off of the lookaheadstack or from the lexer
-
-            #--! DEBUG
-            debug.debug('')
-            debug.debug('State  : %s', state)
-            #--! DEBUG
-
-            if state not in defaulted_states:
-                if not lookahead:
-                    if not lookaheadstack:
-                        lookahead = get_token()     # Get the next token
-                    else:
-                        lookahead = lookaheadstack.pop()
-                    if not lookahead:
-                        lookahead = YaccSymbol()
-                        lookahead.type = '$end'
-
-                # Check the action table
-                ltype = lookahead.type
-                t = actions[state].get(ltype)
-            else:
-                t = defaulted_states[state]
-                #--! DEBUG
-                debug.debug('Defaulted state %s: Reduce using %d', state, -t)
-                #--! DEBUG
-
-            #--! DEBUG
-            debug.debug('Stack  : %s',
-                        ('%s . %s' % (' '.join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip())
-            #--! DEBUG
-
-            if t is not None:
-                if t > 0:
-                    # shift a symbol on the stack
-                    statestack.append(t)
-                    state = t
-
-                    #--! DEBUG
-                    debug.debug('Action : Shift and goto state %s', t)
-                    #--! DEBUG
-
-                    symstack.append(lookahead)
-                    lookahead = None
-
-                    # Decrease error count on successful shift
-                    if errorcount:
-                        errorcount -= 1
-                    continue
-
-                if t < 0:
-                    # reduce a symbol on the stack, emit a production
-                    p = prod[-t]
-                    pname = p.name
-                    plen  = p.len
-
-                    # Get production function
-                    sym = YaccSymbol()
-                    sym.type = pname       # Production name
-                    sym.value = None
-
-                    #--! DEBUG
-                    if plen:
-                        debug.info('Action : Reduce rule [%s] with %s and goto state %d', p.str,
-                                   '['+','.join([format_stack_entry(_v.value) for _v in symstack[-plen:]])+']',
-                                   goto[statestack[-1-plen]][pname])
-                    else:
-                        debug.info('Action : Reduce rule [%s] with %s and goto state %d', p.str, [],
-                                   goto[statestack[-1]][pname])
-
-                    #--! DEBUG
-
-                    if plen:
-                        targ = symstack[-plen-1:]
-                        targ[0] = sym
-
-                        #--! TRACKING
-                        if tracking:
-                            t1 = targ[1]
-                            sym.lineno = t1.lineno
-                            sym.lexpos = t1.lexpos
-                            t1 = targ[-1]
-                            sym.endlineno = getattr(t1, 'endlineno', t1.lineno)
-                            sym.endlexpos = getattr(t1, 'endlexpos', t1.lexpos)
-                        #--! TRACKING
-
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-                        # The code enclosed in this section is duplicated
-                        # below as a performance optimization.  Make sure
-                        # changes get made in both locations.
-
-                        pslice.slice = targ
-
-                        try:
-                            # Call the grammar rule with our special slice object
-                            del symstack[-plen:]
-                            self.state = state
-                            p.callable(pslice)
-                            del statestack[-plen:]
-                            #--! DEBUG
-                            debug.info('Result : %s', format_result(pslice[0]))
-                            #--! DEBUG
-                            symstack.append(sym)
-                            state = goto[statestack[-1]][pname]
-                            statestack.append(state)
-                        except SyntaxError:
-                            # If an error was set. Enter error recovery state
-                            lookaheadstack.append(lookahead)    # Save the current lookahead token
-                            symstack.extend(targ[1:-1])         # Put the production slice back on the stack
-                            statestack.pop()                    # Pop back one state (before the reduce)
-                            state = statestack[-1]
-                            sym.type = 'error'
-                            sym.value = 'error'
-                            lookahead = sym
-                            errorcount = error_count
-                            self.errorok = False
-
-                        continue
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-                    else:
-
-                        #--! TRACKING
-                        if tracking:
-                            sym.lineno = lexer.lineno
-                            sym.lexpos = lexer.lexpos
-                        #--! TRACKING
-
-                        targ = [sym]
-
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-                        # The code enclosed in this section is duplicated
-                        # above as a performance optimization.  Make sure
-                        # changes get made in both locations.
-
-                        pslice.slice = targ
-
-                        try:
-                            # Call the grammar rule with our special slice object
-                            self.state = state
-                            p.callable(pslice)
-                            #--! DEBUG
-                            debug.info('Result : %s', format_result(pslice[0]))
-                            #--! DEBUG
-                            symstack.append(sym)
-                            state = goto[statestack[-1]][pname]
-                            statestack.append(state)
-                        except SyntaxError:
-                            # If an error was set. Enter error recovery state
-                            lookaheadstack.append(lookahead)    # Save the current lookahead token
-                            statestack.pop()                    # Pop back one state (before the reduce)
-                            state = statestack[-1]
-                            sym.type = 'error'
-                            sym.value = 'error'
-                            lookahead = sym
-                            errorcount = error_count
-                            self.errorok = False
-
-                        continue
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-                if t == 0:
-                    n = symstack[-1]
-                    result = getattr(n, 'value', None)
-                    #--! DEBUG
-                    debug.info('Done   : Returning %s', format_result(result))
-                    debug.info('PLY: PARSE DEBUG END')
-                    #--! DEBUG
-                    return result
-
-            if t is None:
-
-                #--! DEBUG
-                debug.error('Error  : %s',
-                            ('%s . %s' % (' '.join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip())
-                #--! DEBUG
-
-                # We have some kind of parsing error here.  To handle
-                # this, we are going to push the current token onto
-                # the tokenstack and replace it with an 'error' token.
-                # If there are any synchronization rules, they may
-                # catch it.
-                #
-                # In addition to pushing the error token, we call call
-                # the user defined p_error() function if this is the
-                # first syntax error.  This function is only called if
-                # errorcount == 0.
-                if errorcount == 0 or self.errorok:
-                    errorcount = error_count
-                    self.errorok = False
-                    errtoken = lookahead
-                    if errtoken.type == '$end':
-                        errtoken = None               # End of file!
-                    if self.errorfunc:
-                        if errtoken and not hasattr(errtoken, 'lexer'):
-                            errtoken.lexer = lexer
-                        self.state = state
-                        tok = call_errorfunc(self.errorfunc, errtoken, self)
-                        if self.errorok:
-                            # User must have done some kind of panic
-                            # mode recovery on their own.  The
-                            # returned token is the next lookahead
-                            lookahead = tok
-                            errtoken = None
-                            continue
-                    else:
-                        if errtoken:
-                            if hasattr(errtoken, 'lineno'):
-                                lineno = lookahead.lineno
-                            else:
-                                lineno = 0
-                            if lineno:
-                                sys.stderr.write('yacc: Syntax error at line %d, token=%s\n' % (lineno, errtoken.type))
-                            else:
-                                sys.stderr.write('yacc: Syntax error, token=%s' % errtoken.type)
-                        else:
-                            sys.stderr.write('yacc: Parse error in input. EOF\n')
-                            return
-
-                else:
-                    errorcount = error_count
-
-                # case 1:  the statestack only has 1 entry on it.  If we're in this state, the
-                # entire parse has been rolled back and we're completely hosed.   The token is
-                # discarded and we just keep going.
-
-                if len(statestack) <= 1 and lookahead.type != '$end':
-                    lookahead = None
-                    errtoken = None
-                    state = 0
-                    # Nuke the pushback stack
-                    del lookaheadstack[:]
-                    continue
-
-                # case 2: the statestack has a couple of entries on it, but we're
-                # at the end of the file. nuke the top entry and generate an error token
-
-                # Start nuking entries on the stack
-                if lookahead.type == '$end':
-                    # Whoa. We're really hosed here. Bail out
-                    return
-
-                if lookahead.type != 'error':
-                    sym = symstack[-1]
-                    if sym.type == 'error':
-                        # Hmmm. Error is on top of stack, we'll just nuke input
-                        # symbol and continue
-                        #--! TRACKING
-                        if tracking:
-                            sym.endlineno = getattr(lookahead, 'lineno', sym.lineno)
-                            sym.endlexpos = getattr(lookahead, 'lexpos', sym.lexpos)
-                        #--! TRACKING
-                        lookahead = None
-                        continue
-
-                    # Create the error symbol for the first time and make it the new lookahead symbol
-                    t = YaccSymbol()
-                    t.type = 'error'
-
-                    if hasattr(lookahead, 'lineno'):
-                        t.lineno = t.endlineno = lookahead.lineno
-                    if hasattr(lookahead, 'lexpos'):
-                        t.lexpos = t.endlexpos = lookahead.lexpos
-                    t.value = lookahead
-                    lookaheadstack.append(lookahead)
-                    lookahead = t
-                else:
-                    sym = symstack.pop()
-                    #--! TRACKING
-                    if tracking:
-                        lookahead.lineno = sym.lineno
-                        lookahead.lexpos = sym.lexpos
-                    #--! TRACKING
-                    statestack.pop()
-                    state = statestack[-1]
-
-                continue
-
-            # Call an error function here
-            raise RuntimeError('yacc: internal parser error!!!\n')
-
-        #--! parsedebug-end
-
-    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-    # parseopt().
-    #
-    # Optimized version of parse() method.  DO NOT EDIT THIS CODE DIRECTLY!
-    # This code is automatically generated by the ply/ygen.py script. Make
-    # changes to the parsedebug() method instead.
-    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-    def parseopt(self, input=None, lexer=None, debug=False, tracking=False, tokenfunc=None):
-        #--! parseopt-start
-        lookahead = None                         # Current lookahead symbol
-        lookaheadstack = []                      # Stack of lookahead symbols
-        actions = self.action                    # Local reference to action table (to avoid lookup on self.)
-        goto    = self.goto                      # Local reference to goto table (to avoid lookup on self.)
-        prod    = self.productions               # Local reference to production list (to avoid lookup on self.)
-        defaulted_states = self.defaulted_states # Local reference to defaulted states
-        pslice  = YaccProduction(None)           # Production object passed to grammar rules
-        errorcount = 0                           # Used during error recovery
-
-
-        # If no lexer was given, we will try to use the lex module
-        if not lexer:
-            from . import lex
-            lexer = lex.lexer
-
-        # Set up the lexer and parser objects on pslice
-        pslice.lexer = lexer
-        pslice.parser = self
-
-        # If input was supplied, pass to lexer
-        if input is not None:
-            lexer.input(input)
-
-        if tokenfunc is None:
-            # Tokenize function
-            get_token = lexer.token
-        else:
-            get_token = tokenfunc
-
-        # Set the parser() token method (sometimes used in error recovery)
-        self.token = get_token
-
-        # Set up the state and symbol stacks
-
-        statestack = []                # Stack of parsing states
-        self.statestack = statestack
-        symstack   = []                # Stack of grammar symbols
-        self.symstack = symstack
-
-        pslice.stack = symstack         # Put in the production
-        errtoken   = None               # Err token
-
-        # The start state is assumed to be (0,$end)
-
-        statestack.append(0)
-        sym = YaccSymbol()
-        sym.type = '$end'
-        symstack.append(sym)
-        state = 0
-        while True:
-            # Get the next symbol on the input.  If a lookahead symbol
-            # is already set, we just use that. Otherwise, we'll pull
-            # the next token off of the lookaheadstack or from the lexer
-
-
-            if state not in defaulted_states:
-                if not lookahead:
-                    if not lookaheadstack:
-                        lookahead = get_token()     # Get the next token
-                    else:
-                        lookahead = lookaheadstack.pop()
-                    if not lookahead:
-                        lookahead = YaccSymbol()
-                        lookahead.type = '$end'
-
-                # Check the action table
-                ltype = lookahead.type
-                t = actions[state].get(ltype)
-            else:
-                t = defaulted_states[state]
-
-
-            if t is not None:
-                if t > 0:
-                    # shift a symbol on the stack
-                    statestack.append(t)
-                    state = t
-
-
-                    symstack.append(lookahead)
-                    lookahead = None
-
-                    # Decrease error count on successful shift
-                    if errorcount:
-                        errorcount -= 1
-                    continue
-
-                if t < 0:
-                    # reduce a symbol on the stack, emit a production
-                    p = prod[-t]
-                    pname = p.name
-                    plen  = p.len
-
-                    # Get production function
-                    sym = YaccSymbol()
-                    sym.type = pname       # Production name
-                    sym.value = None
-
-
-                    if plen:
-                        targ = symstack[-plen-1:]
-                        targ[0] = sym
-
-                        #--! TRACKING
-                        if tracking:
-                            t1 = targ[1]
-                            sym.lineno = t1.lineno
-                            sym.lexpos = t1.lexpos
-                            t1 = targ[-1]
-                            sym.endlineno = getattr(t1, 'endlineno', t1.lineno)
-                            sym.endlexpos = getattr(t1, 'endlexpos', t1.lexpos)
-                        #--! TRACKING
-
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-                        # The code enclosed in this section is duplicated
-                        # below as a performance optimization.  Make sure
-                        # changes get made in both locations.
-
-                        pslice.slice = targ
-
-                        try:
-                            # Call the grammar rule with our special slice object
-                            del symstack[-plen:]
-                            self.state = state
-                            p.callable(pslice)
-                            del statestack[-plen:]
-                            symstack.append(sym)
-                            state = goto[statestack[-1]][pname]
-                            statestack.append(state)
-                        except SyntaxError:
-                            # If an error was set. Enter error recovery state
-                            lookaheadstack.append(lookahead)    # Save the current lookahead token
-                            symstack.extend(targ[1:-1])         # Put the production slice back on the stack
-                            statestack.pop()                    # Pop back one state (before the reduce)
-                            state = statestack[-1]
-                            sym.type = 'error'
-                            sym.value = 'error'
-                            lookahead = sym
-                            errorcount = error_count
-                            self.errorok = False
-
-                        continue
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-                    else:
-
-                        #--! TRACKING
-                        if tracking:
-                            sym.lineno = lexer.lineno
-                            sym.lexpos = lexer.lexpos
-                        #--! TRACKING
-
-                        targ = [sym]
-
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-                        # The code enclosed in this section is duplicated
-                        # above as a performance optimization.  Make sure
-                        # changes get made in both locations.
-
-                        pslice.slice = targ
-
-                        try:
-                            # Call the grammar rule with our special slice object
-                            self.state = state
-                            p.callable(pslice)
-                            symstack.append(sym)
-                            state = goto[statestack[-1]][pname]
-                            statestack.append(state)
-                        except SyntaxError:
-                            # If an error was set. Enter error recovery state
-                            lookaheadstack.append(lookahead)    # Save the current lookahead token
-                            statestack.pop()                    # Pop back one state (before the reduce)
-                            state = statestack[-1]
-                            sym.type = 'error'
-                            sym.value = 'error'
-                            lookahead = sym
-                            errorcount = error_count
-                            self.errorok = False
-
-                        continue
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-                if t == 0:
-                    n = symstack[-1]
-                    result = getattr(n, 'value', None)
-                    return result
-
-            if t is None:
-
-
-                # We have some kind of parsing error here.  To handle
-                # this, we are going to push the current token onto
-                # the tokenstack and replace it with an 'error' token.
-                # If there are any synchronization rules, they may
-                # catch it.
-                #
-                # In addition to pushing the error token, we call call
-                # the user defined p_error() function if this is the
-                # first syntax error.  This function is only called if
-                # errorcount == 0.
-                if errorcount == 0 or self.errorok:
-                    errorcount = error_count
-                    self.errorok = False
-                    errtoken = lookahead
-                    if errtoken.type == '$end':
-                        errtoken = None               # End of file!
-                    if self.errorfunc:
-                        if errtoken and not hasattr(errtoken, 'lexer'):
-                            errtoken.lexer = lexer
-                        self.state = state
-                        tok = call_errorfunc(self.errorfunc, errtoken, self)
-                        if self.errorok:
-                            # User must have done some kind of panic
-                            # mode recovery on their own.  The
-                            # returned token is the next lookahead
-                            lookahead = tok
-                            errtoken = None
-                            continue
-                    else:
-                        if errtoken:
-                            if hasattr(errtoken, 'lineno'):
-                                lineno = lookahead.lineno
-                            else:
-                                lineno = 0
-                            if lineno:
-                                sys.stderr.write('yacc: Syntax error at line %d, token=%s\n' % (lineno, errtoken.type))
-                            else:
-                                sys.stderr.write('yacc: Syntax error, token=%s' % errtoken.type)
-                        else:
-                            sys.stderr.write('yacc: Parse error in input. EOF\n')
-                            return
-
-                else:
-                    errorcount = error_count
-
-                # case 1:  the statestack only has 1 entry on it.  If we're in this state, the
-                # entire parse has been rolled back and we're completely hosed.   The token is
-                # discarded and we just keep going.
-
-                if len(statestack) <= 1 and lookahead.type != '$end':
-                    lookahead = None
-                    errtoken = None
-                    state = 0
-                    # Nuke the pushback stack
-                    del lookaheadstack[:]
-                    continue
-
-                # case 2: the statestack has a couple of entries on it, but we're
-                # at the end of the file. nuke the top entry and generate an error token
-
-                # Start nuking entries on the stack
-                if lookahead.type == '$end':
-                    # Whoa. We're really hosed here. Bail out
-                    return
-
-                if lookahead.type != 'error':
-                    sym = symstack[-1]
-                    if sym.type == 'error':
-                        # Hmmm. Error is on top of stack, we'll just nuke input
-                        # symbol and continue
-                        #--! TRACKING
-                        if tracking:
-                            sym.endlineno = getattr(lookahead, 'lineno', sym.lineno)
-                            sym.endlexpos = getattr(lookahead, 'lexpos', sym.lexpos)
-                        #--! TRACKING
-                        lookahead = None
-                        continue
-
-                    # Create the error symbol for the first time and make it the new lookahead symbol
-                    t = YaccSymbol()
-                    t.type = 'error'
-
-                    if hasattr(lookahead, 'lineno'):
-                        t.lineno = t.endlineno = lookahead.lineno
-                    if hasattr(lookahead, 'lexpos'):
-                        t.lexpos = t.endlexpos = lookahead.lexpos
-                    t.value = lookahead
-                    lookaheadstack.append(lookahead)
-                    lookahead = t
-                else:
-                    sym = symstack.pop()
-                    #--! TRACKING
-                    if tracking:
-                        lookahead.lineno = sym.lineno
-                        lookahead.lexpos = sym.lexpos
-                    #--! TRACKING
-                    statestack.pop()
-                    state = statestack[-1]
-
-                continue
-
-            # Call an error function here
-            raise RuntimeError('yacc: internal parser error!!!\n')
-
-        #--! parseopt-end
-
-    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-    # parseopt_notrack().
-    #
-    # Optimized version of parseopt() with line number tracking removed.
-    # DO NOT EDIT THIS CODE DIRECTLY. This code is automatically generated
-    # by the ply/ygen.py script. Make changes to the parsedebug() method instead.
-    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-    def parseopt_notrack(self, input=None, lexer=None, debug=False, tracking=False, tokenfunc=None):
-        #--! parseopt-notrack-start
-        lookahead = None                         # Current lookahead symbol
-        lookaheadstack = []                      # Stack of lookahead symbols
-        actions = self.action                    # Local reference to action table (to avoid lookup on self.)
-        goto    = self.goto                      # Local reference to goto table (to avoid lookup on self.)
-        prod    = self.productions               # Local reference to production list (to avoid lookup on self.)
-        defaulted_states = self.defaulted_states # Local reference to defaulted states
-        pslice  = YaccProduction(None)           # Production object passed to grammar rules
-        errorcount = 0                           # Used during error recovery
-
-
-        # If no lexer was given, we will try to use the lex module
-        if not lexer:
-            from . import lex
-            lexer = lex.lexer
-
-        # Set up the lexer and parser objects on pslice
-        pslice.lexer = lexer
-        pslice.parser = self
-
-        # If input was supplied, pass to lexer
-        if input is not None:
-            lexer.input(input)
-
-        if tokenfunc is None:
-            # Tokenize function
-            get_token = lexer.token
-        else:
-            get_token = tokenfunc
-
-        # Set the parser() token method (sometimes used in error recovery)
-        self.token = get_token
-
-        # Set up the state and symbol stacks
-
-        statestack = []                # Stack of parsing states
-        self.statestack = statestack
-        symstack   = []                # Stack of grammar symbols
-        self.symstack = symstack
-
-        pslice.stack = symstack         # Put in the production
-        errtoken   = None               # Err token
-
-        # The start state is assumed to be (0,$end)
-
-        statestack.append(0)
-        sym = YaccSymbol()
-        sym.type = '$end'
-        symstack.append(sym)
-        state = 0
-        while True:
-            # Get the next symbol on the input.  If a lookahead symbol
-            # is already set, we just use that. Otherwise, we'll pull
-            # the next token off of the lookaheadstack or from the lexer
-
-
-            if state not in defaulted_states:
-                if not lookahead:
-                    if not lookaheadstack:
-                        lookahead = get_token()     # Get the next token
-                    else:
-                        lookahead = lookaheadstack.pop()
-                    if not lookahead:
-                        lookahead = YaccSymbol()
-                        lookahead.type = '$end'
-
-                # Check the action table
-                ltype = lookahead.type
-                t = actions[state].get(ltype)
-            else:
-                t = defaulted_states[state]
-
-
-            if t is not None:
-                if t > 0:
-                    # shift a symbol on the stack
-                    statestack.append(t)
-                    state = t
-
-
-                    symstack.append(lookahead)
-                    lookahead = None
-
-                    # Decrease error count on successful shift
-                    if errorcount:
-                        errorcount -= 1
-                    continue
-
-                if t < 0:
-                    # reduce a symbol on the stack, emit a production
-                    p = prod[-t]
-                    pname = p.name
-                    plen  = p.len
-
-                    # Get production function
-                    sym = YaccSymbol()
-                    sym.type = pname       # Production name
-                    sym.value = None
-
-
-                    if plen:
-                        targ = symstack[-plen-1:]
-                        targ[0] = sym
-
-
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-                        # The code enclosed in this section is duplicated
-                        # below as a performance optimization.  Make sure
-                        # changes get made in both locations.
-
-                        pslice.slice = targ
-
-                        try:
-                            # Call the grammar rule with our special slice object
-                            del symstack[-plen:]
-                            self.state = state
-                            p.callable(pslice)
-                            del statestack[-plen:]
-                            symstack.append(sym)
-                            state = goto[statestack[-1]][pname]
-                            statestack.append(state)
-                        except SyntaxError:
-                            # If an error was set. Enter error recovery state
-                            lookaheadstack.append(lookahead)    # Save the current lookahead token
-                            symstack.extend(targ[1:-1])         # Put the production slice back on the stack
-                            statestack.pop()                    # Pop back one state (before the reduce)
-                            state = statestack[-1]
-                            sym.type = 'error'
-                            sym.value = 'error'
-                            lookahead = sym
-                            errorcount = error_count
-                            self.errorok = False
-
-                        continue
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-                    else:
-
-
-                        targ = [sym]
-
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-                        # The code enclosed in this section is duplicated
-                        # above as a performance optimization.  Make sure
-                        # changes get made in both locations.
-
-                        pslice.slice = targ
-
-                        try:
-                            # Call the grammar rule with our special slice object
-                            self.state = state
-                            p.callable(pslice)
-                            symstack.append(sym)
-                            state = goto[statestack[-1]][pname]
-                            statestack.append(state)
-                        except SyntaxError:
-                            # If an error was set. Enter error recovery state
-                            lookaheadstack.append(lookahead)    # Save the current lookahead token
-                            statestack.pop()                    # Pop back one state (before the reduce)
-                            state = statestack[-1]
-                            sym.type = 'error'
-                            sym.value = 'error'
-                            lookahead = sym
-                            errorcount = error_count
-                            self.errorok = False
-
-                        continue
-                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-                if t == 0:
-                    n = symstack[-1]
-                    result = getattr(n, 'value', None)
-                    return result
-
-            if t is None:
-
-
-                # We have some kind of parsing error here.  To handle
-                # this, we are going to push the current token onto
-                # the tokenstack and replace it with an 'error' token.
-                # If there are any synchronization rules, they may
-                # catch it.
-                #
-                # In addition to pushing the error token, we call call
-                # the user defined p_error() function if this is the
-                # first syntax error.  This function is only called if
-                # errorcount == 0.
-                if errorcount == 0 or self.errorok:
-                    errorcount = error_count
-                    self.errorok = False
-                    errtoken = lookahead
-                    if errtoken.type == '$end':
-                        errtoken = None               # End of file!
-                    if self.errorfunc:
-                        if errtoken and not hasattr(errtoken, 'lexer'):
-                            errtoken.lexer = lexer
-                        self.state = state
-                        tok = call_errorfunc(self.errorfunc, errtoken, self)
-                        if self.errorok:
-                            # User must have done some kind of panic
-                            # mode recovery on their own.  The
-                            # returned token is the next lookahead
-                            lookahead = tok
-                            errtoken = None
-                            continue
-                    else:
-                        if errtoken:
-                            if hasattr(errtoken, 'lineno'):
-                                lineno = lookahead.lineno
-                            else:
-                                lineno = 0
-                            if lineno:
-                                sys.stderr.write('yacc: Syntax error at line %d, token=%s\n' % (lineno, errtoken.type))
-                            else:
-                                sys.stderr.write('yacc: Syntax error, token=%s' % errtoken.type)
-                        else:
-                            sys.stderr.write('yacc: Parse error in input. EOF\n')
-                            return
-
-                else:
-                    errorcount = error_count
-
-                # case 1:  the statestack only has 1 entry on it.  If we're in this state, the
-                # entire parse has been rolled back and we're completely hosed.   The token is
-                # discarded and we just keep going.
-
-                if len(statestack) <= 1 and lookahead.type != '$end':
-                    lookahead = None
-                    errtoken = None
-                    state = 0
-                    # Nuke the pushback stack
-                    del lookaheadstack[:]
-                    continue
-
-                # case 2: the statestack has a couple of entries on it, but we're
-                # at the end of the file. nuke the top entry and generate an error token
-
-                # Start nuking entries on the stack
-                if lookahead.type == '$end':
-                    # Whoa. We're really hosed here. Bail out
-                    return
-
-                if lookahead.type != 'error':
-                    sym = symstack[-1]
-                    if sym.type == 'error':
-                        # Hmmm. Error is on top of stack, we'll just nuke input
-                        # symbol and continue
-                        lookahead = None
-                        continue
-
-                    # Create the error symbol for the first time and make it the new lookahead symbol
-                    t = YaccSymbol()
-                    t.type = 'error'
-
-                    if hasattr(lookahead, 'lineno'):
-                        t.lineno = t.endlineno = lookahead.lineno
-                    if hasattr(lookahead, 'lexpos'):
-                        t.lexpos = t.endlexpos = lookahead.lexpos
-                    t.value = lookahead
-                    lookaheadstack.append(lookahead)
-                    lookahead = t
-                else:
-                    sym = symstack.pop()
-                    statestack.pop()
-                    state = statestack[-1]
-
-                continue
-
-            # Call an error function here
-            raise RuntimeError('yacc: internal parser error!!!\n')
-
-        #--! parseopt-notrack-end
-
-# -----------------------------------------------------------------------------
-#                          === Grammar Representation ===
-#
-# The following functions, classes, and variables are used to represent and
-# manipulate the rules that make up a grammar.
-# -----------------------------------------------------------------------------
-
-# regex matching identifiers
-_is_identifier = re.compile(r'^[a-zA-Z0-9_-]+$')
-
-# -----------------------------------------------------------------------------
-# class Production:
-#
-# This class stores the raw information about a single production or grammar rule.
-# A grammar rule refers to a specification such as this:
-#
-#       expr : expr PLUS term
-#
-# Here are the basic attributes defined on all productions
-#
-#       name     - Name of the production.  For example 'expr'
-#       prod     - A list of symbols on the right side ['expr','PLUS','term']
-#       prec     - Production precedence level
-#       number   - Production number.
-#       func     - Function that executes on reduce
-#       file     - File where production function is defined
-#       lineno   - Line number where production function is defined
-#
-# The following attributes are defined or optional.
-#
-#       len       - Length of the production (number of symbols on right hand side)
-#       usyms     - Set of unique symbols found in the production
-# -----------------------------------------------------------------------------
-
-class Production(object):
-    reduced = 0
-    def __init__(self, number, name, prod, precedence=('right', 0), func=None, file='', line=0):
-        self.name     = name
-        self.prod     = tuple(prod)
-        self.number   = number
-        self.func     = func
-        self.callable = None
-        self.file     = file
-        self.line     = line
-        self.prec     = precedence
-
-        # Internal settings used during table construction
-
-        self.len  = len(self.prod)   # Length of the production
-
-        # Create a list of unique production symbols used in the production
-        self.usyms = []
-        for s in self.prod:
-            if s not in self.usyms:
-                self.usyms.append(s)
-
-        # List of all LR items for the production
-        self.lr_items = []
-        self.lr_next = None
-
-        # Create a string representation
-        if self.prod:
-            self.str = '%s -> %s' % (self.name, ' '.join(self.prod))
-        else:
-            self.str = '%s -> ' % self.name
-
-    def __str__(self):
-        return self.str
-
-    def __repr__(self):
-        return 'Production(' + str(self) + ')'
-
-    def __len__(self):
-        return len(self.prod)
-
-    def __nonzero__(self):
-        return 1
-
-    def __getitem__(self, index):
-        return self.prod[index]
-
-    # Return the nth lr_item from the production (or None if at the end)
-    def lr_item(self, n):
-        if n > len(self.prod):
-            return None
-        p = LRItem(self, n)
-        # Precompute the list of productions immediately following.
-        try:
-            p.lr_after = self.Prodnames[p.prod[n+1]]
-        except (IndexError, KeyError):
-            p.lr_after = []
-        try:
-            p.lr_before = p.prod[n-1]
-        except IndexError:
-            p.lr_before = None
-        return p
-
-    # Bind the production function name to a callable
-    def bind(self, pdict):
-        if self.func:
-            self.callable = pdict[self.func]
-
-# This class serves as a minimal standin for Production objects when
-# reading table data from files.   It only contains information
-# actually used by the LR parsing engine, plus some additional
-# debugging information.
-class MiniProduction(object):
-    def __init__(self, str, name, len, func, file, line):
-        self.name     = name
-        self.len      = len
-        self.func     = func
-        self.callable = None
-        self.file     = file
-        self.line     = line
-        self.str      = str
-
-    def __str__(self):
-        return self.str
-
-    def __repr__(self):
-        return 'MiniProduction(%s)' % self.str
-
-    # Bind the production function name to a callable
-    def bind(self, pdict):
-        if self.func:
-            self.callable = pdict[self.func]
-
-
-# -----------------------------------------------------------------------------
-# class LRItem
-#
-# This class represents a specific stage of parsing a production rule.  For
-# example:
-#
-#       expr : expr . PLUS term
-#
-# In the above, the "." represents the current location of the parse.  Here
-# basic attributes:
-#
-#       name       - Name of the production.  For example 'expr'
-#       prod       - A list of symbols on the right side ['expr','.', 'PLUS','term']
-#       number     - Production number.
-#
-#       lr_next      Next LR item. Example, if we are ' expr -> expr . PLUS term'
-#                    then lr_next refers to 'expr -> expr PLUS . term'
-#       lr_index   - LR item index (location of the ".") in the prod list.
-#       lookaheads - LALR lookahead symbols for this item
-#       len        - Length of the production (number of symbols on right hand side)
-#       lr_after    - List of all productions that immediately follow
-#       lr_before   - Grammar symbol immediately before
-# -----------------------------------------------------------------------------
-
-class LRItem(object):
-    def __init__(self, p, n):
-        self.name       = p.name
-        self.prod       = list(p.prod)
-        self.number     = p.number
-        self.lr_index   = n
-        self.lookaheads = {}
-        self.prod.insert(n, '.')
-        self.prod       = tuple(self.prod)
-        self.len        = len(self.prod)
-        self.usyms      = p.usyms
-
-    def __str__(self):
-        if self.prod:
-            s = '%s -> %s' % (self.name, ' '.join(self.prod))
-        else:
-            s = '%s -> ' % self.name
-        return s
-
-    def __repr__(self):
-        return 'LRItem(' + str(self) + ')'
-
-# -----------------------------------------------------------------------------
-# rightmost_terminal()
-#
-# Return the rightmost terminal from a list of symbols.  Used in add_production()
-# -----------------------------------------------------------------------------
-def rightmost_terminal(symbols, terminals):
-    i = len(symbols) - 1
-    while i >= 0:
-        if symbols[i] in terminals:
-            return symbols[i]
-        i -= 1
-    return None
-
-# -----------------------------------------------------------------------------
-#                           === GRAMMAR CLASS ===
-#
-# The following class represents the contents of the specified grammar along
-# with various computed properties such as first sets, follow sets, LR items, etc.
-# This data is used for critical parts of the table generation process later.
-# -----------------------------------------------------------------------------
-
-class GrammarError(YaccError):
-    pass
-
-class Grammar(object):
-    def __init__(self, terminals):
-        self.Productions  = [None]  # A list of all of the productions.  The first
-                                    # entry is always reserved for the purpose of
-                                    # building an augmented grammar
-
-        self.Prodnames    = {}      # A dictionary mapping the names of nonterminals to a list of all
-                                    # productions of that nonterminal.
-
-        self.Prodmap      = {}      # A dictionary that is only used to detect duplicate
-                                    # productions.
-
-        self.Terminals    = {}      # A dictionary mapping the names of terminal symbols to a
-                                    # list of the rules where they are used.
-
-        for term in terminals:
-            self.Terminals[term] = []
-
-        self.Terminals['error'] = []
-
-        self.Nonterminals = {}      # A dictionary mapping names of nonterminals to a list
-                                    # of rule numbers where they are used.
-
-        self.First        = {}      # A dictionary of precomputed FIRST(x) symbols
-
-        self.Follow       = {}      # A dictionary of precomputed FOLLOW(x) symbols
-
-        self.Precedence   = {}      # Precedence rules for each terminal. Contains tuples of the
-                                    # form ('right',level) or ('nonassoc', level) or ('left',level)
-
-        self.UsedPrecedence = set() # Precedence rules that were actually used by the grammer.
-                                    # This is only used to provide error checking and to generate
-                                    # a warning about unused precedence rules.
-
-        self.Start = None           # Starting symbol for the grammar
-
-
-    def __len__(self):
-        return len(self.Productions)
-
-    def __getitem__(self, index):
-        return self.Productions[index]
-
-    # -----------------------------------------------------------------------------
-    # set_precedence()
-    #
-    # Sets the precedence for a given terminal. assoc is the associativity such as
-    # 'left','right', or 'nonassoc'.  level is a numeric level.
-    #
-    # -----------------------------------------------------------------------------
-
-    def set_precedence(self, term, assoc, level):
-        assert self.Productions == [None], 'Must call set_precedence() before add_production()'
-        if term in self.Precedence:
-            raise GrammarError('Precedence already specified for terminal %r' % term)
-        if assoc not in ['left', 'right', 'nonassoc']:
-            raise GrammarError("Associativity must be one of 'left','right', or 'nonassoc'")
-        self.Precedence[term] = (assoc, level)
-
-    # -----------------------------------------------------------------------------
-    # add_production()
-    #
-    # Given an action function, this function assembles a production rule and
-    # computes its precedence level.
-    #
-    # The production rule is supplied as a list of symbols.   For example,
-    # a rule such as 'expr : expr PLUS term' has a production name of 'expr' and
-    # symbols ['expr','PLUS','term'].
-    #
-    # Precedence is determined by the precedence of the right-most non-terminal
-    # or the precedence of a terminal specified by %prec.
-    #
-    # A variety of error checks are performed to make sure production symbols
-    # are valid and that %prec is used correctly.
-    # -----------------------------------------------------------------------------
-
-    def add_production(self, prodname, syms, func=None, file='', line=0):
-
-        if prodname in self.Terminals:
-            raise GrammarError('%s:%d: Illegal rule name %r. Already defined as a token' % (file, line, prodname))
-        if prodname == 'error':
-            raise GrammarError('%s:%d: Illegal rule name %r. error is a reserved word' % (file, line, prodname))
-        if not _is_identifier.match(prodname):
-            raise GrammarError('%s:%d: Illegal rule name %r' % (file, line, prodname))
-
-        # Look for literal tokens
-        for n, s in enumerate(syms):
-            if s[0] in "'\"":
-                try:
-                    c = eval(s)
-                    if (len(c) > 1):
-                        raise GrammarError('%s:%d: Literal token %s in rule %r may only be a single character' %
-                                           (file, line, s, prodname))
-                    if c not in self.Terminals:
-                        self.Terminals[c] = []
-                    syms[n] = c
-                    continue
-                except SyntaxError:
-                    pass
-            if not _is_identifier.match(s) and s != '%prec':
-                raise GrammarError('%s:%d: Illegal name %r in rule %r' % (file, line, s, prodname))
-
-        # Determine the precedence level
-        if '%prec' in syms:
-            if syms[-1] == '%prec':
-                raise GrammarError('%s:%d: Syntax error. Nothing follows %%prec' % (file, line))
-            if syms[-2] != '%prec':
-                raise GrammarError('%s:%d: Syntax error. %%prec can only appear at the end of a grammar rule' %
-                                   (file, line))
-            precname = syms[-1]
-            prodprec = self.Precedence.get(precname)
-            if not prodprec:
-                raise GrammarError('%s:%d: Nothing known about the precedence of %r' % (file, line, precname))
-            else:
-                self.UsedPrecedence.add(precname)
-            del syms[-2:]     # Drop %prec from the rule
-        else:
-            # If no %prec, precedence is determined by the rightmost terminal symbol
-            precname = rightmost_terminal(syms, self.Terminals)
-            prodprec = self.Precedence.get(precname, ('right', 0))
-
-        # See if the rule is already in the rulemap
-        map = '%s -> %s' % (prodname, syms)
-        if map in self.Prodmap:
-            m = self.Prodmap[map]
-            raise GrammarError('%s:%d: Duplicate rule %s. ' % (file, line, m) +
-                               'Previous definition at %s:%d' % (m.file, m.line))
-
-        # From this point on, everything is valid.  Create a new Production instance
-        pnumber  = len(self.Productions)
-        if prodname not in self.Nonterminals:
-            self.Nonterminals[prodname] = []
-
-        # Add the production number to Terminals and Nonterminals
-        for t in syms:
-            if t in self.Terminals:
-                self.Terminals[t].append(pnumber)
-            else:
-                if t not in self.Nonterminals:
-                    self.Nonterminals[t] = []
-                self.Nonterminals[t].append(pnumber)
-
-        # Create a production and add it to the list of productions
-        p = Production(pnumber, prodname, syms, prodprec, func, file, line)
-        self.Productions.append(p)
-        self.Prodmap[map] = p
-
-        # Add to the global productions list
-        try:
-            self.Prodnames[prodname].append(p)
-        except KeyError:
-            self.Prodnames[prodname] = [p]
-
-    # -----------------------------------------------------------------------------
-    # set_start()
-    #
-    # Sets the starting symbol and creates the augmented grammar.  Production
-    # rule 0 is S' -> start where start is the start symbol.
-    # -----------------------------------------------------------------------------
-
-    def set_start(self, start=None):
-        if not start:
-            start = self.Productions[1].name
-        if start not in self.Nonterminals:
-            raise GrammarError('start symbol %s undefined' % start)
-        self.Productions[0] = Production(0, "S'", [start])
-        self.Nonterminals[start].append(0)
-        self.Start = start
-
-    # -----------------------------------------------------------------------------
-    # find_unreachable()
-    #
-    # Find all of the nonterminal symbols that can't be reached from the starting
-    # symbol.  Returns a list of nonterminals that can't be reached.
-    # -----------------------------------------------------------------------------
-
-    def find_unreachable(self):
-
-        # Mark all symbols that are reachable from a symbol s
-        def mark_reachable_from(s):
-            if s in reachable:
-                return
-            reachable.add(s)
-            for p in self.Prodnames.get(s, []):
-                for r in p.prod:
-                    mark_reachable_from(r)
-
-        reachable = set()
-        mark_reachable_from(self.Productions[0].prod[0])
-        return [s for s in self.Nonterminals if s not in reachable]
-
-    # -----------------------------------------------------------------------------
-    # infinite_cycles()
-    #
-    # This function looks at the various parsing rules and tries to detect
-    # infinite recursion cycles (grammar rules where there is no possible way
-    # to derive a string of only terminals).
-    # -----------------------------------------------------------------------------
-
-    def infinite_cycles(self):
-        terminates = {}
-
-        # Terminals:
-        for t in self.Terminals:
-            terminates[t] = True
-
-        terminates['$end'] = True
-
-        # Nonterminals:
-
-        # Initialize to false:
-        for n in self.Nonterminals:
-            terminates[n] = False
-
-        # Then propagate termination until no change:
-        while True:
-            some_change = False
-            for (n, pl) in self.Prodnames.items():
-                # Nonterminal n terminates iff any of its productions terminates.
-                for p in pl:
-                    # Production p terminates iff all of its rhs symbols terminate.
-                    for s in p.prod:
-                        if not terminates[s]:
-                            # The symbol s does not terminate,
-                            # so production p does not terminate.
-                            p_terminates = False
-                            break
-                    else:
-                        # didn't break from the loop,
-                        # so every symbol s terminates
-                        # so production p terminates.
-                        p_terminates = True
-
-                    if p_terminates:
-                        # symbol n terminates!
-                        if not terminates[n]:
-                            terminates[n] = True
-                            some_change = True
-                        # Don't need to consider any more productions for this n.
-                        break
-
-            if not some_change:
-                break
-
-        infinite = []
-        for (s, term) in terminates.items():
-            if not term:
-                if s not in self.Prodnames and s not in self.Terminals and s != 'error':
-                    # s is used-but-not-defined, and we've already warned of that,
-                    # so it would be overkill to say that it's also non-terminating.
-                    pass
-                else:
-                    infinite.append(s)
-
-        return infinite
-
-    # -----------------------------------------------------------------------------
-    # undefined_symbols()
-    #
-    # Find all symbols that were used the grammar, but not defined as tokens or
-    # grammar rules.  Returns a list of tuples (sym, prod) where sym in the symbol
-    # and prod is the production where the symbol was used.
-    # -----------------------------------------------------------------------------
-    def undefined_symbols(self):
-        result = []
-        for p in self.Productions:
-            if not p:
-                continue
-
-            for s in p.prod:
-                if s not in self.Prodnames and s not in self.Terminals and s != 'error':
-                    result.append((s, p))
-        return result
-
-    # -----------------------------------------------------------------------------
-    # unused_terminals()
-    #
-    # Find all terminals that were defined, but not used by the grammar.  Returns
-    # a list of all symbols.
-    # -----------------------------------------------------------------------------
-    def unused_terminals(self):
-        unused_tok = []
-        for s, v in self.Terminals.items():
-            if s != 'error' and not v:
-                unused_tok.append(s)
-
-        return unused_tok
-
-    # ------------------------------------------------------------------------------
-    # unused_rules()
-    #
-    # Find all grammar rules that were defined,  but not used (maybe not reachable)
-    # Returns a list of productions.
-    # ------------------------------------------------------------------------------
-
-    def unused_rules(self):
-        unused_prod = []
-        for s, v in self.Nonterminals.items():
-            if not v:
-                p = self.Prodnames[s][0]
-                unused_prod.append(p)
-        return unused_prod
-
-    # -----------------------------------------------------------------------------
-    # unused_precedence()
-    #
-    # Returns a list of tuples (term,precedence) corresponding to precedence
-    # rules that were never used by the grammar.  term is the name of the terminal
-    # on which precedence was applied and precedence is a string such as 'left' or
-    # 'right' corresponding to the type of precedence.
-    # -----------------------------------------------------------------------------
-
-    def unused_precedence(self):
-        unused = []
-        for termname in self.Precedence:
-            if not (termname in self.Terminals or termname in self.UsedPrecedence):
-                unused.append((termname, self.Precedence[termname][0]))
-
-        return unused
-
-    # -------------------------------------------------------------------------
-    # _first()
-    #
-    # Compute the value of FIRST1(beta) where beta is a tuple of symbols.
-    #
-    # During execution of compute_first1, the result may be incomplete.
-    # Afterward (e.g., when called from compute_follow()), it will be complete.
-    # -------------------------------------------------------------------------
-    def _first(self, beta):
-
-        # We are computing First(x1,x2,x3,...,xn)
-        result = []
-        for x in beta:
-            x_produces_empty = False
-
-            # Add all the non- symbols of First[x] to the result.
-            for f in self.First[x]:
-                if f == '':
-                    x_produces_empty = True
-                else:
-                    if f not in result:
-                        result.append(f)
-
-            if x_produces_empty:
-                # We have to consider the next x in beta,
-                # i.e. stay in the loop.
-                pass
-            else:
-                # We don't have to consider any further symbols in beta.
-                break
-        else:
-            # There was no 'break' from the loop,
-            # so x_produces_empty was true for all x in beta,
-            # so beta produces empty as well.
-            result.append('')
-
-        return result
-
-    # -------------------------------------------------------------------------
-    # compute_first()
-    #
-    # Compute the value of FIRST1(X) for all symbols
-    # -------------------------------------------------------------------------
-    def compute_first(self):
-        if self.First:
-            return self.First
-
-        # Terminals:
-        for t in self.Terminals:
-            self.First[t] = [t]
-
-        self.First['$end'] = ['$end']
-
-        # Nonterminals:
-
-        # Initialize to the empty set:
-        for n in self.Nonterminals:
-            self.First[n] = []
-
-        # Then propagate symbols until no change:
-        while True:
-            some_change = False
-            for n in self.Nonterminals:
-                for p in self.Prodnames[n]:
-                    for f in self._first(p.prod):
-                        if f not in self.First[n]:
-                            self.First[n].append(f)
-                            some_change = True
-            if not some_change:
-                break
-
-        return self.First
-
-    # ---------------------------------------------------------------------
-    # compute_follow()
-    #
-    # Computes all of the follow sets for every non-terminal symbol.  The
-    # follow set is the set of all symbols that might follow a given
-    # non-terminal.  See the Dragon book, 2nd Ed. p. 189.
-    # ---------------------------------------------------------------------
-    def compute_follow(self, start=None):
-        # If already computed, return the result
-        if self.Follow:
-            return self.Follow
-
-        # If first sets not computed yet, do that first.
-        if not self.First:
-            self.compute_first()
-
-        # Add '$end' to the follow list of the start symbol
-        for k in self.Nonterminals:
-            self.Follow[k] = []
-
-        if not start:
-            start = self.Productions[1].name
-
-        self.Follow[start] = ['$end']
-
-        while True:
-            didadd = False
-            for p in self.Productions[1:]:
-                # Here is the production set
-                for i, B in enumerate(p.prod):
-                    if B in self.Nonterminals:
-                        # Okay. We got a non-terminal in a production
-                        fst = self._first(p.prod[i+1:])
-                        hasempty = False
-                        for f in fst:
-                            if f != '' and f not in self.Follow[B]:
-                                self.Follow[B].append(f)
-                                didadd = True
-                            if f == '':
-                                hasempty = True
-                        if hasempty or i == (len(p.prod)-1):
-                            # Add elements of follow(a) to follow(b)
-                            for f in self.Follow[p.name]:
-                                if f not in self.Follow[B]:
-                                    self.Follow[B].append(f)
-                                    didadd = True
-            if not didadd:
-                break
-        return self.Follow
-
-
-    # -----------------------------------------------------------------------------
-    # build_lritems()
-    #
-    # This function walks the list of productions and builds a complete set of the
-    # LR items.  The LR items are stored in two ways:  First, they are uniquely
-    # numbered and placed in the list _lritems.  Second, a linked list of LR items
-    # is built for each production.  For example:
-    #
-    #   E -> E PLUS E
-    #
-    # Creates the list
-    #
-    #  [E -> . E PLUS E, E -> E . PLUS E, E -> E PLUS . E, E -> E PLUS E . ]
-    # -----------------------------------------------------------------------------
-
-    def build_lritems(self):
-        for p in self.Productions:
-            lastlri = p
-            i = 0
-            lr_items = []
-            while True:
-                if i > len(p):
-                    lri = None
-                else:
-                    lri = LRItem(p, i)
-                    # Precompute the list of productions immediately following
-                    try:
-                        lri.lr_after = self.Prodnames[lri.prod[i+1]]
-                    except (IndexError, KeyError):
-                        lri.lr_after = []
-                    try:
-                        lri.lr_before = lri.prod[i-1]
-                    except IndexError:
-                        lri.lr_before = None
-
-                lastlri.lr_next = lri
-                if not lri:
-                    break
-                lr_items.append(lri)
-                lastlri = lri
-                i += 1
-            p.lr_items = lr_items
-
-# -----------------------------------------------------------------------------
-#                            == Class LRTable ==
-#
-# This basic class represents a basic table of LR parsing information.
-# Methods for generating the tables are not defined here.  They are defined
-# in the derived class LRGeneratedTable.
-# -----------------------------------------------------------------------------
-
-class VersionError(YaccError):
-    pass
-
-class LRTable(object):
-    def __init__(self):
-        self.lr_action = None
-        self.lr_goto = None
-        self.lr_productions = None
-        self.lr_method = None
-
-    def read_table(self, module):
-        if isinstance(module, types.ModuleType):
-            parsetab = module
-        else:
-            exec('import %s' % module)
-            parsetab = sys.modules[module]
-
-        if parsetab._tabversion != __tabversion__:
-            raise VersionError('yacc table file version is out of date')
-
-        self.lr_action = parsetab._lr_action
-        self.lr_goto = parsetab._lr_goto
-
-        self.lr_productions = []
-        for p in parsetab._lr_productions:
-            self.lr_productions.append(MiniProduction(*p))
-
-        self.lr_method = parsetab._lr_method
-        return parsetab._lr_signature
-
-    def read_pickle(self, filename):
-        try:
-            import cPickle as pickle
-        except ImportError:
-            import pickle
-
-        if not os.path.exists(filename):
-          raise ImportError
-
-        in_f = open(filename, 'rb')
-
-        tabversion = pickle.load(in_f)
-        if tabversion != __tabversion__:
-            raise VersionError('yacc table file version is out of date')
-        self.lr_method = pickle.load(in_f)
-        signature      = pickle.load(in_f)
-        self.lr_action = pickle.load(in_f)
-        self.lr_goto   = pickle.load(in_f)
-        productions    = pickle.load(in_f)
-
-        self.lr_productions = []
-        for p in productions:
-            self.lr_productions.append(MiniProduction(*p))
-
-        in_f.close()
-        return signature
-
-    # Bind all production function names to callable objects in pdict
-    def bind_callables(self, pdict):
-        for p in self.lr_productions:
-            p.bind(pdict)
-
-
-# -----------------------------------------------------------------------------
-#                           === LR Generator ===
-#
-# The following classes and functions are used to generate LR parsing tables on
-# a grammar.
-# -----------------------------------------------------------------------------
-
-# -----------------------------------------------------------------------------
-# digraph()
-# traverse()
-#
-# The following two functions are used to compute set valued functions
-# of the form:
-#
-#     F(x) = F'(x) U U{F(y) | x R y}
-#
-# This is used to compute the values of Read() sets as well as FOLLOW sets
-# in LALR(1) generation.
-#
-# Inputs:  X    - An input set
-#          R    - A relation
-#          FP   - Set-valued function
-# ------------------------------------------------------------------------------
-
-def digraph(X, R, FP):
-    N = {}
-    for x in X:
-        N[x] = 0
-    stack = []
-    F = {}
-    for x in X:
-        if N[x] == 0:
-            traverse(x, N, stack, F, X, R, FP)
-    return F
-
-def traverse(x, N, stack, F, X, R, FP):
-    stack.append(x)
-    d = len(stack)
-    N[x] = d
-    F[x] = FP(x)             # F(X) <- F'(x)
-
-    rel = R(x)               # Get y's related to x
-    for y in rel:
-        if N[y] == 0:
-            traverse(y, N, stack, F, X, R, FP)
-        N[x] = min(N[x], N[y])
-        for a in F.get(y, []):
-            if a not in F[x]:
-                F[x].append(a)
-    if N[x] == d:
-        N[stack[-1]] = MAXINT
-        F[stack[-1]] = F[x]
-        element = stack.pop()
-        while element != x:
-            N[stack[-1]] = MAXINT
-            F[stack[-1]] = F[x]
-            element = stack.pop()
-
-class LALRError(YaccError):
-    pass
-
-# -----------------------------------------------------------------------------
-#                             == LRGeneratedTable ==
-#
-# This class implements the LR table generation algorithm.  There are no
-# public methods except for write()
-# -----------------------------------------------------------------------------
-
-class LRGeneratedTable(LRTable):
-    def __init__(self, grammar, method='LALR', log=None):
-        if method not in ['SLR', 'LALR']:
-            raise LALRError('Unsupported method %s' % method)
-
-        self.grammar = grammar
-        self.lr_method = method
-
-        # Set up the logger
-        if not log:
-            log = NullLogger()
-        self.log = log
-
-        # Internal attributes
-        self.lr_action     = {}        # Action table
-        self.lr_goto       = {}        # Goto table
-        self.lr_productions  = grammar.Productions    # Copy of grammar Production array
-        self.lr_goto_cache = {}        # Cache of computed gotos
-        self.lr0_cidhash   = {}        # Cache of closures
-
-        self._add_count    = 0         # Internal counter used to detect cycles
-
-        # Diagonistic information filled in by the table generator
-        self.sr_conflict   = 0
-        self.rr_conflict   = 0
-        self.conflicts     = []        # List of conflicts
-
-        self.sr_conflicts  = []
-        self.rr_conflicts  = []
-
-        # Build the tables
-        self.grammar.build_lritems()
-        self.grammar.compute_first()
-        self.grammar.compute_follow()
-        self.lr_parse_table()
-
-    # Compute the LR(0) closure operation on I, where I is a set of LR(0) items.
-
-    def lr0_closure(self, I):
-        self._add_count += 1
-
-        # Add everything in I to J
-        J = I[:]
-        didadd = True
-        while didadd:
-            didadd = False
-            for j in J:
-                for x in j.lr_after:
-                    if getattr(x, 'lr0_added', 0) == self._add_count:
-                        continue
-                    # Add B --> .G to J
-                    J.append(x.lr_next)
-                    x.lr0_added = self._add_count
-                    didadd = True
-
-        return J
-
-    # Compute the LR(0) goto function goto(I,X) where I is a set
-    # of LR(0) items and X is a grammar symbol.   This function is written
-    # in a way that guarantees uniqueness of the generated goto sets
-    # (i.e. the same goto set will never be returned as two different Python
-    # objects).  With uniqueness, we can later do fast set comparisons using
-    # id(obj) instead of element-wise comparison.
-
-    def lr0_goto(self, I, x):
-        # First we look for a previously cached entry
-        g = self.lr_goto_cache.get((id(I), x))
-        if g:
-            return g
-
-        # Now we generate the goto set in a way that guarantees uniqueness
-        # of the result
-
-        s = self.lr_goto_cache.get(x)
-        if not s:
-            s = {}
-            self.lr_goto_cache[x] = s
-
-        gs = []
-        for p in I:
-            n = p.lr_next
-            if n and n.lr_before == x:
-                s1 = s.get(id(n))
-                if not s1:
-                    s1 = {}
-                    s[id(n)] = s1
-                gs.append(n)
-                s = s1
-        g = s.get('$end')
-        if not g:
-            if gs:
-                g = self.lr0_closure(gs)
-                s['$end'] = g
-            else:
-                s['$end'] = gs
-        self.lr_goto_cache[(id(I), x)] = g
-        return g
-
-    # Compute the LR(0) sets of item function
-    def lr0_items(self):
-        C = [self.lr0_closure([self.grammar.Productions[0].lr_next])]
-        i = 0
-        for I in C:
-            self.lr0_cidhash[id(I)] = i
-            i += 1
-
-        # Loop over the items in C and each grammar symbols
-        i = 0
-        while i < len(C):
-            I = C[i]
-            i += 1
-
-            # Collect all of the symbols that could possibly be in the goto(I,X) sets
-            asyms = {}
-            for ii in I:
-                for s in ii.usyms:
-                    asyms[s] = None
-
-            for x in asyms:
-                g = self.lr0_goto(I, x)
-                if not g or id(g) in self.lr0_cidhash:
-                    continue
-                self.lr0_cidhash[id(g)] = len(C)
-                C.append(g)
-
-        return C
-
-    # -----------------------------------------------------------------------------
-    #                       ==== LALR(1) Parsing ====
-    #
-    # LALR(1) parsing is almost exactly the same as SLR except that instead of
-    # relying upon Follow() sets when performing reductions, a more selective
-    # lookahead set that incorporates the state of the LR(0) machine is utilized.
-    # Thus, we mainly just have to focus on calculating the lookahead sets.
-    #
-    # The method used here is due to DeRemer and Pennelo (1982).
-    #
-    # DeRemer, F. L., and T. J. Pennelo: "Efficient Computation of LALR(1)
-    #     Lookahead Sets", ACM Transactions on Programming Languages and Systems,
-    #     Vol. 4, No. 4, Oct. 1982, pp. 615-649
-    #
-    # Further details can also be found in:
-    #
-    #  J. Tremblay and P. Sorenson, "The Theory and Practice of Compiler Writing",
-    #      McGraw-Hill Book Company, (1985).
-    #
-    # -----------------------------------------------------------------------------
-
-    # -----------------------------------------------------------------------------
-    # compute_nullable_nonterminals()
-    #
-    # Creates a dictionary containing all of the non-terminals that might produce
-    # an empty production.
-    # -----------------------------------------------------------------------------
-
-    def compute_nullable_nonterminals(self):
-        nullable = set()
-        num_nullable = 0
-        while True:
-            for p in self.grammar.Productions[1:]:
-                if p.len == 0:
-                    nullable.add(p.name)
-                    continue
-                for t in p.prod:
-                    if t not in nullable:
-                        break
-                else:
-                    nullable.add(p.name)
-            if len(nullable) == num_nullable:
-                break
-            num_nullable = len(nullable)
-        return nullable
-
-    # -----------------------------------------------------------------------------
-    # find_nonterminal_trans(C)
-    #
-    # Given a set of LR(0) items, this functions finds all of the non-terminal
-    # transitions.    These are transitions in which a dot appears immediately before
-    # a non-terminal.   Returns a list of tuples of the form (state,N) where state
-    # is the state number and N is the nonterminal symbol.
-    #
-    # The input C is the set of LR(0) items.
-    # -----------------------------------------------------------------------------
-
-    def find_nonterminal_transitions(self, C):
-        trans = []
-        for stateno, state in enumerate(C):
-            for p in state:
-                if p.lr_index < p.len - 1:
-                    t = (stateno, p.prod[p.lr_index+1])
-                    if t[1] in self.grammar.Nonterminals:
-                        if t not in trans:
-                            trans.append(t)
-        return trans
-
-    # -----------------------------------------------------------------------------
-    # dr_relation()
-    #
-    # Computes the DR(p,A) relationships for non-terminal transitions.  The input
-    # is a tuple (state,N) where state is a number and N is a nonterminal symbol.
-    #
-    # Returns a list of terminals.
-    # -----------------------------------------------------------------------------
-
-    def dr_relation(self, C, trans, nullable):
-        state, N = trans
-        terms = []
-
-        g = self.lr0_goto(C[state], N)
-        for p in g:
-            if p.lr_index < p.len - 1:
-                a = p.prod[p.lr_index+1]
-                if a in self.grammar.Terminals:
-                    if a not in terms:
-                        terms.append(a)
-
-        # This extra bit is to handle the start state
-        if state == 0 and N == self.grammar.Productions[0].prod[0]:
-            terms.append('$end')
-
-        return terms
-
-    # -----------------------------------------------------------------------------
-    # reads_relation()
-    #
-    # Computes the READS() relation (p,A) READS (t,C).
-    # -----------------------------------------------------------------------------
-
-    def reads_relation(self, C, trans, empty):
-        # Look for empty transitions
-        rel = []
-        state, N = trans
-
-        g = self.lr0_goto(C[state], N)
-        j = self.lr0_cidhash.get(id(g), -1)
-        for p in g:
-            if p.lr_index < p.len - 1:
-                a = p.prod[p.lr_index + 1]
-                if a in empty:
-                    rel.append((j, a))
-
-        return rel
-
-    # -----------------------------------------------------------------------------
-    # compute_lookback_includes()
-    #
-    # Determines the lookback and includes relations
-    #
-    # LOOKBACK:
-    #
-    # This relation is determined by running the LR(0) state machine forward.
-    # For example, starting with a production "N : . A B C", we run it forward
-    # to obtain "N : A B C ."   We then build a relationship between this final
-    # state and the starting state.   These relationships are stored in a dictionary
-    # lookdict.
-    #
-    # INCLUDES:
-    #
-    # Computes the INCLUDE() relation (p,A) INCLUDES (p',B).
-    #
-    # This relation is used to determine non-terminal transitions that occur
-    # inside of other non-terminal transition states.   (p,A) INCLUDES (p', B)
-    # if the following holds:
-    #
-    #       B -> LAT, where T -> epsilon and p' -L-> p
-    #
-    # L is essentially a prefix (which may be empty), T is a suffix that must be
-    # able to derive an empty string.  State p' must lead to state p with the string L.
-    #
-    # -----------------------------------------------------------------------------
-
-    def compute_lookback_includes(self, C, trans, nullable):
-        lookdict = {}          # Dictionary of lookback relations
-        includedict = {}       # Dictionary of include relations
-
-        # Make a dictionary of non-terminal transitions
-        dtrans = {}
-        for t in trans:
-            dtrans[t] = 1
-
-        # Loop over all transitions and compute lookbacks and includes
-        for state, N in trans:
-            lookb = []
-            includes = []
-            for p in C[state]:
-                if p.name != N:
-                    continue
-
-                # Okay, we have a name match.  We now follow the production all the way
-                # through the state machine until we get the . on the right hand side
-
-                lr_index = p.lr_index
-                j = state
-                while lr_index < p.len - 1:
-                    lr_index = lr_index + 1
-                    t = p.prod[lr_index]
-
-                    # Check to see if this symbol and state are a non-terminal transition
-                    if (j, t) in dtrans:
-                        # Yes.  Okay, there is some chance that this is an includes relation
-                        # the only way to know for certain is whether the rest of the
-                        # production derives empty
-
-                        li = lr_index + 1
-                        while li < p.len:
-                            if p.prod[li] in self.grammar.Terminals:
-                                break      # No forget it
-                            if p.prod[li] not in nullable:
-                                break
-                            li = li + 1
-                        else:
-                            # Appears to be a relation between (j,t) and (state,N)
-                            includes.append((j, t))
-
-                    g = self.lr0_goto(C[j], t)               # Go to next set
-                    j = self.lr0_cidhash.get(id(g), -1)      # Go to next state
-
-                # When we get here, j is the final state, now we have to locate the production
-                for r in C[j]:
-                    if r.name != p.name:
-                        continue
-                    if r.len != p.len:
-                        continue
-                    i = 0
-                    # This look is comparing a production ". A B C" with "A B C ."
-                    while i < r.lr_index:
-                        if r.prod[i] != p.prod[i+1]:
-                            break
-                        i = i + 1
-                    else:
-                        lookb.append((j, r))
-            for i in includes:
-                if i not in includedict:
-                    includedict[i] = []
-                includedict[i].append((state, N))
-            lookdict[(state, N)] = lookb
-
-        return lookdict, includedict
-
-    # -----------------------------------------------------------------------------
-    # compute_read_sets()
-    #
-    # Given a set of LR(0) items, this function computes the read sets.
-    #
-    # Inputs:  C        =  Set of LR(0) items
-    #          ntrans   = Set of nonterminal transitions
-    #          nullable = Set of empty transitions
-    #
-    # Returns a set containing the read sets
-    # -----------------------------------------------------------------------------
-
-    def compute_read_sets(self, C, ntrans, nullable):
-        FP = lambda x: self.dr_relation(C, x, nullable)
-        R =  lambda x: self.reads_relation(C, x, nullable)
-        F = digraph(ntrans, R, FP)
-        return F
-
-    # -----------------------------------------------------------------------------
-    # compute_follow_sets()
-    #
-    # Given a set of LR(0) items, a set of non-terminal transitions, a readset,
-    # and an include set, this function computes the follow sets
-    #
-    # Follow(p,A) = Read(p,A) U U {Follow(p',B) | (p,A) INCLUDES (p',B)}
-    #
-    # Inputs:
-    #            ntrans     = Set of nonterminal transitions
-    #            readsets   = Readset (previously computed)
-    #            inclsets   = Include sets (previously computed)
-    #
-    # Returns a set containing the follow sets
-    # -----------------------------------------------------------------------------
-
-    def compute_follow_sets(self, ntrans, readsets, inclsets):
-        FP = lambda x: readsets[x]
-        R  = lambda x: inclsets.get(x, [])
-        F = digraph(ntrans, R, FP)
-        return F
-
-    # -----------------------------------------------------------------------------
-    # add_lookaheads()
-    #
-    # Attaches the lookahead symbols to grammar rules.
-    #
-    # Inputs:    lookbacks         -  Set of lookback relations
-    #            followset         -  Computed follow set
-    #
-    # This function directly attaches the lookaheads to productions contained
-    # in the lookbacks set
-    # -----------------------------------------------------------------------------
-
-    def add_lookaheads(self, lookbacks, followset):
-        for trans, lb in lookbacks.items():
-            # Loop over productions in lookback
-            for state, p in lb:
-                if state not in p.lookaheads:
-                    p.lookaheads[state] = []
-                f = followset.get(trans, [])
-                for a in f:
-                    if a not in p.lookaheads[state]:
-                        p.lookaheads[state].append(a)
-
-    # -----------------------------------------------------------------------------
-    # add_lalr_lookaheads()
-    #
-    # This function does all of the work of adding lookahead information for use
-    # with LALR parsing
-    # -----------------------------------------------------------------------------
-
-    def add_lalr_lookaheads(self, C):
-        # Determine all of the nullable nonterminals
-        nullable = self.compute_nullable_nonterminals()
-
-        # Find all non-terminal transitions
-        trans = self.find_nonterminal_transitions(C)
-
-        # Compute read sets
-        readsets = self.compute_read_sets(C, trans, nullable)
-
-        # Compute lookback/includes relations
-        lookd, included = self.compute_lookback_includes(C, trans, nullable)
-
-        # Compute LALR FOLLOW sets
-        followsets = self.compute_follow_sets(trans, readsets, included)
-
-        # Add all of the lookaheads
-        self.add_lookaheads(lookd, followsets)
-
-    # -----------------------------------------------------------------------------
-    # lr_parse_table()
-    #
-    # This function constructs the parse tables for SLR or LALR
-    # -----------------------------------------------------------------------------
-    def lr_parse_table(self):
-        Productions = self.grammar.Productions
-        Precedence  = self.grammar.Precedence
-        goto   = self.lr_goto         # Goto array
-        action = self.lr_action       # Action array
-        log    = self.log             # Logger for output
-
-        actionp = {}                  # Action production array (temporary)
-
-        log.info('Parsing method: %s', self.lr_method)
-
-        # Step 1: Construct C = { I0, I1, ... IN}, collection of LR(0) items
-        # This determines the number of states
-
-        C = self.lr0_items()
-
-        if self.lr_method == 'LALR':
-            self.add_lalr_lookaheads(C)
-
-        # Build the parser table, state by state
-        st = 0
-        for I in C:
-            # Loop over each production in I
-            actlist = []              # List of actions
-            st_action  = {}
-            st_actionp = {}
-            st_goto    = {}
-            log.info('')
-            log.info('state %d', st)
-            log.info('')
-            for p in I:
-                log.info('    (%d) %s', p.number, p)
-            log.info('')
-
-            for p in I:
-                    if p.len == p.lr_index + 1:
-                        if p.name == "S'":
-                            # Start symbol. Accept!
-                            st_action['$end'] = 0
-                            st_actionp['$end'] = p
-                        else:
-                            # We are at the end of a production.  Reduce!
-                            if self.lr_method == 'LALR':
-                                laheads = p.lookaheads[st]
-                            else:
-                                laheads = self.grammar.Follow[p.name]
-                            for a in laheads:
-                                actlist.append((a, p, 'reduce using rule %d (%s)' % (p.number, p)))
-                                r = st_action.get(a)
-                                if r is not None:
-                                    # Whoa. Have a shift/reduce or reduce/reduce conflict
-                                    if r > 0:
-                                        # Need to decide on shift or reduce here
-                                        # By default we favor shifting. Need to add
-                                        # some precedence rules here.
-
-                                        # Shift precedence comes from the token
-                                        sprec, slevel = Precedence.get(a, ('right', 0))
-
-                                        # Reduce precedence comes from rule being reduced (p)
-                                        rprec, rlevel = Productions[p.number].prec
-
-                                        if (slevel < rlevel) or ((slevel == rlevel) and (rprec == 'left')):
-                                            # We really need to reduce here.
-                                            st_action[a] = -p.number
-                                            st_actionp[a] = p
-                                            if not slevel and not rlevel:
-                                                log.info('  ! shift/reduce conflict for %s resolved as reduce', a)
-                                                self.sr_conflicts.append((st, a, 'reduce'))
-                                            Productions[p.number].reduced += 1
-                                        elif (slevel == rlevel) and (rprec == 'nonassoc'):
-                                            st_action[a] = None
-                                        else:
-                                            # Hmmm. Guess we'll keep the shift
-                                            if not rlevel:
-                                                log.info('  ! shift/reduce conflict for %s resolved as shift', a)
-                                                self.sr_conflicts.append((st, a, 'shift'))
-                                    elif r < 0:
-                                        # Reduce/reduce conflict.   In this case, we favor the rule
-                                        # that was defined first in the grammar file
-                                        oldp = Productions[-r]
-                                        pp = Productions[p.number]
-                                        if oldp.line > pp.line:
-                                            st_action[a] = -p.number
-                                            st_actionp[a] = p
-                                            chosenp, rejectp = pp, oldp
-                                            Productions[p.number].reduced += 1
-                                            Productions[oldp.number].reduced -= 1
-                                        else:
-                                            chosenp, rejectp = oldp, pp
-                                        self.rr_conflicts.append((st, chosenp, rejectp))
-                                        log.info('  ! reduce/reduce conflict for %s resolved using rule %d (%s)',
-                                                 a, st_actionp[a].number, st_actionp[a])
-                                    else:
-                                        raise LALRError('Unknown conflict in state %d' % st)
-                                else:
-                                    st_action[a] = -p.number
-                                    st_actionp[a] = p
-                                    Productions[p.number].reduced += 1
-                    else:
-                        i = p.lr_index
-                        a = p.prod[i+1]       # Get symbol right after the "."
-                        if a in self.grammar.Terminals:
-                            g = self.lr0_goto(I, a)
-                            j = self.lr0_cidhash.get(id(g), -1)
-                            if j >= 0:
-                                # We are in a shift state
-                                actlist.append((a, p, 'shift and go to state %d' % j))
-                                r = st_action.get(a)
-                                if r is not None:
-                                    # Whoa have a shift/reduce or shift/shift conflict
-                                    if r > 0:
-                                        if r != j:
-                                            raise LALRError('Shift/shift conflict in state %d' % st)
-                                    elif r < 0:
-                                        # Do a precedence check.
-                                        #   -  if precedence of reduce rule is higher, we reduce.
-                                        #   -  if precedence of reduce is same and left assoc, we reduce.
-                                        #   -  otherwise we shift
-
-                                        # Shift precedence comes from the token
-                                        sprec, slevel = Precedence.get(a, ('right', 0))
-
-                                        # Reduce precedence comes from the rule that could have been reduced
-                                        rprec, rlevel = Productions[st_actionp[a].number].prec
-
-                                        if (slevel > rlevel) or ((slevel == rlevel) and (rprec == 'right')):
-                                            # We decide to shift here... highest precedence to shift
-                                            Productions[st_actionp[a].number].reduced -= 1
-                                            st_action[a] = j
-                                            st_actionp[a] = p
-                                            if not rlevel:
-                                                log.info('  ! shift/reduce conflict for %s resolved as shift', a)
-                                                self.sr_conflicts.append((st, a, 'shift'))
-                                        elif (slevel == rlevel) and (rprec == 'nonassoc'):
-                                            st_action[a] = None
-                                        else:
-                                            # Hmmm. Guess we'll keep the reduce
-                                            if not slevel and not rlevel:
-                                                log.info('  ! shift/reduce conflict for %s resolved as reduce', a)
-                                                self.sr_conflicts.append((st, a, 'reduce'))
-
-                                    else:
-                                        raise LALRError('Unknown conflict in state %d' % st)
-                                else:
-                                    st_action[a] = j
-                                    st_actionp[a] = p
-
-            # Print the actions associated with each terminal
-            _actprint = {}
-            for a, p, m in actlist:
-                if a in st_action:
-                    if p is st_actionp[a]:
-                        log.info('    %-15s %s', a, m)
-                        _actprint[(a, m)] = 1
-            log.info('')
-            # Print the actions that were not used. (debugging)
-            not_used = 0
-            for a, p, m in actlist:
-                if a in st_action:
-                    if p is not st_actionp[a]:
-                        if not (a, m) in _actprint:
-                            log.debug('  ! %-15s [ %s ]', a, m)
-                            not_used = 1
-                            _actprint[(a, m)] = 1
-            if not_used:
-                log.debug('')
-
-            # Construct the goto table for this state
-
-            nkeys = {}
-            for ii in I:
-                for s in ii.usyms:
-                    if s in self.grammar.Nonterminals:
-                        nkeys[s] = None
-            for n in nkeys:
-                g = self.lr0_goto(I, n)
-                j = self.lr0_cidhash.get(id(g), -1)
-                if j >= 0:
-                    st_goto[n] = j
-                    log.info('    %-30s shift and go to state %d', n, j)
-
-            action[st] = st_action
-            actionp[st] = st_actionp
-            goto[st] = st_goto
-            st += 1
-
-    # -----------------------------------------------------------------------------
-    # write()
-    #
-    # This function writes the LR parsing tables to a file
-    # -----------------------------------------------------------------------------
-
-    def write_table(self, tabmodule, outputdir='', signature=''):
-        if isinstance(tabmodule, types.ModuleType):
-            raise IOError("Won't overwrite existing tabmodule")
-
-        basemodulename = tabmodule.split('.')[-1]
-        filename = os.path.join(outputdir, basemodulename) + '.py'
-        try:
-            f = open(filename, 'w')
-
-            f.write('''
-# %s
-# This file is automatically generated. Do not edit.
-# pylint: disable=W,C,R
-_tabversion = %r
-
-_lr_method = %r
-
-_lr_signature = %r
-    ''' % (os.path.basename(filename), __tabversion__, self.lr_method, signature))
-
-            # Change smaller to 0 to go back to original tables
-            smaller = 1
-
-            # Factor out names to try and make smaller
-            if smaller:
-                items = {}
-
-                for s, nd in self.lr_action.items():
-                    for name, v in nd.items():
-                        i = items.get(name)
-                        if not i:
-                            i = ([], [])
-                            items[name] = i
-                        i[0].append(s)
-                        i[1].append(v)
-
-                f.write('\n_lr_action_items = {')
-                for k, v in items.items():
-                    f.write('%r:([' % k)
-                    for i in v[0]:
-                        f.write('%r,' % i)
-                    f.write('],[')
-                    for i in v[1]:
-                        f.write('%r,' % i)
-
-                    f.write(']),')
-                f.write('}\n')
-
-                f.write('''
-_lr_action = {}
-for _k, _v in _lr_action_items.items():
-   for _x,_y in zip(_v[0],_v[1]):
-      if not _x in _lr_action:  _lr_action[_x] = {}
-      _lr_action[_x][_k] = _y
-del _lr_action_items
-''')
-
-            else:
-                f.write('\n_lr_action = { ')
-                for k, v in self.lr_action.items():
-                    f.write('(%r,%r):%r,' % (k[0], k[1], v))
-                f.write('}\n')
-
-            if smaller:
-                # Factor out names to try and make smaller
-                items = {}
-
-                for s, nd in self.lr_goto.items():
-                    for name, v in nd.items():
-                        i = items.get(name)
-                        if not i:
-                            i = ([], [])
-                            items[name] = i
-                        i[0].append(s)
-                        i[1].append(v)
-
-                f.write('\n_lr_goto_items = {')
-                for k, v in items.items():
-                    f.write('%r:([' % k)
-                    for i in v[0]:
-                        f.write('%r,' % i)
-                    f.write('],[')
-                    for i in v[1]:
-                        f.write('%r,' % i)
-
-                    f.write(']),')
-                f.write('}\n')
-
-                f.write('''
-_lr_goto = {}
-for _k, _v in _lr_goto_items.items():
-   for _x, _y in zip(_v[0], _v[1]):
-       if not _x in _lr_goto: _lr_goto[_x] = {}
-       _lr_goto[_x][_k] = _y
-del _lr_goto_items
-''')
-            else:
-                f.write('\n_lr_goto = { ')
-                for k, v in self.lr_goto.items():
-                    f.write('(%r,%r):%r,' % (k[0], k[1], v))
-                f.write('}\n')
-
-            # Write production table
-            f.write('_lr_productions = [\n')
-            for p in self.lr_productions:
-                if p.func:
-                    f.write('  (%r,%r,%d,%r,%r,%d),\n' % (p.str, p.name, p.len,
-                                                          p.func, os.path.basename(p.file), p.line))
-                else:
-                    f.write('  (%r,%r,%d,None,None,None),\n' % (str(p), p.name, p.len))
-            f.write(']\n')
-            f.close()
-
-        except IOError as e:
-            raise
-
-
-    # -----------------------------------------------------------------------------
-    # pickle_table()
-    #
-    # This function pickles the LR parsing tables to a supplied file object
-    # -----------------------------------------------------------------------------
-
-    def pickle_table(self, filename, signature=''):
-        try:
-            import cPickle as pickle
-        except ImportError:
-            import pickle
-        with open(filename, 'wb') as outf:
-            pickle.dump(__tabversion__, outf, pickle_protocol)
-            pickle.dump(self.lr_method, outf, pickle_protocol)
-            pickle.dump(signature, outf, pickle_protocol)
-            pickle.dump(self.lr_action, outf, pickle_protocol)
-            pickle.dump(self.lr_goto, outf, pickle_protocol)
-
-            outp = []
-            for p in self.lr_productions:
-                if p.func:
-                    outp.append((p.str, p.name, p.len, p.func, os.path.basename(p.file), p.line))
-                else:
-                    outp.append((str(p), p.name, p.len, None, None, None))
-            pickle.dump(outp, outf, pickle_protocol)
-
-# -----------------------------------------------------------------------------
-#                            === INTROSPECTION ===
-#
-# The following functions and classes are used to implement the PLY
-# introspection features followed by the yacc() function itself.
-# -----------------------------------------------------------------------------
-
-# -----------------------------------------------------------------------------
-# get_caller_module_dict()
-#
-# This function returns a dictionary containing all of the symbols defined within
-# a caller further down the call stack.  This is used to get the environment
-# associated with the yacc() call if none was provided.
-# -----------------------------------------------------------------------------
-
-def get_caller_module_dict(levels):
-    f = sys._getframe(levels)
-    ldict = f.f_globals.copy()
-    if f.f_globals != f.f_locals:
-        ldict.update(f.f_locals)
-    return ldict
-
-# -----------------------------------------------------------------------------
-# parse_grammar()
-#
-# This takes a raw grammar rule string and parses it into production data
-# -----------------------------------------------------------------------------
-def parse_grammar(doc, file, line):
-    grammar = []
-    # Split the doc string into lines
-    pstrings = doc.splitlines()
-    lastp = None
-    dline = line
-    for ps in pstrings:
-        dline += 1
-        p = ps.split()
-        if not p:
-            continue
-        try:
-            if p[0] == '|':
-                # This is a continuation of a previous rule
-                if not lastp:
-                    raise SyntaxError("%s:%d: Misplaced '|'" % (file, dline))
-                prodname = lastp
-                syms = p[1:]
-            else:
-                prodname = p[0]
-                lastp = prodname
-                syms   = p[2:]
-                assign = p[1]
-                if assign != ':' and assign != '::=':
-                    raise SyntaxError("%s:%d: Syntax error. Expected ':'" % (file, dline))
-
-            grammar.append((file, dline, prodname, syms))
-        except SyntaxError:
-            raise
-        except Exception:
-            raise SyntaxError('%s:%d: Syntax error in rule %r' % (file, dline, ps.strip()))
-
-    return grammar
-
-# -----------------------------------------------------------------------------
-# ParserReflect()
-#
-# This class represents information extracted for building a parser including
-# start symbol, error function, tokens, precedence list, action functions,
-# etc.
-# -----------------------------------------------------------------------------
-class ParserReflect(object):
-    def __init__(self, pdict, log=None):
-        self.pdict      = pdict
-        self.start      = None
-        self.error_func = None
-        self.tokens     = None
-        self.modules    = set()
-        self.grammar    = []
-        self.error      = False
-
-        if log is None:
-            self.log = PlyLogger(sys.stderr)
-        else:
-            self.log = log
-
-    # Get all of the basic information
-    def get_all(self):
-        self.get_start()
-        self.get_error_func()
-        self.get_tokens()
-        self.get_precedence()
-        self.get_pfunctions()
-
-    # Validate all of the information
-    def validate_all(self):
-        self.validate_start()
-        self.validate_error_func()
-        self.validate_tokens()
-        self.validate_precedence()
-        self.validate_pfunctions()
-        self.validate_modules()
-        return self.error
-
-    # Compute a signature over the grammar
-    def signature(self):
-        parts = []
-        try:
-            if self.start:
-                parts.append(self.start)
-            if self.prec:
-                parts.append(''.join([''.join(p) for p in self.prec]))
-            if self.tokens:
-                parts.append(' '.join(self.tokens))
-            for f in self.pfuncs:
-                if f[3]:
-                    parts.append(f[3])
-        except (TypeError, ValueError):
-            pass
-        return ''.join(parts)
-
-    # -----------------------------------------------------------------------------
-    # validate_modules()
-    #
-    # This method checks to see if there are duplicated p_rulename() functions
-    # in the parser module file.  Without this function, it is really easy for
-    # users to make mistakes by cutting and pasting code fragments (and it's a real
-    # bugger to try and figure out why the resulting parser doesn't work).  Therefore,
-    # we just do a little regular expression pattern matching of def statements
-    # to try and detect duplicates.
-    # -----------------------------------------------------------------------------
-
-    def validate_modules(self):
-        # Match def p_funcname(
-        fre = re.compile(r'\s*def\s+(p_[a-zA-Z_0-9]*)\(')
-
-        for module in self.modules:
-            try:
-                lines, linen = inspect.getsourcelines(module)
-            except IOError:
-                continue
-
-            counthash = {}
-            for linen, line in enumerate(lines):
-                linen += 1
-                m = fre.match(line)
-                if m:
-                    name = m.group(1)
-                    prev = counthash.get(name)
-                    if not prev:
-                        counthash[name] = linen
-                    else:
-                        filename = inspect.getsourcefile(module)
-                        self.log.warning('%s:%d: Function %s redefined. Previously defined on line %d',
-                                         filename, linen, name, prev)
-
-    # Get the start symbol
-    def get_start(self):
-        self.start = self.pdict.get('start')
-
-    # Validate the start symbol
-    def validate_start(self):
-        if self.start is not None:
-            if not isinstance(self.start, string_types):
-                self.log.error("'start' must be a string")
-
-    # Look for error handler
-    def get_error_func(self):
-        self.error_func = self.pdict.get('p_error')
-
-    # Validate the error function
-    def validate_error_func(self):
-        if self.error_func:
-            if isinstance(self.error_func, types.FunctionType):
-                ismethod = 0
-            elif isinstance(self.error_func, types.MethodType):
-                ismethod = 1
-            else:
-                self.log.error("'p_error' defined, but is not a function or method")
-                self.error = True
-                return
-
-            eline = self.error_func.__code__.co_firstlineno
-            efile = self.error_func.__code__.co_filename
-            module = inspect.getmodule(self.error_func)
-            self.modules.add(module)
-
-            argcount = self.error_func.__code__.co_argcount - ismethod
-            if argcount != 1:
-                self.log.error('%s:%d: p_error() requires 1 argument', efile, eline)
-                self.error = True
-
-    # Get the tokens map
-    def get_tokens(self):
-        tokens = self.pdict.get('tokens')
-        if not tokens:
-            self.log.error('No token list is defined')
-            self.error = True
-            return
-
-        if not isinstance(tokens, (list, tuple)):
-            self.log.error('tokens must be a list or tuple')
-            self.error = True
-            return
-
-        if not tokens:
-            self.log.error('tokens is empty')
-            self.error = True
-            return
-
-        self.tokens = sorted(tokens)
-
-    # Validate the tokens
-    def validate_tokens(self):
-        # Validate the tokens.
-        if 'error' in self.tokens:
-            self.log.error("Illegal token name 'error'. Is a reserved word")
-            self.error = True
-            return
-
-        terminals = set()
-        for n in self.tokens:
-            if n in terminals:
-                self.log.warning('Token %r multiply defined', n)
-            terminals.add(n)
-
-    # Get the precedence map (if any)
-    def get_precedence(self):
-        self.prec = self.pdict.get('precedence')
-
-    # Validate and parse the precedence map
-    def validate_precedence(self):
-        preclist = []
-        if self.prec:
-            if not isinstance(self.prec, (list, tuple)):
-                self.log.error('precedence must be a list or tuple')
-                self.error = True
-                return
-            for level, p in enumerate(self.prec):
-                if not isinstance(p, (list, tuple)):
-                    self.log.error('Bad precedence table')
-                    self.error = True
-                    return
-
-                if len(p) < 2:
-                    self.log.error('Malformed precedence entry %s. Must be (assoc, term, ..., term)', p)
-                    self.error = True
-                    return
-                assoc = p[0]
-                if not isinstance(assoc, string_types):
-                    self.log.error('precedence associativity must be a string')
-                    self.error = True
-                    return
-                for term in p[1:]:
-                    if not isinstance(term, string_types):
-                        self.log.error('precedence items must be strings')
-                        self.error = True
-                        return
-                    preclist.append((term, assoc, level+1))
-        self.preclist = preclist
-
-    # Get all p_functions from the grammar
-    def get_pfunctions(self):
-        p_functions = []
-        for name, item in self.pdict.items():
-            if not name.startswith('p_') or name == 'p_error':
-                continue
-            if isinstance(item, (types.FunctionType, types.MethodType)):
-                line = getattr(item, 'co_firstlineno', item.__code__.co_firstlineno)
-                module = inspect.getmodule(item)
-                p_functions.append((line, module, name, item.__doc__))
-
-        # Sort all of the actions by line number; make sure to stringify
-        # modules to make them sortable, since `line` may not uniquely sort all
-        # p functions
-        p_functions.sort(key=lambda p_function: (
-            p_function[0],
-            str(p_function[1]),
-            p_function[2],
-            p_function[3]))
-        self.pfuncs = p_functions
-
-    # Validate all of the p_functions
-    def validate_pfunctions(self):
-        grammar = []
-        # Check for non-empty symbols
-        if len(self.pfuncs) == 0:
-            self.log.error('no rules of the form p_rulename are defined')
-            self.error = True
-            return
-
-        for line, module, name, doc in self.pfuncs:
-            file = inspect.getsourcefile(module)
-            func = self.pdict[name]
-            if isinstance(func, types.MethodType):
-                reqargs = 2
-            else:
-                reqargs = 1
-            if func.__code__.co_argcount > reqargs:
-                self.log.error('%s:%d: Rule %r has too many arguments', file, line, func.__name__)
-                self.error = True
-            elif func.__code__.co_argcount < reqargs:
-                self.log.error('%s:%d: Rule %r requires an argument', file, line, func.__name__)
-                self.error = True
-            elif not func.__doc__:
-                self.log.warning('%s:%d: No documentation string specified in function %r (ignored)',
-                                 file, line, func.__name__)
-            else:
-                try:
-                    parsed_g = parse_grammar(doc, file, line)
-                    for g in parsed_g:
-                        grammar.append((name, g))
-                except SyntaxError as e:
-                    self.log.error(str(e))
-                    self.error = True
-
-                # Looks like a valid grammar rule
-                # Mark the file in which defined.
-                self.modules.add(module)
-
-        # Secondary validation step that looks for p_ definitions that are not functions
-        # or functions that look like they might be grammar rules.
-
-        for n, v in self.pdict.items():
-            if n.startswith('p_') and isinstance(v, (types.FunctionType, types.MethodType)):
-                continue
-            if n.startswith('t_'):
-                continue
-            if n.startswith('p_') and n != 'p_error':
-                self.log.warning('%r not defined as a function', n)
-            if ((isinstance(v, types.FunctionType) and v.__code__.co_argcount == 1) or
-                   (isinstance(v, types.MethodType) and v.__func__.__code__.co_argcount == 2)):
-                if v.__doc__:
-                    try:
-                        doc = v.__doc__.split(' ')
-                        if doc[1] == ':':
-                            self.log.warning('%s:%d: Possible grammar rule %r defined without p_ prefix',
-                                             v.__code__.co_filename, v.__code__.co_firstlineno, n)
-                    except IndexError:
-                        pass
-
-        self.grammar = grammar
-
-# -----------------------------------------------------------------------------
-# yacc(module)
-#
-# Build a parser
-# -----------------------------------------------------------------------------
-
-def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, start=None,
-         check_recursion=True, optimize=False, write_tables=True, debugfile=debug_file,
-         outputdir=None, debuglog=None, errorlog=None, picklefile=None):
-
-    if tabmodule is None:
-        tabmodule = tab_module
-
-    # Reference to the parsing method of the last built parser
-    global parse
-
-    # If pickling is enabled, table files are not created
-    if picklefile:
-        write_tables = 0
-
-    if errorlog is None:
-        errorlog = PlyLogger(sys.stderr)
-
-    # Get the module dictionary used for the parser
-    if module:
-        _items = [(k, getattr(module, k)) for k in dir(module)]
-        pdict = dict(_items)
-        # If no __file__ or __package__ attributes are available, try to obtain them
-        # from the __module__ instead
-        if '__file__' not in pdict:
-            pdict['__file__'] = sys.modules[pdict['__module__']].__file__
-        if '__package__' not in pdict and '__module__' in pdict:
-            if hasattr(sys.modules[pdict['__module__']], '__package__'):
-                pdict['__package__'] = sys.modules[pdict['__module__']].__package__
-    else:
-        pdict = get_caller_module_dict(2)
-
-    if outputdir is None:
-        # If no output directory is set, the location of the output files
-        # is determined according to the following rules:
-        #     - If tabmodule specifies a package, files go into that package directory
-        #     - Otherwise, files go in the same directory as the specifying module
-        if isinstance(tabmodule, types.ModuleType):
-            srcfile = tabmodule.__file__
-        else:
-            if '.' not in tabmodule:
-                srcfile = pdict['__file__']
-            else:
-                parts = tabmodule.split('.')
-                pkgname = '.'.join(parts[:-1])
-                exec('import %s' % pkgname)
-                srcfile = getattr(sys.modules[pkgname], '__file__', '')
-        outputdir = os.path.dirname(srcfile)
-
-    # Determine if the module is package of a package or not.
-    # If so, fix the tabmodule setting so that tables load correctly
-    pkg = pdict.get('__package__')
-    if pkg and isinstance(tabmodule, str):
-        if '.' not in tabmodule:
-            tabmodule = pkg + '.' + tabmodule
-
-
-
-    # Set start symbol if it's specified directly using an argument
-    if start is not None:
-        pdict['start'] = start
-
-    # Collect parser information from the dictionary
-    pinfo = ParserReflect(pdict, log=errorlog)
-    pinfo.get_all()
-
-    if pinfo.error:
-        raise YaccError('Unable to build parser')
-
-    # Check signature against table files (if any)
-    signature = pinfo.signature()
-
-    # Read the tables
-    try:
-        lr = LRTable()
-        if picklefile:
-            read_signature = lr.read_pickle(picklefile)
-        else:
-            read_signature = lr.read_table(tabmodule)
-        if optimize or (read_signature == signature):
-            try:
-                lr.bind_callables(pinfo.pdict)
-                parser = LRParser(lr, pinfo.error_func)
-                parse = parser.parse
-                return parser
-            except Exception as e:
-                errorlog.warning('There was a problem loading the table file: %r', e)
-    except VersionError as e:
-        errorlog.warning(str(e))
-    except ImportError:
-        pass
-
-    if debuglog is None:
-        if debug:
-            try:
-                debuglog = PlyLogger(open(os.path.join(outputdir, debugfile), 'w'))
-            except IOError as e:
-                errorlog.warning("Couldn't open %r. %s" % (debugfile, e))
-                debuglog = NullLogger()
-        else:
-            debuglog = NullLogger()
-
-    debuglog.info('Created by PLY version %s (http://www.dabeaz.com/ply)', __version__)
-
-    errors = False
-
-    # Validate the parser information
-    if pinfo.validate_all():
-        raise YaccError('Unable to build parser')
-
-    if not pinfo.error_func:
-        errorlog.warning('no p_error() function is defined')
-
-    # Create a grammar object
-    grammar = Grammar(pinfo.tokens)
-
-    # Set precedence level for terminals
-    for term, assoc, level in pinfo.preclist:
-        try:
-            grammar.set_precedence(term, assoc, level)
-        except GrammarError as e:
-            errorlog.warning('%s', e)
-
-    # Add productions to the grammar
-    for funcname, gram in pinfo.grammar:
-        file, line, prodname, syms = gram
-        try:
-            grammar.add_production(prodname, syms, funcname, file, line)
-        except GrammarError as e:
-            errorlog.error('%s', e)
-            errors = True
-
-    # Set the grammar start symbols
-    try:
-        if start is None:
-            grammar.set_start(pinfo.start)
-        else:
-            grammar.set_start(start)
-    except GrammarError as e:
-        errorlog.error(str(e))
-        errors = True
-
-    if errors:
-        raise YaccError('Unable to build parser')
-
-    # Verify the grammar structure
-    undefined_symbols = grammar.undefined_symbols()
-    for sym, prod in undefined_symbols:
-        errorlog.error('%s:%d: Symbol %r used, but not defined as a token or a rule', prod.file, prod.line, sym)
-        errors = True
-
-    unused_terminals = grammar.unused_terminals()
-    if unused_terminals:
-        debuglog.info('')
-        debuglog.info('Unused terminals:')
-        debuglog.info('')
-        for term in unused_terminals:
-            errorlog.warning('Token %r defined, but not used', term)
-            debuglog.info('    %s', term)
-
-    # Print out all productions to the debug log
-    if debug:
-        debuglog.info('')
-        debuglog.info('Grammar')
-        debuglog.info('')
-        for n, p in enumerate(grammar.Productions):
-            debuglog.info('Rule %-5d %s', n, p)
-
-    # Find unused non-terminals
-    unused_rules = grammar.unused_rules()
-    for prod in unused_rules:
-        errorlog.warning('%s:%d: Rule %r defined, but not used', prod.file, prod.line, prod.name)
-
-    if len(unused_terminals) == 1:
-        errorlog.warning('There is 1 unused token')
-    if len(unused_terminals) > 1:
-        errorlog.warning('There are %d unused tokens', len(unused_terminals))
-
-    if len(unused_rules) == 1:
-        errorlog.warning('There is 1 unused rule')
-    if len(unused_rules) > 1:
-        errorlog.warning('There are %d unused rules', len(unused_rules))
-
-    if debug:
-        debuglog.info('')
-        debuglog.info('Terminals, with rules where they appear')
-        debuglog.info('')
-        terms = list(grammar.Terminals)
-        terms.sort()
-        for term in terms:
-            debuglog.info('%-20s : %s', term, ' '.join([str(s) for s in grammar.Terminals[term]]))
-
-        debuglog.info('')
-        debuglog.info('Nonterminals, with rules where they appear')
-        debuglog.info('')
-        nonterms = list(grammar.Nonterminals)
-        nonterms.sort()
-        for nonterm in nonterms:
-            debuglog.info('%-20s : %s', nonterm, ' '.join([str(s) for s in grammar.Nonterminals[nonterm]]))
-        debuglog.info('')
-
-    if check_recursion:
-        unreachable = grammar.find_unreachable()
-        for u in unreachable:
-            errorlog.warning('Symbol %r is unreachable', u)
-
-        infinite = grammar.infinite_cycles()
-        for inf in infinite:
-            errorlog.error('Infinite recursion detected for symbol %r', inf)
-            errors = True
-
-    unused_prec = grammar.unused_precedence()
-    for term, assoc in unused_prec:
-        errorlog.error('Precedence rule %r defined for unknown symbol %r', assoc, term)
-        errors = True
-
-    if errors:
-        raise YaccError('Unable to build parser')
-
-    # Run the LRGeneratedTable on the grammar
-    if debug:
-        errorlog.debug('Generating %s tables', method)
-
-    lr = LRGeneratedTable(grammar, method, debuglog)
-
-    if debug:
-        num_sr = len(lr.sr_conflicts)
-
-        # Report shift/reduce and reduce/reduce conflicts
-        if num_sr == 1:
-            errorlog.warning('1 shift/reduce conflict')
-        elif num_sr > 1:
-            errorlog.warning('%d shift/reduce conflicts', num_sr)
-
-        num_rr = len(lr.rr_conflicts)
-        if num_rr == 1:
-            errorlog.warning('1 reduce/reduce conflict')
-        elif num_rr > 1:
-            errorlog.warning('%d reduce/reduce conflicts', num_rr)
-
-    # Write out conflicts to the output file
-    if debug and (lr.sr_conflicts or lr.rr_conflicts):
-        debuglog.warning('')
-        debuglog.warning('Conflicts:')
-        debuglog.warning('')
-
-        for state, tok, resolution in lr.sr_conflicts:
-            debuglog.warning('shift/reduce conflict for %s in state %d resolved as %s',  tok, state, resolution)
-
-        already_reported = set()
-        for state, rule, rejected in lr.rr_conflicts:
-            if (state, id(rule), id(rejected)) in already_reported:
-                continue
-            debuglog.warning('reduce/reduce conflict in state %d resolved using rule (%s)', state, rule)
-            debuglog.warning('rejected rule (%s) in state %d', rejected, state)
-            errorlog.warning('reduce/reduce conflict in state %d resolved using rule (%s)', state, rule)
-            errorlog.warning('rejected rule (%s) in state %d', rejected, state)
-            already_reported.add((state, id(rule), id(rejected)))
-
-        warned_never = []
-        for state, rule, rejected in lr.rr_conflicts:
-            if not rejected.reduced and (rejected not in warned_never):
-                debuglog.warning('Rule (%s) is never reduced', rejected)
-                errorlog.warning('Rule (%s) is never reduced', rejected)
-                warned_never.append(rejected)
-
-    # Write the table file if requested
-    if write_tables:
-        try:
-            lr.write_table(tabmodule, outputdir, signature)
-            if tabmodule in sys.modules:
-                del sys.modules[tabmodule]
-        except IOError as e:
-            errorlog.warning("Couldn't create %r. %s" % (tabmodule, e))
-
-    # Write a pickled version of the tables
-    if picklefile:
-        try:
-            lr.pickle_table(picklefile, signature)
-        except IOError as e:
-            errorlog.warning("Couldn't create %r. %s" % (picklefile, e))
-
-    # Build the parser
-    lr.bind_callables(pinfo.pdict)
-    parser = LRParser(lr, pinfo.error_func)
-
-    parse = parser.parse
-    return parser
diff --git a/server/libs/ply/ygen.py b/server/libs/ply/ygen.py
deleted file mode 100644
index 03b9318..0000000
--- a/server/libs/ply/ygen.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# ply: ygen.py
-#
-# This is a support program that auto-generates different versions of the YACC parsing
-# function with different features removed for the purposes of performance.
-#
-# Users should edit the method LRParser.parsedebug() in yacc.py.   The source code
-# for that method is then used to create the other methods.   See the comments in
-# yacc.py for further details.
-
-import os.path
-import shutil
-
-def get_source_range(lines, tag):
-    srclines = enumerate(lines)
-    start_tag = '#--! %s-start' % tag
-    end_tag = '#--! %s-end' % tag
-
-    for start_index, line in srclines:
-        if line.strip().startswith(start_tag):
-            break
-
-    for end_index, line in srclines:
-        if line.strip().endswith(end_tag):
-            break
-
-    return (start_index + 1, end_index)
-
-def filter_section(lines, tag):
-    filtered_lines = []
-    include = True
-    tag_text = '#--! %s' % tag
-    for line in lines:
-        if line.strip().startswith(tag_text):
-            include = not include
-        elif include:
-            filtered_lines.append(line)
-    return filtered_lines
-
-def main():
-    dirname = os.path.dirname(__file__)
-    shutil.copy2(os.path.join(dirname, 'yacc.py'), os.path.join(dirname, 'yacc.py.bak'))
-    with open(os.path.join(dirname, 'yacc.py'), 'r') as f:
-        lines = f.readlines()
-
-    parse_start, parse_end = get_source_range(lines, 'parsedebug')
-    parseopt_start, parseopt_end = get_source_range(lines, 'parseopt')
-    parseopt_notrack_start, parseopt_notrack_end = get_source_range(lines, 'parseopt-notrack')
-
-    # Get the original source
-    orig_lines = lines[parse_start:parse_end]
-
-    # Filter the DEBUG sections out
-    parseopt_lines = filter_section(orig_lines, 'DEBUG')
-
-    # Filter the TRACKING sections out
-    parseopt_notrack_lines = filter_section(parseopt_lines, 'TRACKING')
-
-    # Replace the parser source sections with updated versions
-    lines[parseopt_notrack_start:parseopt_notrack_end] = parseopt_notrack_lines
-    lines[parseopt_start:parseopt_end] = parseopt_lines
-
-    lines = [line.rstrip()+'\n' for line in lines]
-    with open(os.path.join(dirname, 'yacc.py'), 'w') as f:
-        f.writelines(lines)
-
-    print('Updated yacc.py')
-
-if __name__ == '__main__':
-    main()
diff --git a/server/libs/pygls-1.3.1.dist-info/INSTALLER b/server/libs/pygls-1.3.1.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/server/libs/pygls-1.3.1.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/server/libs/pygls-1.3.1.dist-info/LICENSE.txt b/server/libs/pygls-1.3.1.dist-info/LICENSE.txt
deleted file mode 100644
index 80f617c..0000000
--- a/server/libs/pygls-1.3.1.dist-info/LICENSE.txt
+++ /dev/null
@@ -1,201 +0,0 @@
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright (c) Open Law Library. All rights reserved.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/server/libs/pygls-1.3.1.dist-info/METADATA b/server/libs/pygls-1.3.1.dist-info/METADATA
deleted file mode 100644
index 70de8e1..0000000
--- a/server/libs/pygls-1.3.1.dist-info/METADATA
+++ /dev/null
@@ -1,105 +0,0 @@
-Metadata-Version: 2.1
-Name: pygls
-Version: 1.3.1
-Summary: A pythonic generic language server (pronounced like 'pie glass')
-Home-page: https://github.com/openlawlibrary/pygls
-License: Apache-2.0
-Author: Open Law Library
-Author-email: info@openlawlib.org
-Maintainer: Tom BH
-Maintainer-email: tom@tombh.co.uk
-Requires-Python: >=3.8
-Classifier: License :: OSI Approved :: Apache Software License
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: 3.12
-Provides-Extra: ws
-Requires-Dist: cattrs (>=23.1.2)
-Requires-Dist: lsprotocol (==2023.0.1)
-Requires-Dist: websockets (>=11.0.3) ; extra == "ws"
-Project-URL: Documentation, https://pygls.readthedocs.io/en/latest
-Project-URL: Repository, https://github.com/openlawlibrary/pygls
-Description-Content-Type: text/markdown
-
-[![PyPI Version](https://img.shields.io/pypi/v/pygls.svg)](https://pypi.org/project/pygls/) ![!pyversions](https://img.shields.io/pypi/pyversions/pygls.svg) ![license](https://img.shields.io/pypi/l/pygls.svg) [![Documentation Status](https://img.shields.io/badge/docs-latest-green.svg)](https://pygls.readthedocs.io/en/latest/)
-
-# pygls: The Generic Language Server Framework
-
-_pygls_ (pronounced like "pie glass") is a pythonic generic implementation of the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/specification) for use as a foundation for writing your own [Language Servers](https://langserver.org/) in just a few lines of code.
-
-## Quickstart
-```python
-from pygls.server import LanguageServer
-from lsprotocol.types import (
-    TEXT_DOCUMENT_COMPLETION,
-    CompletionItem,
-    CompletionList,
-    CompletionParams,
-)
-
-server = LanguageServer("example-server", "v0.1")
-
-@server.feature(TEXT_DOCUMENT_COMPLETION)
-def completions(params: CompletionParams):
-    items = []
-    document = server.workspace.get_document(params.text_document.uri)
-    current_line = document.lines[params.position.line].strip()
-    if current_line.endswith("hello."):
-        items = [
-            CompletionItem(label="world"),
-            CompletionItem(label="friend"),
-        ]
-    return CompletionList(is_incomplete=False, items=items)
-
-server.start_io()
-```
-
-Which might look something like this when you trigger autocompletion in your editor:
-
-![completions](https://raw.githubusercontent.com/openlawlibrary/pygls/master/docs/assets/hello-world-completion.png)
-
-## Docs and Tutorial
-
-The full documentation and a tutorial are available at .
-
-## Projects based on _pygls_
-
-We keep a table of all known _pygls_ [implementations](https://github.com/openlawlibrary/pygls/blob/master/Implementations.md). Please submit a Pull Request with your own or any that you find are missing.
-
-## Alternatives
-
-The main alternative to _pygls_ is Microsoft's [NodeJS-based Generic Language Server Framework](https://github.com/microsoft/vscode-languageserver-node). Being from Microsoft it is focussed on extending VSCode, although in theory it could be used to support any editor. So this is where pygls might be a better choice if you want to support more editors, as pygls is not focussed around VSCode.
-
-There are also other Language Servers with "general" in their descriptons, or at least intentions. They are however only general in the sense of having powerful _configuration_. They achieve generality in so much as configuration is able to, as opposed to what programming (in _pygls'_ case) can achieve.
-  * https://github.com/iamcco/diagnostic-languageserver
-  * https://github.com/mattn/efm-langserver
-  * https://github.com/jose-elias-alvarez/null-ls.nvim (Neovim only)
-
-## Tests
-All Pygls sub-tasks require the Poetry `poe` plugin: https://github.com/nat-n/poethepoet
-
-* `poetry install --all-extras`
-* `poetry run poe test`
-* `poetry run poe test-pyodide`
-
-
-## Contributing
-
-Your contributions to _pygls_ are most welcome ❤️ Please review the [Contributing](https://github.com/openlawlibrary/pygls/blob/master/CONTRIBUTING.md) and [Code of Conduct](https://github.com/openlawlibrary/pygls/blob/master/CODE_OF_CONDUCT.md) documents for how to get started.
-
-## Donating
-
-[Open Law Library](http://www.openlawlib.org/) is a 501(c)(3) tax exempt organization. Help us maintain our open source projects and open the law to all with [sponsorship](https://github.com/sponsors/openlawlibrary).
-
-### Supporters
-
-We would like to give special thanks to the following supporters:
-* [mpourmpoulis](https://github.com/mpourmpoulis)
-
-## License
-
-Apache-2.0
-
diff --git a/server/libs/pygls-1.3.1.dist-info/RECORD b/server/libs/pygls-1.3.1.dist-info/RECORD
deleted file mode 100644
index 518102f..0000000
--- a/server/libs/pygls-1.3.1.dist-info/RECORD
+++ /dev/null
@@ -1,45 +0,0 @@
-pygls-1.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-pygls-1.3.1.dist-info/LICENSE.txt,sha256=b0kVxr8adbxhHDGM8t6T3jWLMbQJ7QLrngwkWnnWCl8,11367
-pygls-1.3.1.dist-info/METADATA,sha256=ZZmXz51Jk7TTtWO1hLfSWQynv6rDCM798YWVbloCqHk,4726
-pygls-1.3.1.dist-info/RECORD,,
-pygls-1.3.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pygls-1.3.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
-pygls/__init__.py,sha256=rdTb3X-53tCjgNpS5dRsxv0ukMDjEly2pVEOPTnjx5k,1488
-pygls/__pycache__/__init__.cpython-311.pyc,,
-pygls/__pycache__/capabilities.cpython-311.pyc,,
-pygls/__pycache__/client.cpython-311.pyc,,
-pygls/__pycache__/constants.cpython-311.pyc,,
-pygls/__pycache__/exceptions.cpython-311.pyc,,
-pygls/__pycache__/feature_manager.cpython-311.pyc,,
-pygls/__pycache__/progress.cpython-311.pyc,,
-pygls/__pycache__/server.cpython-311.pyc,,
-pygls/__pycache__/uris.cpython-311.pyc,,
-pygls/capabilities.py,sha256=3tl-cqu82QpxHz-Z3NtlU6z-gbPqIvyvZ6gyZ-dr0-0,16756
-pygls/client.py,sha256=loVwqagoY0BnS6RwfpYtXwhg0NiIE6Tvbj2DzpOF7GA,6292
-pygls/constants.py,sha256=0YsX4Egp9jVLuAu9v8T_ThrObrVKGP916-X-9bkmId8,1470
-pygls/exceptions.py,sha256=skJKYaJCXI5At2eS1pNdQ6r3_B9Z-SMlyqr0_dwUVEw,6302
-pygls/feature_manager.py,sha256=7C--ra3GaG44LoZd8MaZ6Jh_8uxQMZo5jzykGwT7Fdg,8494
-pygls/lsp/__init__.py,sha256=pp9PCQhGzgPPFfWID47cdz_Q0LpZjT2kFPgTS-N7iVM,5236
-pygls/lsp/__pycache__/__init__.cpython-311.pyc,,
-pygls/lsp/__pycache__/client.cpython-311.pyc,,
-pygls/lsp/client.py,sha256=8JVgyjXXOblPlDhLAvNbukK-qrQNf__757elz9XYkCo,76358
-pygls/progress.py,sha256=Ml8vgJ9ueFC4YUqwvrgHatX8l_O3odhvmoPOLIcMNok,2789
-pygls/protocol/__init__.py,sha256=YI5xMBILWYKexx343wUDrHUVPuJFu9A48VSf0ieXYJM,1822
-pygls/protocol/__pycache__/__init__.cpython-311.pyc,,
-pygls/protocol/__pycache__/json_rpc.cpython-311.pyc,,
-pygls/protocol/__pycache__/language_server.cpython-311.pyc,,
-pygls/protocol/__pycache__/lsp_meta.cpython-311.pyc,,
-pygls/protocol/json_rpc.py,sha256=01nqJoCNDmZQ78tyFxPfA9_kEBHyuBe-7ZUXCqwmu4g,20124
-pygls/protocol/language_server.py,sha256=b6X30DCLN4sdG85OhLVdrBJ9cweL4eKVgsc10bnMzXk,20109
-pygls/protocol/lsp_meta.py,sha256=kX1nL7XGVIYWp6UUyT3yDFnhcvpoCU_3mdyzpDTtUyQ,1593
-pygls/py.typed,sha256=ZfGKUcVseOxYpg6BU9EuhkP4dErsepCA4apkj_9YnYc,65
-pygls/server.py,sha256=T-k2wsP0W5a6KHmE9Afrv2PTy3qACEuCPGSJPmzC30w,20753
-pygls/uris.py,sha256=lknA_8hNYfs47mOFQxnFYW2TWH-8iL68ghTVD0Cccsc,5764
-pygls/workspace/__init__.py,sha256=tD6ahYMIPVsDdsWJ32EhF8wK-IJy6IQGInkI-BmIAxY,2883
-pygls/workspace/__pycache__/__init__.cpython-311.pyc,,
-pygls/workspace/__pycache__/position_codec.cpython-311.pyc,,
-pygls/workspace/__pycache__/text_document.cpython-311.pyc,,
-pygls/workspace/__pycache__/workspace.cpython-311.pyc,,
-pygls/workspace/position_codec.py,sha256=UDv1kXFMyCDnu-iGhEbylCJP74L0TAL2hFvhoFrSpOY,8019
-pygls/workspace/text_document.py,sha256=8LcxsQeawuPNDrNDm3A2oMjWxYA3YxXm3NiHyQJQp8M,9031
-pygls/workspace/workspace.py,sha256=Zpd96kvVM7po7cI_XLenRAq8Wp3mjlMBX_YxO6Ecvs8,11556
diff --git a/server/libs/pygls-1.3.1.dist-info/REQUESTED b/server/libs/pygls-1.3.1.dist-info/REQUESTED
deleted file mode 100644
index e69de29..0000000
diff --git a/server/libs/pygls-1.3.1.dist-info/WHEEL b/server/libs/pygls-1.3.1.dist-info/WHEEL
deleted file mode 100644
index d73ccaa..0000000
--- a/server/libs/pygls-1.3.1.dist-info/WHEEL
+++ /dev/null
@@ -1,4 +0,0 @@
-Wheel-Version: 1.0
-Generator: poetry-core 1.9.0
-Root-Is-Purelib: true
-Tag: py3-none-any
diff --git a/server/libs/pygls/__init__.py b/server/libs/pygls/__init__.py
deleted file mode 100644
index 147cd9e..0000000
--- a/server/libs/pygls/__init__.py
+++ /dev/null
@@ -1,25 +0,0 @@
-############################################################################
-# Original work Copyright 2018 Palantir Technologies, Inc.                 #
-# Original work licensed under the MIT License.                            #
-# See ThirdPartyNotices.txt in the project root for license information.   #
-# All modifications Copyright (c) Open Law Library. All rights reserved.   #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-import os
-import sys
-
-IS_WIN = os.name == "nt"
-IS_PYODIDE = "pyodide" in sys.modules
-
-pygls = "pygls"
diff --git a/server/libs/pygls/capabilities.py b/server/libs/pygls/capabilities.py
deleted file mode 100644
index 9db4744..0000000
--- a/server/libs/pygls/capabilities.py
+++ /dev/null
@@ -1,460 +0,0 @@
-############################################################################
-# Copyright(c) Open Law Library. All rights reserved.                      #
-# See ThirdPartyNotices.txt in the project root for additional notices.    #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-from functools import reduce
-from typing import Any, Dict, List, Optional, Set, Union, TypeVar
-import logging
-
-from lsprotocol import types
-
-
-logger = logging.getLogger(__name__)
-T = TypeVar("T")
-
-
-def get_capability(
-    client_capabilities: types.ClientCapabilities, field: str, default: Any = None
-) -> Any:
-    """Check if ClientCapabilities has some nested value without raising
-    AttributeError.
-    e.g. get_capability('text_document.synchronization.will_save')
-    """
-    try:
-        value = reduce(getattr, field.split("."), client_capabilities)
-    except AttributeError:
-        return default
-
-    # If we reach the desired leaf value but it's None, return the default.
-    return default if value is None else value
-
-
-class ServerCapabilitiesBuilder:
-    """Create `ServerCapabilities` instance depending on builtin and user registered
-    features.
-    """
-
-    def __init__(
-        self,
-        client_capabilities: types.ClientCapabilities,
-        features: Set[str],
-        feature_options: Dict[str, Any],
-        commands: List[str],
-        text_document_sync_kind: types.TextDocumentSyncKind,
-        notebook_document_sync: Optional[types.NotebookDocumentSyncOptions] = None,
-    ):
-        self.client_capabilities = client_capabilities
-        self.features = features
-        self.feature_options = feature_options
-        self.commands = commands
-        self.text_document_sync_kind = text_document_sync_kind
-        self.notebook_document_sync = notebook_document_sync
-
-        self.server_cap = types.ServerCapabilities()
-
-    def _provider_options(self, feature: str, default: T) -> Optional[Union[T, Any]]:
-        if feature in self.features:
-            return self.feature_options.get(feature, default)
-        return None
-
-    def _with_text_document_sync(self):
-        open_close = (
-            types.TEXT_DOCUMENT_DID_OPEN in self.features
-            or types.TEXT_DOCUMENT_DID_CLOSE in self.features
-        )
-        will_save = (
-            get_capability(
-                self.client_capabilities, "text_document.synchronization.will_save"
-            )
-            and types.TEXT_DOCUMENT_WILL_SAVE in self.features
-        )
-        will_save_wait_until = (
-            get_capability(
-                self.client_capabilities,
-                "text_document.synchronization.will_save_wait_until",
-            )
-            and types.TEXT_DOCUMENT_WILL_SAVE_WAIT_UNTIL in self.features
-        )
-        if types.TEXT_DOCUMENT_DID_SAVE in self.features:
-            save = self.feature_options.get(types.TEXT_DOCUMENT_DID_SAVE, True)
-        else:
-            save = False
-
-        self.server_cap.text_document_sync = types.TextDocumentSyncOptions(
-            open_close=open_close,
-            change=self.text_document_sync_kind,
-            will_save=will_save,
-            will_save_wait_until=will_save_wait_until,
-            save=save,
-        )
-
-        return self
-
-    def _with_notebook_document_sync(self):
-        if self.client_capabilities.notebook_document is None:
-            return self
-
-        self.server_cap.notebook_document_sync = self.notebook_document_sync
-        return self
-
-    def _with_completion(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_COMPLETION, default=types.CompletionOptions()
-        )
-        if value is not None:
-            self.server_cap.completion_provider = value
-        return self
-
-    def _with_hover(self):
-        value = self._provider_options(types.TEXT_DOCUMENT_HOVER, default=True)
-        if value is not None:
-            self.server_cap.hover_provider = value
-        return self
-
-    def _with_signature_help(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_SIGNATURE_HELP, default=types.SignatureHelpOptions()
-        )
-        if value is not None:
-            self.server_cap.signature_help_provider = value
-        return self
-
-    def _with_declaration(self):
-        value = self._provider_options(types.TEXT_DOCUMENT_DECLARATION, default=True)
-        if value is not None:
-            self.server_cap.declaration_provider = value
-        return self
-
-    def _with_definition(self):
-        value = self._provider_options(types.TEXT_DOCUMENT_DEFINITION, default=True)
-        if value is not None:
-            self.server_cap.definition_provider = value
-        return self
-
-    def _with_type_definition(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_TYPE_DEFINITION, default=types.TypeDefinitionOptions()
-        )
-        if value is not None:
-            self.server_cap.type_definition_provider = value
-        return self
-
-    def _with_inlay_hints(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_INLAY_HINT, default=types.InlayHintOptions()
-        )
-        if value is not None:
-            value.resolve_provider = types.INLAY_HINT_RESOLVE in self.features
-            self.server_cap.inlay_hint_provider = value
-        return self
-
-    def _with_implementation(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_IMPLEMENTATION, default=types.ImplementationOptions()
-        )
-        if value is not None:
-            self.server_cap.implementation_provider = value
-        return self
-
-    def _with_references(self):
-        value = self._provider_options(types.TEXT_DOCUMENT_REFERENCES, default=True)
-        if value is not None:
-            self.server_cap.references_provider = value
-        return self
-
-    def _with_document_highlight(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_DOCUMENT_HIGHLIGHT, default=True
-        )
-        if value is not None:
-            self.server_cap.document_highlight_provider = value
-        return self
-
-    def _with_document_symbol(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_DOCUMENT_SYMBOL, default=True
-        )
-        if value is not None:
-            self.server_cap.document_symbol_provider = value
-        return self
-
-    def _with_code_action(self):
-        value = self._provider_options(types.TEXT_DOCUMENT_CODE_ACTION, default=True)
-        if value is not None:
-            self.server_cap.code_action_provider = value
-        return self
-
-    def _with_code_lens(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_CODE_LENS, default=types.CodeLensOptions()
-        )
-        if value is not None:
-            self.server_cap.code_lens_provider = value
-        return self
-
-    def _with_document_link(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_DOCUMENT_LINK, default=types.DocumentLinkOptions()
-        )
-        if value is not None:
-            self.server_cap.document_link_provider = value
-        return self
-
-    def _with_color(self):
-        value = self._provider_options(types.TEXT_DOCUMENT_DOCUMENT_COLOR, default=True)
-        if value is not None:
-            self.server_cap.color_provider = value
-        return self
-
-    def _with_document_formatting(self):
-        value = self._provider_options(types.TEXT_DOCUMENT_FORMATTING, default=True)
-        if value is not None:
-            self.server_cap.document_formatting_provider = value
-        return self
-
-    def _with_document_range_formatting(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_RANGE_FORMATTING, default=True
-        )
-        if value is not None:
-            self.server_cap.document_range_formatting_provider = value
-        return self
-
-    def _with_document_on_type_formatting(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_ON_TYPE_FORMATTING, default=None
-        )
-        if value is not None:
-            self.server_cap.document_on_type_formatting_provider = value
-        return self
-
-    def _with_rename(self):
-        value = self._provider_options(types.TEXT_DOCUMENT_RENAME, default=True)
-        if value is not None:
-            self.server_cap.rename_provider = value
-        return self
-
-    def _with_folding_range(self):
-        value = self._provider_options(types.TEXT_DOCUMENT_FOLDING_RANGE, default=True)
-        if value is not None:
-            self.server_cap.folding_range_provider = value
-        return self
-
-    def _with_execute_command(self):
-        self.server_cap.execute_command_provider = types.ExecuteCommandOptions(
-            commands=self.commands
-        )
-        return self
-
-    def _with_selection_range(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_SELECTION_RANGE, default=True
-        )
-        if value is not None:
-            self.server_cap.selection_range_provider = value
-        return self
-
-    def _with_call_hierarchy(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_PREPARE_CALL_HIERARCHY, default=True
-        )
-        if value is not None:
-            self.server_cap.call_hierarchy_provider = value
-        return self
-
-    def _with_type_hierarchy(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_PREPARE_TYPE_HIERARCHY, default=True
-        )
-        if value is not None:
-            self.server_cap.type_hierarchy_provider = value
-        return self
-
-    def _with_semantic_tokens(self):
-        providers = [
-            types.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
-            types.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL_DELTA,
-            types.TEXT_DOCUMENT_SEMANTIC_TOKENS_RANGE,
-        ]
-
-        value = None
-        for provider in providers:
-            value = self._provider_options(provider, default=None)
-            if value is not None:
-                break
-
-        if value is None:
-            return self
-
-        if isinstance(value, types.SemanticTokensRegistrationOptions):
-            self.server_cap.semantic_tokens_provider = value
-            return self
-
-        full_support: Union[bool, types.SemanticTokensOptionsFullType1] = (
-            types.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL in self.features
-        )
-
-        if types.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL_DELTA in self.features:
-            full_support = types.SemanticTokensOptionsFullType1(delta=True)
-
-        options = types.SemanticTokensOptions(
-            legend=value,
-            full=full_support or None,
-            range=types.TEXT_DOCUMENT_SEMANTIC_TOKENS_RANGE in self.features or None,
-        )
-
-        if options.full or options.range:
-            self.server_cap.semantic_tokens_provider = options
-
-        return self
-
-    def _with_linked_editing_range(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_LINKED_EDITING_RANGE, default=True
-        )
-        if value is not None:
-            self.server_cap.linked_editing_range_provider = value
-        return self
-
-    def _with_moniker(self):
-        value = self._provider_options(types.TEXT_DOCUMENT_MONIKER, default=True)
-        if value is not None:
-            self.server_cap.moniker_provider = value
-        return self
-
-    def _with_workspace_symbol(self):
-        value = self._provider_options(
-            types.WORKSPACE_SYMBOL, default=types.WorkspaceSymbolOptions()
-        )
-        if value is not None:
-            value.resolve_provider = types.WORKSPACE_SYMBOL_RESOLVE in self.features
-            self.server_cap.workspace_symbol_provider = value
-        return self
-
-    def _with_workspace_capabilities(self):
-        # File operations
-        file_operations = types.FileOperationOptions()
-        operations = [
-            (types.WORKSPACE_WILL_CREATE_FILES, "will_create"),
-            (types.WORKSPACE_DID_CREATE_FILES, "did_create"),
-            (types.WORKSPACE_WILL_DELETE_FILES, "will_delete"),
-            (types.WORKSPACE_DID_DELETE_FILES, "did_delete"),
-            (types.WORKSPACE_WILL_RENAME_FILES, "will_rename"),
-            (types.WORKSPACE_DID_RENAME_FILES, "did_rename"),
-        ]
-
-        for method_name, capability_name in operations:
-            client_supports_method = get_capability(
-                self.client_capabilities, f"workspace.file_operations.{capability_name}"
-            )
-
-            if client_supports_method:
-                value = self._provider_options(method_name, default=None)
-                setattr(file_operations, capability_name, value)
-
-        self.server_cap.workspace = types.ServerCapabilitiesWorkspaceType(
-            workspace_folders=types.WorkspaceFoldersServerCapabilities(
-                supported=True,
-                change_notifications=True,
-            ),
-            file_operations=file_operations,
-        )
-        return self
-
-    def _with_diagnostic_provider(self):
-        value = self._provider_options(
-            types.TEXT_DOCUMENT_DIAGNOSTIC,
-            default=types.DiagnosticOptions(
-                inter_file_dependencies=False, workspace_diagnostics=False
-            ),
-        )
-        if value is not None:
-            value.workspace_diagnostics = types.WORKSPACE_DIAGNOSTIC in self.features
-            self.server_cap.diagnostic_provider = value
-        return self
-
-    def _with_inline_value_provider(self):
-        value = self._provider_options(types.TEXT_DOCUMENT_INLINE_VALUE, default=True)
-        if value is not None:
-            self.server_cap.inline_value_provider = value
-        return self
-
-    def _with_position_encodings(self):
-        self.server_cap.position_encoding = types.PositionEncodingKind.Utf16
-
-        general = self.client_capabilities.general
-        if general is None:
-            return self
-
-        encodings = general.position_encodings
-        if encodings is None:
-            return self
-
-        if types.PositionEncodingKind.Utf16 in encodings:
-            return self
-
-        if types.PositionEncodingKind.Utf32 in encodings:
-            self.server_cap.position_encoding = types.PositionEncodingKind.Utf32
-            return self
-
-        if types.PositionEncodingKind.Utf8 in encodings:
-            self.server_cap.position_encoding = types.PositionEncodingKind.Utf8
-            return self
-
-        logger.warning(f"Unknown `PositionEncoding`s: {encodings}")
-
-        return self
-
-    def _build(self):
-        return self.server_cap
-
-    def build(self):
-        return (
-            self._with_text_document_sync()
-            ._with_notebook_document_sync()
-            ._with_completion()
-            ._with_hover()
-            ._with_signature_help()
-            ._with_declaration()
-            ._with_definition()
-            ._with_type_definition()
-            ._with_inlay_hints()
-            ._with_implementation()
-            ._with_references()
-            ._with_document_highlight()
-            ._with_document_symbol()
-            ._with_code_action()
-            ._with_code_lens()
-            ._with_document_link()
-            ._with_color()
-            ._with_document_formatting()
-            ._with_document_range_formatting()
-            ._with_document_on_type_formatting()
-            ._with_rename()
-            ._with_folding_range()
-            ._with_execute_command()
-            ._with_selection_range()
-            ._with_call_hierarchy()
-            ._with_type_hierarchy()
-            ._with_semantic_tokens()
-            ._with_linked_editing_range()
-            ._with_moniker()
-            ._with_workspace_symbol()
-            ._with_workspace_capabilities()
-            ._with_diagnostic_provider()
-            ._with_inline_value_provider()
-            ._with_position_encodings()
-            ._build()
-        )
diff --git a/server/libs/pygls/client.py b/server/libs/pygls/client.py
deleted file mode 100644
index 577f05e..0000000
--- a/server/libs/pygls/client.py
+++ /dev/null
@@ -1,176 +0,0 @@
-############################################################################
-# Copyright(c) Open Law Library. All rights reserved.                      #
-# See ThirdPartyNotices.txt in the project root for additional notices.    #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-import asyncio
-import logging
-import re
-from threading import Event
-from typing import Any
-from typing import Callable
-from typing import List
-from typing import Optional
-from typing import Type
-from typing import Union
-
-from cattrs import Converter
-
-from pygls.exceptions import PyglsError, JsonRpcException
-from pygls.protocol import JsonRPCProtocol, default_converter
-
-
-logger = logging.getLogger(__name__)
-
-
-async def aio_readline(stop_event, reader, message_handler):
-    CONTENT_LENGTH_PATTERN = re.compile(rb"^Content-Length: (\d+)\r\n$")
-
-    # Initialize message buffer
-    message = []
-    content_length = 0
-
-    while not stop_event.is_set():
-        # Read a header line
-        header = await reader.readline()
-        if not header:
-            break
-        message.append(header)
-
-        # Extract content length if possible
-        if not content_length:
-            match = CONTENT_LENGTH_PATTERN.fullmatch(header)
-            if match:
-                content_length = int(match.group(1))
-                logger.debug("Content length: %s", content_length)
-
-        # Check if all headers have been read (as indicated by an empty line \r\n)
-        if content_length and not header.strip():
-            # Read body
-            body = await reader.readexactly(content_length)
-            if not body:
-                break
-            message.append(body)
-
-            # Pass message to protocol
-            message_handler(b"".join(message))
-
-            # Reset the buffer
-            message = []
-            content_length = 0
-
-
-class JsonRPCClient:
-    """Base JSON-RPC client."""
-
-    def __init__(
-        self,
-        protocol_cls: Type[JsonRPCProtocol] = JsonRPCProtocol,
-        converter_factory: Callable[[], Converter] = default_converter,
-    ):
-        # Strictly speaking `JsonRPCProtocol` wants a `LanguageServer`, not a
-        # `JsonRPCClient`. However there similar enough for our purposes, which is
-        # that this client will mostly be used in testing contexts.
-        self.protocol = protocol_cls(self, converter_factory())  # type: ignore
-
-        self._server: Optional[asyncio.subprocess.Process] = None
-        self._stop_event = Event()
-        self._async_tasks: List[asyncio.Task] = []
-
-    @property
-    def stopped(self) -> bool:
-        """Return ``True`` if the client has been stopped."""
-        return self._stop_event.is_set()
-
-    def feature(
-        self,
-        feature_name: str,
-        options: Optional[Any] = None,
-    ):
-        """Decorator used to register LSP features.
-
-        Example
-        -------
-        ::
-
-           import logging
-           from pygls.client import JsonRPCClient
-
-           ls = JsonRPCClient()
-
-           @ls.feature('window/logMessage')
-           def completions(ls, params):
-               logging.info("%s", params.message)
-        """
-        return self.protocol.fm.feature(feature_name, options)
-
-    async def start_io(self, cmd: str, *args, **kwargs):
-        """Start the given server and communicate with it over stdio."""
-
-        logger.debug("Starting server process: %s", " ".join([cmd, *args]))
-        server = await asyncio.create_subprocess_exec(
-            cmd,
-            *args,
-            stdout=asyncio.subprocess.PIPE,
-            stdin=asyncio.subprocess.PIPE,
-            stderr=asyncio.subprocess.PIPE,
-            **kwargs,
-        )
-
-        self.protocol.connection_made(server.stdin)  # type: ignore
-        connection = asyncio.create_task(
-            aio_readline(self._stop_event, server.stdout, self.protocol.data_received)
-        )
-        notify_exit = asyncio.create_task(self._server_exit())
-
-        self._server = server
-        self._async_tasks.extend([connection, notify_exit])
-
-    async def _server_exit(self):
-        if self._server is not None:
-            await self._server.wait()
-            logger.debug(
-                "Server process %s exited with return code: %s",
-                self._server.pid,
-                self._server.returncode,
-            )
-            await self.server_exit(self._server)
-            self._stop_event.set()
-
-    async def server_exit(self, server: asyncio.subprocess.Process):
-        """Called when the server process exits."""
-
-    def _report_server_error(
-        self, error: Exception, source: Union[PyglsError, JsonRpcException]
-    ):
-        try:
-            self.report_server_error(error, source)
-        except Exception:
-            logger.error("Unable to report error", exc_info=True)
-
-    def report_server_error(
-        self, error: Exception, source: Union[PyglsError, JsonRpcException]
-    ):
-        """Called when the server does something unexpected e.g. respond with malformed
-        JSON."""
-
-    async def stop(self):
-        self._stop_event.set()
-
-        if self._server is not None and self._server.returncode is None:
-            logger.debug("Terminating server process: %s", self._server.pid)
-            self._server.terminate()
-
-        if len(self._async_tasks) > 0:
-            await asyncio.gather(*self._async_tasks)
diff --git a/server/libs/pygls/constants.py b/server/libs/pygls/constants.py
deleted file mode 100644
index ec2fa09..0000000
--- a/server/libs/pygls/constants.py
+++ /dev/null
@@ -1,26 +0,0 @@
-############################################################################
-# Copyright(c) Open Law Library. All rights reserved.                      #
-# See ThirdPartyNotices.txt in the project root for additional notices.    #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-
-# Dynamically assigned attributes
-ATTR_EXECUTE_IN_THREAD = "execute_in_thread"
-ATTR_COMMAND_TYPE = "command"
-ATTR_FEATURE_TYPE = "feature"
-ATTR_REGISTERED_NAME = "reg_name"
-ATTR_REGISTERED_TYPE = "reg_type"
-
-# Parameters
-PARAM_LS = "ls"
diff --git a/server/libs/pygls/exceptions.py b/server/libs/pygls/exceptions.py
deleted file mode 100644
index 5faf269..0000000
--- a/server/libs/pygls/exceptions.py
+++ /dev/null
@@ -1,215 +0,0 @@
-############################################################################
-# Original work Copyright 2018 Palantir Technologies, Inc.                 #
-# Original work licensed under the MIT License.                            #
-# See ThirdPartyNotices.txt in the project root for license information.   #
-# All modifications Copyright (c) Open Law Library. All rights reserved.   #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-import traceback
-from typing import Set
-from typing import Type
-from lsprotocol.types import ResponseError
-
-
-class JsonRpcException(Exception):
-    """A class used as a base class for json rpc exceptions."""
-
-    def __init__(self, message=None, code=None, data=None):
-        message = message or getattr(self.__class__, "MESSAGE")
-        super().__init__(message)
-        self.message = message
-        self.code = code or getattr(self.__class__, "CODE")
-        self.data = data
-
-    def __eq__(self, other):
-        return (
-            isinstance(other, self.__class__)
-            and self.code == other.code
-            and self.message == other.message
-        )
-
-    def __hash__(self):
-        return hash((self.code, self.message))
-
-    @staticmethod
-    def from_error(error):
-        for exc_class in _EXCEPTIONS:
-            if exc_class.supports_code(error.code):
-                return exc_class(
-                    code=error.code, message=error.message, data=error.data
-                )
-
-        return JsonRpcException(code=error.code, message=error.message, data=error.data)
-
-    @classmethod
-    def supports_code(cls, code):
-        # Defaults to UnknownErrorCode
-        return getattr(cls, "CODE", -32001) == code
-
-    def to_response_error(self) -> ResponseError:
-        return ResponseError(code=self.code, message=self.message, data=self.data)
-
-
-class JsonRpcInternalError(JsonRpcException):
-    CODE = -32603
-    MESSAGE = "Internal Error"
-
-    @classmethod
-    def of(cls, exc_info):
-        exc_type, exc_value, exc_tb = exc_info
-        return cls(
-            message="".join(
-                traceback.format_exception_only(exc_type, exc_value)
-            ).strip(),
-            data={"traceback": traceback.format_tb(exc_tb)},
-        )
-
-
-class JsonRpcInvalidParams(JsonRpcException):
-    CODE = -32602
-    MESSAGE = "Invalid Params"
-
-
-class JsonRpcInvalidRequest(JsonRpcException):
-    CODE = -32600
-    MESSAGE = "Invalid Request"
-
-
-class JsonRpcMethodNotFound(JsonRpcException):
-    CODE = -32601
-    MESSAGE = "Method Not Found"
-
-    @classmethod
-    def of(cls, method):
-        return cls(message=cls.MESSAGE + ": " + method)
-
-
-class JsonRpcParseError(JsonRpcException):
-    CODE = -32700
-    MESSAGE = "Parse Error"
-
-
-class JsonRpcRequestCancelled(JsonRpcException):
-    CODE = -32800
-    MESSAGE = "Request Cancelled"
-
-
-class JsonRpcContentModified(JsonRpcException):
-    CODE = -32801
-    MESSAGE = "Content Modified"
-
-
-class JsonRpcServerNotInitialized(JsonRpcException):
-    CODE = -32002
-    MESSAGE = "ServerNotInitialized"
-
-
-class JsonRpcUnknownErrorCode(JsonRpcException):
-    CODE = -32001
-    MESSAGE = "UnknownErrorCode"
-
-
-class JsonRpcReservedErrorRangeStart(JsonRpcException):
-    CODE = -32099
-    MESSAGE = "jsonrpcReservedErrorRangeStart"
-
-
-class JsonRpcReservedErrorRangeEnd(JsonRpcException):
-    CODE = -32000
-    MESSAGE = "jsonrpcReservedErrorRangeEnd"
-
-
-class LspReservedErrorRangeStart(JsonRpcException):
-    CODE = -32899
-    MESSAGE = "lspReservedErrorRangeStart"
-
-
-class LspReservedErrorRangeEnd(JsonRpcException):
-    CODE = -32800
-    MESSAGE = "lspReservedErrorRangeEnd"
-
-
-class JsonRpcServerError(JsonRpcException):
-    def __init__(self, message, code, data=None):
-        if not _is_server_error_code(code):
-            raise ValueError("Error code should be in range -32099 - -32000")
-        super().__init__(message=message, code=code, data=data)
-
-    @classmethod
-    def supports_code(cls, code):
-        return _is_server_error_code(code)
-
-
-def _is_server_error_code(code):
-    return -32099 <= code <= -32000
-
-
-_EXCEPTIONS: Set[Type[JsonRpcException]] = {
-    JsonRpcInternalError,
-    JsonRpcInvalidParams,
-    JsonRpcInvalidRequest,
-    JsonRpcMethodNotFound,
-    JsonRpcParseError,
-    JsonRpcRequestCancelled,
-    JsonRpcServerError,
-}
-
-
-class PyglsError(Exception):
-    pass
-
-
-class CommandAlreadyRegisteredError(PyglsError):
-    def __init__(self, command_name):
-        self.command_name = command_name
-
-    def __repr__(self):
-        return f'Command "{self.command_name}" is already registered.'
-
-
-class FeatureAlreadyRegisteredError(PyglsError):
-    def __init__(self, feature_name):
-        self.feature_name = feature_name
-
-    def __repr__(self):
-        return f'Feature "{self.feature_name}" is already registered.'
-
-
-class FeatureRequestError(PyglsError):
-    pass
-
-
-class FeatureNotificationError(PyglsError):
-    pass
-
-
-class MethodTypeNotRegisteredError(PyglsError):
-    def __init__(self, name):
-        self.name = name
-
-    def __repr__(self):
-        return f'"{self.name}" is not added to `pygls.lsp.LSP_METHODS_MAP`.'
-
-
-class ThreadDecoratorError(PyglsError):
-    pass
-
-
-class ValidationError(PyglsError):
-    def __init__(self, errors=None):
-        self.errors = errors or []
-
-    def __repr__(self):
-        opt_errs = "\n-".join([e for e in self.errors])
-        return f"Missing options: {opt_errs}"
diff --git a/server/libs/pygls/feature_manager.py b/server/libs/pygls/feature_manager.py
deleted file mode 100644
index d00283a..0000000
--- a/server/libs/pygls/feature_manager.py
+++ /dev/null
@@ -1,244 +0,0 @@
-############################################################################
-# Copyright(c) Open Law Library. All rights reserved.                      #
-# See ThirdPartyNotices.txt in the project root for additional notices.    #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-import asyncio
-import functools
-import inspect
-import itertools
-import logging
-from typing import Any, Callable, Dict, Optional, get_type_hints
-
-from pygls.constants import (
-    ATTR_COMMAND_TYPE,
-    ATTR_EXECUTE_IN_THREAD,
-    ATTR_FEATURE_TYPE,
-    ATTR_REGISTERED_NAME,
-    ATTR_REGISTERED_TYPE,
-    PARAM_LS,
-)
-from pygls.exceptions import (
-    CommandAlreadyRegisteredError,
-    FeatureAlreadyRegisteredError,
-    ThreadDecoratorError,
-    ValidationError,
-)
-from pygls.lsp import get_method_options_type, is_instance
-
-logger = logging.getLogger(__name__)
-
-
-def assign_help_attrs(f, reg_name, reg_type):
-    setattr(f, ATTR_REGISTERED_NAME, reg_name)
-    setattr(f, ATTR_REGISTERED_TYPE, reg_type)
-
-
-def assign_thread_attr(f):
-    setattr(f, ATTR_EXECUTE_IN_THREAD, True)
-
-
-def get_help_attrs(f):
-    return getattr(f, ATTR_REGISTERED_NAME, None), getattr(
-        f, ATTR_REGISTERED_TYPE, None
-    )
-
-
-def has_ls_param_or_annotation(f, annotation):
-    """Returns true if callable has first parameter named `ls` or type of
-    annotation"""
-    try:
-        sig = inspect.signature(f)
-        first_p = next(itertools.islice(sig.parameters.values(), 0, 1))
-        return first_p.name == PARAM_LS or get_type_hints(f)[first_p.name] == annotation
-    except Exception:
-        return False
-
-
-def is_thread_function(f):
-    return getattr(f, ATTR_EXECUTE_IN_THREAD, False)
-
-
-def wrap_with_server(f, server):
-    """Returns a new callable/coroutine with server as first argument."""
-    if not has_ls_param_or_annotation(f, type(server)):
-        return f
-
-    if asyncio.iscoroutinefunction(f):
-
-        async def wrapped(*args, **kwargs):
-            return await f(server, *args, **kwargs)
-
-    else:
-        wrapped = functools.partial(f, server)
-        if is_thread_function(f):
-            assign_thread_attr(wrapped)
-
-    return wrapped
-
-
-class FeatureManager:
-    """A class for managing server features.
-
-    Attributes:
-        _builtin_features(dict): Predefined set of lsp methods
-        _feature_options(dict): Registered feature's options
-        _features(dict): Registered features
-        _commands(dict): Registered commands
-        server(LanguageServer): Reference to the language server
-                                If passed, server will be passed to registered
-                                features/commands with first parameter:
-                                    1. ls - parameter naming convention
-                                    2. name: LanguageServer - add typings
-    """
-
-    def __init__(self, server=None, converter=None):
-        self._builtin_features = {}
-        self._feature_options = {}
-        self._features = {}
-        self._commands = {}
-        self.server = server
-        self.converter = converter
-
-    def add_builtin_feature(self, feature_name: str, func: Callable) -> None:
-        """Registers builtin (predefined) feature."""
-        self._builtin_features[feature_name] = func
-        logger.info("Registered builtin feature %s", feature_name)
-
-    @property
-    def builtin_features(self) -> Dict:
-        """Returns server builtin features."""
-        return self._builtin_features
-
-    def command(self, command_name: str) -> Callable:
-        """Decorator used to register custom commands.
-
-        Example:
-            @ls.command('myCustomCommand')
-        """
-
-        def decorator(f):
-            # Validate
-            if command_name is None or command_name.strip() == "":
-                logger.error("Missing command name.")
-                raise ValidationError("Command name is required.")
-
-            # Check if not already registered
-            if command_name in self._commands:
-                logger.error('Command "%s" is already registered.', command_name)
-                raise CommandAlreadyRegisteredError(command_name)
-
-            assign_help_attrs(f, command_name, ATTR_COMMAND_TYPE)
-
-            wrapped = wrap_with_server(f, self.server)
-            # Assign help attributes for thread decorator
-            assign_help_attrs(wrapped, command_name, ATTR_COMMAND_TYPE)
-
-            self._commands[command_name] = wrapped
-
-            logger.info('Command "%s" is successfully registered.', command_name)
-
-            return f
-
-        return decorator
-
-    @property
-    def commands(self) -> Dict:
-        """Returns registered custom commands."""
-        return self._commands
-
-    def feature(
-        self,
-        feature_name: str,
-        options: Optional[Any] = None,
-    ) -> Callable:
-        """Decorator used to register LSP features.
-
-        Example:
-            @ls.feature('textDocument/completion', CompletionItems(trigger_characters=['.']))
-        """
-
-        def decorator(f):
-            # Validate
-            if feature_name is None or feature_name.strip() == "":
-                logger.error("Missing feature name.")
-                raise ValidationError("Feature name is required.")
-
-            # Add feature if not exists
-            if feature_name in self._features:
-                logger.error('Feature "%s" is already registered.', feature_name)
-                raise FeatureAlreadyRegisteredError(feature_name)
-
-            assign_help_attrs(f, feature_name, ATTR_FEATURE_TYPE)
-
-            wrapped = wrap_with_server(f, self.server)
-            # Assign help attributes for thread decorator
-            assign_help_attrs(wrapped, feature_name, ATTR_FEATURE_TYPE)
-
-            self._features[feature_name] = wrapped
-
-            if options:
-                options_type = get_method_options_type(feature_name)
-                if options_type and not is_instance(
-                    self.converter, options, options_type
-                ):
-                    raise TypeError(
-                        (
-                            f'Options of method "{feature_name}"'
-                            f" should be instance of type {options_type}"
-                        )
-                    )
-                self._feature_options[feature_name] = options
-
-            logger.info('Registered "%s" with options "%s"', feature_name, options)
-
-            return f
-
-        return decorator
-
-    @property
-    def feature_options(self) -> Dict:
-        """Returns feature options for registered features."""
-        return self._feature_options
-
-    @property
-    def features(self) -> Dict:
-        """Returns registered features"""
-        return self._features
-
-    def thread(self) -> Callable:
-        """Decorator that mark function to execute it in a thread."""
-
-        def decorator(f):
-            if asyncio.iscoroutinefunction(f):
-                raise ThreadDecoratorError(
-                    f'Thread decorator cannot be used with async functions "{f.__name__}"'
-                )
-
-            # Allow any decorator order
-            try:
-                reg_name = getattr(f, ATTR_REGISTERED_NAME)
-                reg_type = getattr(f, ATTR_REGISTERED_TYPE)
-
-                if reg_type is ATTR_FEATURE_TYPE:
-                    assign_thread_attr(self.features[reg_name])
-                elif reg_type is ATTR_COMMAND_TYPE:
-                    assign_thread_attr(self.commands[reg_name])
-
-            except AttributeError:
-                assign_thread_attr(f)
-
-            return f
-
-        return decorator
diff --git a/server/libs/pygls/lsp/__init__.py b/server/libs/pygls/lsp/__init__.py
deleted file mode 100644
index aa0725d..0000000
--- a/server/libs/pygls/lsp/__init__.py
+++ /dev/null
@@ -1,139 +0,0 @@
-############################################################################
-# Copyright(c) Open Law Library. All rights reserved.                      #
-# See ThirdPartyNotices.txt in the project root for additional notices.    #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-import cattrs
-from typing import Any, Callable, List, Optional, Union
-
-from lsprotocol.types import (
-    ALL_TYPES_MAP,
-    METHOD_TO_TYPES,
-    TEXT_DOCUMENT_DID_SAVE,
-    TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
-    TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL_DELTA,
-    TEXT_DOCUMENT_SEMANTIC_TOKENS_RANGE,
-    WORKSPACE_DID_CREATE_FILES,
-    WORKSPACE_DID_DELETE_FILES,
-    WORKSPACE_DID_RENAME_FILES,
-    WORKSPACE_WILL_CREATE_FILES,
-    WORKSPACE_WILL_DELETE_FILES,
-    WORKSPACE_WILL_RENAME_FILES,
-    FileOperationRegistrationOptions,
-    SaveOptions,
-    SemanticTokensLegend,
-    SemanticTokensRegistrationOptions,
-    ShowDocumentResult,
-)
-
-from pygls.exceptions import MethodTypeNotRegisteredError
-
-ConfigCallbackType = Callable[[List[Any]], None]
-ShowDocumentCallbackType = Callable[[ShowDocumentResult], None]
-
-METHOD_TO_OPTIONS = {
-    TEXT_DOCUMENT_DID_SAVE: SaveOptions,
-    TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL: Union[
-        SemanticTokensLegend, SemanticTokensRegistrationOptions
-    ],
-    TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL_DELTA: Union[
-        SemanticTokensLegend, SemanticTokensRegistrationOptions
-    ],
-    TEXT_DOCUMENT_SEMANTIC_TOKENS_RANGE: Union[
-        SemanticTokensLegend, SemanticTokensRegistrationOptions
-    ],
-    WORKSPACE_DID_CREATE_FILES: FileOperationRegistrationOptions,
-    WORKSPACE_DID_DELETE_FILES: FileOperationRegistrationOptions,
-    WORKSPACE_DID_RENAME_FILES: FileOperationRegistrationOptions,
-    WORKSPACE_WILL_CREATE_FILES: FileOperationRegistrationOptions,
-    WORKSPACE_WILL_DELETE_FILES: FileOperationRegistrationOptions,
-    WORKSPACE_WILL_RENAME_FILES: FileOperationRegistrationOptions,
-}
-
-
-def get_method_registration_options_type(
-    method_name, lsp_methods_map=METHOD_TO_TYPES
-) -> Optional[Any]:
-    """The type corresponding with a method's options when dynamically registering
-    capability for it."""
-
-    try:
-        return lsp_methods_map[method_name][3]
-    except KeyError:
-        raise MethodTypeNotRegisteredError(method_name)
-
-
-def get_method_options_type(
-    method_name, lsp_options_map=METHOD_TO_OPTIONS, lsp_methods_map=METHOD_TO_TYPES
-) -> Optional[Any]:
-    """Return the type corresponding with a method's ``ServerCapabilities`` fields.
-
-    In the majority of cases this simply means returning the ``Options``
-    type, which we can easily derive from the method's
-    ``RegistrationOptions`` type.
-
-    However, where the options are more involved (such as semantic tokens) and
-    ``pygls`` does some extra work to help derive the options for the user the type
-    has to be provided via the ``lsp_options_map``
-
-    Arguments:
-        method_name:
-            The lsp method name to retrieve the options for
-
-        lsp_options_map:
-            The map used to override the default options type finding behavior
-
-        lsp_methods_map:
-            The standard map used to look up the various method types.
-    """
-
-    options_type = lsp_options_map.get(method_name, None)
-    if options_type is not None:
-        return options_type
-
-    registration_type = get_method_registration_options_type(
-        method_name, lsp_methods_map
-    )
-    if registration_type is None:
-        return None
-
-    type_name = registration_type.__name__.replace("Registration", "")
-    options_type = ALL_TYPES_MAP.get(type_name, None)
-
-    if options_type is None:
-        raise MethodTypeNotRegisteredError(method_name)
-
-    return options_type
-
-
-def get_method_params_type(method_name, lsp_methods_map=METHOD_TO_TYPES):
-    try:
-        return lsp_methods_map[method_name][2]
-    except KeyError:
-        raise MethodTypeNotRegisteredError(method_name)
-
-
-def get_method_return_type(method_name, lsp_methods_map=METHOD_TO_TYPES):
-    try:
-        return lsp_methods_map[method_name][1]
-    except KeyError:
-        raise MethodTypeNotRegisteredError(method_name)
-
-
-def is_instance(cv: cattrs.Converter, o, t):
-    try:
-        cv.unstructure(o, t)
-        return True
-    except TypeError:
-        return False
diff --git a/server/libs/pygls/lsp/client.py b/server/libs/pygls/lsp/client.py
deleted file mode 100644
index c877fdb..0000000
--- a/server/libs/pygls/lsp/client.py
+++ /dev/null
@@ -1,1961 +0,0 @@
-# GENERATED FROM scripts/gen-client.py -- DO NOT EDIT
-# flake8: noqa
-from concurrent.futures import Future
-from lsprotocol import types
-from pygls.client import JsonRPCClient
-from pygls.protocol import LanguageServerProtocol
-from pygls.protocol import default_converter
-from typing import Any
-from typing import Callable
-from typing import List
-from typing import Optional
-from typing import Union
-
-
-class BaseLanguageClient(JsonRPCClient):
-
-    def __init__(
-        self,
-        name: str,
-        version: str,
-        protocol_cls=LanguageServerProtocol,
-        converter_factory=default_converter,
-        **kwargs,
-    ):
-        self.name = name
-        self.version = version
-        super().__init__(protocol_cls, converter_factory, **kwargs)
-
-    def call_hierarchy_incoming_calls(
-        self,
-        params: types.CallHierarchyIncomingCallsParams,
-        callback: Optional[Callable[[Optional[List[types.CallHierarchyIncomingCall]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`callHierarchy/incomingCalls` request.
-
-        A request to resolve the incoming calls for a given `CallHierarchyItem`.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("callHierarchy/incomingCalls", params, callback)
-
-    async def call_hierarchy_incoming_calls_async(
-        self,
-        params: types.CallHierarchyIncomingCallsParams,
-    ) -> Optional[List[types.CallHierarchyIncomingCall]]:
-        """Make a :lsp:`callHierarchy/incomingCalls` request.
-
-        A request to resolve the incoming calls for a given `CallHierarchyItem`.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("callHierarchy/incomingCalls", params)
-
-    def call_hierarchy_outgoing_calls(
-        self,
-        params: types.CallHierarchyOutgoingCallsParams,
-        callback: Optional[Callable[[Optional[List[types.CallHierarchyOutgoingCall]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`callHierarchy/outgoingCalls` request.
-
-        A request to resolve the outgoing calls for a given `CallHierarchyItem`.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("callHierarchy/outgoingCalls", params, callback)
-
-    async def call_hierarchy_outgoing_calls_async(
-        self,
-        params: types.CallHierarchyOutgoingCallsParams,
-    ) -> Optional[List[types.CallHierarchyOutgoingCall]]:
-        """Make a :lsp:`callHierarchy/outgoingCalls` request.
-
-        A request to resolve the outgoing calls for a given `CallHierarchyItem`.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("callHierarchy/outgoingCalls", params)
-
-    def code_action_resolve(
-        self,
-        params: types.CodeAction,
-        callback: Optional[Callable[[types.CodeAction], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`codeAction/resolve` request.
-
-        Request to resolve additional information for a given code action.The request's
-        parameter is of type {@link CodeAction} the response
-        is of type {@link CodeAction} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("codeAction/resolve", params, callback)
-
-    async def code_action_resolve_async(
-        self,
-        params: types.CodeAction,
-    ) -> types.CodeAction:
-        """Make a :lsp:`codeAction/resolve` request.
-
-        Request to resolve additional information for a given code action.The request's
-        parameter is of type {@link CodeAction} the response
-        is of type {@link CodeAction} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("codeAction/resolve", params)
-
-    def code_lens_resolve(
-        self,
-        params: types.CodeLens,
-        callback: Optional[Callable[[types.CodeLens], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`codeLens/resolve` request.
-
-        A request to resolve a command for a given code lens.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("codeLens/resolve", params, callback)
-
-    async def code_lens_resolve_async(
-        self,
-        params: types.CodeLens,
-    ) -> types.CodeLens:
-        """Make a :lsp:`codeLens/resolve` request.
-
-        A request to resolve a command for a given code lens.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("codeLens/resolve", params)
-
-    def completion_item_resolve(
-        self,
-        params: types.CompletionItem,
-        callback: Optional[Callable[[types.CompletionItem], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`completionItem/resolve` request.
-
-        Request to resolve additional information for a given completion item.The request's
-        parameter is of type {@link CompletionItem} the response
-        is of type {@link CompletionItem} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("completionItem/resolve", params, callback)
-
-    async def completion_item_resolve_async(
-        self,
-        params: types.CompletionItem,
-    ) -> types.CompletionItem:
-        """Make a :lsp:`completionItem/resolve` request.
-
-        Request to resolve additional information for a given completion item.The request's
-        parameter is of type {@link CompletionItem} the response
-        is of type {@link CompletionItem} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("completionItem/resolve", params)
-
-    def document_link_resolve(
-        self,
-        params: types.DocumentLink,
-        callback: Optional[Callable[[types.DocumentLink], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`documentLink/resolve` request.
-
-        Request to resolve additional information for a given document link. The request's
-        parameter is of type {@link DocumentLink} the response
-        is of type {@link DocumentLink} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("documentLink/resolve", params, callback)
-
-    async def document_link_resolve_async(
-        self,
-        params: types.DocumentLink,
-    ) -> types.DocumentLink:
-        """Make a :lsp:`documentLink/resolve` request.
-
-        Request to resolve additional information for a given document link. The request's
-        parameter is of type {@link DocumentLink} the response
-        is of type {@link DocumentLink} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("documentLink/resolve", params)
-
-    def initialize(
-        self,
-        params: types.InitializeParams,
-        callback: Optional[Callable[[types.InitializeResult], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`initialize` request.
-
-        The initialize request is sent from the client to the server.
-        It is sent once as the request after starting up the server.
-        The requests parameter is of type {@link InitializeParams}
-        the response if of type {@link InitializeResult} of a Thenable that
-        resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("initialize", params, callback)
-
-    async def initialize_async(
-        self,
-        params: types.InitializeParams,
-    ) -> types.InitializeResult:
-        """Make a :lsp:`initialize` request.
-
-        The initialize request is sent from the client to the server.
-        It is sent once as the request after starting up the server.
-        The requests parameter is of type {@link InitializeParams}
-        the response if of type {@link InitializeResult} of a Thenable that
-        resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("initialize", params)
-
-    def inlay_hint_resolve(
-        self,
-        params: types.InlayHint,
-        callback: Optional[Callable[[types.InlayHint], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`inlayHint/resolve` request.
-
-        A request to resolve additional properties for an inlay hint.
-        The request's parameter is of type {@link InlayHint}, the response is
-        of type {@link InlayHint} or a Thenable that resolves to such.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("inlayHint/resolve", params, callback)
-
-    async def inlay_hint_resolve_async(
-        self,
-        params: types.InlayHint,
-    ) -> types.InlayHint:
-        """Make a :lsp:`inlayHint/resolve` request.
-
-        A request to resolve additional properties for an inlay hint.
-        The request's parameter is of type {@link InlayHint}, the response is
-        of type {@link InlayHint} or a Thenable that resolves to such.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("inlayHint/resolve", params)
-
-    def shutdown(
-        self,
-        params: None,
-        callback: Optional[Callable[[None], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`shutdown` request.
-
-        A shutdown request is sent from the client to the server.
-        It is sent once when the client decides to shutdown the
-        server. The only notification that is sent after a shutdown request
-        is the exit event.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("shutdown", params, callback)
-
-    async def shutdown_async(
-        self,
-        params: None,
-    ) -> None:
-        """Make a :lsp:`shutdown` request.
-
-        A shutdown request is sent from the client to the server.
-        It is sent once when the client decides to shutdown the
-        server. The only notification that is sent after a shutdown request
-        is the exit event.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("shutdown", params)
-
-    def text_document_code_action(
-        self,
-        params: types.CodeActionParams,
-        callback: Optional[Callable[[Optional[List[Union[types.Command, types.CodeAction]]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/codeAction` request.
-
-        A request to provide commands for the given text document and range.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/codeAction", params, callback)
-
-    async def text_document_code_action_async(
-        self,
-        params: types.CodeActionParams,
-    ) -> Optional[List[Union[types.Command, types.CodeAction]]]:
-        """Make a :lsp:`textDocument/codeAction` request.
-
-        A request to provide commands for the given text document and range.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/codeAction", params)
-
-    def text_document_code_lens(
-        self,
-        params: types.CodeLensParams,
-        callback: Optional[Callable[[Optional[List[types.CodeLens]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/codeLens` request.
-
-        A request to provide code lens for the given text document.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/codeLens", params, callback)
-
-    async def text_document_code_lens_async(
-        self,
-        params: types.CodeLensParams,
-    ) -> Optional[List[types.CodeLens]]:
-        """Make a :lsp:`textDocument/codeLens` request.
-
-        A request to provide code lens for the given text document.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/codeLens", params)
-
-    def text_document_color_presentation(
-        self,
-        params: types.ColorPresentationParams,
-        callback: Optional[Callable[[List[types.ColorPresentation]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/colorPresentation` request.
-
-        A request to list all presentation for a color. The request's
-        parameter is of type {@link ColorPresentationParams} the
-        response is of type {@link ColorInformation ColorInformation[]} or a Thenable
-        that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/colorPresentation", params, callback)
-
-    async def text_document_color_presentation_async(
-        self,
-        params: types.ColorPresentationParams,
-    ) -> List[types.ColorPresentation]:
-        """Make a :lsp:`textDocument/colorPresentation` request.
-
-        A request to list all presentation for a color. The request's
-        parameter is of type {@link ColorPresentationParams} the
-        response is of type {@link ColorInformation ColorInformation[]} or a Thenable
-        that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/colorPresentation", params)
-
-    def text_document_completion(
-        self,
-        params: types.CompletionParams,
-        callback: Optional[Callable[[Union[List[types.CompletionItem], types.CompletionList, None]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/completion` request.
-
-        Request to request completion at a given text document position. The request's
-        parameter is of type {@link TextDocumentPosition} the response
-        is of type {@link CompletionItem CompletionItem[]} or {@link CompletionList}
-        or a Thenable that resolves to such.
-
-        The request can delay the computation of the {@link CompletionItem.detail `detail`}
-        and {@link CompletionItem.documentation `documentation`} properties to the `completionItem/resolve`
-        request. However, properties that are needed for the initial sorting and filtering, like `sortText`,
-        `filterText`, `insertText`, and `textEdit`, must not be changed during resolve.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/completion", params, callback)
-
-    async def text_document_completion_async(
-        self,
-        params: types.CompletionParams,
-    ) -> Union[List[types.CompletionItem], types.CompletionList, None]:
-        """Make a :lsp:`textDocument/completion` request.
-
-        Request to request completion at a given text document position. The request's
-        parameter is of type {@link TextDocumentPosition} the response
-        is of type {@link CompletionItem CompletionItem[]} or {@link CompletionList}
-        or a Thenable that resolves to such.
-
-        The request can delay the computation of the {@link CompletionItem.detail `detail`}
-        and {@link CompletionItem.documentation `documentation`} properties to the `completionItem/resolve`
-        request. However, properties that are needed for the initial sorting and filtering, like `sortText`,
-        `filterText`, `insertText`, and `textEdit`, must not be changed during resolve.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/completion", params)
-
-    def text_document_declaration(
-        self,
-        params: types.DeclarationParams,
-        callback: Optional[Callable[[Union[types.Location, List[types.Location], List[types.LocationLink], None]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/declaration` request.
-
-        A request to resolve the type definition locations of a symbol at a given text
-        document position. The request's parameter is of type {@link TextDocumentPositionParams}
-        the response is of type {@link Declaration} or a typed array of {@link DeclarationLink}
-        or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/declaration", params, callback)
-
-    async def text_document_declaration_async(
-        self,
-        params: types.DeclarationParams,
-    ) -> Union[types.Location, List[types.Location], List[types.LocationLink], None]:
-        """Make a :lsp:`textDocument/declaration` request.
-
-        A request to resolve the type definition locations of a symbol at a given text
-        document position. The request's parameter is of type {@link TextDocumentPositionParams}
-        the response is of type {@link Declaration} or a typed array of {@link DeclarationLink}
-        or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/declaration", params)
-
-    def text_document_definition(
-        self,
-        params: types.DefinitionParams,
-        callback: Optional[Callable[[Union[types.Location, List[types.Location], List[types.LocationLink], None]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/definition` request.
-
-        A request to resolve the definition location of a symbol at a given text
-        document position. The request's parameter is of type {@link TextDocumentPosition}
-        the response is of either type {@link Definition} or a typed array of
-        {@link DefinitionLink} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/definition", params, callback)
-
-    async def text_document_definition_async(
-        self,
-        params: types.DefinitionParams,
-    ) -> Union[types.Location, List[types.Location], List[types.LocationLink], None]:
-        """Make a :lsp:`textDocument/definition` request.
-
-        A request to resolve the definition location of a symbol at a given text
-        document position. The request's parameter is of type {@link TextDocumentPosition}
-        the response is of either type {@link Definition} or a typed array of
-        {@link DefinitionLink} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/definition", params)
-
-    def text_document_diagnostic(
-        self,
-        params: types.DocumentDiagnosticParams,
-        callback: Optional[Callable[[Union[types.RelatedFullDocumentDiagnosticReport, types.RelatedUnchangedDocumentDiagnosticReport]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/diagnostic` request.
-
-        The document diagnostic request definition.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/diagnostic", params, callback)
-
-    async def text_document_diagnostic_async(
-        self,
-        params: types.DocumentDiagnosticParams,
-    ) -> Union[types.RelatedFullDocumentDiagnosticReport, types.RelatedUnchangedDocumentDiagnosticReport]:
-        """Make a :lsp:`textDocument/diagnostic` request.
-
-        The document diagnostic request definition.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/diagnostic", params)
-
-    def text_document_document_color(
-        self,
-        params: types.DocumentColorParams,
-        callback: Optional[Callable[[List[types.ColorInformation]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/documentColor` request.
-
-        A request to list all color symbols found in a given text document. The request's
-        parameter is of type {@link DocumentColorParams} the
-        response is of type {@link ColorInformation ColorInformation[]} or a Thenable
-        that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/documentColor", params, callback)
-
-    async def text_document_document_color_async(
-        self,
-        params: types.DocumentColorParams,
-    ) -> List[types.ColorInformation]:
-        """Make a :lsp:`textDocument/documentColor` request.
-
-        A request to list all color symbols found in a given text document. The request's
-        parameter is of type {@link DocumentColorParams} the
-        response is of type {@link ColorInformation ColorInformation[]} or a Thenable
-        that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/documentColor", params)
-
-    def text_document_document_highlight(
-        self,
-        params: types.DocumentHighlightParams,
-        callback: Optional[Callable[[Optional[List[types.DocumentHighlight]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/documentHighlight` request.
-
-        Request to resolve a {@link DocumentHighlight} for a given
-        text document position. The request's parameter is of type {@link TextDocumentPosition}
-        the request response is an array of type {@link DocumentHighlight}
-        or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/documentHighlight", params, callback)
-
-    async def text_document_document_highlight_async(
-        self,
-        params: types.DocumentHighlightParams,
-    ) -> Optional[List[types.DocumentHighlight]]:
-        """Make a :lsp:`textDocument/documentHighlight` request.
-
-        Request to resolve a {@link DocumentHighlight} for a given
-        text document position. The request's parameter is of type {@link TextDocumentPosition}
-        the request response is an array of type {@link DocumentHighlight}
-        or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/documentHighlight", params)
-
-    def text_document_document_link(
-        self,
-        params: types.DocumentLinkParams,
-        callback: Optional[Callable[[Optional[List[types.DocumentLink]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/documentLink` request.
-
-        A request to provide document links
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/documentLink", params, callback)
-
-    async def text_document_document_link_async(
-        self,
-        params: types.DocumentLinkParams,
-    ) -> Optional[List[types.DocumentLink]]:
-        """Make a :lsp:`textDocument/documentLink` request.
-
-        A request to provide document links
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/documentLink", params)
-
-    def text_document_document_symbol(
-        self,
-        params: types.DocumentSymbolParams,
-        callback: Optional[Callable[[Union[List[types.SymbolInformation], List[types.DocumentSymbol], None]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/documentSymbol` request.
-
-        A request to list all symbols found in a given text document. The request's
-        parameter is of type {@link TextDocumentIdentifier} the
-        response is of type {@link SymbolInformation SymbolInformation[]} or a Thenable
-        that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/documentSymbol", params, callback)
-
-    async def text_document_document_symbol_async(
-        self,
-        params: types.DocumentSymbolParams,
-    ) -> Union[List[types.SymbolInformation], List[types.DocumentSymbol], None]:
-        """Make a :lsp:`textDocument/documentSymbol` request.
-
-        A request to list all symbols found in a given text document. The request's
-        parameter is of type {@link TextDocumentIdentifier} the
-        response is of type {@link SymbolInformation SymbolInformation[]} or a Thenable
-        that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/documentSymbol", params)
-
-    def text_document_folding_range(
-        self,
-        params: types.FoldingRangeParams,
-        callback: Optional[Callable[[Optional[List[types.FoldingRange]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/foldingRange` request.
-
-        A request to provide folding ranges in a document. The request's
-        parameter is of type {@link FoldingRangeParams}, the
-        response is of type {@link FoldingRangeList} or a Thenable
-        that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/foldingRange", params, callback)
-
-    async def text_document_folding_range_async(
-        self,
-        params: types.FoldingRangeParams,
-    ) -> Optional[List[types.FoldingRange]]:
-        """Make a :lsp:`textDocument/foldingRange` request.
-
-        A request to provide folding ranges in a document. The request's
-        parameter is of type {@link FoldingRangeParams}, the
-        response is of type {@link FoldingRangeList} or a Thenable
-        that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/foldingRange", params)
-
-    def text_document_formatting(
-        self,
-        params: types.DocumentFormattingParams,
-        callback: Optional[Callable[[Optional[List[types.TextEdit]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/formatting` request.
-
-        A request to format a whole document.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/formatting", params, callback)
-
-    async def text_document_formatting_async(
-        self,
-        params: types.DocumentFormattingParams,
-    ) -> Optional[List[types.TextEdit]]:
-        """Make a :lsp:`textDocument/formatting` request.
-
-        A request to format a whole document.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/formatting", params)
-
-    def text_document_hover(
-        self,
-        params: types.HoverParams,
-        callback: Optional[Callable[[Optional[types.Hover]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/hover` request.
-
-        Request to request hover information at a given text document position. The request's
-        parameter is of type {@link TextDocumentPosition} the response is of
-        type {@link Hover} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/hover", params, callback)
-
-    async def text_document_hover_async(
-        self,
-        params: types.HoverParams,
-    ) -> Optional[types.Hover]:
-        """Make a :lsp:`textDocument/hover` request.
-
-        Request to request hover information at a given text document position. The request's
-        parameter is of type {@link TextDocumentPosition} the response is of
-        type {@link Hover} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/hover", params)
-
-    def text_document_implementation(
-        self,
-        params: types.ImplementationParams,
-        callback: Optional[Callable[[Union[types.Location, List[types.Location], List[types.LocationLink], None]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/implementation` request.
-
-        A request to resolve the implementation locations of a symbol at a given text
-        document position. The request's parameter is of type {@link TextDocumentPositionParams}
-        the response is of type {@link Definition} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/implementation", params, callback)
-
-    async def text_document_implementation_async(
-        self,
-        params: types.ImplementationParams,
-    ) -> Union[types.Location, List[types.Location], List[types.LocationLink], None]:
-        """Make a :lsp:`textDocument/implementation` request.
-
-        A request to resolve the implementation locations of a symbol at a given text
-        document position. The request's parameter is of type {@link TextDocumentPositionParams}
-        the response is of type {@link Definition} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/implementation", params)
-
-    def text_document_inlay_hint(
-        self,
-        params: types.InlayHintParams,
-        callback: Optional[Callable[[Optional[List[types.InlayHint]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/inlayHint` request.
-
-        A request to provide inlay hints in a document. The request's parameter is of
-        type {@link InlayHintsParams}, the response is of type
-        {@link InlayHint InlayHint[]} or a Thenable that resolves to such.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/inlayHint", params, callback)
-
-    async def text_document_inlay_hint_async(
-        self,
-        params: types.InlayHintParams,
-    ) -> Optional[List[types.InlayHint]]:
-        """Make a :lsp:`textDocument/inlayHint` request.
-
-        A request to provide inlay hints in a document. The request's parameter is of
-        type {@link InlayHintsParams}, the response is of type
-        {@link InlayHint InlayHint[]} or a Thenable that resolves to such.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/inlayHint", params)
-
-    def text_document_inline_completion(
-        self,
-        params: types.InlineCompletionParams,
-        callback: Optional[Callable[[Union[types.InlineCompletionList, List[types.InlineCompletionItem], None]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/inlineCompletion` request.
-
-        A request to provide inline completions in a document. The request's parameter is of
-        type {@link InlineCompletionParams}, the response is of type
-        {@link InlineCompletion InlineCompletion[]} or a Thenable that resolves to such.
-
-        @since 3.18.0
-        @proposed
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/inlineCompletion", params, callback)
-
-    async def text_document_inline_completion_async(
-        self,
-        params: types.InlineCompletionParams,
-    ) -> Union[types.InlineCompletionList, List[types.InlineCompletionItem], None]:
-        """Make a :lsp:`textDocument/inlineCompletion` request.
-
-        A request to provide inline completions in a document. The request's parameter is of
-        type {@link InlineCompletionParams}, the response is of type
-        {@link InlineCompletion InlineCompletion[]} or a Thenable that resolves to such.
-
-        @since 3.18.0
-        @proposed
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/inlineCompletion", params)
-
-    def text_document_inline_value(
-        self,
-        params: types.InlineValueParams,
-        callback: Optional[Callable[[Optional[List[Union[types.InlineValueText, types.InlineValueVariableLookup, types.InlineValueEvaluatableExpression]]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/inlineValue` request.
-
-        A request to provide inline values in a document. The request's parameter is of
-        type {@link InlineValueParams}, the response is of type
-        {@link InlineValue InlineValue[]} or a Thenable that resolves to such.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/inlineValue", params, callback)
-
-    async def text_document_inline_value_async(
-        self,
-        params: types.InlineValueParams,
-    ) -> Optional[List[Union[types.InlineValueText, types.InlineValueVariableLookup, types.InlineValueEvaluatableExpression]]]:
-        """Make a :lsp:`textDocument/inlineValue` request.
-
-        A request to provide inline values in a document. The request's parameter is of
-        type {@link InlineValueParams}, the response is of type
-        {@link InlineValue InlineValue[]} or a Thenable that resolves to such.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/inlineValue", params)
-
-    def text_document_linked_editing_range(
-        self,
-        params: types.LinkedEditingRangeParams,
-        callback: Optional[Callable[[Optional[types.LinkedEditingRanges]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/linkedEditingRange` request.
-
-        A request to provide ranges that can be edited together.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/linkedEditingRange", params, callback)
-
-    async def text_document_linked_editing_range_async(
-        self,
-        params: types.LinkedEditingRangeParams,
-    ) -> Optional[types.LinkedEditingRanges]:
-        """Make a :lsp:`textDocument/linkedEditingRange` request.
-
-        A request to provide ranges that can be edited together.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/linkedEditingRange", params)
-
-    def text_document_moniker(
-        self,
-        params: types.MonikerParams,
-        callback: Optional[Callable[[Optional[List[types.Moniker]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/moniker` request.
-
-        A request to get the moniker of a symbol at a given text document position.
-        The request parameter is of type {@link TextDocumentPositionParams}.
-        The response is of type {@link Moniker Moniker[]} or `null`.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/moniker", params, callback)
-
-    async def text_document_moniker_async(
-        self,
-        params: types.MonikerParams,
-    ) -> Optional[List[types.Moniker]]:
-        """Make a :lsp:`textDocument/moniker` request.
-
-        A request to get the moniker of a symbol at a given text document position.
-        The request parameter is of type {@link TextDocumentPositionParams}.
-        The response is of type {@link Moniker Moniker[]} or `null`.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/moniker", params)
-
-    def text_document_on_type_formatting(
-        self,
-        params: types.DocumentOnTypeFormattingParams,
-        callback: Optional[Callable[[Optional[List[types.TextEdit]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/onTypeFormatting` request.
-
-        A request to format a document on type.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/onTypeFormatting", params, callback)
-
-    async def text_document_on_type_formatting_async(
-        self,
-        params: types.DocumentOnTypeFormattingParams,
-    ) -> Optional[List[types.TextEdit]]:
-        """Make a :lsp:`textDocument/onTypeFormatting` request.
-
-        A request to format a document on type.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/onTypeFormatting", params)
-
-    def text_document_prepare_call_hierarchy(
-        self,
-        params: types.CallHierarchyPrepareParams,
-        callback: Optional[Callable[[Optional[List[types.CallHierarchyItem]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/prepareCallHierarchy` request.
-
-        A request to result a `CallHierarchyItem` in a document at a given position.
-        Can be used as an input to an incoming or outgoing call hierarchy.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/prepareCallHierarchy", params, callback)
-
-    async def text_document_prepare_call_hierarchy_async(
-        self,
-        params: types.CallHierarchyPrepareParams,
-    ) -> Optional[List[types.CallHierarchyItem]]:
-        """Make a :lsp:`textDocument/prepareCallHierarchy` request.
-
-        A request to result a `CallHierarchyItem` in a document at a given position.
-        Can be used as an input to an incoming or outgoing call hierarchy.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/prepareCallHierarchy", params)
-
-    def text_document_prepare_rename(
-        self,
-        params: types.PrepareRenameParams,
-        callback: Optional[Callable[[Union[types.Range, types.PrepareRenameResult_Type1, types.PrepareRenameResult_Type2, None]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/prepareRename` request.
-
-        A request to test and perform the setup necessary for a rename.
-
-        @since 3.16 - support for default behavior
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/prepareRename", params, callback)
-
-    async def text_document_prepare_rename_async(
-        self,
-        params: types.PrepareRenameParams,
-    ) -> Union[types.Range, types.PrepareRenameResult_Type1, types.PrepareRenameResult_Type2, None]:
-        """Make a :lsp:`textDocument/prepareRename` request.
-
-        A request to test and perform the setup necessary for a rename.
-
-        @since 3.16 - support for default behavior
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/prepareRename", params)
-
-    def text_document_prepare_type_hierarchy(
-        self,
-        params: types.TypeHierarchyPrepareParams,
-        callback: Optional[Callable[[Optional[List[types.TypeHierarchyItem]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/prepareTypeHierarchy` request.
-
-        A request to result a `TypeHierarchyItem` in a document at a given position.
-        Can be used as an input to a subtypes or supertypes type hierarchy.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/prepareTypeHierarchy", params, callback)
-
-    async def text_document_prepare_type_hierarchy_async(
-        self,
-        params: types.TypeHierarchyPrepareParams,
-    ) -> Optional[List[types.TypeHierarchyItem]]:
-        """Make a :lsp:`textDocument/prepareTypeHierarchy` request.
-
-        A request to result a `TypeHierarchyItem` in a document at a given position.
-        Can be used as an input to a subtypes or supertypes type hierarchy.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/prepareTypeHierarchy", params)
-
-    def text_document_ranges_formatting(
-        self,
-        params: types.DocumentRangesFormattingParams,
-        callback: Optional[Callable[[Optional[List[types.TextEdit]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/rangesFormatting` request.
-
-        A request to format ranges in a document.
-
-        @since 3.18.0
-        @proposed
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/rangesFormatting", params, callback)
-
-    async def text_document_ranges_formatting_async(
-        self,
-        params: types.DocumentRangesFormattingParams,
-    ) -> Optional[List[types.TextEdit]]:
-        """Make a :lsp:`textDocument/rangesFormatting` request.
-
-        A request to format ranges in a document.
-
-        @since 3.18.0
-        @proposed
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/rangesFormatting", params)
-
-    def text_document_range_formatting(
-        self,
-        params: types.DocumentRangeFormattingParams,
-        callback: Optional[Callable[[Optional[List[types.TextEdit]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/rangeFormatting` request.
-
-        A request to format a range in a document.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/rangeFormatting", params, callback)
-
-    async def text_document_range_formatting_async(
-        self,
-        params: types.DocumentRangeFormattingParams,
-    ) -> Optional[List[types.TextEdit]]:
-        """Make a :lsp:`textDocument/rangeFormatting` request.
-
-        A request to format a range in a document.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/rangeFormatting", params)
-
-    def text_document_references(
-        self,
-        params: types.ReferenceParams,
-        callback: Optional[Callable[[Optional[List[types.Location]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/references` request.
-
-        A request to resolve project-wide references for the symbol denoted
-        by the given text document position. The request's parameter is of
-        type {@link ReferenceParams} the response is of type
-        {@link Location Location[]} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/references", params, callback)
-
-    async def text_document_references_async(
-        self,
-        params: types.ReferenceParams,
-    ) -> Optional[List[types.Location]]:
-        """Make a :lsp:`textDocument/references` request.
-
-        A request to resolve project-wide references for the symbol denoted
-        by the given text document position. The request's parameter is of
-        type {@link ReferenceParams} the response is of type
-        {@link Location Location[]} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/references", params)
-
-    def text_document_rename(
-        self,
-        params: types.RenameParams,
-        callback: Optional[Callable[[Optional[types.WorkspaceEdit]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/rename` request.
-
-        A request to rename a symbol.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/rename", params, callback)
-
-    async def text_document_rename_async(
-        self,
-        params: types.RenameParams,
-    ) -> Optional[types.WorkspaceEdit]:
-        """Make a :lsp:`textDocument/rename` request.
-
-        A request to rename a symbol.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/rename", params)
-
-    def text_document_selection_range(
-        self,
-        params: types.SelectionRangeParams,
-        callback: Optional[Callable[[Optional[List[types.SelectionRange]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/selectionRange` request.
-
-        A request to provide selection ranges in a document. The request's
-        parameter is of type {@link SelectionRangeParams}, the
-        response is of type {@link SelectionRange SelectionRange[]} or a Thenable
-        that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/selectionRange", params, callback)
-
-    async def text_document_selection_range_async(
-        self,
-        params: types.SelectionRangeParams,
-    ) -> Optional[List[types.SelectionRange]]:
-        """Make a :lsp:`textDocument/selectionRange` request.
-
-        A request to provide selection ranges in a document. The request's
-        parameter is of type {@link SelectionRangeParams}, the
-        response is of type {@link SelectionRange SelectionRange[]} or a Thenable
-        that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/selectionRange", params)
-
-    def text_document_semantic_tokens_full(
-        self,
-        params: types.SemanticTokensParams,
-        callback: Optional[Callable[[Optional[types.SemanticTokens]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/semanticTokens/full` request.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/semanticTokens/full", params, callback)
-
-    async def text_document_semantic_tokens_full_async(
-        self,
-        params: types.SemanticTokensParams,
-    ) -> Optional[types.SemanticTokens]:
-        """Make a :lsp:`textDocument/semanticTokens/full` request.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/semanticTokens/full", params)
-
-    def text_document_semantic_tokens_full_delta(
-        self,
-        params: types.SemanticTokensDeltaParams,
-        callback: Optional[Callable[[Union[types.SemanticTokens, types.SemanticTokensDelta, None]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/semanticTokens/full/delta` request.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/semanticTokens/full/delta", params, callback)
-
-    async def text_document_semantic_tokens_full_delta_async(
-        self,
-        params: types.SemanticTokensDeltaParams,
-    ) -> Union[types.SemanticTokens, types.SemanticTokensDelta, None]:
-        """Make a :lsp:`textDocument/semanticTokens/full/delta` request.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/semanticTokens/full/delta", params)
-
-    def text_document_semantic_tokens_range(
-        self,
-        params: types.SemanticTokensRangeParams,
-        callback: Optional[Callable[[Optional[types.SemanticTokens]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/semanticTokens/range` request.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/semanticTokens/range", params, callback)
-
-    async def text_document_semantic_tokens_range_async(
-        self,
-        params: types.SemanticTokensRangeParams,
-    ) -> Optional[types.SemanticTokens]:
-        """Make a :lsp:`textDocument/semanticTokens/range` request.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/semanticTokens/range", params)
-
-    def text_document_signature_help(
-        self,
-        params: types.SignatureHelpParams,
-        callback: Optional[Callable[[Optional[types.SignatureHelp]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/signatureHelp` request.
-
-
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/signatureHelp", params, callback)
-
-    async def text_document_signature_help_async(
-        self,
-        params: types.SignatureHelpParams,
-    ) -> Optional[types.SignatureHelp]:
-        """Make a :lsp:`textDocument/signatureHelp` request.
-
-
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/signatureHelp", params)
-
-    def text_document_type_definition(
-        self,
-        params: types.TypeDefinitionParams,
-        callback: Optional[Callable[[Union[types.Location, List[types.Location], List[types.LocationLink], None]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/typeDefinition` request.
-
-        A request to resolve the type definition locations of a symbol at a given text
-        document position. The request's parameter is of type {@link TextDocumentPositionParams}
-        the response is of type {@link Definition} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/typeDefinition", params, callback)
-
-    async def text_document_type_definition_async(
-        self,
-        params: types.TypeDefinitionParams,
-    ) -> Union[types.Location, List[types.Location], List[types.LocationLink], None]:
-        """Make a :lsp:`textDocument/typeDefinition` request.
-
-        A request to resolve the type definition locations of a symbol at a given text
-        document position. The request's parameter is of type {@link TextDocumentPositionParams}
-        the response is of type {@link Definition} or a Thenable that resolves to such.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/typeDefinition", params)
-
-    def text_document_will_save_wait_until(
-        self,
-        params: types.WillSaveTextDocumentParams,
-        callback: Optional[Callable[[Optional[List[types.TextEdit]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`textDocument/willSaveWaitUntil` request.
-
-        A document will save request is sent from the client to the server before
-        the document is actually saved. The request can return an array of TextEdits
-        which will be applied to the text document before it is saved. Please note that
-        clients might drop results if computing the text edits took too long or if a
-        server constantly fails on this request. This is done to keep the save fast and
-        reliable.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("textDocument/willSaveWaitUntil", params, callback)
-
-    async def text_document_will_save_wait_until_async(
-        self,
-        params: types.WillSaveTextDocumentParams,
-    ) -> Optional[List[types.TextEdit]]:
-        """Make a :lsp:`textDocument/willSaveWaitUntil` request.
-
-        A document will save request is sent from the client to the server before
-        the document is actually saved. The request can return an array of TextEdits
-        which will be applied to the text document before it is saved. Please note that
-        clients might drop results if computing the text edits took too long or if a
-        server constantly fails on this request. This is done to keep the save fast and
-        reliable.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("textDocument/willSaveWaitUntil", params)
-
-    def type_hierarchy_subtypes(
-        self,
-        params: types.TypeHierarchySubtypesParams,
-        callback: Optional[Callable[[Optional[List[types.TypeHierarchyItem]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`typeHierarchy/subtypes` request.
-
-        A request to resolve the subtypes for a given `TypeHierarchyItem`.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("typeHierarchy/subtypes", params, callback)
-
-    async def type_hierarchy_subtypes_async(
-        self,
-        params: types.TypeHierarchySubtypesParams,
-    ) -> Optional[List[types.TypeHierarchyItem]]:
-        """Make a :lsp:`typeHierarchy/subtypes` request.
-
-        A request to resolve the subtypes for a given `TypeHierarchyItem`.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("typeHierarchy/subtypes", params)
-
-    def type_hierarchy_supertypes(
-        self,
-        params: types.TypeHierarchySupertypesParams,
-        callback: Optional[Callable[[Optional[List[types.TypeHierarchyItem]]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`typeHierarchy/supertypes` request.
-
-        A request to resolve the supertypes for a given `TypeHierarchyItem`.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("typeHierarchy/supertypes", params, callback)
-
-    async def type_hierarchy_supertypes_async(
-        self,
-        params: types.TypeHierarchySupertypesParams,
-    ) -> Optional[List[types.TypeHierarchyItem]]:
-        """Make a :lsp:`typeHierarchy/supertypes` request.
-
-        A request to resolve the supertypes for a given `TypeHierarchyItem`.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("typeHierarchy/supertypes", params)
-
-    def workspace_diagnostic(
-        self,
-        params: types.WorkspaceDiagnosticParams,
-        callback: Optional[Callable[[types.WorkspaceDiagnosticReport], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`workspace/diagnostic` request.
-
-        The workspace diagnostic request definition.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("workspace/diagnostic", params, callback)
-
-    async def workspace_diagnostic_async(
-        self,
-        params: types.WorkspaceDiagnosticParams,
-    ) -> types.WorkspaceDiagnosticReport:
-        """Make a :lsp:`workspace/diagnostic` request.
-
-        The workspace diagnostic request definition.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("workspace/diagnostic", params)
-
-    def workspace_execute_command(
-        self,
-        params: types.ExecuteCommandParams,
-        callback: Optional[Callable[[Optional[Any]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`workspace/executeCommand` request.
-
-        A request send from the client to the server to execute a command. The request might return
-        a workspace edit which the client will apply to the workspace.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("workspace/executeCommand", params, callback)
-
-    async def workspace_execute_command_async(
-        self,
-        params: types.ExecuteCommandParams,
-    ) -> Optional[Any]:
-        """Make a :lsp:`workspace/executeCommand` request.
-
-        A request send from the client to the server to execute a command. The request might return
-        a workspace edit which the client will apply to the workspace.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("workspace/executeCommand", params)
-
-    def workspace_symbol(
-        self,
-        params: types.WorkspaceSymbolParams,
-        callback: Optional[Callable[[Union[List[types.SymbolInformation], List[types.WorkspaceSymbol], None]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`workspace/symbol` request.
-
-        A request to list project-wide symbols matching the query string given
-        by the {@link WorkspaceSymbolParams}. The response is
-        of type {@link SymbolInformation SymbolInformation[]} or a Thenable that
-        resolves to such.
-
-        @since 3.17.0 - support for WorkspaceSymbol in the returned data. Clients
-         need to advertise support for WorkspaceSymbols via the client capability
-         `workspace.symbol.resolveSupport`.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("workspace/symbol", params, callback)
-
-    async def workspace_symbol_async(
-        self,
-        params: types.WorkspaceSymbolParams,
-    ) -> Union[List[types.SymbolInformation], List[types.WorkspaceSymbol], None]:
-        """Make a :lsp:`workspace/symbol` request.
-
-        A request to list project-wide symbols matching the query string given
-        by the {@link WorkspaceSymbolParams}. The response is
-        of type {@link SymbolInformation SymbolInformation[]} or a Thenable that
-        resolves to such.
-
-        @since 3.17.0 - support for WorkspaceSymbol in the returned data. Clients
-         need to advertise support for WorkspaceSymbols via the client capability
-         `workspace.symbol.resolveSupport`.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("workspace/symbol", params)
-
-    def workspace_symbol_resolve(
-        self,
-        params: types.WorkspaceSymbol,
-        callback: Optional[Callable[[types.WorkspaceSymbol], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`workspaceSymbol/resolve` request.
-
-        A request to resolve the range inside the workspace
-        symbol's location.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("workspaceSymbol/resolve", params, callback)
-
-    async def workspace_symbol_resolve_async(
-        self,
-        params: types.WorkspaceSymbol,
-    ) -> types.WorkspaceSymbol:
-        """Make a :lsp:`workspaceSymbol/resolve` request.
-
-        A request to resolve the range inside the workspace
-        symbol's location.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("workspaceSymbol/resolve", params)
-
-    def workspace_will_create_files(
-        self,
-        params: types.CreateFilesParams,
-        callback: Optional[Callable[[Optional[types.WorkspaceEdit]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`workspace/willCreateFiles` request.
-
-        The will create files request is sent from the client to the server before files are actually
-        created as long as the creation is triggered from within the client.
-
-        The request can return a `WorkspaceEdit` which will be applied to workspace before the
-        files are created. Hence the `WorkspaceEdit` can not manipulate the content of the file
-        to be created.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("workspace/willCreateFiles", params, callback)
-
-    async def workspace_will_create_files_async(
-        self,
-        params: types.CreateFilesParams,
-    ) -> Optional[types.WorkspaceEdit]:
-        """Make a :lsp:`workspace/willCreateFiles` request.
-
-        The will create files request is sent from the client to the server before files are actually
-        created as long as the creation is triggered from within the client.
-
-        The request can return a `WorkspaceEdit` which will be applied to workspace before the
-        files are created. Hence the `WorkspaceEdit` can not manipulate the content of the file
-        to be created.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("workspace/willCreateFiles", params)
-
-    def workspace_will_delete_files(
-        self,
-        params: types.DeleteFilesParams,
-        callback: Optional[Callable[[Optional[types.WorkspaceEdit]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`workspace/willDeleteFiles` request.
-
-        The did delete files notification is sent from the client to the server when
-        files were deleted from within the client.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("workspace/willDeleteFiles", params, callback)
-
-    async def workspace_will_delete_files_async(
-        self,
-        params: types.DeleteFilesParams,
-    ) -> Optional[types.WorkspaceEdit]:
-        """Make a :lsp:`workspace/willDeleteFiles` request.
-
-        The did delete files notification is sent from the client to the server when
-        files were deleted from within the client.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("workspace/willDeleteFiles", params)
-
-    def workspace_will_rename_files(
-        self,
-        params: types.RenameFilesParams,
-        callback: Optional[Callable[[Optional[types.WorkspaceEdit]], None]] = None,
-    ) -> Future:
-        """Make a :lsp:`workspace/willRenameFiles` request.
-
-        The will rename files request is sent from the client to the server before files are actually
-        renamed as long as the rename is triggered from within the client.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return self.protocol.send_request("workspace/willRenameFiles", params, callback)
-
-    async def workspace_will_rename_files_async(
-        self,
-        params: types.RenameFilesParams,
-    ) -> Optional[types.WorkspaceEdit]:
-        """Make a :lsp:`workspace/willRenameFiles` request.
-
-        The will rename files request is sent from the client to the server before files are actually
-        renamed as long as the rename is triggered from within the client.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        return await self.protocol.send_request_async("workspace/willRenameFiles", params)
-
-    def cancel_request(self, params: types.CancelParams) -> None:
-        """Send a :lsp:`$/cancelRequest` notification.
-
-
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("$/cancelRequest", params)
-
-    def exit(self, params: None) -> None:
-        """Send a :lsp:`exit` notification.
-
-        The exit event is sent from the client to the server to
-        ask the server to exit its process.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("exit", params)
-
-    def initialized(self, params: types.InitializedParams) -> None:
-        """Send a :lsp:`initialized` notification.
-
-        The initialized notification is sent from the client to the
-        server after the client is fully initialized and the server
-        is allowed to send requests from the server to the client.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("initialized", params)
-
-    def notebook_document_did_change(self, params: types.DidChangeNotebookDocumentParams) -> None:
-        """Send a :lsp:`notebookDocument/didChange` notification.
-
-
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("notebookDocument/didChange", params)
-
-    def notebook_document_did_close(self, params: types.DidCloseNotebookDocumentParams) -> None:
-        """Send a :lsp:`notebookDocument/didClose` notification.
-
-        A notification sent when a notebook closes.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("notebookDocument/didClose", params)
-
-    def notebook_document_did_open(self, params: types.DidOpenNotebookDocumentParams) -> None:
-        """Send a :lsp:`notebookDocument/didOpen` notification.
-
-        A notification sent when a notebook opens.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("notebookDocument/didOpen", params)
-
-    def notebook_document_did_save(self, params: types.DidSaveNotebookDocumentParams) -> None:
-        """Send a :lsp:`notebookDocument/didSave` notification.
-
-        A notification sent when a notebook document is saved.
-
-        @since 3.17.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("notebookDocument/didSave", params)
-
-    def progress(self, params: types.ProgressParams) -> None:
-        """Send a :lsp:`$/progress` notification.
-
-
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("$/progress", params)
-
-    def set_trace(self, params: types.SetTraceParams) -> None:
-        """Send a :lsp:`$/setTrace` notification.
-
-
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("$/setTrace", params)
-
-    def text_document_did_change(self, params: types.DidChangeTextDocumentParams) -> None:
-        """Send a :lsp:`textDocument/didChange` notification.
-
-        The document change notification is sent from the client to the server to signal
-        changes to a text document.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("textDocument/didChange", params)
-
-    def text_document_did_close(self, params: types.DidCloseTextDocumentParams) -> None:
-        """Send a :lsp:`textDocument/didClose` notification.
-
-        The document close notification is sent from the client to the server when
-        the document got closed in the client. The document's truth now exists where
-        the document's uri points to (e.g. if the document's uri is a file uri the
-        truth now exists on disk). As with the open notification the close notification
-        is about managing the document's content. Receiving a close notification
-        doesn't mean that the document was open in an editor before. A close
-        notification requires a previous open notification to be sent.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("textDocument/didClose", params)
-
-    def text_document_did_open(self, params: types.DidOpenTextDocumentParams) -> None:
-        """Send a :lsp:`textDocument/didOpen` notification.
-
-        The document open notification is sent from the client to the server to signal
-        newly opened text documents. The document's truth is now managed by the client
-        and the server must not try to read the document's truth using the document's
-        uri. Open in this sense means it is managed by the client. It doesn't necessarily
-        mean that its content is presented in an editor. An open notification must not
-        be sent more than once without a corresponding close notification send before.
-        This means open and close notification must be balanced and the max open count
-        is one.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("textDocument/didOpen", params)
-
-    def text_document_did_save(self, params: types.DidSaveTextDocumentParams) -> None:
-        """Send a :lsp:`textDocument/didSave` notification.
-
-        The document save notification is sent from the client to the server when
-        the document got saved in the client.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("textDocument/didSave", params)
-
-    def text_document_will_save(self, params: types.WillSaveTextDocumentParams) -> None:
-        """Send a :lsp:`textDocument/willSave` notification.
-
-        A document will save notification is sent from the client to the server before
-        the document is actually saved.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("textDocument/willSave", params)
-
-    def window_work_done_progress_cancel(self, params: types.WorkDoneProgressCancelParams) -> None:
-        """Send a :lsp:`window/workDoneProgress/cancel` notification.
-
-        The `window/workDoneProgress/cancel` notification is sent from  the client to the server to cancel a progress
-        initiated on the server side.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("window/workDoneProgress/cancel", params)
-
-    def workspace_did_change_configuration(self, params: types.DidChangeConfigurationParams) -> None:
-        """Send a :lsp:`workspace/didChangeConfiguration` notification.
-
-        The configuration change notification is sent from the client to the server
-        when the client's configuration has changed. The notification contains
-        the changed configuration as defined by the language client.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("workspace/didChangeConfiguration", params)
-
-    def workspace_did_change_watched_files(self, params: types.DidChangeWatchedFilesParams) -> None:
-        """Send a :lsp:`workspace/didChangeWatchedFiles` notification.
-
-        The watched files notification is sent from the client to the server when
-        the client detects changes to file watched by the language client.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("workspace/didChangeWatchedFiles", params)
-
-    def workspace_did_change_workspace_folders(self, params: types.DidChangeWorkspaceFoldersParams) -> None:
-        """Send a :lsp:`workspace/didChangeWorkspaceFolders` notification.
-
-        The `workspace/didChangeWorkspaceFolders` notification is sent from the client to the server when the workspace
-        folder configuration changes.
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("workspace/didChangeWorkspaceFolders", params)
-
-    def workspace_did_create_files(self, params: types.CreateFilesParams) -> None:
-        """Send a :lsp:`workspace/didCreateFiles` notification.
-
-        The did create files notification is sent from the client to the server when
-        files were created from within the client.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("workspace/didCreateFiles", params)
-
-    def workspace_did_delete_files(self, params: types.DeleteFilesParams) -> None:
-        """Send a :lsp:`workspace/didDeleteFiles` notification.
-
-        The will delete files request is sent from the client to the server before files are actually
-        deleted as long as the deletion is triggered from within the client.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("workspace/didDeleteFiles", params)
-
-    def workspace_did_rename_files(self, params: types.RenameFilesParams) -> None:
-        """Send a :lsp:`workspace/didRenameFiles` notification.
-
-        The did rename files notification is sent from the client to the server when
-        files were renamed from within the client.
-
-        @since 3.16.0
-        """
-        if self.stopped:
-            raise RuntimeError("Client has been stopped.")
-
-        self.protocol.notify("workspace/didRenameFiles", params)
diff --git a/server/libs/pygls/progress.py b/server/libs/pygls/progress.py
deleted file mode 100644
index a2f0e5c..0000000
--- a/server/libs/pygls/progress.py
+++ /dev/null
@@ -1,79 +0,0 @@
-import asyncio
-from concurrent.futures import Future
-from typing import Dict
-
-from lsprotocol.types import (
-    PROGRESS,
-    WINDOW_WORK_DONE_PROGRESS_CREATE,
-    ProgressParams,
-    ProgressToken,
-    WorkDoneProgressBegin,
-    WorkDoneProgressEnd,
-    WorkDoneProgressReport,
-    WorkDoneProgressCreateParams,
-)
-from pygls.protocol import LanguageServerProtocol
-
-
-class Progress:
-    """A class for working with client's progress bar.
-
-    Attributes:
-        _lsp(LanguageServerProtocol): Language server protocol instance
-        tokens(dict): Holds futures for work done progress tokens that are
-            already registered. These futures will be cancelled if the client
-            sends a cancel work done process notification.
-    """
-
-    def __init__(self, lsp: LanguageServerProtocol) -> None:
-        self._lsp = lsp
-
-        self.tokens: Dict[ProgressToken, Future] = {}
-
-    def _check_token_registered(self, token: ProgressToken) -> None:
-        if token in self.tokens:
-            raise Exception("Token is already registered!")
-
-    def _register_token(self, token: ProgressToken) -> None:
-        self.tokens[token] = Future()
-
-    def create(self, token: ProgressToken, callback=None) -> Future:
-        """Create a server initiated work done progress."""
-        self._check_token_registered(token)
-
-        def on_created(*args, **kwargs):
-            self._register_token(token)
-            if callback is not None:
-                callback(*args, **kwargs)
-
-        return self._lsp.send_request(
-            WINDOW_WORK_DONE_PROGRESS_CREATE,
-            WorkDoneProgressCreateParams(token=token),
-            on_created,
-        )
-
-    async def create_async(self, token: ProgressToken) -> asyncio.Future:
-        """Create a server initiated work done progress."""
-        self._check_token_registered(token)
-
-        result = await self._lsp.send_request_async(
-            WINDOW_WORK_DONE_PROGRESS_CREATE,
-            WorkDoneProgressCreateParams(token=token),
-        )
-        self._register_token(token)
-        return result
-
-    def begin(self, token: ProgressToken, value: WorkDoneProgressBegin) -> None:
-        """Notify beginning of work."""
-        # Register cancellation future for the case of client initiated progress
-        self.tokens.setdefault(token, Future())
-
-        return self._lsp.notify(PROGRESS, ProgressParams(token=token, value=value))
-
-    def report(self, token: ProgressToken, value: WorkDoneProgressReport) -> None:
-        """Notify progress of work."""
-        self._lsp.notify(PROGRESS, ProgressParams(token=token, value=value))
-
-    def end(self, token: ProgressToken, value: WorkDoneProgressEnd) -> None:
-        """Notify end of work."""
-        self._lsp.notify(PROGRESS, ProgressParams(token=token, value=value))
diff --git a/server/libs/pygls/protocol/__init__.py b/server/libs/pygls/protocol/__init__.py
deleted file mode 100644
index 1a30b48..0000000
--- a/server/libs/pygls/protocol/__init__.py
+++ /dev/null
@@ -1,78 +0,0 @@
-import json
-from typing import Any
-
-from collections import namedtuple
-
-from lsprotocol import converters
-
-from pygls.protocol.json_rpc import (
-    JsonRPCNotification,
-    JsonRPCProtocol,
-    JsonRPCRequestMessage,
-    JsonRPCResponseMessage,
-)
-from pygls.protocol.language_server import LanguageServerProtocol, lsp_method
-from pygls.protocol.lsp_meta import LSPMeta, call_user_feature
-
-
-def _dict_to_object(d: Any):
-    """Create nested objects (namedtuple) from dict."""
-
-    if d is None:
-        return None
-
-    if not isinstance(d, dict):
-        return d
-
-    type_name = d.pop("type_name", "Object")
-    return json.loads(
-        json.dumps(d),
-        object_hook=lambda p: namedtuple(type_name, p.keys(), rename=True)(*p.values()),
-    )
-
-
-def _params_field_structure_hook(obj, cls):
-    if "params" in obj:
-        obj["params"] = _dict_to_object(obj["params"])
-
-    return cls(**obj)
-
-
-def _result_field_structure_hook(obj, cls):
-    if "result" in obj:
-        obj["result"] = _dict_to_object(obj["result"])
-
-    return cls(**obj)
-
-
-def default_converter():
-    """Default converter factory function."""
-
-    converter = converters.get_converter()
-    converter.register_structure_hook(
-        JsonRPCRequestMessage, _params_field_structure_hook
-    )
-
-    converter.register_structure_hook(
-        JsonRPCResponseMessage, _result_field_structure_hook
-    )
-
-    converter.register_structure_hook(JsonRPCNotification, _params_field_structure_hook)
-
-    return converter
-
-
-__all__ = (
-    "JsonRPCProtocol",
-    "LanguageServerProtocol",
-    "JsonRPCRequestMessage",
-    "JsonRPCResponseMessage",
-    "JsonRPCNotification",
-    "LSPMeta",
-    "call_user_feature",
-    "_dict_to_object",
-    "_params_field_structure_hook",
-    "_result_field_structure_hook",
-    "default_converter",
-    "lsp_method",
-)
diff --git a/server/libs/pygls/protocol/json_rpc.py b/server/libs/pygls/protocol/json_rpc.py
deleted file mode 100644
index 75a4b34..0000000
--- a/server/libs/pygls/protocol/json_rpc.py
+++ /dev/null
@@ -1,560 +0,0 @@
-############################################################################
-# Copyright(c) Open Law Library. All rights reserved.                      #
-# See ThirdPartyNotices.txt in the project root for additional notices.    #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-from __future__ import annotations
-import asyncio
-import enum
-import json
-import logging
-import re
-import sys
-import uuid
-import traceback
-from concurrent.futures import Future
-from functools import partial
-from typing import (
-    Any,
-    Dict,
-    List,
-    Optional,
-    Type,
-    Union,
-    TYPE_CHECKING,
-)
-
-if TYPE_CHECKING:
-    from pygls.server import LanguageServer, WebSocketTransportAdapter
-
-
-import attrs
-from cattrs.errors import ClassValidationError
-
-from lsprotocol.types import (
-    CANCEL_REQUEST,
-    EXIT,
-    WORKSPACE_EXECUTE_COMMAND,
-    ResponseError,
-    ResponseErrorMessage,
-)
-
-from pygls.exceptions import (
-    JsonRpcException,
-    JsonRpcInternalError,
-    JsonRpcInvalidParams,
-    JsonRpcMethodNotFound,
-    JsonRpcRequestCancelled,
-    FeatureNotificationError,
-    FeatureRequestError,
-)
-from pygls.feature_manager import FeatureManager, is_thread_function
-
-logger = logging.getLogger(__name__)
-
-
-@attrs.define
-class JsonRPCNotification:
-    """A class that represents a generic json rpc notification message.
-    Used as a fallback for unknown types.
-    """
-
-    method: str
-    jsonrpc: str
-    params: Any
-
-
-@attrs.define
-class JsonRPCRequestMessage:
-    """A class that represents a generic json rpc request message.
-    Used as a fallback for unknown types.
-    """
-
-    id: Union[int, str]
-    method: str
-    jsonrpc: str
-    params: Any
-
-
-@attrs.define
-class JsonRPCResponseMessage:
-    """A class that represents a generic json rpc response message.
-    Used as a fallback for unknown types.
-    """
-
-    id: Union[int, str]
-    jsonrpc: str
-    result: Any
-
-
-class JsonRPCProtocol(asyncio.Protocol):
-    """Json RPC protocol implementation using on top of `asyncio.Protocol`.
-
-    Specification of the protocol can be found here:
-        https://www.jsonrpc.org/specification
-
-    This class provides bidirectional communication which is needed for LSP.
-    """
-
-    CHARSET = "utf-8"
-    CONTENT_TYPE = "application/vscode-jsonrpc"
-
-    MESSAGE_PATTERN = re.compile(
-        rb"^(?:[^\r\n]+\r\n)*"
-        + rb"Content-Length: (?P\d+)\r\n"
-        + rb"(?:[^\r\n]+\r\n)*\r\n"
-        + rb"(?P{.*)",
-        re.DOTALL,
-    )
-
-    VERSION = "2.0"
-
-    def __init__(self, server: LanguageServer, converter):
-        self._server = server
-        self._converter = converter
-
-        self._shutdown = False
-
-        # Book keeping for in-flight requests
-        self._request_futures: Dict[str, Future[Any]] = {}
-        self._result_types: Dict[str, Any] = {}
-
-        self.fm = FeatureManager(server, converter)
-        self.transport: Optional[
-            Union[asyncio.WriteTransport, WebSocketTransportAdapter]
-        ] = None
-        self._message_buf: List[bytes] = []
-
-        self._send_only_body = False
-
-    def __call__(self):
-        return self
-
-    def _execute_notification(self, handler, *params):
-        """Executes notification message handler."""
-        if asyncio.iscoroutinefunction(handler):
-            future = asyncio.ensure_future(handler(*params))
-            future.add_done_callback(self._execute_notification_callback)
-        else:
-            if is_thread_function(handler):
-                self._server.thread_pool.apply_async(handler, (*params,))
-            else:
-                handler(*params)
-
-    def _execute_notification_callback(self, future):
-        """Success callback used for coroutine notification message."""
-        if future.exception():
-            try:
-                raise future.exception()
-            except Exception:
-                error = JsonRpcInternalError.of(sys.exc_info())
-                logger.exception('Exception occurred in notification: "%s"', error)
-
-            # Revisit. Client does not support response with msg_id = None
-            # https://stackoverflow.com/questions/31091376/json-rpc-2-0-allow-notifications-to-have-an-error-response
-            # self._send_response(None, error=error)
-
-    def _execute_request(self, msg_id, handler, params):
-        """Executes request message handler."""
-
-        if asyncio.iscoroutinefunction(handler):
-            future = asyncio.ensure_future(handler(params))
-            self._request_futures[msg_id] = future
-            future.add_done_callback(partial(self._execute_request_callback, msg_id))
-        else:
-            # Can't be canceled
-            if is_thread_function(handler):
-                self._server.thread_pool.apply_async(
-                    handler,
-                    (params,),
-                    callback=partial(
-                        self._send_response,
-                        msg_id,
-                    ),
-                    error_callback=partial(self._execute_request_err_callback, msg_id),
-                )
-            else:
-                self._send_response(msg_id, handler(params))
-
-    def _execute_request_callback(self, msg_id, future):
-        """Success callback used for coroutine request message."""
-        try:
-            if not future.cancelled():
-                self._send_response(msg_id, result=future.result())
-            else:
-                self._send_response(
-                    msg_id,
-                    error=JsonRpcRequestCancelled(
-                        f'Request with id "{msg_id}" is canceled'
-                    ).to_response_error(),
-                )
-            self._request_futures.pop(msg_id, None)
-        except Exception:
-            error = JsonRpcInternalError.of(sys.exc_info())
-            logger.exception('Exception occurred for message "%s": %s', msg_id, error)
-            self._send_response(msg_id, error=error.to_response_error())
-
-    def _execute_request_err_callback(self, msg_id, exc):
-        """Error callback used for coroutine request message."""
-        exc_info = (type(exc), exc, None)
-        error = JsonRpcInternalError.of(exc_info)
-        logger.exception('Exception occurred for message "%s": %s', msg_id, error)
-        self._send_response(msg_id, error=error.to_response_error())
-
-    def _get_handler(self, feature_name):
-        """Returns builtin or used defined feature by name if exists."""
-        try:
-            return self.fm.builtin_features[feature_name]
-        except KeyError:
-            try:
-                return self.fm.features[feature_name]
-            except KeyError:
-                raise JsonRpcMethodNotFound.of(feature_name)
-
-    def _handle_cancel_notification(self, msg_id):
-        """Handles a cancel notification from the client."""
-        future = self._request_futures.pop(msg_id, None)
-
-        if not future:
-            logger.warning('Cancel notification for unknown message id "%s"', msg_id)
-            return
-
-        # Will only work if the request hasn't started executing
-        if future.cancel():
-            logger.info('Cancelled request with id "%s"', msg_id)
-
-    def _handle_notification(self, method_name, params):
-        """Handles a notification from the client."""
-        if method_name == CANCEL_REQUEST:
-            self._handle_cancel_notification(params.id)
-            return
-
-        try:
-            handler = self._get_handler(method_name)
-            self._execute_notification(handler, params)
-        except (KeyError, JsonRpcMethodNotFound):
-            logger.warning('Ignoring notification for unknown method "%s"', method_name)
-        except Exception as error:
-            logger.exception(
-                'Failed to handle notification "%s": %s',
-                method_name,
-                params,
-                exc_info=True,
-            )
-            self._server._report_server_error(error, FeatureNotificationError)
-
-    def _handle_request(self, msg_id, method_name, params):
-        """Handles a request from the client."""
-        try:
-            handler = self._get_handler(method_name)
-
-            # workspace/executeCommand is a special case
-            if method_name == WORKSPACE_EXECUTE_COMMAND:
-                handler(params, msg_id)
-            else:
-                self._execute_request(msg_id, handler, params)
-
-        except JsonRpcException as error:
-            logger.exception(
-                "Failed to handle request %s %s %s",
-                msg_id,
-                method_name,
-                params,
-                exc_info=True,
-            )
-            self._send_response(msg_id, None, error.to_response_error())
-            self._server._report_server_error(error, FeatureRequestError)
-        except Exception as error:
-            logger.exception(
-                "Failed to handle request %s %s %s",
-                msg_id,
-                method_name,
-                params,
-                exc_info=True,
-            )
-            err = JsonRpcInternalError.of(sys.exc_info()).to_response_error()
-            self._send_response(msg_id, None, err)
-            self._server._report_server_error(error, FeatureRequestError)
-
-    def _handle_response(self, msg_id, result=None, error=None):
-        """Handles a response from the client."""
-        future = self._request_futures.pop(msg_id, None)
-
-        if not future:
-            logger.warning('Received response to unknown message id "%s"', msg_id)
-            return
-
-        if error is not None:
-            logger.debug('Received error response to message "%s": %s', msg_id, error)
-            future.set_exception(JsonRpcException.from_error(error))
-        else:
-            logger.debug('Received result for message "%s": %s', msg_id, result)
-            future.set_result(result)
-
-    def _serialize_message(self, data):
-        """Function used to serialize data sent to the client."""
-
-        if hasattr(data, "__attrs_attrs__"):
-            return self._converter.unstructure(data)
-
-        if isinstance(data, enum.Enum):
-            return data.value
-
-        return data.__dict__
-
-    def _deserialize_message(self, data):
-        """Function used to deserialize data recevied from the client."""
-
-        if "jsonrpc" not in data:
-            return data
-
-        try:
-            if "id" in data:
-                if "error" in data:
-                    return self._converter.structure(data, ResponseErrorMessage)
-                elif "method" in data:
-                    request_type = (
-                        self.get_message_type(data["method"]) or JsonRPCRequestMessage
-                    )
-                    return self._converter.structure(data, request_type)
-                else:
-                    response_type = (
-                        self._result_types.pop(data["id"]) or JsonRPCResponseMessage
-                    )
-                    return self._converter.structure(data, response_type)
-
-            else:
-                method = data.get("method", "")
-                notification_type = self.get_message_type(method) or JsonRPCNotification
-                return self._converter.structure(data, notification_type)
-
-        except ClassValidationError as exc:
-            logger.error("Unable to deserialize message\n%s", traceback.format_exc())
-            raise JsonRpcInvalidParams() from exc
-
-        except Exception as exc:
-            logger.error("Unable to deserialize message\n%s", traceback.format_exc())
-            raise JsonRpcInternalError() from exc
-
-    def _procedure_handler(self, message):
-        """Delegates message to handlers depending on message type."""
-
-        if message.jsonrpc != JsonRPCProtocol.VERSION:
-            logger.warning('Unknown message "%s"', message)
-            return
-
-        if self._shutdown and getattr(message, "method", "") != EXIT:
-            logger.warning("Server shutting down. No more requests!")
-            return
-
-        if hasattr(message, "method"):
-            if hasattr(message, "id"):
-                logger.debug("Request message received.")
-                self._handle_request(message.id, message.method, message.params)
-            else:
-                logger.debug("Notification message received.")
-                self._handle_notification(message.method, message.params)
-        else:
-            if hasattr(message, "error"):
-                logger.debug("Error message received.")
-                self._handle_response(message.id, None, message.error)
-            else:
-                logger.debug("Response message received.")
-                self._handle_response(message.id, message.result)
-
-    def _send_data(self, data):
-        """Sends data to the client."""
-        if not data:
-            return
-
-        if self.transport is None:
-            logger.error("Unable to send data, no available transport!")
-            return
-
-        try:
-            body = json.dumps(data, default=self._serialize_message)
-            logger.info("Sending data: %s", body)
-
-            if self._send_only_body:
-                # Mypy/Pyright seem to think `write()` wants `"bytes | bytearray | memoryview"`
-                # But runtime errors with anything but `str`.
-                self.transport.write(body)  # type: ignore
-                return
-
-            header = (
-                f"Content-Length: {len(body)}\r\n"
-                f"Content-Type: {self.CONTENT_TYPE}; charset={self.CHARSET}\r\n\r\n"
-            ).encode(self.CHARSET)
-
-            self.transport.write(header + body.encode(self.CHARSET))
-        except Exception as error:
-            logger.exception("Error sending data", exc_info=True)
-            self._server._report_server_error(error, JsonRpcInternalError)
-
-    def _send_response(
-        self, msg_id, result=None, error: Union[ResponseError, None] = None
-    ):
-        """Sends a JSON RPC response to the client.
-
-        Args:
-            msg_id(str): Id from request
-            result(any): Result returned by handler
-            error(any): Error returned by handler
-        """
-
-        if error is not None:
-            response = ResponseErrorMessage(id=msg_id, error=error)
-
-        else:
-            response_type = self._result_types.pop(msg_id, JsonRPCResponseMessage)
-            response = response_type(
-                id=msg_id, result=result, jsonrpc=JsonRPCProtocol.VERSION
-            )
-
-        self._send_data(response)
-
-    def connection_lost(self, exc):
-        """Method from base class, called when connection is lost, in which case we
-        want to shutdown the server's process as well.
-        """
-        logger.error("Connection to the client is lost! Shutting down the server.")
-        sys.exit(1)
-
-    def connection_made(  # type: ignore # see: https://github.com/python/typeshed/issues/3021
-        self,
-        transport: asyncio.Transport,
-    ):
-        """Method from base class, called when connection is established"""
-        self.transport = transport
-
-    def data_received(self, data: bytes):
-        try:
-            self._data_received(data)
-        except Exception as error:
-            logger.exception("Error receiving data", exc_info=True)
-            self._server._report_server_error(error, JsonRpcInternalError)
-
-    def _data_received(self, data: bytes):
-        """Method from base class, called when server receives the data"""
-        logger.debug("Received %r", data)
-
-        while len(data):
-            # Append the incoming chunk to the message buffer
-            self._message_buf.append(data)
-
-            # Look for the body of the message
-            message = b"".join(self._message_buf)
-            found = JsonRPCProtocol.MESSAGE_PATTERN.fullmatch(message)
-
-            body = found.group("body") if found else b""
-            length = int(found.group("length")) if found else 1
-
-            if len(body) < length:
-                # Message is incomplete; bail until more data arrives
-                return
-
-            # Message is complete;
-            # extract the body and any remaining data,
-            # and reset the buffer for the next message
-            body, data = body[:length], body[length:]
-            self._message_buf = []
-
-            # Parse the body
-            self._procedure_handler(
-                json.loads(
-                    body.decode(self.CHARSET), object_hook=self._deserialize_message
-                )
-            )
-
-    def get_message_type(self, method: str) -> Optional[Type]:
-        """Return the type definition of the message associated with the given method."""
-        return None
-
-    def get_result_type(self, method: str) -> Optional[Type]:
-        """Return the type definition of the result associated with the given method."""
-        return None
-
-    def notify(self, method: str, params=None):
-        """Sends a JSON RPC notification to the client."""
-
-        logger.debug("Sending notification: '%s' %s", method, params)
-
-        notification_type = self.get_message_type(method) or JsonRPCNotification
-        notification = notification_type(
-            method=method, params=params, jsonrpc=JsonRPCProtocol.VERSION
-        )
-
-        self._send_data(notification)
-
-    def send_request(self, method, params=None, callback=None, msg_id=None):
-        """Sends a JSON RPC request to the client.
-
-        Args:
-            method(str): The method name of the message to send
-            params(any): The payload of the message
-
-        Returns:
-            Future that will be resolved once a response has been received
-        """
-
-        if msg_id is None:
-            msg_id = str(uuid.uuid4())
-
-        request_type = self.get_message_type(method) or JsonRPCRequestMessage
-        logger.debug('Sending request with id "%s": %s %s', msg_id, method, params)
-
-        request = request_type(
-            id=msg_id,
-            method=method,
-            params=params,
-            jsonrpc=JsonRPCProtocol.VERSION,
-        )
-
-        future = Future()  # type: ignore[var-annotated]
-        # If callback function is given, call it when result is received
-        if callback:
-
-            def wrapper(future: Future):
-                result = future.result()
-                logger.info("Client response for %s received: %s", params, result)
-                callback(result)
-
-            future.add_done_callback(wrapper)
-
-        self._request_futures[msg_id] = future
-        self._result_types[msg_id] = self.get_result_type(method)
-
-        self._send_data(request)
-
-        return future
-
-    def send_request_async(self, method, params=None, msg_id=None):
-        """Calls `send_request` and wraps `concurrent.futures.Future` with
-        `asyncio.Future` so it can be used with `await` keyword.
-
-        Args:
-            method(str): The method name of the message to send
-            params(any): The payload of the message
-            msg_id(str|int): Optional, message id
-
-        Returns:
-            `asyncio.Future` that can be awaited
-        """
-        return asyncio.wrap_future(
-            self.send_request(method, params=params, msg_id=msg_id)
-        )
-
-    def thread(self):
-        """Decorator that mark function to execute it in a thread."""
-        return self.fm.thread()
diff --git a/server/libs/pygls/protocol/language_server.py b/server/libs/pygls/protocol/language_server.py
deleted file mode 100644
index 42b1319..0000000
--- a/server/libs/pygls/protocol/language_server.py
+++ /dev/null
@@ -1,569 +0,0 @@
-############################################################################
-# Copyright(c) Open Law Library. All rights reserved.                      #
-# See ThirdPartyNotices.txt in the project root for additional notices.    #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-from __future__ import annotations
-import asyncio
-import json
-import logging
-import sys
-from concurrent.futures import Future
-from functools import lru_cache
-from itertools import zip_longest
-from typing import (
-    Callable,
-    List,
-    Optional,
-    Type,
-    TypeVar,
-    Union,
-)
-
-
-from pygls.capabilities import ServerCapabilitiesBuilder
-from pygls.lsp import ConfigCallbackType, ShowDocumentCallbackType
-from lsprotocol.types import (
-    CLIENT_REGISTER_CAPABILITY,
-    CLIENT_UNREGISTER_CAPABILITY,
-    EXIT,
-    INITIALIZE,
-    INITIALIZED,
-    METHOD_TO_TYPES,
-    NOTEBOOK_DOCUMENT_DID_CHANGE,
-    NOTEBOOK_DOCUMENT_DID_CLOSE,
-    NOTEBOOK_DOCUMENT_DID_OPEN,
-    LOG_TRACE,
-    SET_TRACE,
-    SHUTDOWN,
-    TEXT_DOCUMENT_DID_CHANGE,
-    TEXT_DOCUMENT_DID_CLOSE,
-    TEXT_DOCUMENT_DID_OPEN,
-    TEXT_DOCUMENT_PUBLISH_DIAGNOSTICS,
-    WINDOW_LOG_MESSAGE,
-    WINDOW_SHOW_DOCUMENT,
-    WINDOW_SHOW_MESSAGE,
-    WINDOW_WORK_DONE_PROGRESS_CANCEL,
-    WORKSPACE_APPLY_EDIT,
-    WORKSPACE_CONFIGURATION,
-    WORKSPACE_DID_CHANGE_WORKSPACE_FOLDERS,
-    WORKSPACE_EXECUTE_COMMAND,
-    WORKSPACE_SEMANTIC_TOKENS_REFRESH,
-)
-from lsprotocol.types import (
-    ApplyWorkspaceEditParams,
-    Diagnostic,
-    DidChangeNotebookDocumentParams,
-    DidChangeTextDocumentParams,
-    DidChangeWorkspaceFoldersParams,
-    DidCloseNotebookDocumentParams,
-    DidCloseTextDocumentParams,
-    DidOpenNotebookDocumentParams,
-    DidOpenTextDocumentParams,
-    ExecuteCommandParams,
-    InitializeParams,
-    InitializeResult,
-    LogMessageParams,
-    LogTraceParams,
-    MessageType,
-    PublishDiagnosticsParams,
-    RegistrationParams,
-    SetTraceParams,
-    ShowDocumentParams,
-    ShowMessageParams,
-    TraceValues,
-    UnregistrationParams,
-    WorkspaceApplyEditResponse,
-    WorkspaceEdit,
-    InitializeResultServerInfoType,
-    WorkspaceConfigurationParams,
-    WorkDoneProgressCancelParams,
-)
-from pygls.protocol.json_rpc import JsonRPCProtocol
-from pygls.protocol.lsp_meta import LSPMeta
-from pygls.uris import from_fs_path
-from pygls.workspace import Workspace
-
-
-F = TypeVar("F", bound=Callable)
-
-logger = logging.getLogger(__name__)
-
-
-def lsp_method(method_name: str) -> Callable[[F], F]:
-    def decorator(f: F) -> F:
-        f.method_name = method_name  # type: ignore[attr-defined]
-        return f
-
-    return decorator
-
-
-class LanguageServerProtocol(JsonRPCProtocol, metaclass=LSPMeta):
-    """A class that represents language server protocol.
-
-    It contains implementations for generic LSP features.
-
-    Attributes:
-        workspace(Workspace): In memory workspace
-    """
-
-    def __init__(self, server, converter):
-        super().__init__(server, converter)
-
-        self._workspace: Optional[Workspace] = None
-        self.trace = None
-
-        from pygls.progress import Progress
-
-        self.progress = Progress(self)
-
-        self.server_info = InitializeResultServerInfoType(
-            name=server.name,
-            version=server.version,
-        )
-
-        self._register_builtin_features()
-
-    def _register_builtin_features(self):
-        """Registers generic LSP features from this class."""
-        for name in dir(self):
-            if name in {"workspace"}:
-                continue
-
-            attr = getattr(self, name)
-            if callable(attr) and hasattr(attr, "method_name"):
-                self.fm.add_builtin_feature(attr.method_name, attr)
-
-    @property
-    def workspace(self) -> Workspace:
-        if self._workspace is None:
-            raise RuntimeError(
-                "The workspace is not available - has the server been initialized?"
-            )
-
-        return self._workspace
-
-    @lru_cache()
-    def get_message_type(self, method: str) -> Optional[Type]:
-        """Return LSP type definitions, as provided by `lsprotocol`"""
-        return METHOD_TO_TYPES.get(method, (None,))[0]
-
-    @lru_cache()
-    def get_result_type(self, method: str) -> Optional[Type]:
-        return METHOD_TO_TYPES.get(method, (None, None))[1]
-
-    def apply_edit(
-        self, edit: WorkspaceEdit, label: Optional[str] = None
-    ) -> WorkspaceApplyEditResponse:
-        """Sends apply edit request to the client."""
-        return self.send_request(
-            WORKSPACE_APPLY_EDIT, ApplyWorkspaceEditParams(edit=edit, label=label)
-        )
-
-    def apply_edit_async(
-        self, edit: WorkspaceEdit, label: Optional[str] = None
-    ) -> WorkspaceApplyEditResponse:
-        """Sends apply edit request to the client. Should be called with `await`"""
-        return self.send_request_async(
-            WORKSPACE_APPLY_EDIT, ApplyWorkspaceEditParams(edit=edit, label=label)
-        )
-
-    @lsp_method(EXIT)
-    def lsp_exit(self, *args) -> None:
-        """Stops the server process."""
-        if self.transport is not None:
-            self.transport.close()
-
-        sys.exit(0 if self._shutdown else 1)
-
-    @lsp_method(INITIALIZE)
-    def lsp_initialize(self, params: InitializeParams) -> InitializeResult:
-        """Method that initializes language server.
-        It will compute and return server capabilities based on
-        registered features.
-        """
-        logger.info("Language server initialized %s", params)
-
-        self._server.process_id = params.process_id
-
-        text_document_sync_kind = self._server._text_document_sync_kind
-        notebook_document_sync = self._server._notebook_document_sync
-
-        # Initialize server capabilities
-        self.client_capabilities = params.capabilities
-        self.server_capabilities = ServerCapabilitiesBuilder(
-            self.client_capabilities,
-            set({**self.fm.features, **self.fm.builtin_features}.keys()),
-            self.fm.feature_options,
-            list(self.fm.commands.keys()),
-            text_document_sync_kind,
-            notebook_document_sync,
-        ).build()
-        logger.debug(
-            "Server capabilities: %s",
-            json.dumps(self.server_capabilities, default=self._serialize_message),
-        )
-
-        root_path = params.root_path
-        root_uri = params.root_uri
-        if root_path is not None and root_uri is None:
-            root_uri = from_fs_path(root_path)
-
-        # Initialize the workspace
-        workspace_folders = params.workspace_folders or []
-        self._workspace = Workspace(
-            root_uri,
-            text_document_sync_kind,
-            workspace_folders,
-            self.server_capabilities.position_encoding,
-        )
-
-        self.trace = TraceValues.Off
-
-        return InitializeResult(
-            capabilities=self.server_capabilities,
-            server_info=self.server_info,
-        )
-
-    @lsp_method(INITIALIZED)
-    def lsp_initialized(self, *args) -> None:
-        """Notification received when client and server are connected."""
-        pass
-
-    @lsp_method(SHUTDOWN)
-    def lsp_shutdown(self, *args) -> None:
-        """Request from client which asks server to shutdown."""
-        for future in self._request_futures.values():
-            future.cancel()
-
-        self._shutdown = True
-        return None
-
-    @lsp_method(TEXT_DOCUMENT_DID_CHANGE)
-    def lsp_text_document__did_change(
-        self, params: DidChangeTextDocumentParams
-    ) -> None:
-        """Updates document's content.
-        (Incremental(from server capabilities); not configurable for now)
-        """
-        for change in params.content_changes:
-            self.workspace.update_text_document(params.text_document, change)
-
-    @lsp_method(TEXT_DOCUMENT_DID_CLOSE)
-    def lsp_text_document__did_close(self, params: DidCloseTextDocumentParams) -> None:
-        """Removes document from workspace."""
-        self.workspace.remove_text_document(params.text_document.uri)
-
-    @lsp_method(TEXT_DOCUMENT_DID_OPEN)
-    def lsp_text_document__did_open(self, params: DidOpenTextDocumentParams) -> None:
-        """Puts document to the workspace."""
-        self.workspace.put_text_document(params.text_document)
-
-    @lsp_method(NOTEBOOK_DOCUMENT_DID_OPEN)
-    def lsp_notebook_document__did_open(
-        self, params: DidOpenNotebookDocumentParams
-    ) -> None:
-        """Put a notebook document into the workspace"""
-        self.workspace.put_notebook_document(params)
-
-    @lsp_method(NOTEBOOK_DOCUMENT_DID_CHANGE)
-    def lsp_notebook_document__did_change(
-        self, params: DidChangeNotebookDocumentParams
-    ) -> None:
-        """Update a notebook's contents"""
-        self.workspace.update_notebook_document(params)
-
-    @lsp_method(NOTEBOOK_DOCUMENT_DID_CLOSE)
-    def lsp_notebook_document__did_close(
-        self, params: DidCloseNotebookDocumentParams
-    ) -> None:
-        """Remove a notebook document from the workspace."""
-        self.workspace.remove_notebook_document(params)
-
-    @lsp_method(SET_TRACE)
-    def lsp_set_trace(self, params: SetTraceParams) -> None:
-        """Changes server trace value."""
-        self.trace = params.value
-
-    @lsp_method(WORKSPACE_DID_CHANGE_WORKSPACE_FOLDERS)
-    def lsp_workspace__did_change_workspace_folders(
-        self, params: DidChangeWorkspaceFoldersParams
-    ) -> None:
-        """Adds/Removes folders from the workspace."""
-        logger.info("Workspace folders changed: %s", params)
-
-        added_folders = params.event.added or []
-        removed_folders = params.event.removed or []
-
-        for f_add, f_remove in zip_longest(added_folders, removed_folders):
-            if f_add:
-                self.workspace.add_folder(f_add)
-            if f_remove:
-                self.workspace.remove_folder(f_remove.uri)
-
-    @lsp_method(WORKSPACE_EXECUTE_COMMAND)
-    def lsp_workspace__execute_command(
-        self, params: ExecuteCommandParams, msg_id: str
-    ) -> None:
-        """Executes commands with passed arguments and returns a value."""
-        cmd_handler = self.fm.commands[params.command]
-        self._execute_request(msg_id, cmd_handler, params.arguments)
-
-    @lsp_method(WINDOW_WORK_DONE_PROGRESS_CANCEL)
-    def lsp_work_done_progress_cancel(
-        self, params: WorkDoneProgressCancelParams
-    ) -> None:
-        """Received a progress cancellation from client."""
-        future = self.progress.tokens.get(params.token)
-        if future is None:
-            logger.warning(
-                "Ignoring work done progress cancel for unknown token %s", params.token
-            )
-        else:
-            future.cancel()
-
-    def get_configuration(
-        self,
-        params: WorkspaceConfigurationParams,
-        callback: Optional[ConfigCallbackType] = None,
-    ) -> Future:
-        """Sends configuration request to the client.
-
-        Args:
-            params(WorkspaceConfigurationParams): WorkspaceConfigurationParams from lsp specs
-            callback(callable): Callabe which will be called after
-                                response from the client is received
-        Returns:
-            concurrent.futures.Future object that will be resolved once a
-            response has been received
-        """
-        return self.send_request(WORKSPACE_CONFIGURATION, params, callback)
-
-    def get_configuration_async(
-        self, params: WorkspaceConfigurationParams
-    ) -> asyncio.Future:
-        """Calls `get_configuration` method but designed to use with coroutines
-
-        Args:
-            params(WorkspaceConfigurationParams): WorkspaceConfigurationParams from lsp specs
-        Returns:
-            asyncio.Future that can be awaited
-        """
-        return asyncio.wrap_future(self.get_configuration(params))
-
-    def log_trace(self, message: str, verbose: Optional[str] = None) -> None:
-        """Sends trace notification to the client."""
-        if self.trace == TraceValues.Off:
-            return
-
-        params = LogTraceParams(message=message)
-        if verbose and self.trace == TraceValues.Verbose:
-            params.verbose = verbose
-
-        self.notify(LOG_TRACE, params)
-
-    def _publish_diagnostics_deprecator(
-        self,
-        params_or_uri: Union[str, PublishDiagnosticsParams],
-        diagnostics: Optional[List[Diagnostic]],
-        version: Optional[int],
-        **kwargs,
-    ) -> PublishDiagnosticsParams:
-        if isinstance(params_or_uri, str):
-            message = "DEPRECATION: "
-            "`publish_diagnostics("
-            "self, doc_uri: str, diagnostics: List[Diagnostic], version: Optional[int] = None)`"
-            "will be replaced with `publish_diagnostics(self, params: PublishDiagnosticsParams)`"
-            logging.warning(message)
-
-            params = self._construct_publish_diagnostic_type(
-                params_or_uri, diagnostics, version, **kwargs
-            )
-        else:
-            params = params_or_uri
-        return params
-
-    def _construct_publish_diagnostic_type(
-        self,
-        uri: str,
-        diagnostics: Optional[List[Diagnostic]],
-        version: Optional[int],
-        **kwargs,
-    ) -> PublishDiagnosticsParams:
-        if diagnostics is None:
-            diagnostics = []
-
-        args = {
-            **{"uri": uri, "diagnostics": diagnostics, "version": version},
-            **kwargs,
-        }
-
-        params = PublishDiagnosticsParams(**args)  # type:ignore
-        return params
-
-    def publish_diagnostics(
-        self,
-        params_or_uri: Union[str, PublishDiagnosticsParams],
-        diagnostics: Optional[List[Diagnostic]] = None,
-        version: Optional[int] = None,
-        **kwargs,
-    ):
-        """Sends diagnostic notification to the client.
-
-        .. deprecated:: 1.0.1
-
-           Passing ``(uri, diagnostics, version)`` as arguments is deprecated.
-           Pass an instance of :class:`~lsprotocol.types.PublishDiagnosticParams`
-           instead.
-
-        Parameters
-        ----------
-        params_or_uri
-           The :class:`~lsprotocol.types.PublishDiagnosticParams` to send to the client.
-
-        diagnostics
-           *Deprecated*. The diagnostics to publish
-
-        version
-           *Deprecated*: The version number
-        """
-        params = self._publish_diagnostics_deprecator(
-            params_or_uri, diagnostics, version, **kwargs
-        )
-        self.notify(TEXT_DOCUMENT_PUBLISH_DIAGNOSTICS, params)
-
-    def register_capability(
-        self, params: RegistrationParams, callback: Optional[Callable[[], None]] = None
-    ) -> Future:
-        """Register a new capability on the client.
-
-        Args:
-            params(RegistrationParams): RegistrationParams from lsp specs
-            callback(callable): Callabe which will be called after
-                                response from the client is received
-        Returns:
-            concurrent.futures.Future object that will be resolved once a
-            response has been received
-        """
-        return self.send_request(CLIENT_REGISTER_CAPABILITY, params, callback)
-
-    def register_capability_async(self, params: RegistrationParams) -> asyncio.Future:
-        """Register a new capability on the client.
-
-        Args:
-            params(RegistrationParams): RegistrationParams from lsp specs
-
-        Returns:
-            asyncio.Future object that will be resolved once a
-            response has been received
-        """
-        return asyncio.wrap_future(self.register_capability(params, None))
-
-    def semantic_tokens_refresh(
-        self, callback: Optional[Callable[[], None]] = None
-    ) -> Future:
-        """Requesting a refresh of all semantic tokens.
-
-        Args:
-            callback(callable): Callabe which will be called after
-                                response from the client is received
-
-        Returns:
-            concurrent.futures.Future object that will be resolved once a
-            response has been received
-        """
-        return self.send_request(WORKSPACE_SEMANTIC_TOKENS_REFRESH, callback=callback)
-
-    def semantic_tokens_refresh_async(self) -> asyncio.Future:
-        """Requesting a refresh of all semantic tokens.
-
-        Returns:
-            asyncio.Future object that will be resolved once a
-            response has been received
-        """
-        return asyncio.wrap_future(self.semantic_tokens_refresh(None))
-
-    def show_document(
-        self,
-        params: ShowDocumentParams,
-        callback: Optional[ShowDocumentCallbackType] = None,
-    ) -> Future:
-        """Display a particular document in the user interface.
-
-        Args:
-            params(ShowDocumentParams): ShowDocumentParams from lsp specs
-            callback(callable): Callabe which will be called after
-                                response from the client is received
-
-        Returns:
-            concurrent.futures.Future object that will be resolved once a
-            response has been received
-        """
-        return self.send_request(WINDOW_SHOW_DOCUMENT, params, callback)
-
-    def show_document_async(self, params: ShowDocumentParams) -> asyncio.Future:
-        """Display a particular document in the user interface.
-
-        Args:
-            params(ShowDocumentParams): ShowDocumentParams from lsp specs
-
-        Returns:
-            asyncio.Future object that will be resolved once a
-            response has been received
-        """
-        return asyncio.wrap_future(self.show_document(params, None))
-
-    def show_message(self, message, msg_type=MessageType.Info):
-        """Sends message to the client to display message."""
-        self.notify(
-            WINDOW_SHOW_MESSAGE, ShowMessageParams(type=msg_type, message=message)
-        )
-
-    def show_message_log(self, message, msg_type=MessageType.Log):
-        """Sends message to the client's output channel."""
-        self.notify(
-            WINDOW_LOG_MESSAGE, LogMessageParams(type=msg_type, message=message)
-        )
-
-    def unregister_capability(
-        self,
-        params: UnregistrationParams,
-        callback: Optional[Callable[[], None]] = None,
-    ) -> Future:
-        """Unregister a new capability on the client.
-
-        Args:
-            params(UnregistrationParams): UnregistrationParams from lsp specs
-            callback(callable): Callabe which will be called after
-                                response from the client is received
-        Returns:
-            concurrent.futures.Future object that will be resolved once a
-            response has been received
-        """
-        return self.send_request(CLIENT_UNREGISTER_CAPABILITY, params, callback)
-
-    def unregister_capability_async(
-        self, params: UnregistrationParams
-    ) -> asyncio.Future:
-        """Unregister a new capability on the client.
-
-        Args:
-            params(UnregistrationParams): UnregistrationParams from lsp specs
-            callback(callable): Callabe which will be called after
-                                response from the client is received
-        Returns:
-            asyncio.Future object that will be resolved once a
-            response has been received
-        """
-        return asyncio.wrap_future(self.unregister_capability(params, None))
diff --git a/server/libs/pygls/protocol/lsp_meta.py b/server/libs/pygls/protocol/lsp_meta.py
deleted file mode 100644
index 0dc52db..0000000
--- a/server/libs/pygls/protocol/lsp_meta.py
+++ /dev/null
@@ -1,51 +0,0 @@
-import functools
-import logging
-from pygls.constants import ATTR_FEATURE_TYPE
-from pygls.feature_manager import assign_help_attrs
-
-
-logger = logging.getLogger(__name__)
-
-
-def call_user_feature(base_func, method_name):
-    """Wraps generic LSP features and calls user registered feature
-    immediately after it.
-    """
-
-    @functools.wraps(base_func)
-    def decorator(self, *args, **kwargs):
-        ret_val = base_func(self, *args, **kwargs)
-
-        try:
-            user_func = self.fm.features[method_name]
-            self._execute_notification(user_func, *args, **kwargs)
-        except KeyError:
-            pass
-        except Exception:
-            logger.exception(
-                'Failed to handle user defined notification "%s": %s', method_name, args
-            )
-
-        return ret_val
-
-    return decorator
-
-
-class LSPMeta(type):
-    """Wraps LSP built-in features (`lsp_` naming convention).
-
-    Built-in features cannot be overridden but user defined features with
-    the same LSP name will be called after them.
-    """
-
-    def __new__(mcs, cls_name, cls_bases, cls):
-        for attr_name, attr_val in cls.items():
-            if callable(attr_val) and hasattr(attr_val, "method_name"):
-                method_name = attr_val.method_name
-                wrapped = call_user_feature(attr_val, method_name)
-                assign_help_attrs(wrapped, method_name, ATTR_FEATURE_TYPE)
-                cls[attr_name] = wrapped
-
-                logger.debug('Added decorator for lsp method: "%s"', attr_name)
-
-        return super().__new__(mcs, cls_name, cls_bases, cls)
diff --git a/server/libs/pygls/py.typed b/server/libs/pygls/py.typed
deleted file mode 100644
index a9beb24..0000000
--- a/server/libs/pygls/py.typed
+++ /dev/null
@@ -1,2 +0,0 @@
-# Marker file for PEP 561. The pygls package uses inline types.
-
diff --git a/server/libs/pygls/server.py b/server/libs/pygls/server.py
deleted file mode 100644
index 7717b84..0000000
--- a/server/libs/pygls/server.py
+++ /dev/null
@@ -1,616 +0,0 @@
-############################################################################
-# Copyright(c) Open Law Library. All rights reserved.                      #
-# See ThirdPartyNotices.txt in the project root for additional notices.    #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-import asyncio
-import json
-import logging
-import re
-import sys
-from concurrent.futures import Future, ThreadPoolExecutor
-from threading import Event
-from typing import (
-    Any,
-    Callable,
-    List,
-    Optional,
-    TextIO,
-    Type,
-    TypeVar,
-    Union,
-)
-
-import cattrs
-from pygls import IS_PYODIDE
-from pygls.lsp import ConfigCallbackType, ShowDocumentCallbackType
-from pygls.exceptions import (
-    FeatureNotificationError,
-    JsonRpcInternalError,
-    PyglsError,
-    JsonRpcException,
-    FeatureRequestError,
-)
-from lsprotocol.types import (
-    ClientCapabilities,
-    Diagnostic,
-    MessageType,
-    NotebookDocumentSyncOptions,
-    RegistrationParams,
-    ServerCapabilities,
-    ShowDocumentParams,
-    TextDocumentSyncKind,
-    UnregistrationParams,
-    WorkspaceApplyEditResponse,
-    WorkspaceEdit,
-    WorkspaceConfigurationParams,
-)
-from pygls.progress import Progress
-from pygls.protocol import JsonRPCProtocol, LanguageServerProtocol, default_converter
-from pygls.workspace import Workspace
-
-if not IS_PYODIDE:
-    from multiprocessing.pool import ThreadPool
-
-
-logger = logging.getLogger(__name__)
-
-F = TypeVar("F", bound=Callable)
-
-ServerErrors = Union[
-    PyglsError,
-    JsonRpcException,
-    Type[JsonRpcInternalError],
-    Type[FeatureNotificationError],
-    Type[FeatureRequestError],
-]
-
-
-async def aio_readline(loop, executor, stop_event, rfile, proxy):
-    """Reads data from stdin in separate thread (asynchronously)."""
-
-    CONTENT_LENGTH_PATTERN = re.compile(rb"^Content-Length: (\d+)\r\n$")
-
-    # Initialize message buffer
-    message = []
-    content_length = 0
-
-    while not stop_event.is_set() and not rfile.closed:
-        # Read a header line
-        header = await loop.run_in_executor(executor, rfile.readline)
-        if not header:
-            break
-        message.append(header)
-
-        # Extract content length if possible
-        if not content_length:
-            match = CONTENT_LENGTH_PATTERN.fullmatch(header)
-            if match:
-                content_length = int(match.group(1))
-                logger.debug("Content length: %s", content_length)
-
-        # Check if all headers have been read (as indicated by an empty line \r\n)
-        if content_length and not header.strip():
-            # Read body
-            body = await loop.run_in_executor(executor, rfile.read, content_length)
-            if not body:
-                break
-            message.append(body)
-
-            # Pass message to language server protocol
-            proxy(b"".join(message))
-
-            # Reset the buffer
-            message = []
-            content_length = 0
-
-
-class StdOutTransportAdapter:
-    """Protocol adapter which overrides write method.
-
-    Write method sends data to stdout.
-    """
-
-    def __init__(self, rfile, wfile):
-        self.rfile = rfile
-        self.wfile = wfile
-
-    def close(self):
-        self.rfile.close()
-        self.wfile.close()
-
-    def write(self, data):
-        self.wfile.write(data)
-        self.wfile.flush()
-
-
-class PyodideTransportAdapter:
-    """Protocol adapter which overrides write method.
-
-    Write method sends data to stdout.
-    """
-
-    def __init__(self, wfile):
-        self.wfile = wfile
-
-    def close(self):
-        self.wfile.close()
-
-    def write(self, data):
-        self.wfile.write(data)
-        self.wfile.flush()
-
-
-class WebSocketTransportAdapter:
-    """Protocol adapter which calls write method.
-
-    Write method sends data via the WebSocket interface.
-    """
-
-    def __init__(self, ws, loop):
-        self._ws = ws
-        self._loop = loop
-
-    def close(self) -> None:
-        """Stop the WebSocket server."""
-        self._ws.close()
-
-    def write(self, data: Any) -> None:
-        """Create a task to write specified data into a WebSocket."""
-        asyncio.ensure_future(self._ws.send(data))
-
-
-class Server:
-    """Base server class
-
-    Parameters
-    ----------
-    protocol_cls
-       Protocol implementation that must be derive from :class:`~pygls.protocol.JsonRPCProtocol`
-
-    converter_factory
-       Factory function to use when constructing a cattrs converter.
-
-    loop
-       The asyncio event loop
-
-    max_workers
-       Maximum number of workers for `ThreadPool` and `ThreadPoolExecutor`
-
-    """
-
-    def __init__(
-        self,
-        protocol_cls: Type[JsonRPCProtocol],
-        converter_factory: Callable[[], cattrs.Converter],
-        loop: Optional[asyncio.AbstractEventLoop] = None,
-        max_workers: int = 2,
-        sync_kind: TextDocumentSyncKind = TextDocumentSyncKind.Incremental,
-    ):
-        if not issubclass(protocol_cls, asyncio.Protocol):
-            raise TypeError("Protocol class should be subclass of asyncio.Protocol")
-
-        self._max_workers = max_workers
-        self._server = None
-        self._stop_event: Optional[Event] = None
-        self._thread_pool: Optional[ThreadPool] = None
-        self._thread_pool_executor: Optional[ThreadPoolExecutor] = None
-
-        if sync_kind is not None:
-            self.text_document_sync_kind = sync_kind
-
-        if loop is None:
-            loop = asyncio.new_event_loop()
-            asyncio.set_event_loop(loop)
-            self._owns_loop = True
-        else:
-            self._owns_loop = False
-
-        self.loop = loop
-
-        # TODO: Will move this to `LanguageServer` soon
-        self.lsp = protocol_cls(self, converter_factory())  # type: ignore
-
-    def shutdown(self):
-        """Shutdown server."""
-        logger.info("Shutting down the server")
-
-        if self._stop_event is not None:
-            self._stop_event.set()
-
-        if self._thread_pool:
-            self._thread_pool.terminate()
-            self._thread_pool.join()
-
-        if self._thread_pool_executor:
-            self._thread_pool_executor.shutdown()
-
-        if self._server:
-            self._server.close()
-            self.loop.run_until_complete(self._server.wait_closed())
-
-        if self._owns_loop and not self.loop.is_closed():
-            logger.info("Closing the event loop.")
-            self.loop.close()
-
-    def start_io(self, stdin: Optional[TextIO] = None, stdout: Optional[TextIO] = None):
-        """Starts IO server."""
-        logger.info("Starting IO server")
-
-        self._stop_event = Event()
-        transport = StdOutTransportAdapter(
-            stdin or sys.stdin.buffer, stdout or sys.stdout.buffer
-        )
-        self.lsp.connection_made(transport)  # type: ignore[arg-type]
-
-        try:
-            self.loop.run_until_complete(
-                aio_readline(
-                    self.loop,
-                    self.thread_pool_executor,
-                    self._stop_event,
-                    stdin or sys.stdin.buffer,
-                    self.lsp.data_received,
-                )
-            )
-        except BrokenPipeError:
-            logger.error("Connection to the client is lost! Shutting down the server.")
-        except (KeyboardInterrupt, SystemExit):
-            pass
-        finally:
-            self.shutdown()
-
-    def start_pyodide(self):
-        logger.info("Starting Pyodide server")
-
-        # Note: We don't actually start anything running as the main event
-        # loop will be handled by the web platform.
-        transport = PyodideTransportAdapter(sys.stdout)
-        self.lsp.connection_made(transport)  # type: ignore[arg-type]
-        self.lsp._send_only_body = True  # Don't send headers within the payload
-
-    def start_tcp(self, host: str, port: int) -> None:
-        """Starts TCP server."""
-        logger.info("Starting TCP server on %s:%s", host, port)
-
-        self._stop_event = Event()
-        self._server = self.loop.run_until_complete(  # type: ignore[assignment]
-            self.loop.create_server(self.lsp, host, port)
-        )
-        try:
-            self.loop.run_forever()
-        except (KeyboardInterrupt, SystemExit):
-            pass
-        finally:
-            self.shutdown()
-
-    def start_ws(self, host: str, port: int) -> None:
-        """Starts WebSocket server."""
-        try:
-            from websockets.server import serve
-        except ImportError:
-            logger.error("Run `pip install pygls[ws]` to install `websockets`.")
-            sys.exit(1)
-
-        logger.info("Starting WebSocket server on {}:{}".format(host, port))
-
-        self._stop_event = Event()
-        self.lsp._send_only_body = True  # Don't send headers within the payload
-
-        async def connection_made(websocket, _):
-            """Handle new connection wrapped in the WebSocket."""
-            self.lsp.transport = WebSocketTransportAdapter(websocket, self.loop)
-            async for message in websocket:
-                self.lsp._procedure_handler(
-                    json.loads(message, object_hook=self.lsp._deserialize_message)
-                )
-
-        start_server = serve(connection_made, host, port, loop=self.loop)
-        self._server = start_server.ws_server  # type: ignore[assignment]
-        self.loop.run_until_complete(start_server)
-
-        try:
-            self.loop.run_forever()
-        except (KeyboardInterrupt, SystemExit):
-            pass
-        finally:
-            self._stop_event.set()
-            self.shutdown()
-
-    if not IS_PYODIDE:
-
-        @property
-        def thread_pool(self) -> ThreadPool:
-            """Returns thread pool instance (lazy initialization)."""
-            if not self._thread_pool:
-                self._thread_pool = ThreadPool(processes=self._max_workers)
-
-            return self._thread_pool
-
-        @property
-        def thread_pool_executor(self) -> ThreadPoolExecutor:
-            """Returns thread pool instance (lazy initialization)."""
-            if not self._thread_pool_executor:
-                self._thread_pool_executor = ThreadPoolExecutor(
-                    max_workers=self._max_workers
-                )
-
-            return self._thread_pool_executor
-
-
-class LanguageServer(Server):
-    """The default LanguageServer
-
-    This class can be extended and it can be passed as a first argument to
-    registered commands/features.
-
-    .. |ServerInfo| replace:: :class:`~lsprotocol.types.InitializeResultServerInfoType`
-
-    Parameters
-    ----------
-    name
-       Name of the server, used to populate |ServerInfo| which is sent to
-       the client during initialization
-
-    version
-       Version of the server, used to populate |ServerInfo| which is sent to
-       the client during initialization
-
-    protocol_cls
-       The :class:`~pygls.protocol.LanguageServerProtocol` class definition, or any
-       subclass of it.
-
-    max_workers
-       Maximum number of workers for ``ThreadPool`` and ``ThreadPoolExecutor``
-
-    text_document_sync_kind
-       Text document synchronization method
-
-       None
-          No synchronization
-
-       :attr:`~lsprotocol.types.TextDocumentSyncKind.Full`
-          Send entire document text with each update
-
-       :attr:`~lsprotocol.types.TextDocumentSyncKind.Incremental`
-          Send only the region of text that changed with each update
-
-    notebook_document_sync
-       Advertise :lsp:`NotebookDocument` support to the client.
-    """
-
-    lsp: LanguageServerProtocol
-
-    default_error_message = (
-        "Unexpected error in LSP server, see server's logs for details"
-    )
-    """
-    The default error message sent to the user's editor when this server encounters an uncaught
-    exception.
-    """
-
-    def __init__(
-        self,
-        name: str,
-        version: str,
-        loop=None,
-        protocol_cls: Type[LanguageServerProtocol] = LanguageServerProtocol,
-        converter_factory=default_converter,
-        text_document_sync_kind: TextDocumentSyncKind = TextDocumentSyncKind.Incremental,
-        notebook_document_sync: Optional[NotebookDocumentSyncOptions] = None,
-        max_workers: int = 2,
-    ):
-        if not issubclass(protocol_cls, LanguageServerProtocol):
-            raise TypeError(
-                "Protocol class should be subclass of LanguageServerProtocol"
-            )
-
-        self.name = name
-        self.version = version
-        self._text_document_sync_kind = text_document_sync_kind
-        self._notebook_document_sync = notebook_document_sync
-        self.process_id: Optional[Union[int, None]] = None
-        super().__init__(protocol_cls, converter_factory, loop, max_workers)
-
-    def apply_edit(
-        self, edit: WorkspaceEdit, label: Optional[str] = None
-    ) -> WorkspaceApplyEditResponse:
-        """Sends apply edit request to the client."""
-        return self.lsp.apply_edit(edit, label)
-
-    def apply_edit_async(
-        self, edit: WorkspaceEdit, label: Optional[str] = None
-    ) -> WorkspaceApplyEditResponse:
-        """Sends apply edit request to the client. Should be called with `await`"""
-        return self.lsp.apply_edit_async(edit, label)
-
-    def command(self, command_name: str) -> Callable[[F], F]:
-        """Decorator used to register custom commands.
-
-        Example
-        -------
-        ::
-
-           @ls.command('myCustomCommand')
-           def my_cmd(ls, a, b, c):
-               pass
-        """
-        return self.lsp.fm.command(command_name)
-
-    @property
-    def client_capabilities(self) -> ClientCapabilities:
-        """The client's capabilities."""
-        return self.lsp.client_capabilities
-
-    def feature(
-        self,
-        feature_name: str,
-        options: Optional[Any] = None,
-    ) -> Callable[[F], F]:
-        """Decorator used to register LSP features.
-
-        Example
-        -------
-        ::
-
-           @ls.feature('textDocument/completion', CompletionOptions(trigger_characters=['.']))
-           def completions(ls, params: CompletionParams):
-               return CompletionList(is_incomplete=False, items=[CompletionItem("Completion 1")])
-        """
-        return self.lsp.fm.feature(feature_name, options)
-
-    def get_configuration(
-        self,
-        params: WorkspaceConfigurationParams,
-        callback: Optional[ConfigCallbackType] = None,
-    ) -> Future:
-        """Gets the configuration settings from the client."""
-        return self.lsp.get_configuration(params, callback)
-
-    def get_configuration_async(
-        self, params: WorkspaceConfigurationParams
-    ) -> asyncio.Future:
-        """Gets the configuration settings from the client. Should be called with `await`"""
-        return self.lsp.get_configuration_async(params)
-
-    def log_trace(self, message: str, verbose: Optional[str] = None) -> None:
-        """Sends trace notification to the client."""
-        self.lsp.log_trace(message, verbose)
-
-    @property
-    def progress(self) -> Progress:
-        """Gets the object to manage client's progress bar."""
-        return self.lsp.progress
-
-    def publish_diagnostics(
-        self,
-        uri: str,
-        diagnostics: Optional[List[Diagnostic]] = None,
-        version: Optional[int] = None,
-        **kwargs
-    ):
-        """
-        Sends diagnostic notification to the client.
-        """
-        params = self.lsp._construct_publish_diagnostic_type(
-            uri, diagnostics, version, **kwargs
-        )
-        self.lsp.publish_diagnostics(params, **kwargs)
-
-    def register_capability(
-        self, params: RegistrationParams, callback: Optional[Callable[[], None]] = None
-    ) -> Future:
-        """Register a new capability on the client."""
-        return self.lsp.register_capability(params, callback)
-
-    def register_capability_async(self, params: RegistrationParams) -> asyncio.Future:
-        """Register a new capability on the client. Should be called with `await`"""
-        return self.lsp.register_capability_async(params)
-
-    def semantic_tokens_refresh(
-        self, callback: Optional[Callable[[], None]] = None
-    ) -> Future:
-        """Request a refresh of all semantic tokens."""
-        return self.lsp.semantic_tokens_refresh(callback)
-
-    def semantic_tokens_refresh_async(self) -> asyncio.Future:
-        """Request a refresh of all semantic tokens. Should be called with `await`"""
-        return self.lsp.semantic_tokens_refresh_async()
-
-    def send_notification(self, method: str, params: object = None) -> None:
-        """Sends notification to the client."""
-        self.lsp.notify(method, params)
-
-    @property
-    def server_capabilities(self) -> ServerCapabilities:
-        """Return server capabilities."""
-        return self.lsp.server_capabilities
-
-    def show_document(
-        self,
-        params: ShowDocumentParams,
-        callback: Optional[ShowDocumentCallbackType] = None,
-    ) -> Future:
-        """Display a particular document in the user interface."""
-        return self.lsp.show_document(params, callback)
-
-    def show_document_async(self, params: ShowDocumentParams) -> asyncio.Future:
-        """Display a particular document in the user interface. Should be called with `await`"""
-        return self.lsp.show_document_async(params)
-
-    def show_message(self, message, msg_type=MessageType.Info) -> None:
-        """Sends message to the client to display message."""
-        self.lsp.show_message(message, msg_type)
-
-    def show_message_log(self, message, msg_type=MessageType.Log) -> None:
-        """Sends message to the client's output channel."""
-        self.lsp.show_message_log(message, msg_type)
-
-    def _report_server_error(
-        self,
-        error: Exception,
-        source: ServerErrors,
-    ):
-        # Prevent recursive error reporting
-        try:
-            self.report_server_error(error, source)
-        except Exception:
-            logger.warning("Failed to report error to client")
-
-    def report_server_error(self, error: Exception, source: ServerErrors):
-        """
-        Sends error to the client for displaying.
-
-        By default this fucntion does not handle LSP request errors. This is because LSP requests
-        require direct responses and so already have a mechanism for including unexpected errors
-        in the response body.
-
-        All other errors are "out of band" in the sense that the client isn't explicitly waiting
-        for them. For example diagnostics are returned as notifications, not responses to requests,
-        and so can seemingly be sent at random. Also for example consider JSON RPC serialization
-        and deserialization, if a payload cannot be parsed then the whole request/response cycle
-        cannot be completed and so one of these "out of band" error messages is sent.
-
-        These "out of band" error messages are not a requirement of the LSP spec. Pygls simply
-        offers this behaviour as a recommended default. It is perfectly reasonble to override this
-        default.
-        """
-
-        if source == FeatureRequestError:
-            return
-
-        self.show_message(self.default_error_message, msg_type=MessageType.Error)
-
-    def thread(self) -> Callable[[F], F]:
-        """Decorator that mark function to execute it in a thread."""
-        return self.lsp.thread()
-
-    def unregister_capability(
-        self,
-        params: UnregistrationParams,
-        callback: Optional[Callable[[], None]] = None,
-    ) -> Future:
-        """Unregister a new capability on the client."""
-        return self.lsp.unregister_capability(params, callback)
-
-    def unregister_capability_async(
-        self, params: UnregistrationParams
-    ) -> asyncio.Future:
-        """Unregister a new capability on the client. Should be called with `await`"""
-        return self.lsp.unregister_capability_async(params)
-
-    @property
-    def workspace(self) -> Workspace:
-        """Returns in-memory workspace."""
-        return self.lsp.workspace
diff --git a/server/libs/pygls/uris.py b/server/libs/pygls/uris.py
deleted file mode 100644
index 8c40f70..0000000
--- a/server/libs/pygls/uris.py
+++ /dev/null
@@ -1,184 +0,0 @@
-############################################################################
-# Original work Copyright 2017 Palantir Technologies, Inc.                 #
-# Original work licensed under the MIT License.                            #
-# See ThirdPartyNotices.txt in the project root for license information.   #
-# All modifications Copyright (c) Open Law Library. All rights reserved.   #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-"""
-A collection of URI utilities with logic built on the VSCode URI library.
-
-https://github.com/Microsoft/vscode-uri/blob/e59cab84f5df6265aed18ae5f43552d3eef13bb9/lib/index.ts
-"""
-from typing import Optional, Tuple
-
-import re
-from urllib import parse
-
-from pygls import IS_WIN
-
-RE_DRIVE_LETTER_PATH = re.compile(r"^\/[a-zA-Z]:")
-
-URLParts = Tuple[str, str, str, str, str, str]
-
-
-def _normalize_win_path(path: str):
-    netloc = ""
-
-    # normalize to fwd-slashes on windows,
-    # on other systems bwd-slashes are valid
-    # filename character, eg /f\oo/ba\r.txt
-    if IS_WIN:
-        path = path.replace("\\", "/")
-
-    # check for authority as used in UNC shares
-    # or use the path as given
-    if path[:2] == "//":
-        idx = path.index("/", 2)
-        if idx == -1:
-            netloc = path[2:]
-        else:
-            netloc = path[2:idx]
-            path = path[idx:]
-
-    # Ensure that path starts with a slash
-    # or that it is at least a slash
-    if not path.startswith("/"):
-        path = "/" + path
-
-    # Normalize drive paths to lower case
-    if RE_DRIVE_LETTER_PATH.match(path):
-        path = path[0] + path[1].lower() + path[2:]
-
-    return path, netloc
-
-
-def from_fs_path(path: str):
-    """Returns a URI for the given filesystem path."""
-    try:
-        scheme = "file"
-        params, query, fragment = "", "", ""
-        path, netloc = _normalize_win_path(path)
-        return urlunparse((scheme, netloc, path, params, query, fragment))
-    except (AttributeError, TypeError):
-        return None
-
-
-def to_fs_path(uri: str):
-    """
-    Returns the filesystem path of the given URI.
-
-    Will handle UNC paths and normalize windows drive letters to lower-case.
-    Also uses the platform specific path separator. Will *not* validate the
-    path for invalid characters and semantics.
-    Will *not* look at the scheme of this URI.
-    """
-    try:
-        # scheme://netloc/path;parameters?query#fragment
-        scheme, netloc, path, _, _, _ = urlparse(uri)
-
-        if netloc and path and scheme == "file":
-            # unc path: file://shares/c$/far/boo
-            value = f"//{netloc}{path}"
-
-        elif RE_DRIVE_LETTER_PATH.match(path):
-            # windows drive letter: file:///C:/far/boo
-            value = path[1].lower() + path[2:]
-
-        else:
-            # Other path
-            value = path
-
-        if IS_WIN:
-            value = value.replace("/", "\\")
-
-        return value
-    except TypeError:
-        return None
-
-
-def uri_scheme(uri: str):
-    try:
-        return urlparse(uri)[0]
-    except (TypeError, IndexError):
-        return None
-
-
-# TODO: Use `URLParts` type
-def uri_with(
-    uri: str,
-    scheme: Optional[str] = None,
-    netloc: Optional[str] = None,
-    path: Optional[str] = None,
-    params: Optional[str] = None,
-    query: Optional[str] = None,
-    fragment: Optional[str] = None,
-):
-    """
-    Return a URI with the given part(s) replaced.
-    Parts are decoded / encoded.
-    """
-    old_scheme, old_netloc, old_path, old_params, old_query, old_fragment = urlparse(
-        uri
-    )
-
-    if path is None:
-        raise Exception("`path` must not be None")
-
-    path, _ = _normalize_win_path(path)
-    return urlunparse(
-        (
-            scheme or old_scheme,
-            netloc or old_netloc,
-            path or old_path,
-            params or old_params,
-            query or old_query,
-            fragment or old_fragment,
-        )
-    )
-
-
-def urlparse(uri: str):
-    """Parse and decode the parts of a URI."""
-    scheme, netloc, path, params, query, fragment = parse.urlparse(uri)
-    return (
-        parse.unquote(scheme),
-        parse.unquote(netloc),
-        parse.unquote(path),
-        parse.unquote(params),
-        parse.unquote(query),
-        parse.unquote(fragment),
-    )
-
-
-def urlunparse(parts: URLParts) -> str:
-    """Unparse and encode parts of a URI."""
-    scheme, netloc, path, params, query, fragment = parts
-
-    # Avoid encoding the windows drive letter colon
-    if RE_DRIVE_LETTER_PATH.match(path):
-        quoted_path = path[:3] + parse.quote(path[3:])
-    else:
-        quoted_path = parse.quote(path)
-
-    return parse.urlunparse(
-        (
-            parse.quote(scheme),
-            parse.quote(netloc),
-            quoted_path,
-            parse.quote(params),
-            parse.quote(query),
-            parse.quote(fragment),
-        )
-    )
diff --git a/server/libs/pygls/workspace/__init__.py b/server/libs/pygls/workspace/__init__.py
deleted file mode 100644
index 53e9b1f..0000000
--- a/server/libs/pygls/workspace/__init__.py
+++ /dev/null
@@ -1,97 +0,0 @@
-from typing import List
-import warnings
-
-from lsprotocol import types
-
-from .workspace import Workspace
-from .text_document import TextDocument
-from .position_codec import PositionCodec
-
-# For backwards compatibility
-Document = TextDocument
-
-
-def utf16_unit_offset(chars: str):
-    warnings.warn(
-        "'utf16_unit_offset' has been deprecated, instead use "
-        "'PositionCodec.utf16_unit_offset' via 'workspace.position_codec' "
-        "or 'text_document.position_codec'",
-        DeprecationWarning,
-        stacklevel=2,
-    )
-    _codec = PositionCodec()
-    return _codec.utf16_unit_offset(chars)
-
-
-def utf16_num_units(chars: str):
-    warnings.warn(
-        "'utf16_num_units' has been deprecated, instead use "
-        "'PositionCodec.client_num_units' via 'workspace.position_codec' "
-        "or 'text_document.position_codec'",
-        DeprecationWarning,
-        stacklevel=2,
-    )
-    _codec = PositionCodec()
-    return _codec.client_num_units(chars)
-
-
-def position_from_utf16(lines: List[str], position: types.Position):
-    warnings.warn(
-        "'position_from_utf16' has been deprecated, instead use "
-        "'PositionCodec.position_from_client_units' via "
-        "'workspace.position_codec' or 'text_document.position_codec'",
-        DeprecationWarning,
-        stacklevel=2,
-    )
-    _codec = PositionCodec()
-    return _codec.position_from_client_units(lines, position)
-
-
-def position_to_utf16(lines: List[str], position: types.Position):
-    warnings.warn(
-        "'position_to_utf16' has been deprecated, instead use "
-        "'PositionCodec.position_to_client_units' via "
-        "'workspace.position_codec' or 'text_document.position_codec'",
-        DeprecationWarning,
-        stacklevel=2,
-    )
-    _codec = PositionCodec()
-    return _codec.position_to_client_units(lines, position)
-
-
-def range_from_utf16(lines: List[str], range: types.Range):
-    warnings.warn(
-        "'range_from_utf16' has been deprecated, instead use "
-        "'PositionCodec.range_from_client_units' via "
-        "'workspace.position_codec' or 'text_document.position_codec'",
-        DeprecationWarning,
-        stacklevel=2,
-    )
-    _codec = PositionCodec()
-    return _codec.range_from_client_units(lines, range)
-
-
-def range_to_utf16(lines: List[str], range: types.Range):
-    warnings.warn(
-        "'range_to_utf16' has been deprecated, instead use "
-        "'PositionCodec.range_to_client_units' via 'workspace.position_codec' "
-        "or 'text_document.position_codec'",
-        DeprecationWarning,
-        stacklevel=2,
-    )
-    _codec = PositionCodec()
-    return _codec.range_to_client_units(lines, range)
-
-
-__all__ = (
-    "Workspace",
-    "TextDocument",
-    "PositionCodec",
-    "Document",
-    "utf16_unit_offset",
-    "utf16_num_units",
-    "position_from_utf16",
-    "position_to_utf16",
-    "range_from_utf16",
-    "range_to_utf16",
-)
diff --git a/server/libs/pygls/workspace/position_codec.py b/server/libs/pygls/workspace/position_codec.py
deleted file mode 100644
index b182c62..0000000
--- a/server/libs/pygls/workspace/position_codec.py
+++ /dev/null
@@ -1,206 +0,0 @@
-############################################################################
-# Original work Copyright 2017 Palantir Technologies, Inc.                 #
-# Original work licensed under the MIT License.                            #
-# See ThirdPartyNotices.txt in the project root for license information.   #
-# All modifications Copyright (c) Open Law Library. All rights reserved.   #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-import logging
-from typing import List, Optional, Union
-
-from lsprotocol import types
-
-
-log = logging.getLogger(__name__)
-
-
-class PositionCodec:
-    def __init__(
-        self,
-        encoding: Optional[
-            Union[types.PositionEncodingKind, str]
-        ] = types.PositionEncodingKind.Utf16,
-    ):
-        self.encoding = encoding
-
-    @classmethod
-    def is_char_beyond_multilingual_plane(cls, char: str) -> bool:
-        return ord(char) > 0xFFFF
-
-    def utf16_unit_offset(self, chars: str):
-        """
-        Calculate the number of characters which need two utf-16 code units.
-
-        Arguments:
-            chars (str): The string to count occurrences of utf-16 code units for.
-        """
-        return sum(self.is_char_beyond_multilingual_plane(ch) for ch in chars)
-
-    def client_num_units(self, chars: str):
-        """
-        Calculate the length of `str` in client-supported UTF-[32|16|8] code units.
-
-        Arguments:
-            chars (str): The string to return the length in UTF-[32|16|8] code units for.
-        """
-        utf32_units = len(chars)
-        if self.encoding == types.PositionEncodingKind.Utf32:
-            return utf32_units
-
-        if self.encoding == types.PositionEncodingKind.Utf8:
-            return utf32_units + (self.utf16_unit_offset(chars) * 2)
-
-        return utf32_units + self.utf16_unit_offset(chars)
-
-    def position_from_client_units(
-        self, lines: List[str], position: types.Position
-    ) -> types.Position:
-        """
-        Convert the position.character from UTF-[32|16|8] code units to UTF-32.
-
-        A python application can't use the character member of `Position`
-        directly. As per specification it is represented as a zero-based line and
-        character offset based on posible a UTF-[32|16|8] string representation.
-
-        All characters whose code point exceeds the Basic Multilingual Plane are
-        represented by 2 UTF-16 or 4 UTF-8 code units.
-
-        The offset of the closing quotation mark in x="😋" is
-        - 7 in UTF-8 representation
-        - 5 in UTF-16 representation
-        - 4 in UTF-32 representation
-
-        see: https://github.com/microsoft/language-server-protocol/issues/376
-
-        Arguments:
-            lines (list):
-                The content of the document which the position refers to.
-            position (Position):
-                The line and character offset in UTF-[32|16|8] code units.
-
-        Returns:
-            The position with `character` being converted to UTF-32 code units.
-        """
-        if len(lines) == 0:
-            return types.Position(0, 0)
-        if position.line >= len(lines):
-            return types.Position(len(lines) - 1, self.client_num_units(lines[-1]))
-
-        _line = lines[position.line]
-        _line = _line.replace("\r\n", "\n")  # TODO: it's a bit of a hack
-        _client_len = self.client_num_units(_line)
-        _utf32_len = len(_line)
-
-        if _client_len == 0:
-            return types.Position(position.line, 0)
-
-        _client_end_of_line = self.client_num_units(_line)
-        if position.character > _client_end_of_line:
-            position.character = _client_end_of_line - 1
-
-        _client_index = 0
-        utf32_index = 0
-        while True:
-            _is_searching_queried_position = _client_index < position.character
-            _is_before_end_of_line = utf32_index < _utf32_len
-            _is_searching_for_position = (
-                _is_searching_queried_position and _is_before_end_of_line
-            )
-            if not _is_searching_for_position:
-                break
-
-            _current_char = _line[utf32_index]
-            _is_double_width = PositionCodec.is_char_beyond_multilingual_plane(
-                _current_char
-            )
-            if _is_double_width:
-                if self.encoding == types.PositionEncodingKind.Utf32:
-                    _client_index += 1
-                if self.encoding == types.PositionEncodingKind.Utf8:
-                    _client_index += 4
-                _client_index += 2
-            else:
-                _client_index += 1
-            utf32_index += 1
-
-        position = types.Position(line=position.line, character=utf32_index)
-        return position
-
-    def position_to_client_units(
-        self, lines: List[str], position: types.Position
-    ) -> types.Position:
-        """
-        Convert the position.character from its internal UTF-32 representation
-        to client-supported UTF-[32|16|8] code units.
-
-        Arguments:
-            lines (list):
-                The content of the document which the position refers to.
-            position (Position):
-                The line and character offset in UTF-32 code units.
-
-        Returns:
-            The position with `character` being converted to UTF-[32|16|8] code units.
-        """
-        try:
-            character = self.client_num_units(
-                lines[position.line][: position.character]
-            )
-            return types.Position(
-                line=position.line,
-                character=character,
-            )
-        except IndexError:
-            return types.Position(line=len(lines), character=0)
-
-    def range_from_client_units(
-        self, lines: List[str], range: types.Range
-    ) -> types.Range:
-        """
-        Convert range.[start|end].character from UTF-[32|16|8] code units to UTF-32.
-
-        Arguments:
-            lines (list):
-                The content of the document which the range refers to.
-            range (Range):
-                The line and character offset in UTF-[32|16|8] code units.
-
-        Returns:
-            The range with `character` offsets being converted to UTF-32 code units.
-        """
-        range_new = types.Range(
-            start=self.position_from_client_units(lines, range.start),
-            end=self.position_from_client_units(lines, range.end),
-        )
-        return range_new
-
-    def range_to_client_units(
-        self, lines: List[str], range: types.Range
-    ) -> types.Range:
-        """
-        Convert range.[start|end].character from UTF-32 to UTF-[32|16|8] code units.
-
-        Arguments:
-            lines (list):
-                The content of the document which the range refers to.
-            range (Range):
-                The line and character offset in  code units.
-
-        Returns:
-            The range with `character` offsets being converted to UTF-[32|16|8] code units.
-        """
-        return types.Range(
-            start=self.position_to_client_units(lines, range.start),
-            end=self.position_to_client_units(lines, range.end),
-        )
diff --git a/server/libs/pygls/workspace/text_document.py b/server/libs/pygls/workspace/text_document.py
deleted file mode 100644
index d62c6aa..0000000
--- a/server/libs/pygls/workspace/text_document.py
+++ /dev/null
@@ -1,238 +0,0 @@
-############################################################################
-# Original work Copyright 2017 Palantir Technologies, Inc.                 #
-# Original work licensed under the MIT License.                            #
-# See ThirdPartyNotices.txt in the project root for license information.   #
-# All modifications Copyright (c) Open Law Library. All rights reserved.   #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-import io
-import logging
-import os
-import re
-from typing import List, Optional, Pattern
-
-from lsprotocol import types
-
-from pygls.uris import to_fs_path
-from .position_codec import PositionCodec
-
-# TODO: this is not the best e.g. we capture numbers
-RE_END_WORD = re.compile("^[A-Za-z_0-9]*")
-RE_START_WORD = re.compile("[A-Za-z_0-9]*$")
-
-logger = logging.getLogger(__name__)
-
-
-class TextDocument(object):
-    def __init__(
-        self,
-        uri: str,
-        source: Optional[str] = None,
-        version: Optional[int] = None,
-        language_id: Optional[str] = None,
-        local: bool = True,
-        sync_kind: types.TextDocumentSyncKind = types.TextDocumentSyncKind.Incremental,
-        position_codec: Optional[PositionCodec] = None,
-    ):
-        self.uri = uri
-        self.version = version
-        path = to_fs_path(uri)
-        if path is None:
-            raise Exception("`path` cannot be None")
-        self.path = path
-        self.language_id = language_id
-        self.filename: Optional[str] = os.path.basename(self.path)
-
-        self._local = local
-        self._source = source
-
-        self._is_sync_kind_full = sync_kind == types.TextDocumentSyncKind.Full
-        self._is_sync_kind_incremental = (
-            sync_kind == types.TextDocumentSyncKind.Incremental
-        )
-        self._is_sync_kind_none = sync_kind == types.TextDocumentSyncKind.None_
-
-        self._position_codec = position_codec if position_codec else PositionCodec()
-
-    def __str__(self):
-        return str(self.uri)
-
-    @property
-    def position_codec(self) -> PositionCodec:
-        return self._position_codec
-
-    def _apply_incremental_change(
-        self, change: types.TextDocumentContentChangeEvent_Type1
-    ) -> None:
-        """Apply an ``Incremental`` text change to the document"""
-        lines = self.lines
-        text = change.text
-        change_range = change.range
-
-        range = self._position_codec.range_from_client_units(lines, change_range)
-        start_line = range.start.line
-        start_col = range.start.character
-        end_line = range.end.line
-        end_col = range.end.character
-
-        # Check for an edit occurring at the very end of the file
-        if start_line == len(lines):
-            self._source = self.source + text
-            return
-
-        new = io.StringIO()
-
-        # Iterate over the existing document until we hit the edit range,
-        # at which point we write the new text, then loop until we hit
-        # the end of the range and continue writing.
-        for i, line in enumerate(lines):
-            if i < start_line:
-                new.write(line)
-                continue
-
-            if i > end_line:
-                new.write(line)
-                continue
-
-            if i == start_line:
-                new.write(line[:start_col])
-                new.write(text)
-
-            if i == end_line:
-                new.write(line[end_col:])
-
-        self._source = new.getvalue()
-
-    def _apply_full_change(self, change: types.TextDocumentContentChangeEvent) -> None:
-        """Apply a ``Full`` text change to the document."""
-        self._source = change.text
-
-    def _apply_none_change(self, _: types.TextDocumentContentChangeEvent) -> None:
-        """Apply a ``None`` text change to the document
-
-        Currently does nothing, provided for consistency.
-        """
-        pass
-
-    def apply_change(self, change: types.TextDocumentContentChangeEvent) -> None:
-        """Apply a text change to a document, considering TextDocumentSyncKind
-
-        Performs either
-        :attr:`~lsprotocol.types.TextDocumentSyncKind.Incremental`,
-        :attr:`~lsprotocol.types.TextDocumentSyncKind.Full`, or no synchronization
-        based on both the client request and server capabilities.
-
-        .. admonition:: ``Incremental`` versus ``Full`` synchronization
-
-           Even if a server accepts ``Incremantal`` SyncKinds, clients may request
-           a ``Full`` SyncKind. In LSP 3.x, clients make this request by omitting
-           both Range and RangeLength from their request. Consequently, the
-           attributes "range" and "rangeLength" will be missing from ``Full``
-           content update client requests in the pygls Python library.
-
-        """
-        if isinstance(change, types.TextDocumentContentChangeEvent_Type1):
-            if self._is_sync_kind_incremental:
-                self._apply_incremental_change(change)
-                return
-            # Log an error, but still perform full update to preserve existing
-            # assumptions in test_document/test_document_full_edit. Test breaks
-            # otherwise, and fixing the tests would require a broader fix to
-            # protocol.py.
-            logger.error(
-                "Unsupported client-provided TextDocumentContentChangeEvent. "
-                "Please update / submit a Pull Request to your LSP client."
-            )
-
-        if self._is_sync_kind_none:
-            self._apply_none_change(change)
-        else:
-            self._apply_full_change(change)
-
-    @property
-    def lines(self) -> List[str]:
-        return self.source.splitlines(True)
-
-    def offset_at_position(self, client_position: types.Position) -> int:
-        """Return the character offset pointed at by the given client_position."""
-        lines = self.lines
-        server_position = self._position_codec.position_from_client_units(
-            lines, client_position
-        )
-        row, col = server_position.line, server_position.character
-        return col + sum(
-            self._position_codec.client_num_units(line) for line in lines[:row]
-        )
-
-    @property
-    def source(self) -> str:
-        if self._source is None:
-            with io.open(self.path, "r", encoding="utf-8") as f:
-                return f.read()
-        return self._source
-
-    def word_at_position(
-        self,
-        client_position: types.Position,
-        re_start_word: Pattern[str] = RE_START_WORD,
-        re_end_word: Pattern[str] = RE_END_WORD,
-    ) -> str:
-        """Return the word at position.
-
-        The word is constructed in two halves, the first half is found by taking
-        the first match of ``re_start_word`` on the line up until
-        ``position.character``.
-
-        The second half is found by taking ``position.character`` up until the
-        last match of ``re_end_word`` on the line.
-
-        :func:`python:re.findall` is used to find the matches.
-
-        Parameters
-        ----------
-        position
-           The line and character offset.
-
-        re_start_word
-           The regular expression for extracting the word backward from
-           position. The default pattern is ``[A-Za-z_0-9]*$``.
-
-        re_end_word
-           The regular expression for extracting the word forward from
-           position. The default pattern is ``^[A-Za-z_0-9]*``.
-
-        Returns
-        -------
-        str
-           The word (obtained by concatenating the two matches) at position.
-        """
-        lines = self.lines
-        if client_position.line >= len(lines):
-            return ""
-
-        server_position = self._position_codec.position_from_client_units(
-            lines, client_position
-        )
-        row, col = server_position.line, server_position.character
-        line = lines[row]
-        # Split word in two
-        start = line[:col]
-        end = line[col:]
-
-        # Take end of start and start of end to find word
-        # These are guaranteed to match, even if they match the empty string
-        m_start = re_start_word.findall(start)
-        m_end = re_end_word.findall(end)
-
-        return m_start[0] + m_end[-1]
diff --git a/server/libs/pygls/workspace/workspace.py b/server/libs/pygls/workspace/workspace.py
deleted file mode 100644
index 405a798..0000000
--- a/server/libs/pygls/workspace/workspace.py
+++ /dev/null
@@ -1,323 +0,0 @@
-############################################################################
-# Original work Copyright 2017 Palantir Technologies, Inc.                 #
-# Original work licensed under the MIT License.                            #
-# See ThirdPartyNotices.txt in the project root for license information.   #
-# All modifications Copyright (c) Open Law Library. All rights reserved.   #
-#                                                                          #
-# Licensed under the Apache License, Version 2.0 (the "License")           #
-# you may not use this file except in compliance with the License.         #
-# You may obtain a copy of the License at                                  #
-#                                                                          #
-#     http: // www.apache.org/licenses/LICENSE-2.0                         #
-#                                                                          #
-# Unless required by applicable law or agreed to in writing, software      #
-# distributed under the License is distributed on an "AS IS" BASIS,        #
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
-# See the License for the specific language governing permissions and      #
-# limitations under the License.                                           #
-############################################################################
-import copy
-import logging
-import os
-import warnings
-from typing import Dict, List, Optional, Union
-
-from lsprotocol import types
-from lsprotocol.types import (
-    PositionEncodingKind,
-    TextDocumentSyncKind,
-    WorkspaceFolder,
-)
-from pygls.uris import to_fs_path, uri_scheme
-from pygls.workspace.text_document import TextDocument
-from pygls.workspace.position_codec import PositionCodec
-
-logger = logging.getLogger(__name__)
-
-
-class Workspace(object):
-    def __init__(
-        self,
-        root_uri: Optional[str],
-        sync_kind: TextDocumentSyncKind = TextDocumentSyncKind.Incremental,
-        workspace_folders: Optional[List[WorkspaceFolder]] = None,
-        position_encoding: Optional[
-            Union[PositionEncodingKind, str]
-        ] = PositionEncodingKind.Utf16,
-    ):
-        self._root_uri = root_uri
-        if self._root_uri is not None:
-            self._root_uri_scheme = uri_scheme(self._root_uri)
-            root_path = to_fs_path(self._root_uri)
-            if root_path is None:
-                raise Exception("Couldn't get `root_path` from `root_uri`")
-            self._root_path = root_path
-        else:
-            self._root_path = None
-        self._sync_kind = sync_kind
-        self._text_documents: Dict[str, TextDocument] = {}
-        self._notebook_documents: Dict[str, types.NotebookDocument] = {}
-
-        # Used to lookup notebooks which contain a given cell.
-        self._cell_in_notebook: Dict[str, str] = {}
-        self._folders: Dict[str, WorkspaceFolder] = {}
-        self._docs: Dict[str, TextDocument] = {}
-        self._position_encoding = position_encoding
-        self._position_codec = PositionCodec(encoding=position_encoding)
-
-        if workspace_folders is not None:
-            for folder in workspace_folders:
-                self.add_folder(folder)
-
-    @property
-    def position_encoding(self) -> Optional[Union[PositionEncodingKind, str]]:
-        return self._position_encoding
-
-    @property
-    def position_codec(self) -> PositionCodec:
-        return self._position_codec
-
-    def _create_text_document(
-        self,
-        doc_uri: str,
-        source: Optional[str] = None,
-        version: Optional[int] = None,
-        language_id: Optional[str] = None,
-    ) -> TextDocument:
-        return TextDocument(
-            doc_uri,
-            source=source,
-            version=version,
-            language_id=language_id,
-            sync_kind=self._sync_kind,
-            position_codec=self._position_codec,
-        )
-
-    def add_folder(self, folder: WorkspaceFolder):
-        self._folders[folder.uri] = folder
-
-    @property
-    def documents(self):
-        warnings.warn(
-            "'workspace.documents' has been deprecated, use "
-            "'workspace.text_documents' instead",
-            DeprecationWarning,
-            stacklevel=2,
-        )
-        return self.text_documents
-
-    @property
-    def notebook_documents(self):
-        return self._notebook_documents
-
-    @property
-    def text_documents(self):
-        return self._text_documents
-
-    @property
-    def folders(self):
-        return self._folders
-
-    def get_notebook_document(
-        self, *, notebook_uri: Optional[str] = None, cell_uri: Optional[str] = None
-    ) -> Optional[types.NotebookDocument]:
-        """Return the notebook corresponding with the given uri.
-
-        If both ``notebook_uri`` and ``cell_uri`` are given, ``notebook_uri`` takes
-        precedence.
-
-        Parameters
-        ----------
-        notebook_uri
-           If given, return the notebook document with the given uri.
-
-        cell_uri
-           If given, return the notebook document which contains a cell with the
-           given uri
-
-        Returns
-        -------
-        Optional[NotebookDocument]
-           The requested notebook document if found, ``None`` otherwise.
-        """
-        if notebook_uri is not None:
-            return self._notebook_documents.get(notebook_uri)
-
-        if cell_uri is not None:
-            notebook_uri = self._cell_in_notebook.get(cell_uri)
-            if notebook_uri is None:
-                return None
-
-            return self._notebook_documents.get(notebook_uri)
-
-        return None
-
-    def get_text_document(self, doc_uri: str) -> TextDocument:
-        """
-        Return a managed document if-present,
-        else create one pointing at disk.
-
-        See https://github.com/Microsoft/language-server-protocol/issues/177
-        """
-        return self._text_documents.get(doc_uri) or self._create_text_document(doc_uri)
-
-    def is_local(self):
-        return (
-            self._root_uri_scheme == "" or self._root_uri_scheme == "file"
-        ) and os.path.exists(self._root_path)
-
-    def put_notebook_document(self, params: types.DidOpenNotebookDocumentParams):
-        notebook = params.notebook_document
-
-        # Create a fresh instance to ensure our copy cannot be accidentally modified.
-        self._notebook_documents[notebook.uri] = copy.deepcopy(notebook)
-
-        for cell_document in params.cell_text_documents:
-            self.put_text_document(cell_document, notebook_uri=notebook.uri)
-
-    def put_text_document(
-        self,
-        text_document: types.TextDocumentItem,
-        notebook_uri: Optional[str] = None,
-    ):
-        """Add a text document to the workspace.
-
-        Parameters
-        ----------
-        text_document
-           The text document to add
-
-        notebook_uri
-           If set, indicates that this text document represents a cell in a notebook
-           document
-        """
-        doc_uri = text_document.uri
-
-        self._text_documents[doc_uri] = self._create_text_document(
-            doc_uri,
-            source=text_document.text,
-            version=text_document.version,
-            language_id=text_document.language_id,
-        )
-
-        if notebook_uri:
-            self._cell_in_notebook[doc_uri] = notebook_uri
-
-    def remove_notebook_document(self, params: types.DidCloseNotebookDocumentParams):
-        notebook_uri = params.notebook_document.uri
-        self._notebook_documents.pop(notebook_uri, None)
-
-        for cell_document in params.cell_text_documents:
-            self.remove_text_document(cell_document.uri)
-
-    def remove_text_document(self, doc_uri: str):
-        self._text_documents.pop(doc_uri, None)
-        self._cell_in_notebook.pop(doc_uri, None)
-
-    def remove_folder(self, folder_uri: str):
-        self._folders.pop(folder_uri, None)
-        try:
-            del self._folders[folder_uri]
-        except KeyError:
-            pass
-
-    @property
-    def root_path(self):
-        return self._root_path
-
-    @property
-    def root_uri(self):
-        return self._root_uri
-
-    def update_notebook_document(self, params: types.DidChangeNotebookDocumentParams):
-        uri = params.notebook_document.uri
-        notebook = self._notebook_documents[uri]
-        notebook.version = params.notebook_document.version
-
-        if params.change.metadata:
-            notebook.metadata = params.change.metadata
-
-        cell_changes = params.change.cells
-        if cell_changes is None:
-            return
-
-        # Process changes to any cell metadata.
-        nb_cells = {cell.document: cell for cell in notebook.cells}
-        for new_data in cell_changes.data or []:
-            nb_cell = nb_cells.get(new_data.document)
-            if nb_cell is None:
-                logger.warning(
-                    "Ignoring metadata for '%s': not in notebook.", new_data.document
-                )
-                continue
-
-            nb_cell.kind = new_data.kind
-            nb_cell.metadata = new_data.metadata
-            nb_cell.execution_summary = new_data.execution_summary
-
-        # Process changes to the notebook's structure
-        structure = cell_changes.structure
-        if structure:
-            cells = notebook.cells
-            new_cells = structure.array.cells or []
-
-            # Re-order the cells
-            before = cells[: structure.array.start]
-            after = cells[(structure.array.start + structure.array.delete_count) :]
-            notebook.cells = [*before, *new_cells, *after]
-
-            for new_cell in structure.did_open or []:
-                self.put_text_document(new_cell, notebook_uri=uri)
-
-            for removed_cell in structure.did_close or []:
-                self.remove_text_document(removed_cell.uri)
-
-        # Process changes to the text content of existing cells.
-        for text in cell_changes.text_content or []:
-            for change in text.changes:
-                self.update_text_document(text.document, change)
-
-    def update_text_document(
-        self,
-        text_doc: types.VersionedTextDocumentIdentifier,
-        change: types.TextDocumentContentChangeEvent,
-    ):
-        doc_uri = text_doc.uri
-        self._text_documents[doc_uri].apply_change(change)
-        self._text_documents[doc_uri].version = text_doc.version
-
-    def get_document(self, *args, **kwargs):
-        warnings.warn(
-            "'workspace.get_document' has been deprecated, use "
-            "'workspace.get_text_document' instead",
-            DeprecationWarning,
-            stacklevel=2,
-        )
-        return self.get_text_document(*args, **kwargs)
-
-    def remove_document(self, *args, **kwargs):
-        warnings.warn(
-            "'workspace.remove_document' has been deprecated, use "
-            "'workspace.remove_text_document' instead",
-            DeprecationWarning,
-            stacklevel=2,
-        )
-        return self.remove_text_document(*args, **kwargs)
-
-    def put_document(self, *args, **kwargs):
-        warnings.warn(
-            "'workspace.put_document' has been deprecated, use "
-            "'workspace.put_text_document' instead",
-            DeprecationWarning,
-            stacklevel=2,
-        )
-        return self.put_text_document(*args, **kwargs)
-
-    def update_document(self, *args, **kwargs):
-        warnings.warn(
-            "'workspace.update_document' has been deprecated, use "
-            "'workspace.update_text_document' instead",
-            DeprecationWarning,
-            stacklevel=2,
-        )
-        return self.update_text_document(*args, **kwargs)
diff --git a/server/libs/tclint-0.6.0.dist-info/INSTALLER b/server/libs/tclint-0.6.0.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/server/libs/tclint-0.6.0.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/server/libs/tclint-0.6.0.dist-info/METADATA b/server/libs/tclint-0.6.0.dist-info/METADATA
deleted file mode 100644
index ca24afa..0000000
--- a/server/libs/tclint-0.6.0.dist-info/METADATA
+++ /dev/null
@@ -1,112 +0,0 @@
-Metadata-Version: 2.4
-Name: tclint
-Version: 0.6.0
-Summary: A CLI utility for linting and analyzing Tcl code.
-Author-email: Noah Moroze 
-License: MIT License
-Requires-Python: >=3.9
-Description-Content-Type: text/markdown
-License-File: LICENSE
-Requires-Dist: ply==3.11
-Requires-Dist: tomli~=2.0.1; python_version < "3.11"
-Requires-Dist: pathspec==0.11.2
-Requires-Dist: importlib-metadata==6.8.0
-Requires-Dist: pygls==1.3.1
-Requires-Dist: voluptuous==0.15.2
-Provides-Extra: dev
-Requires-Dist: black; extra == "dev"
-Requires-Dist: flake8; extra == "dev"
-Requires-Dist: pytest; extra == "dev"
-Requires-Dist: pytest-timeout; extra == "dev"
-Requires-Dist: codespell; extra == "dev"
-Requires-Dist: pytest-lsp; extra == "dev"
-Dynamic: license-file
-
-# tclint   [![CI](https://github.com/nmoroze/tclint/actions/workflows/ci.yml/badge.svg)](https://github.com/nmoroze/tclint/actions/workflows/ci.yml)
-
-`tclint` is a collection of modern dev tools for Tcl. It includes a linter, a formatter, and a language server that provides Tcl support to your editor of choice.
-
-### Features
-
-- [Editor integration][lsp] for VS Code, Neovim, and Emacs
-- [Linting][violations] for common Tcl errors
-- [Formatter][tclfmt] that enforces a consistent, readable style
-- [Plugin system](docs/plugins.md) that supports Tcl variants
-- [More features][features] coming soon!
-
-## Getting Started
-
-Install `tclint` from PyPI using [`pipx`](https://pypa.github.io/pipx/) (recommended):
-
-```sh
-pipx install tclint
-```
-
-Or with `pip`:
-
-```sh
-pip install tclint
-```
-
-Run `tclint` on a Tcl source file by providing its path as a positional argument:
-
-```sh
-tclint example.tcl
-```
-
-If the file contains any lint violations, they will be printed and `tclint` will return a non-zero exit code. Otherwise, the output will be empty and `tclint` will exit successfully.
-
-### Example
-
-```console
-$ cat example.tcl
-if { [expr {$input > 10}] } {
-  puts $input is greater than 10!
-}
-$ tclint example.tcl
-data/example.tcl:1:6: unnecessary command substitution within expression [redundant-expr]
-data/example.tcl:2:3: too many args for puts: got 5, expected no more than 3 [command-args]
-```
-
-## Usage
-
-`tclint` is a command-line utility. It takes a list of paths as positional arguments, which may either be direct paths to source files, or directories which will be recursively searched for files ending in `.tcl`, `.sdc`, `.xdc`, or `.upf`.
-
-Collected files will be checked for lint violations.  See the
-[Violations](docs/violations.md) documentation page for a description of all
-lint violations `tclint` may report.
-
-Aspects of `tclint`'s behavior can be controlled by a configuration file. By default, `tclint` will look for a file named `tclint.toml` or `.tclint` in the current working directory (in that order), but a path to an alternate configuration file can be provided using the `-c` or `--config` flag. See [Configuration](docs/configuration.md) for documentation on the configuration file.
-
-`tclint` includes a plugin system for checking EDA tool-specific commands. See the [Plugins](docs/plugins.md) documentation page for more info.
-
-## Contributing
-
-`tclint` welcomes community contributions. The best way to help the project is to [open an issue](https://github.com/nmoroze/tclint/issues/new) if you find a bug or have a feature request.
-
-PRs are also welcome, but for non-trivial changes please open an issue first to solicit feedback. This helps avoid wasted effort.
-
-Use the following steps to set up `tclint` for local development:
-
-```sh
-$ git clone https://github.com/nmoroze/tclint.git # or URL to fork
-$ cd tclint
-$ pip install -e .[dev]
-```
-
-Please format, lint, and run tests before submitting changes:
-
-```sh
-$ black --preview .
-$ ./util/pre-commit
-```
-
-## License
-
-This project is copyright Noah Moroze, released under the [MIT license](LICENSE).
-
-[vscode]: https://marketplace.visualstudio.com/items?itemName=nmoroze.tclint
-[violations]: docs/violations.md
-[lsp]: docs/lsp.md
-[tclfmt]: docs/tclfmt.md
-[features]: https://github.com/nmoroze/tclint/issues/91
diff --git a/server/libs/tclint-0.6.0.dist-info/RECORD b/server/libs/tclint-0.6.0.dist-info/RECORD
deleted file mode 100644
index 6f60013..0000000
--- a/server/libs/tclint-0.6.0.dist-info/RECORD
+++ /dev/null
@@ -1,51 +0,0 @@
-../../bin/tclfmt.exe,sha256=8ZZ_4y2Bn-gjRcDczvxwNhwRfZ-MlnkLw5NSFVnorMI,108435
-../../bin/tclint.exe,sha256=qChLBArPHW4hqqqd04-iDo9uoAQoNYKKCYZWdgaifhc,108435
-../../bin/tclsp.exe,sha256=-GEYOcDbCgp7WBq2zcwTNxO7RM-3vBQUG62K2aqWuCY,108434
-tclint-0.6.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-tclint-0.6.0.dist-info/METADATA,sha256=FMBk7GnSMWPVKrjBqk6Lxu4Wyf0-xG-Fne14sDdfuvA,4061
-tclint-0.6.0.dist-info/RECORD,,
-tclint-0.6.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-tclint-0.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
-tclint-0.6.0.dist-info/entry_points.txt,sha256=IKl_khZUS1DefUWuXWPY2cG0cLD1FRMh3qrhXIOy7O8,112
-tclint-0.6.0.dist-info/licenses/LICENSE,sha256=PGii0wulXro34f25070gTG-JRGM-TAyXyKVObnNJU68,1055
-tclint-0.6.0.dist-info/top_level.txt,sha256=_cnnEELsoakzUgD9HHdivUoNbpKG9tUGznWvbGLmHQM,7
-tclint/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-tclint/__main__.py,sha256=b18i_1-ZvzsA-TjgZUbH7MNVwbmsoiqIXZrg0lUvJNI,64
-tclint/__pycache__/__init__.cpython-311.pyc,,
-tclint/__pycache__/__main__.cpython-311.pyc,,
-tclint/__pycache__/_version.cpython-311.pyc,,
-tclint/__pycache__/checks.cpython-311.pyc,,
-tclint/__pycache__/comments.cpython-311.pyc,,
-tclint/__pycache__/config.cpython-311.pyc,,
-tclint/__pycache__/format.cpython-311.pyc,,
-tclint/__pycache__/lexer.cpython-311.pyc,,
-tclint/__pycache__/parser.cpython-311.pyc,,
-tclint/__pycache__/syntax_tree.cpython-311.pyc,,
-tclint/__pycache__/violations.cpython-311.pyc,,
-tclint/_version.py,sha256=jF9TuoEIJRaca3ScKo6qaz6PzaMlu7jjuSQIrJ3nX4U,511
-tclint/checks.py,sha256=u6EI1V0fNRhcFAGBeKdXlHrCHrOD0cUAyXpzYgzBcq8,6872
-tclint/cli/__pycache__/tclfmt.cpython-311.pyc,,
-tclint/cli/__pycache__/tclint.cpython-311.pyc,,
-tclint/cli/__pycache__/tclsp.cpython-311.pyc,,
-tclint/cli/__pycache__/utils.cpython-311.pyc,,
-tclint/cli/tclfmt.py,sha256=jeVLuPkGUkTx2RTqmdcPZu13m7x43DQwlumXFwlL5oA,5517
-tclint/cli/tclint.py,sha256=RYWm_41AUOdbY0fXOSkOy1-sMVYUmwPyRklG-DOa3dw,4488
-tclint/cli/tclsp.py,sha256=martVsLCMZQKOg0WAZuWLJ8wO2wwh0LVVrkFcbLcFMY,14633
-tclint/cli/utils.py,sha256=eaGUozjoyJecVOHMU_fFJWCv1JoNdH_eonj5os_6XB8,2924
-tclint/commands/__init__.py,sha256=CQVM2J2JOIWkt8GIxbIeCIqQTBmuwKzVO6f1eguwix0,1113
-tclint/commands/__pycache__/__init__.cpython-311.pyc,,
-tclint/commands/__pycache__/builtin.cpython-311.pyc,,
-tclint/commands/__pycache__/checks.cpython-311.pyc,,
-tclint/commands/__pycache__/plugins.cpython-311.pyc,,
-tclint/commands/__pycache__/schema.cpython-311.pyc,,
-tclint/commands/builtin.py,sha256=ny6ERMBsqesK0ML46oVWwOlKuU4Wqq7G8NvkOQbn_Ec,36147
-tclint/commands/checks.py,sha256=7ia0ZbhTLHvSbwVimU2wnEqB1SeRdyC40VMui8s7Z3I,8556
-tclint/commands/plugins.py,sha256=OX42Dm9wXoGUnPUAr4PWj9zWBu7huz6O2YKEqlqprck,2640
-tclint/commands/schema.py,sha256=nPXrgxOl5codb0RtRp-kUI85ML76ZF58eadGanZq3S8,979
-tclint/comments.py,sha256=j50bULPa_l7yhHVJw2HJF0AQMP5_dOYtL78haMIw5kA,3019
-tclint/config.py,sha256=-JM6DtkznWpnJ-wDKxc-uONGjBlmY1--73k-AmTnrZs,13801
-tclint/format.py,sha256=DyYejVdV_gOFkbuo7U2DezoEz129hRHe5hbg61XMHWM,16799
-tclint/lexer.py,sha256=I81EHH47no0ljjpfa0bHNTJrkZqGgU6-AgH0XeIK_5Q,6100
-tclint/parser.py,sha256=fInbPEXRDfgAjf5DX8I7exQwJaRd4qk6FULO-eWVMeM,28223
-tclint/syntax_tree.py,sha256=tfG4_Ff_AD_tGTHID_pW2Qdz7gRH-3NnfyK3hIj-zeg,11727
-tclint/violations.py,sha256=g2nYpPViuxL6LqLL64_kkGzeGxpTZQ1L9z5jusBGFEA,1219
diff --git a/server/libs/tclint-0.6.0.dist-info/REQUESTED b/server/libs/tclint-0.6.0.dist-info/REQUESTED
deleted file mode 100644
index e69de29..0000000
diff --git a/server/libs/tclint-0.6.0.dist-info/WHEEL b/server/libs/tclint-0.6.0.dist-info/WHEEL
deleted file mode 100644
index e7fa31b..0000000
--- a/server/libs/tclint-0.6.0.dist-info/WHEEL
+++ /dev/null
@@ -1,5 +0,0 @@
-Wheel-Version: 1.0
-Generator: setuptools (80.9.0)
-Root-Is-Purelib: true
-Tag: py3-none-any
-
diff --git a/server/libs/tclint-0.6.0.dist-info/entry_points.txt b/server/libs/tclint-0.6.0.dist-info/entry_points.txt
deleted file mode 100644
index c182ada..0000000
--- a/server/libs/tclint-0.6.0.dist-info/entry_points.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-[console_scripts]
-tclfmt = tclint.cli.tclfmt:main
-tclint = tclint.cli.tclint:main
-tclsp = tclint.cli.tclsp:main
diff --git a/server/libs/tclint-0.6.0.dist-info/licenses/LICENSE b/server/libs/tclint-0.6.0.dist-info/licenses/LICENSE
deleted file mode 100644
index 85a1017..0000000
--- a/server/libs/tclint-0.6.0.dist-info/licenses/LICENSE
+++ /dev/null
@@ -1,8 +0,0 @@
-Copyright Noah Moroze
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
diff --git a/server/libs/tclint-0.6.0.dist-info/top_level.txt b/server/libs/tclint-0.6.0.dist-info/top_level.txt
deleted file mode 100644
index 3543f35..0000000
--- a/server/libs/tclint-0.6.0.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-tclint
diff --git a/server/libs/tclint/__init__.py b/server/libs/tclint/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/server/libs/tclint/__main__.py b/server/libs/tclint/__main__.py
deleted file mode 100644
index 95fa5d0..0000000
--- a/server/libs/tclint/__main__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-import sys
-from tclint.cli.tclint import main
-
-sys.exit(main())
diff --git a/server/libs/tclint/_version.py b/server/libs/tclint/_version.py
deleted file mode 100644
index 92633a5..0000000
--- a/server/libs/tclint/_version.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# file generated by setuptools-scm
-# don't change, don't track in version control
-
-__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
-
-TYPE_CHECKING = False
-if TYPE_CHECKING:
-    from typing import Tuple
-    from typing import Union
-
-    VERSION_TUPLE = Tuple[Union[int, str], ...]
-else:
-    VERSION_TUPLE = object
-
-version: str
-__version__: str
-__version_tuple__: VERSION_TUPLE
-version_tuple: VERSION_TUPLE
-
-__version__ = version = '0.6.0'
-__version_tuple__ = version_tuple = (0, 6, 0)
diff --git a/server/libs/tclint/checks.py b/server/libs/tclint/checks.py
deleted file mode 100644
index 8566823..0000000
--- a/server/libs/tclint/checks.py
+++ /dev/null
@@ -1,227 +0,0 @@
-import re
-
-from tclint.commands import get_commands
-from tclint.violations import Rule, Violation
-
-from tclint.syntax_tree import (
-    Visitor,
-    BracedExpression,
-    Expression,
-    BracedWord,
-    QuotedWord,
-    CommandSub,
-)
-
-
-class LineLengthChecker:
-    """Ensures lines aren't too long.
-
-    Reports 'line-length' violations.
-    """
-
-    # ref: https://github.com/eslint/eslint/blob/b29a16b22f234f6134475efb6c7be5ac946556ee/lib/rules/max-len.js#L101 # noqa: E501
-    # ^ ironic lint waiver...
-    URL_RE = re.compile(r"[^:/?#]:\/\/[^?#]")
-
-    def check(self, input, _, config):
-        violations = []
-        for i, line in enumerate(input.split("\n")):
-            if self.URL_RE.search(line) is not None:
-                # ignore URLs
-                continue
-
-            lineno = i + 1
-            if len(line) > config.style_line_length:
-                start = (lineno, 1)
-                end = (lineno, len(line) + 1)
-                violations.append(
-                    Violation(
-                        Rule.LINE_LENGTH,
-                        f"line length is {len(line)}, maximum allowed is"
-                        f" {config.style_line_length}",
-                        start,
-                        end,
-                    )
-                )
-
-        return violations
-
-
-class TrailingWhitespaceChecker:
-    """Ensures lines don't include trailing whitespace.
-
-    Reports 'trailing-whitespace' violations.
-    """
-
-    def check(self, input, _, config):
-        violations = []
-        for i, line in enumerate(input.split("\n")):
-            lineno = i + 1
-
-            WHITESPACE = (" ", "\t")
-            if line.endswith(WHITESPACE):
-                start_col = len(line.rstrip("".join(WHITESPACE)))
-                start = (lineno, start_col + 1)
-                end = (lineno, len(line) + 1)
-                violations.append(
-                    Violation(
-                        Rule.TRAILING_WHITESPACE,
-                        "line has trailing whitespace",
-                        start,
-                        end,
-                    )
-                )
-
-        return violations
-
-
-class RedefinedBuiltinChecker(Visitor):
-    """Ensures names of built-in commands aren't reused by proc definitions.
-
-    Reports 'redefined-builtin' violations.
-    """
-
-    def check(self, _, tree, config):
-        self._violations = []
-
-        plugins = [config.commands] if config.commands is not None else []
-        commands = get_commands(plugins)
-        self._commands = commands.keys()
-
-        tree.accept(self, recurse=True)
-
-        return self._violations
-
-    def visit_command(self, command):
-        if command.routine.contents != "proc":
-            return
-
-        if len(command.args) == 0:
-            # This is a syntax error, but should already be caught as a command-args
-            # error by the parser's `proc` command handling.
-            return
-
-        name = command.args[0].contents
-
-        if name in self._commands:
-            self._violations.append(
-                Violation(
-                    Rule.REDEFINED_BUILTIN,
-                    f"redefinition of built-in command '{name}'",
-                    command.pos,
-                    command.args[1].end_pos,
-                )
-            )
-
-
-class UnbracedExprChecker(Visitor):
-    def check(self, _, tree, __):
-        self._violations = []
-        tree.accept(self, recurse=True)
-        return self._violations
-
-    def visit_command(self, command):
-        if command.routine.contents != "expr":
-            return
-
-        if len(command.args) == 0:
-            # This is a syntax error, but should already be caught as a command-args
-            # error by the parser's `expr` command handling.
-            return
-
-        if len(command.args) == 1 and isinstance(
-            command.args[0], (BracedExpression, Expression)
-        ):
-            return
-
-        # If we got here, tclint had trouble parsing the expression due to one of the
-        # two following cases.
-
-        for child in command.args:
-            if child.contents is None:
-                self._violations.append(
-                    Violation(
-                        Rule.UNBRACED_EXPR,
-                        "expression with substitutions should be enclosed by braces",
-                        command.args[0].pos,
-                        command.args[-1].end_pos,
-                    )
-                )
-                return
-
-        for child in command.args:
-            if isinstance(child, (BracedWord, QuotedWord)):
-                self._violations.append(
-                    Violation(
-                        Rule.UNBRACED_EXPR,
-                        "expression containing braced or quoted words should be"
-                        " enclosed by braces",
-                        command.args[0].pos,
-                        command.args[-1].end_pos,
-                    )
-                )
-                return
-
-        # If we reach here, there's probably a bug in expr parsing logic.
-        assert False, (
-            "Children of expr node were different than expected, please file a bug"
-            " report"
-        )
-
-
-class RedundantExprChecker(Visitor):
-    def check(self, _, tree, __):
-        self._violations = []
-        tree.accept(self, recurse=True)
-        return self._violations
-
-    def _check_operand(self, operand):
-        if not isinstance(operand, CommandSub) or len(operand.children) != 1:
-            return
-
-        command = operand.children[0]
-        if command.routine.contents == "expr":
-            self._violations.append(
-                Violation(
-                    Rule.REDUNDANT_EXPR,
-                    "unnecessary command substitution within expression",
-                    operand.pos,
-                    operand.end_pos,
-                )
-            )
-
-    def visit_braced_expression(self, expression):
-        if len(expression.children) == 1:
-            self._check_operand(expression.children[0])
-
-    def visit_expression(self, expression):
-        if len(expression.children) == 1:
-            self._check_operand(expression.children[0])
-
-    def visit_unary_op(self, expr):
-        self._check_operand(expr.children[1])
-
-    def visit_binary_op(self, expr):
-        self._check_operand(expr.children[0])
-        self._check_operand(expr.children[2])
-
-    def visit_ternary_op(self, expr):
-        self._check_operand(expr.children[0])
-        self._check_operand(expr.children[2])
-        self._check_operand(expr.children[4])
-
-    def visit_function(self, function):
-        for arg in function.children[1:]:
-            self._check_operand(arg)
-
-
-def get_checkers():
-    checkers = (
-        RedefinedBuiltinChecker(),
-        UnbracedExprChecker(),
-        RedundantExprChecker(),
-        LineLengthChecker(),
-        TrailingWhitespaceChecker(),
-    )
-
-    return checkers
diff --git a/server/libs/tclint/cli/tclfmt.py b/server/libs/tclint/cli/tclfmt.py
deleted file mode 100644
index cc7c8be..0000000
--- a/server/libs/tclint/cli/tclfmt.py
+++ /dev/null
@@ -1,182 +0,0 @@
-"""CLI utility for formatting Tcl code."""
-
-import argparse
-import pathlib
-import sys
-
-from tclint.cli.utils import resolve_sources, register_codec_warning
-from tclint.config import (
-    get_config,
-    setup_tclfmt_config_cli_args,
-    Config,
-    ConfigError,
-    RunConfig,
-)
-from tclint.parser import Parser, TclSyntaxError
-from tclint.format import Formatter, FormatterOpts
-
-try:
-    from tclint._version import __version__  # type: ignore
-except ModuleNotFoundError:
-    __version__ = "(unknown version)"
-
-# exit code flags
-EXIT_OK = 0
-EXIT_FORMAT_VIOLATIONS = 1
-EXIT_SYNTAX_ERROR = 2
-EXIT_INPUT_ERROR = 4
-
-
-def format(script: str, config: Config, debug=False) -> str:
-    plugins = [config.commands] if config.commands is not None else []
-    parser = Parser(debug=debug, command_plugins=plugins)
-
-    formatter = Formatter(
-        FormatterOpts(
-            indent=config.get_indent(),
-            spaces_in_braces=config.style_spaces_in_braces,
-            max_blank_lines=config.style_max_blank_lines,
-            indent_namespace_eval=config.style_indent_namespace_eval,
-        )
-    )
-    return formatter.format_top(script, parser)
-
-
-def check(path: pathlib.Path, script: str, formatted: str):
-    parser = Parser()
-    original_tree = parser.parse(script)
-    formatted_tree = parser.parse(formatted)
-    if original_tree != formatted_tree:
-        print(f"Warning: {path} syntax trees don't match", file=sys.stderr)
-        print("\n".join(original_tree.diff(formatted_tree)), file=sys.stderr)
-
-
-def main():
-    parser = argparse.ArgumentParser("tclfmt")
-    parser.add_argument(
-        "--version", action="version", version=f"%(prog)s {__version__}"
-    )
-    parser.add_argument(
-        "source",
-        nargs="+",
-        help=(
-            "files to format. By default, prints formatted files to stdout. Provide '-'"
-            " to read from stdin"
-        ),
-        type=pathlib.Path,
-    )
-
-    mode_group = parser.add_argument_group("mode")
-    mode_mutex = mode_group.add_mutually_exclusive_group(required=False)
-    mode_mutex.add_argument(
-        "--in-place", help="update files that require formatting", action="store_true"
-    )
-    mode_mutex.add_argument(
-        "--check",
-        help="list files that require formatting and set the exit code",
-        action="store_true",
-    )
-    parser.add_argument(
-        "-d",
-        "--debug",
-        action="count",
-        default=0,
-        help=(
-            "display debug output. Provide additional times to increase the verbosity"
-            " of output (e.g. -dd)"
-        ),
-    )
-    parser.add_argument(
-        "-c",
-        "--config",
-        help="path to config file",
-        type=pathlib.Path,
-        default=None,
-        metavar="",
-    )
-    setup_tclfmt_config_cli_args(parser)
-    args = parser.parse_args()
-
-    try:
-        config = get_config(args.config, pathlib.Path.cwd())
-    except ConfigError as e:
-        print(f"Invalid config file: {e}")
-        return EXIT_INPUT_ERROR
-
-    if config is None:
-        config = RunConfig()
-
-    config.apply_cli_args(args)
-
-    try:
-        # TODO: we should eventually allow tclfmt to find a config by walking up
-        # directories, at which point exclude_root should be the parent dir of
-        # the config file, unless -c is used (eslint rules)
-        exclude_root = pathlib.Path.cwd()
-        sources = resolve_sources(
-            args.source,
-            exclude_patterns=config.exclude,
-            exclude_root=exclude_root,
-            extensions=config.extensions,
-        )
-    except FileNotFoundError as e:
-        print(f"Invalid path provided: {e}")
-        return EXIT_INPUT_ERROR
-
-    retcode = EXIT_OK
-
-    register_codec_warning("replace_with_warning")
-
-    reformat_count = 0
-    for path in sources:
-        if path is None:
-            script = sys.stdin.read()
-            out_prefix = "(stdin)"
-        else:
-            with open(path, "r", errors="replace_with_warning") as f:
-                script = f.read()
-            out_prefix = str(path)
-
-        try:
-            formatted = format(
-                script, config.get_for_path(path), debug=(args.debug > 1)
-            )
-            if args.in_place and path:
-                with open(path, "w") as f:
-                    f.write(formatted)
-            elif args.check:
-                if script != formatted:
-                    print(f"{out_prefix}: needs reformatting")
-                    retcode |= EXIT_FORMAT_VIOLATIONS
-                    reformat_count += 1
-            else:
-                if args.in_place:
-                    print("Warning: --in-place option ignored when reading from stdin")
-                print(formatted, end="")
-
-            if args.debug > 0:
-                check(path, script, formatted)
-        except TclSyntaxError as e:
-            line, col = e.pos
-            print(f"{out_prefix}:{line}:{col}: syntax error: {e}", file=sys.stderr)
-            retcode |= EXIT_SYNTAX_ERROR
-            continue
-
-    if args.check:
-        messages = []
-        if reformat_count == 0:
-            messages.append("Formatting clean!")
-        elif reformat_count == 1:
-            messages.append("1 file needs reformatting.")
-        else:
-            messages.append(f"{reformat_count} files need reformatting.")
-        messages.append(
-            f"Checked {len(sources)} file{'s' if len(sources) != 1 else ''}."
-        )
-        print(" ".join(messages))
-
-    return retcode
-
-
-if __name__ == "__main__":
-    sys.exit(main())
diff --git a/server/libs/tclint/cli/tclint.py b/server/libs/tclint/cli/tclint.py
deleted file mode 100644
index 6afd8b1..0000000
--- a/server/libs/tclint/cli/tclint.py
+++ /dev/null
@@ -1,173 +0,0 @@
-"""Main CLI entry point."""
-
-import argparse
-import pathlib
-import sys
-from typing import Dict, List, Optional
-
-
-from tclint.config import (
-    get_config,
-    setup_config_cli_args,
-    Config,
-    ConfigError,
-    RunConfig,
-)
-from tclint.parser import Parser, TclSyntaxError
-from tclint.checks import get_checkers
-from tclint.violations import Violation, Rule
-from tclint.comments import CommentVisitor
-from tclint.cli.utils import resolve_sources, register_codec_warning
-
-try:
-    from tclint._version import __version__  # type: ignore
-except ModuleNotFoundError:
-    __version__ = "(unknown version)"
-
-# exit code flags
-EXIT_OK = 0
-EXIT_LINT_VIOLATIONS = 1
-EXIT_SYNTAX_ERROR = 2
-EXIT_INPUT_ERROR = 4
-
-
-def filter_violations(
-    violations: List[Violation],
-    config_ignore: List[Rule],
-    inline_ignore: Dict[int, List[Rule]],
-) -> List[Violation]:
-    filtered_violations = []
-
-    for violation in violations:
-        if violation.id in config_ignore:
-            continue
-        line = violation.start[0]
-        if line in inline_ignore and violation.id in inline_ignore[line]:
-            continue
-
-        filtered_violations.append(violation)
-
-    return filtered_violations
-
-
-def lint(
-    script: str,
-    config: Config,
-    path: Optional[pathlib.Path],
-    debug=0,
-) -> List[Violation]:
-    plugins = [config.commands] if config.commands is not None else []
-    parser = Parser(debug=(debug > 0), command_plugins=plugins)
-
-    violations = []
-    tree = parser.parse(script)
-    violations += parser.violations
-
-    if debug > 0:
-        print(tree.pretty(positions=(debug > 1)))
-
-    for checker in get_checkers():
-        violations += checker.check(script, tree, config)
-
-    v = CommentVisitor()
-    ignore_lines = v.run(tree, path)
-    violations = filter_violations(violations, config.ignore, ignore_lines)
-
-    return violations
-
-
-def main():
-    parser = argparse.ArgumentParser("tclint")
-    parser.add_argument(
-        "--version", action="version", version=f"%(prog)s {__version__}"
-    )
-    parser.add_argument(
-        "source",
-        nargs="+",
-        help="files to lint. Provide '-' to read from stdin",
-        type=pathlib.Path,
-    )
-    parser.add_argument(
-        "-d",
-        "--debug",
-        action="count",
-        default=0,
-        help=(
-            "display debug output. Provide additional times to increase the verbosity"
-            " of output (e.g. -dd)"
-        ),
-    )
-    parser.add_argument(
-        "-c",
-        "--config",
-        help="path to config file",
-        type=pathlib.Path,
-        default=None,
-        metavar="",
-    )
-    setup_config_cli_args(parser)
-    args = parser.parse_args()
-
-    try:
-        config = get_config(args.config, pathlib.Path())
-    except ConfigError as e:
-        print(f"Invalid config file: {e}")
-        return EXIT_INPUT_ERROR
-
-    if config is None:
-        config = RunConfig()
-
-    config.apply_cli_args(args)
-
-    try:
-        # TODO: we should eventually allow tclint to find a config by walking up
-        # directories, at which point exclude_root should be the parent dir of
-        # the config file, unless -c is used (eslint rules)
-        exclude_root = pathlib.Path.cwd()
-        sources = resolve_sources(
-            args.source,
-            exclude_patterns=config.exclude,
-            exclude_root=exclude_root,
-            extensions=config.extensions,
-        )
-    except FileNotFoundError as e:
-        print(f"Invalid path provided: {e}")
-        return EXIT_INPUT_ERROR
-
-    retcode = EXIT_OK
-
-    register_codec_warning("replace_with_warning")
-
-    for path in sources:
-        if path is None:
-            script = sys.stdin.read()
-            out_prefix = "(stdin)"
-        else:
-            with open(path, "r", errors="replace_with_warning") as f:
-                script = f.read()
-            out_prefix = str(path)
-
-        try:
-            violations = lint(
-                script,
-                config.get_for_path(path),
-                path,
-                debug=args.debug,
-            )
-        except TclSyntaxError as e:
-            line, col = e.start
-            print(f"{out_prefix}:{line}:{col}: syntax error: {e}")
-            retcode |= EXIT_SYNTAX_ERROR
-            continue
-
-        for violation in sorted(violations):
-            print(f"{out_prefix}:{violation}")
-
-        if len(violations) > 0:
-            retcode |= EXIT_LINT_VIOLATIONS
-
-    return retcode
-
-
-if __name__ == "__main__":
-    sys.exit(main())
diff --git a/server/libs/tclint/cli/tclsp.py b/server/libs/tclint/cli/tclsp.py
deleted file mode 100644
index b0b61dd..0000000
--- a/server/libs/tclint/cli/tclsp.py
+++ /dev/null
@@ -1,437 +0,0 @@
-import argparse
-import dataclasses
-import logging
-from pathlib import Path
-from typing import Dict, List, Optional, Tuple
-import uuid
-
-from lsprotocol import types as lsp
-
-from pygls.server import LanguageServer
-from pygls.workspace import TextDocument
-from pygls.uris import to_fs_path
-
-from tclint.cli import tclint
-from tclint.config import get_config, DEFAULT_CONFIGS, RunConfig, Config, ConfigError
-from tclint.format import Formatter, FormatterOpts
-from tclint.lexer import TclSyntaxError
-from tclint.parser import Parser
-from tclint.cli import utils
-
-try:
-    from tclint._version import __version__  # type: ignore
-except ModuleNotFoundError:
-    __version__ = "(unknown version)"
-
-
-DIAGNOSTIC_SOURCE = "tclint"
-
-
-def lint(source, config, path):
-    diagnostics = []
-
-    try:
-        violations = tclint.lint(source, config, path)
-    except TclSyntaxError as e:
-        return [
-            lsp.Diagnostic(
-                message=str(e),
-                severity=lsp.DiagnosticSeverity.Error,
-                range=lsp.Range(
-                    start=lsp.Position(e.start[0] - 1, e.start[1] - 1),
-                    end=lsp.Position(e.end[0] - 1, e.end[1] - 1),
-                ),
-                code="syntax error",
-                source=DIAGNOSTIC_SOURCE,
-            )
-        ]
-
-    for violation in violations:
-        message = violation.message
-        severity = lsp.DiagnosticSeverity.Warning
-        start = lsp.Position(
-            line=violation.start[0] - 1, character=violation.start[1] - 1
-        )
-        end = lsp.Position(line=violation.end[0] - 1, character=violation.end[1] - 1)
-
-        diagnostics.append(
-            lsp.Diagnostic(
-                message=message,
-                severity=severity,
-                range=lsp.Range(
-                    start=start,
-                    end=end,
-                ),
-                code=violation.id,
-                source=DIAGNOSTIC_SOURCE,
-            )
-        )
-
-    return diagnostics
-
-
-@dataclasses.dataclass
-class ExtensionSettings:
-    # This path is expected to be absolute.
-    config_file: Optional[Path] = dataclasses.field(default=None)
-
-
-class TclspServer(LanguageServer):
-    """Main server class. Implements pull diagnostics using a method adapted from
-    https://pygls.readthedocs.io/en/latest/examples/pull-diagnostics.html."""
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self.diagnostics = {}
-        self.global_config: RunConfig = None
-        # Maps workspace roots to configs.
-        self.configs: Dict[Path, RunConfig] = {}
-        self.client_supports_refresh = False
-
-        self.global_settings = ExtensionSettings()
-        self.workspace_settings: Dict[Path, ExtensionSettings] = {}
-
-    def get_roots(self) -> List[Path]:
-        """Returns root folders currently open in the workspace."""
-        roots = []
-        for uri in self.workspace.folders.keys():
-            path = to_fs_path(uri)
-            if path is not None:
-                roots.append(Path(path))
-
-        if len(roots) > 0:
-            return roots
-
-        if self.workspace.root_path is not None:
-            roots.append(Path(self.workspace.root_path))
-
-        return roots
-
-    def get_root(self, path: Path) -> Optional[Path]:
-        """Returns workspace root folder that's closest to path.
-
-        Returns None if path is not in a workspace folder or if there are no workspace
-        folders.
-        """
-        roots = self.get_roots()
-        closest_root = None
-        distance = float("inf")
-        for root in roots:
-            try:
-                relpath = path.relative_to(root)
-            except ValueError:
-                continue
-            if len(relpath.parts) < distance:
-                distance = len(relpath.parts)
-                closest_root = root
-        return closest_root
-
-    def get_config_file(self, workspace_root: Path) -> Optional[Path]:
-        if workspace_root in self.workspace_settings:
-            settings = self.workspace_settings[workspace_root]
-            return settings.config_file
-        return self.global_settings.config_file
-
-    def load_configs(self):
-        self.configs = {}
-        for root in self.get_roots():
-            try:
-                path = self.get_config_file(root)
-                config = get_config(path, root)
-                if config is not None:
-                    self.configs[root] = config
-            except ConfigError as e:
-                self.show_message(f"Error loading config file: {e}")
-
-        # If a global config file exists, we apply it to any file not under a workspace
-        # folder.
-        global_path = self.global_settings.config_file
-        if global_path is not None:
-            try:
-                config = get_config(global_path, global_path.parent)
-                self.global_config = config
-            except ConfigError as e:
-                self.show_message(f"Error loading config file: {e}")
-
-    def get_config(self, path: Path, root: Optional[Path]) -> Config:
-        if root in self.configs:
-            return self.configs[root].get_for_path(path)
-        if self.global_config is not None:
-            return self.global_config.get_for_path(path)
-        return Config()
-
-    def _compute_diagnostics(self, document: TextDocument) -> List[lsp.Diagnostic]:
-        path = Path(document.path)
-        root = self.get_root(path)
-        config = self.get_config(path, root)
-
-        if root is None:
-            root = path.parent
-
-        is_excluded = utils.make_exclude_filter(config.exclude)
-        if is_excluded(path, root):
-            return []
-
-        return lint(document.source, config, path)
-
-    def compute_diagnostics(self, document: TextDocument):
-        # `None` sentinel ensures that `diagnostics` gets updated if the URI is not
-        # present.
-        _, previous = self.diagnostics.get(document.uri, (0, None))
-
-        diagnostics = self._compute_diagnostics(document)
-
-        # Only update if the list has changed
-        if previous != diagnostics:
-            self.diagnostics[document.uri] = (document.version, diagnostics)
-
-    def format(
-        self,
-        document: TextDocument,
-        options: lsp.FormattingOptions,
-        range: Optional[Tuple[int, int]] = None,
-    ):
-        path = Path(document.path)
-        root = self.get_root(path)
-        config = self.get_config(path, root)
-
-        parser = Parser()
-
-        if config.style_indent is None:
-            indent = "\t" if not options.insert_spaces else " " * options.tab_size
-        else:
-            indent = config.get_indent()
-
-        formatter = Formatter(
-            FormatterOpts(
-                indent=indent,
-                spaces_in_braces=config.style_spaces_in_braces,
-                max_blank_lines=config.style_max_blank_lines,
-                indent_namespace_eval=config.style_indent_namespace_eval,
-            )
-        )
-
-        if range is not None:
-            start, end = range
-            return formatter.format_partial(document.source[start:end], parser)
-
-        return formatter.format_top(document.source, parser)
-
-
-server = TclspServer("tclsp", __version__)
-
-
-@server.feature(lsp.TEXT_DOCUMENT_DID_OPEN)
-def did_open(ls: TclspServer, params: lsp.DidOpenTextDocumentParams):
-    """Parse each document when it is opened"""
-    logging.debug("Received %s: %s", lsp.TEXT_DOCUMENT_DID_OPEN, params)
-    doc = ls.workspace.get_text_document(params.text_document.uri)
-    ls.compute_diagnostics(doc)
-
-
-@server.feature(lsp.TEXT_DOCUMENT_DID_CHANGE)
-def did_change(ls: TclspServer, params: lsp.DidOpenTextDocumentParams):
-    """Parse each document when it is changed"""
-    logging.debug("Received %s: %s", lsp.TEXT_DOCUMENT_DID_CHANGE, params)
-    doc = ls.workspace.get_text_document(params.text_document.uri)
-    ls.compute_diagnostics(doc)
-
-
-@server.feature(
-    lsp.TEXT_DOCUMENT_DIAGNOSTIC,
-    lsp.DiagnosticOptions(
-        identifier="pull-diagnostics",
-        inter_file_dependencies=False,
-        # We could support workspace diagnostics, although an implementation based on
-        # the pygls tutorial seems to add client-server noise for no benefit (it ends up
-        # replying to a frequent workspace diagnostics request with "unchanged"
-        # messages).
-        workspace_diagnostics=False,
-    ),
-)
-def document_diagnostic(ls: TclspServer, params: lsp.DocumentDiagnosticParams):
-    """Return diagnostics for the requested document"""
-    logging.debug("Received %s: %s", lsp.TEXT_DOCUMENT_DIAGNOSTIC, params)
-
-    was_cached = True
-    if (uri := params.text_document.uri) not in ls.diagnostics:
-        was_cached = False
-        doc = ls.workspace.get_text_document(uri)
-        ls.compute_diagnostics(doc)
-
-    version, diagnostics = ls.diagnostics[uri]
-    result_id = f"{uri}@{version}"
-
-    if was_cached and result_id == params.previous_result_id:
-        return lsp.UnchangedDocumentDiagnosticReport(result_id)
-
-    return lsp.FullDocumentDiagnosticReport(items=diagnostics, result_id=result_id)
-
-
-@server.feature(lsp.WORKSPACE_DID_CHANGE_WATCHED_FILES)
-def change_watched_files(ls: TclspServer, params: lsp.DidChangeWatchedFilesParams):
-    logging.debug("Received %s: %s", lsp.WORKSPACE_DID_CHANGE_WATCHED_FILES, params)
-
-    # Clear diagnostics cache so they get recalculated when requested
-    ls.diagnostics = {}
-
-    ls.load_configs()
-    if ls.client_supports_refresh:
-        ls.lsp.send_request(lsp.WORKSPACE_DIAGNOSTIC_REFRESH, None)
-
-
-@server.feature(lsp.TEXT_DOCUMENT_FORMATTING)
-def format_document(ls: TclspServer, params: lsp.DocumentFormattingParams):
-    """Format the entire document"""
-    doc = ls.workspace.get_text_document(params.text_document.uri)
-
-    source = doc.source
-    start = lsp.Position(line=0, character=0)
-    last_line = source.rsplit("\n", 1)[-1]
-    end = lsp.Position(line=source.count("\n"), character=len(last_line))
-
-    formatted = ls.format(doc, params.options)
-    return [
-        lsp.TextEdit(
-            range=lsp.Range(start=start, end=end),
-            new_text=formatted,
-        )
-    ]
-
-
-@server.feature(lsp.TEXT_DOCUMENT_RANGE_FORMATTING)
-def format_range(ls: TclspServer, params: lsp.DocumentRangeFormattingParams):
-    """Format the given range with a document"""
-    doc = ls.workspace.get_text_document(params.text_document.uri)
-
-    # Round up range to full lines.
-    start_line = params.range.start.line
-    end_line = params.range.end.line
-    if params.range.end.character > 0:
-        end_line += 1
-    range = lsp.Range(
-        start=lsp.Position(line=start_line, character=0),
-        end=lsp.Position(line=end_line, character=0),
-    )
-
-    start = doc.offset_at_position(range.start)
-    end = doc.offset_at_position(range.end)
-
-    try:
-        formatted = ls.format(doc, params.options, range=(start, end))
-    except TclSyntaxError:
-        return None
-
-    return [
-        lsp.TextEdit(
-            range=range,
-            new_text=formatted,
-        )
-    ]
-
-
-@server.feature(lsp.INITIALIZE)
-def initialize(ls: TclspServer, params: lsp.InitializeParams) -> None:
-    if params.initialization_options is None:
-        return
-
-    # Apply settings provided on initialization. The schema was copied from the template
-    # that the tclint-vscode extension is based on.
-    globalSettings = params.initialization_options.get("globalSettings", {})
-    if globalSettings.get("configPath"):
-        path = Path(globalSettings["configPath"]).expanduser()
-        if not path.is_absolute():
-            ls.show_message(
-                f"Warning: expected global config path to be absolute, got {path}"
-            )
-        else:
-            ls.global_settings.config_file = path
-
-    for settings in params.initialization_options.get("settings", []):
-        root = Path(settings["cwd"])
-        if root not in ls.workspace_settings:
-            ls.workspace_settings[root] = ExtensionSettings()
-        if settings.get("configPath"):
-            path = Path(settings["configPath"]).expanduser()
-            if not path.is_absolute():
-                path = root / path
-            ls.workspace_settings[root].config_file = path
-
-
-@server.feature(lsp.INITIALIZED)
-def init(ls: TclspServer, params: lsp.InitializeParams):
-    """Registers file watchers on config filenames so that we can reload configs and
-    refresh diagnostics if they've changed.
-
-    Based on code snippet in
-    https://github.com/openlawlibrary/pygls/issues/376#issuecomment-1717656614.
-    """
-    capabilities = ls.client_capabilities.workspace
-
-    try:
-        ls.client_supports_refresh = (
-            capabilities.diagnostics.refresh_support  # type: ignore[union-attr]
-        )
-    except AttributeError:
-        ls.client_supports_refresh = False
-
-    try:
-        client_supports_watched_files_registration = (
-            capabilities.did_change_watched_files.dynamic_registration  # type: ignore[union-attr] # noqa: E501
-        )
-    except AttributeError:
-        client_supports_watched_files_registration = False
-
-    if client_supports_watched_files_registration:
-        watchers = []
-        for filename in (*DEFAULT_CONFIGS, "pyproject.toml"):
-            pattern = f"**/{filename}"
-            watchers.append(lsp.FileSystemWatcher(glob_pattern=pattern))
-
-        for settings in (ls.global_settings, *ls.workspace_settings.values()):
-            if settings.config_file is not None:
-                watchers.append(
-                    lsp.FileSystemWatcher(glob_pattern=settings.config_file)
-                )
-
-        ls.register_capability(
-            lsp.RegistrationParams(
-                registrations=[
-                    lsp.Registration(
-                        id=str(uuid.uuid4()),
-                        method=lsp.WORKSPACE_DID_CHANGE_WATCHED_FILES,
-                        register_options=lsp.DidChangeWatchedFilesRegistrationOptions(
-                            watchers=watchers
-                        ),
-                    )
-                ]
-            )
-        )
-
-    ls.load_configs()
-
-
-def main():
-    parser = argparse.ArgumentParser("tclsp")
-    log_levels = {
-        "debug": logging.DEBUG,
-        "info": logging.INFO,
-        "warning": logging.WARNING,
-        "error": logging.ERROR,
-    }
-    parser.add_argument(
-        "-l",
-        "--log-level",
-        default="info",
-        type=lambda x: x.lower(),
-        help="set the log level. defaults to info",
-        choices=log_levels.keys(),
-    )
-    args = parser.parse_args()
-    logging.basicConfig(level=log_levels[args.log_level], format="%(message)s")
-
-    server.start_io()
-
-
-if __name__ == "__main__":
-    main()
diff --git a/server/libs/tclint/cli/utils.py b/server/libs/tclint/cli/utils.py
deleted file mode 100644
index a9c1e20..0000000
--- a/server/libs/tclint/cli/utils.py
+++ /dev/null
@@ -1,88 +0,0 @@
-import codecs
-import os
-import pathlib
-import re
-from typing import List, Optional
-
-import pathspec
-
-
-def register_codec_warning(name):
-    def replace_with_warning_handler(e):
-        # TODO: formal warning mechanism, include path
-        print("Warning: non-unicode characters in file, replacing with �")
-        return codecs.replace_errors(e)
-
-    codecs.register_error(name, replace_with_warning_handler)
-
-
-def make_exclude_filter(exclude_patterns: List[str]):
-    exclude_patterns = [
-        re.sub(r"^\s*#", r"\#", pattern) for pattern in exclude_patterns
-    ]
-    exclude_spec = pathspec.PathSpec.from_lines("gitwildmatch", exclude_patterns)
-
-    def is_excluded(path: pathlib.Path, root: pathlib.Path) -> bool:
-        abspath = path.resolve()
-        root = root.resolve()
-
-        try:
-            relpath = pathlib.Path(os.path.relpath(abspath, start=root))
-        except ValueError:
-            # We get here if path and exclude_root are on different drives (on Windows).
-            # Things should still behave roughly as expected without using a relative
-            # path. See test_cli_utils.py::test_exclude_filter_windows for test cases.
-            relpath = abspath
-
-        if exclude_spec.match_file(relpath):
-            return True
-        return False
-
-    return is_excluded
-
-
-def resolve_sources(
-    paths: List[pathlib.Path],
-    exclude_patterns: List[str],
-    exclude_root: pathlib.Path,
-    extensions: List[str],
-) -> List[Optional[pathlib.Path]]:
-    """Resolves paths passed via CLI to a list of filepaths to lint.
-
-    `paths` is a list of paths that may be files or directories. Files are
-    returned verbatim if they exist, and directories are recursively searched
-    for files that have an extension specified in `extensions`. Paths that match a
-    pattern in `exclude_patterns` are ignored (based on gitignore pattern
-    format, see https://git-scm.com/docs/gitignore#_pattern_format).
-
-    Raises FileNotFoundError if a supplied path does not exist.
-    """
-    extensions = [f".{ext}" if not ext.startswith(".") else ext for ext in extensions]
-    is_excluded = make_exclude_filter(exclude_patterns)
-
-    sources: List[Optional[pathlib.Path]] = []
-
-    for path in paths:
-        if str(path) == "-":
-            sources.append(None)
-            continue
-
-        if not path.exists():
-            raise FileNotFoundError(f"path {path} does not exist")
-
-        if is_excluded(path, exclude_root):
-            continue
-
-        if not path.is_dir():
-            sources.append(path)
-            continue
-
-        for dirpath, _, filenames in os.walk(path):
-            for name in filenames:
-                _, ext = os.path.splitext(name)
-                if ext.lower() in extensions:
-                    child = pathlib.Path(dirpath) / name
-                    if not is_excluded(child, exclude_root):
-                        sources.append(child)
-
-    return sources
diff --git a/server/libs/tclint/commands/__init__.py b/server/libs/tclint/commands/__init__.py
deleted file mode 100644
index b6c4222..0000000
--- a/server/libs/tclint/commands/__init__.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import pathlib
-from typing import List, Dict, Union
-
-from tclint.commands import builtin as _builtin
-from tclint.commands.plugins import PluginManager
-
-# import to expose in package
-from tclint.commands.checks import CommandArgError
-
-__all__ = ["CommandArgError", "validate_command_plugins", "get_commands"]
-
-
-def validate_command_plugins(plugins: List[str]) -> List[str]:
-    valid_plugins = []
-    for plugin in set(plugins):
-        if PluginManager.load(plugin) is not None:
-            valid_plugins.append(plugin)
-
-    return valid_plugins
-
-
-def get_commands(plugins: List[Union[str, pathlib.Path]]) -> Dict:
-    commands = {}
-    commands.update(_builtin.commands)
-
-    for plugin in plugins:
-        if isinstance(plugin, str):
-            plugin_commands = PluginManager.load(plugin)
-        elif isinstance(plugin, pathlib.Path):
-            plugin_commands = PluginManager.load_from_spec(plugin)
-        else:
-            raise TypeError(f"Plugins must be strings or paths, got {type(plugin)}")
-
-        if plugin_commands is not None:
-            commands.update(plugin_commands)
-
-    return commands
diff --git a/server/libs/tclint/commands/builtin.py b/server/libs/tclint/commands/builtin.py
deleted file mode 100644
index 44a1691..0000000
--- a/server/libs/tclint/commands/builtin.py
+++ /dev/null
@@ -1,1078 +0,0 @@
-"""Parse-time handling of Tcl's builtin commands.
-
-Based on Tcl 8.6, https://www.tcl-lang.org/man/tcl8.6/TclCmd/contents.htm.
-
-Note that the following commands are not currently supported. If support for any of
-these would be helpful for your use case, please file an issue.
-
-- Anything related to TclOO:
-  - https://www.tcl.tk/man/tcl/TclCmd/my.html
-  - https://www.tcl.tk/man/tcl/TclCmd/next.html
-  - https://www.tcl.tk/man/tcl/TclCmd/class.html
-  - https://www.tcl.tk/man/tcl/TclCmd/copy.html
-  - https://www.tcl.tk/man/tcl/TclCmd/define.html
-  - https://www.tcl.tk/man/tcl/TclCmd/object.html
-  - https://www.tcl.tk/man/tcl/TclCmd/self.html
-
-- Things that are imported via `package require`
-  - https://www.tcl.tk/man/tcl/TclCmd/dde.html
-  - https://www.tcl.tk/man/tcl/TclCmd/http.html
-  - https://www.tcl.tk/man/tcl/TclCmd/msgcat.html
-  - https://www.tcl.tk/man/tcl/TclCmd/platform.html
-  - https://www.tcl.tk/man/tcl/TclCmd/platform_shell.html
-  - https://www.tcl.tk/man/tcl/TclCmd/transchan.html
-  - https://www.tcl.tk/man/tcl/TclCmd/tcltest.html
-
-- Tcl library commands: https://www.tcl.tk/man/tcl/TclCmd/library.html
-
-- The "unknown" command: https://www.tcl.tk/man/tcl/TclCmd/unknown.html
-
-- Math ops:
-  - https://www.tcl.tk/man/tcl/TclCmd/mathfunc.html
-  - https://www.tcl.tk/man/tcl/TclCmd/mathop.html
-"""
-
-from tclint.commands.checks import (
-    CommandArgError,
-    check_count,
-    eval,
-)
-from tclint.commands.schema import commands_schema
-from tclint.syntax_tree import BareWord
-
-
-def _check_code(arg):
-    """Check 'code' argument used by return and try."""
-
-    val = arg.contents
-    if val is None:
-        return
-
-    try:
-        int(val)
-    except ValueError:
-        pass
-    else:
-        return
-
-    if val in {"ok", "error", "return", "break", "continue"}:
-        return
-
-    raise CommandArgError(
-        f"got {val}, expected one of ok, error, return, break, continue, or an integer"
-    )
-
-
-def _after(args, parser):
-    """after ms [script...]"""
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/after.html
-
-    script_arg = []
-    if len(args) > 1:
-        script_arg = eval(args[1:], parser, "after")
-
-    return args[0:1] + script_arg
-
-
-def _after_cancel(args, parser):
-    """after id|(script...)"""
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/after.html
-    check_count("after cancel", 1, None)
-
-    # TODO: raise warning about not checking code
-
-    return None
-
-
-def _after_idle(args, parser):
-    """after idle [script...]"""
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/after.html
-    return eval(args, parser, "after idle")
-
-
-def _apply(args, parser):
-    """apply func [arg...]"""
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/apply.html
-    if len(args) < 1:
-        raise CommandArgError(
-            f"not enough args to apply: got {len(args)}, expected at least 1"
-        )
-
-    func_list = parser.parse_list(args[0])
-    list_len = len(func_list.children)
-    if list_len < 2 or list_len > 3:
-        raise CommandArgError(
-            f"Invalid first argument to apply: got list of {list_len} elements,"
-            " expected 2 or 3"
-        )
-
-    body = parser.parse_script(func_list.children[1])
-    func_list.children[1] = body
-
-    return [func_list] + args[1:]
-
-
-_array = {
-    "subcommands": {
-        "anymore": {
-            "positionals": [
-                {"name": "arrayName", "value": {"type": "any"}, "required": True},
-                {"name": "searchId", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "donesearch": {
-            "positionals": [
-                {"name": "arrayName", "value": {"type": "any"}, "required": True},
-                {"name": "searchId", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "exists": {
-            "positionals": [
-                {"name": "arrayName", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "get": {
-            "positionals": [
-                {"name": "arrayName", "value": {"type": "any"}, "required": True},
-                {"name": "pattern", "value": {"type": "any"}, "required": False},
-            ]
-        },
-        "names": {
-            "positionals": [
-                {"name": "arrayName", "value": {"type": "any"}, "required": True},
-                {"name": "mode", "value": {"type": "any"}, "required": False},
-                {"name": "pattern", "value": {"type": "any"}, "required": False},
-            ]
-        },
-        "nextelement": {
-            "positionals": [
-                {"name": "arrayName", "value": {"type": "any"}, "required": True},
-                {"name": "searchId", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "set": {
-            "positionals": [
-                {"name": "arrayName", "value": {"type": "any"}, "required": True},
-                {"name": "list", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "size": {
-            "positionals": [
-                {"name": "arrayName", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "startsearch": {
-            "positionals": [
-                {"name": "arrayName", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "statistics": {
-            "positionals": [
-                {"name": "arrayName", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "unset": {
-            "positionals": [
-                {"name": "arrayName", "value": {"type": "any"}, "required": True},
-                {"name": "pattern", "value": {"type": "any"}, "required": False},
-            ]
-        },
-    },
-}
-
-
-def _catch(args, parser):
-    """catch script [resultVarName] [optionsVarName]"""
-    if len(args) < 1:
-        raise CommandArgError(
-            f"not enough args to catch: got {len(args)}, expected at least 1"
-        )
-    if len(args) > 3:
-        raise CommandArgError(
-            f"too many args to catch: got {len(args)}, expected no more than 3"
-        )
-
-    return [parser.parse_script(args[0])] + args[1:]
-
-
-_chan = {
-    "subcommands": {
-        "blocked": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "close": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-                {"name": "direction", "value": {"type": "any"}, "required": False},
-            ]
-        },
-        "configure": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-                {"name": "options", "value": {"type": "variadic"}, "required": False},
-            ],
-        },
-        "copy": {
-            "positionals": [
-                {"name": "inputChan", "value": {"type": "any"}, "required": True},
-                {"name": "outputChan", "value": {"type": "any"}, "required": True},
-                {"name": "options", "value": {"type": "variadic"}, "required": False},
-            ],
-        },
-        "create": {
-            "positionals": [
-                {"name": "mode", "value": {"type": "any"}, "required": True},
-                {"name": "cmdPrefix", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "eof": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "event": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-                {"name": "event", "value": {"type": "any"}, "required": True},
-                # TODO: parse this as script
-                {"name": "script", "value": {"type": "any"}, "required": False},
-            ]
-        },
-        "flush": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "gets": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-                {"name": "varName", "value": {"type": "any"}, "required": False},
-            ]
-        },
-        "names": {
-            "positionals": [
-                {"name": "pattern", "value": {"type": "any"}, "required": False},
-            ]
-        },
-        "pending": {
-            "positionals": [
-                {"name": "mode", "value": {"type": "any"}, "required": True},
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "pipe": {},
-        "pop": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "postevent": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-                {"name": "eventSpec", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "push": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-                {"name": "cmdPrefix", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "puts": {
-            "positionals": [
-                {"name": "-nonewline", "value": {"type": "any"}, "required": False},
-                {"name": "channelId", "value": {"type": "any"}, "required": False},
-                {"name": "string", "value": {"type": "any"}, "required": True},
-            ],
-        },
-        "read": {
-            "positionals": [
-                {"name": "-nonewline", "value": {"type": "any"}, "required": False},
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-                {"name": "numChars", "value": {"type": "any"}, "required": False},
-            ],
-        },
-        "seek": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-                {"name": "offset", "value": {"type": "any"}, "required": True},
-                {"name": "origin", "value": {"type": "any"}, "required": False},
-            ]
-        },
-        "tell": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-            ]
-        },
-        "truncate": {
-            "positionals": [
-                {"name": "channelId", "value": {"type": "any"}, "required": True},
-                {"name": "length", "value": {"type": "any"}, "required": False},
-            ]
-        },
-    },
-}
-
-
-def _dict_filter(args, parser):
-    """dict filter    [arg...]
-    dict filter  key [globPattern...]
-    dict filter  value [globPattern...]
-    """
-
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/dict.html#M8
-
-    if len(args) < 2:
-        raise CommandArgError(
-            f"not enough args to 'dict filter': got {len(args)}, expected at least 2"
-        )
-
-    if args[1].contents not in {"key", "script", "value"}:
-        raise CommandArgError(
-            "invalid argument to 'dict filter': expected filter type to be one of key,"
-            " script, or value"
-        )
-
-    if args[1].contents == "script":
-        kv_pair = parser.parse_list(args[2])
-        list_len = len(kv_pair.children)
-        if len(kv_pair.children) != 2:
-            raise CommandArgError(
-                "invalid argument to 'dict filter': expected list of 2 elements in"
-                f" second-to-last argument, got {list_len}"
-            )
-        return args[0:2] + [kv_pair, parser.parse_script(args[3])]
-
-    return None
-
-
-def _dict_map_for(cmd):
-    def check(args, parser):
-        if len(args) != 3:
-            raise CommandArgError(
-                f"wrong # of args to '{cmd}': got {len(args)}, expected 3"
-            )
-
-        # TODO: might be worth checking that arg[0] is a pair?
-
-        return args[0:2] + [parser.parse_script(args[2])]
-
-    return check
-
-
-def _dict_update(args, parser):
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/dict.html#M25
-
-    if len(args) < 4:
-        raise CommandArgError(
-            f"not enough args to 'dict update': got {len(args)}, expected at least 4"
-        )
-
-    if len(args) % 2 != 0:
-        raise CommandArgError(
-            "invalid # of args to 'dict update': expected an even number"
-        )
-
-    return args[0:-1] + [parser.parse_script(args[-1])]
-
-
-def _dict_with(args, parser):
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/dict.html#M27
-
-    if len(args) < 2:
-        raise CommandArgError(
-            f"not enough args to 'dict with': got {len(args)}, expected at least 2"
-        )
-
-    return args[0:-1] + [parser.parse_script(args[-1])]
-
-
-def _eval(args, parser):
-    return eval(args, parser, "eval")
-
-
-def _expr(args, parser):
-    if len(args) == 0:
-        raise CommandArgError("not enough args to 'expr': got 0, expected at least 1")
-
-    # Handle single argument consisting of BareWord, BracedWord, or concrete QuotedWord.
-    if len(args) == 1 and args[0].contents is not None:
-        # this method will handle the `node.contents is None` case fine, but
-        # will throw an error. We'll instead pass thru silently, since that error
-        # will be caught by a separate lint check.
-        return [parser.parse_expression(args[0])]
-
-    # Handle multiple BareWord arguments. Non-BareWords are hard to handle in this case,
-    # since we need to pop the contents out of quoted or braced words, but then we have
-    # no way of storing the original info about these words in the syntax tree.
-    contents = ""
-    last_pos = args[0].pos
-    for arg in args:
-        if not isinstance(arg, BareWord):
-            return None
-
-        if arg.pos[0] != last_pos[0]:
-            contents += "\n" * (arg.pos[0] - last_pos[0])
-            contents += " " * (arg.pos[1] - 1)
-        else:
-            contents += " " * (arg.pos[1] - last_pos[1])
-        contents += arg.contents
-        last_pos = arg.end_pos
-
-    node = BareWord(contents, pos=args[0].pos, end_pos=args[-1].end_pos)
-    return [parser.parse_expression(node)]
-
-
-def _fileevent(args, parser):
-    # ref: https://www.tcl.tk/man/tcl8.4/TclCmd/fileevent.html
-    # TODO: implement
-    raise CommandArgError(
-        "argument parsing for 'fileevent' not implemented, script argument will not be"
-        " checked for violations"
-    )
-
-
-def _for(args, parser):
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/for.html
-    if len(args) != 4:
-        raise CommandArgError(f"wrong # of args to for: got {len(args)}, expected 4")
-
-    return [
-        parser.parse_script(args[0]),
-        parser.parse_expression(args[1]),
-        parser.parse_script(args[2]),
-        parser.parse_script(args[3]),
-    ]
-
-
-def _foreach(args, parser):
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/foreach.html
-    if len(args) < 3:
-        raise CommandArgError(
-            f"insufficient args to foreach: got {len(args)}, expected at least 3"
-        )
-
-    # last argument is script body
-    return args[0:-1] + [parser.parse_script(args[-1])]
-
-
-def _if(args, parser):
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/if.html
-    # TODO: make arg checking strict
-
-    new_args = []
-
-    new_args.append(parser.parse_expression(args[0]))
-
-    while len(new_args) < len(args):
-        arg = args[len(new_args)]
-
-        if arg.contents == "then" or arg.contents == "else":
-            new_args.append(arg)
-            continue
-        if arg.contents == "elseif":
-            new_args.append(arg)
-            new_args.append(parser.parse_expression(args[len(new_args)]))
-            continue
-
-        arg = parser.parse_script(arg)
-        new_args.append(arg)
-
-    return new_args
-
-
-def _interp_eval(args, parser):
-    if len(args) < 2:
-        raise CommandArgError(
-            f"not enough args to 'interp eval': got {len(args)}, expected at least 2"
-        )
-    return args[0:1] + eval(args[1:], parser, "interp eval")
-
-
-def _lmap(args, parser):
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/lmap.html
-    if len(args) < 3:
-        raise CommandArgError(
-            f"not enough args to lmap: got {len(args)}, expected at least 3"
-        )
-
-    return args[:-1] + [parser.parse_script(args[-1])]
-
-
-def _namespace_code(args, parser):
-    # ref: https://www.tcl.tk/man/tcl8.4/TclCmd/namespace.html#M6
-    # TODO: seems like a possible pattern is to execute things in these scripts
-    # with additional args provided, so command-args checks within this might
-    # actually be false positive. will keep as-is for now though.
-    return [parser.parse_script(args[0])]
-
-
-def _namespace_eval(args, parser):
-    if len(args) < 2:
-        raise CommandArgError(
-            f"not enough args to 'namespace eval': got {len(args)}, expected at least 2"
-        )
-    return args[0:1] + eval(args[1:], parser, "namespace eval")
-
-
-def _namespace_inscope(args, parser):
-    # ref: https://www.tcl.tk/man/tcl8.4/TclCmd/namespace.html#M14
-    raise CommandArgError(
-        "'namespace inscope' is not meant to be called directly, consider using"
-        " 'namespace code' or 'namespace eval' instead"
-    )
-
-
-def _package_ifneeded(args, parser):
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/package.html
-
-    # TODO: implement
-
-    # one issue with this one - it seems like calls to package ifneeded are
-    # often generated by pkg_MkIndex and these calls won't lint clean. Probably
-    # need a special case to ensure that these don't generate violations
-
-    raise CommandArgError(
-        "argument parsing for 'package ifneeded' not implemented, any script argument"
-        " will not be checked for violations"
-    )
-
-
-def _proc(args, parser):
-    if len(args) != 3:
-        raise CommandArgError(f"wrong # of args to proc: got {len(args)}, expected 3")
-
-    # Parse args as list, then iterate over each item to parse arg specifier lists and
-    # do some validation. We don't store non-defaulted arguments as Lists so that they
-    # don't get formatted inside braces.
-    arg_list = parser.parse_list(args[1])
-    for i, arg in enumerate(arg_list.children):
-        if isinstance(arg, BareWord):
-            continue
-
-        arg_specifier = parser.parse_list(arg)
-        arg_specifier_len = len(arg_specifier.children)
-
-        if arg_specifier_len == 2:
-            arg_list.children[i] = arg_specifier
-        elif arg_specifier_len != 1:
-            raise CommandArgError(
-                f"too many fields in argument specifier: got {arg_specifier_len},"
-                " expected no more than 2"
-            )
-
-    return args[0:1] + [arg_list, parser.parse_script(args[2])]
-
-
-def _return(args, parser):
-    args = list(args)
-    while len(args) > 0:
-        option = args.pop(0).contents
-
-        try:
-            if option == "-code":
-                arg = args.pop(0)
-                try:
-                    _check_code(arg)
-                except CommandArgError as e:
-                    raise CommandArgError(f"invalid value for return -code: {e}")
-            elif option == "-level":
-                val = args.pop(0).contents
-
-                if val is None:
-                    continue
-
-                try:
-                    if int(val) >= 0:
-                        continue
-                except ValueError:
-                    pass
-
-                raise CommandArgError(
-                    f"invalid value for return -level: got {val}, expected a"
-                    " non-negative integer"
-                )
-            elif option in {"-errorcode", "-errorinfo", "-errorstack", "-options"}:
-                args.pop(0)
-            else:
-                break
-        except IndexError:
-            raise CommandArgError(
-                f"insufficient args to return: expected value after {option}"
-            )
-
-    if len(args) > 0:
-        raise CommandArgError(
-            "too many arguments to return: expected no more than 1 argument after"
-            " explicit options. Provide -options argument if you intend to specify"
-            " additional return options."
-        )
-
-    return None
-
-
-def _switch(args, parser):
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/switch.html
-    # This one's complicated...
-
-    # TODO: better checking of malformed switch command
-
-    arg_contents = [arg.contents for arg in args]
-    arg_i = 0
-
-    try:
-        arg_i = arg_contents.index("--") + 1
-    except ValueError:
-        while True:
-            contents = args[arg_i].contents
-            if contents in {"-exact", "-glob", "-regexp", "-nocase"}:
-                arg_i += 1
-            elif contents in {"-matchvar", "-indexvar"}:
-                arg_i += 2
-            else:
-                break
-
-    # accounts for string to be matched
-    arg_i += 1
-
-    new_args = args[0:arg_i]
-
-    # one argument left => form where patterns and bodies are in list
-    last_arg_is_list = arg_i == len(args) - 1
-
-    if last_arg_is_list:
-        pattern_and_commands_list = parser.parse_list(args[arg_i])
-        new_args.append(pattern_and_commands_list)
-        pattern_and_commands = pattern_and_commands_list.children
-    else:
-        pattern_and_commands = args[arg_i:]
-
-    if len(pattern_and_commands) % 2 != 0:
-        raise CommandArgError("Expected even number of patterns and commands")
-
-    parsed_patterns_and_commands = []
-    for i, node in enumerate(pattern_and_commands):
-        if i % 2 == 0:
-            parsed_patterns_and_commands.append(node)
-        else:
-            parsed_patterns_and_commands.append(parser.parse_script(node))
-
-    if last_arg_is_list:
-        pattern_and_commands_list.children = parsed_patterns_and_commands
-    else:
-        new_args.extend(parsed_patterns_and_commands)
-
-    return new_args
-
-
-def _time(args, parser):
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/time.html
-    if len(args) < 1:
-        raise CommandArgError(
-            f"not enough args to time: got {len(args)}, expected at least 1"
-        )
-
-    if len(args) > 2:
-        raise CommandArgError(
-            f"too many args to time: got {len(args)}, expected no more than 2"
-        )
-
-    if len(args) == 2:
-        time = args[1].contents
-        if time is not None:
-            try:
-                int(time)
-            except ValueError:
-                raise CommandArgError(
-                    "invalid argument to time: expected integer for last argument"
-                )
-
-    return [parser.parse_script(args[0])] + args[1:]
-
-
-def _timerate(args, parser):
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/timerate.html
-    # timerate doesn't seem to be implemented in tclsh 8.6 for me - why?
-
-    args = list(args)
-    new_args = []
-
-    while True:
-        try:
-            arg = args.pop(0)
-        except IndexError:
-            raise CommandArgError("invalid arguments to timerate: expected script body")
-
-        if arg.contents in {"-direct", "-calibrate"}:
-            new_args.append(arg)
-        elif arg.contents in {"-overhead"}:
-            new_args.append(arg)
-            try:
-                val = args.pop(0)
-                if val.contents is not None:
-                    float(val.contents)
-            except (ValueError, IndexError, TypeError):
-                raise CommandArgError(
-                    "invalid argument to timerate: -overhead must be followed by a"
-                    " double"
-                )
-            new_args.append(val)
-        else:
-            break
-
-    new_args.append(parser.parse_script(arg))
-
-    if len(args) > 2:
-        raise CommandArgError(
-            "too many arguments to timerate: expected no more than 2 arguments"
-            " following script body"
-        )
-
-    try:
-        [int(arg.contents) for arg in args]
-    except ValueError:
-        raise CommandArgError(
-            "invalid argument to timerate: expected one or two integers following"
-            " script body"
-        )
-
-    return new_args + args
-
-
-def _try(args, parser):
-    # ref: https://www.tcl.tk/man/tcl/TclCmd/try.html
-    args = list(args)
-    new_args = []
-
-    while True:
-        try:
-            arg = args.pop(0)
-        except IndexError:
-            raise CommandArgError("invalid arguments to try: missing script body")
-        new_args.append(parser.parse_script(arg))
-
-        try:
-            arg = args.pop(0)
-        except IndexError:
-            break
-
-        new_args.append(arg)
-
-        if arg.contents == "on":
-            try:
-                code = args.pop(0)
-                try:
-                    _check_code(code)
-                except CommandArgError as e:
-                    raise CommandArgError(
-                        f"invalid code argument to 'on' handler in try: {e}"
-                    )
-                new_args.append(code)
-                new_args.append(args.pop(0))
-            except IndexError:
-                raise CommandArgError(
-                    "invalid arguments to try: expected 3 arguments after 'on' handler"
-                )
-        elif arg.contents == "trap":
-            try:
-                new_args.append(args.pop(0))
-                new_args.append(args.pop(0))
-            except IndexError:
-                raise CommandArgError(
-                    "invalid arguments to try: expected 3 arguments after 'trap'"
-                    " handler"
-                )
-        elif arg.contents == "finally":
-            continue
-        else:
-            raise CommandArgError(
-                "invalid handler argument to try: expected one of 'on', 'trap', or"
-                " 'finally'"
-            )
-
-    return new_args
-
-
-def _while(args, parser):
-    if len(args) != 2:
-        raise CommandArgError(f"wrong # of args to while: got {len(args)}, expected 2")
-
-    return [
-        parser.parse_expression(args[0]),
-        parser.parse_script(args[1]),
-    ]
-
-
-commands = commands_schema({
-    "after": {
-        "subcommands": {
-            "cancel": _after_cancel,
-            "idle": _after_idle,
-            "info": {
-                "positionals": [
-                    {"name": "id", "value": {"type": "any"}, "required": False}
-                ]
-            },
-            "": _after,
-        },
-    },
-    "append": {
-        "positionals": [
-            {"name": "varname", "value": {"type": "any"}, "required": True},
-            {"name": "value", "value": {"type": "variadic"}, "required": False},
-        ]
-    },
-    "apply": _apply,
-    "array": _array,
-    "binary": {
-        "subcommands": {
-            "decode": check_count("binary decode", 2, None),
-            "encode": check_count("binary encode", 2, None),
-            "format": check_count("binary format", 1, None),
-            "scan": check_count("binary scan", 2, None),
-        },
-    },
-    "break": check_count("break", 0, 0),
-    "catch": _catch,
-    "cd": {
-        "positionals": [
-            {"name": "dirName", "value": {"type": "any"}, "required": False}
-        ],
-    },
-    "chan": _chan,
-    # TODO: check subcommands
-    "clock": check_count("clock"),
-    "close": {
-        "positionals": [
-            {"name": "channelId", "value": {"type": "any"}, "required": True},
-            {"name": "read|write", "value": {"type": "any"}, "required": False},
-        ],
-    },
-    "concat": {
-        "positionals": [
-            {"name": "arg", "value": {"type": "variadic"}, "required": True},
-        ]
-    },
-    "continue": {},
-    "coroutine": {
-        "positionals": [
-            {"name": "name", "value": {"type": "any"}, "required": True},
-            {"name": "command", "value": {"type": "any"}, "required": True},
-            {"name": "arg", "value": {"type": "variadic"}, "required": False},
-        ]
-    },
-    "dict": {
-        "subcommands": {
-            "append": check_count("dict append", 2, None),
-            "create": check_count("dict create"),
-            "exists": check_count("dict exists", 2, None),
-            "filter": _dict_filter,
-            "for": _dict_map_for("dict for"),
-            "get": check_count("dict get", 1, None),
-            "incr": check_count("dict incr", 2, 3),
-            "info": check_count("dict info", 1, 1),
-            "keys": check_count("dict keys", 1, 2),
-            "lappend": check_count("dict lappend", 2, None),
-            "map": _dict_map_for("dict map"),
-            "merge": check_count("dict merge"),
-            "remove": check_count("dict remove", 1, None),
-            "replace": check_count("dict replace", 1, None),
-            "set": check_count("dict set", 3, None),
-            "size": check_count("dict size", 1, 1),
-            "unset": check_count("dict unset", 2, None),
-            "update": _dict_update,
-            "values": check_count("dict values", 1, 2),
-            "with": _dict_with,
-        },
-    },
-    "encoding": {
-        "subcommands": {
-            "convertfrom": check_count("encoding convertfrom", 1, 2),
-            "convertto": check_count("encoding convertto", 1, 2),
-            "dirs": check_count("encoding dirs", 0, 1),
-            "names": check_count("encoding names", 0, 0),
-            "system": check_count("encoding system", 0, 1),
-        },
-    },
-    "eof": check_count("eof", 1, 1),
-    "error": check_count("error", 1, 3),
-    "eval": _eval,
-    "exec": check_count("exec", 1, None),
-    "exit": check_count("exit", 0, 1),
-    "expr": _expr,
-    "fblocked": check_count("fblocked", 1, 1),
-    "fconfigure": check_count("fconfigure", 1, None),
-    "fcopy": check_count("fcopy", 2, 6),
-    # TODO: check subcommands
-    "file": check_count("file", 1, None),
-    "fileevent": _fileevent,
-    "flush": check_count("flush", 1, 1),
-    "for": _for,
-    "foreach": _foreach,
-    "format": check_count("format", 1, None),
-    "gets": check_count("gets", 1, 2),
-    "glob": check_count("glob"),
-    "global": check_count("global"),
-    "history": check_count("history"),
-    "if": _if,
-    "incr": check_count("incr", 1, 2),
-    # TODO: check subcommands
-    "info": check_count("info", 1, None),
-    # TODO: check other subcommands
-    "interp": {
-        "subcommands": {
-            "eval": _interp_eval,
-            "": check_count("interp", 1, None),
-        },
-    },
-    "join": check_count("join", 1, 2),
-    "lappend": check_count("lappend", 1, None),
-    "lassign": check_count("lassign", 1, None),
-    "lindex": check_count("lindex", 1, None),
-    "linsert": check_count("linsert", 2, None),
-    "list": check_count("list", 0, None),
-    "llength": check_count("llength", 1, 1),
-    "lrepeat": check_count("lrepeat", 1, None),
-    "lreplace": check_count("lreplace", 3, None),
-    "lreverse": check_count("lreverse", 1, 1),
-    "lset": check_count("lset", 2, None),
-    "lsort": check_count("lsort", 1, None),
-    "lmap": _lmap,
-    "load": check_count("load", 1, 6),
-    "lrange": check_count("lrange", 3, 3),
-    "lsearch": check_count("lsearch", 2, None),
-    "memory": {
-        "subcommands": {
-            "active": check_count("memory active", 1, 1),
-            "break_on_malloc": check_count("memory break_on_malloc", 1, 1),
-            "info": check_count("memory info", 0, 0),
-            # just on or off
-            "init": check_count("memory init", 1, 1),
-            "objs": check_count("memory objs", 1, 1),
-            "onexit": check_count("memory onexit", 1, 1),
-            "tag": check_count("memory tag", 1, 1),
-            # just on or off
-            "trace": check_count("memory trace", 1, 1),
-            "trace_on_at_malloc": check_count("memory trace_on_at_malloc", 1, 1),
-            # just on or off
-            "validate": check_count("memory validate", 1, 1),
-        },
-    },
-    "namespace": {
-        "subcommands": {
-            "children": check_count("namespace children", 0, 2),
-            "code": _namespace_code,
-            "current": check_count("namespace current", 0, 0),
-            "delete": None,
-            "eval": _namespace_eval,
-            "exists": check_count("namespace exists", 1, 1),
-            "export": None,
-            "forget": None,
-            "import": None,
-            "inscope": _namespace_inscope,
-            "origin": check_count("namespace origin", 1, 1),
-            "parent": check_count("namespace parent", 0, 1),
-            "qualifiers": check_count("namespace qualifiers", 1, 1),
-            "tail": check_count("namespace tail", 1, 1),
-            "which": check_count("namespace which", 1, 2),
-            "ensemble": {
-                "subcommands": {
-                    "create": None,
-                    "configure": check_count("namespace ensemble configure", 1, None),
-                    "exists": check_count("namespace ensemble exists", 1, 1),
-                },
-            },
-        },
-    },
-    "open": check_count("open", 1, 3),
-    "package": {
-        "subcommands": {
-            "forget": None,
-            "ifneeded": _package_ifneeded,
-            "names": check_count("package names", 0, 0),
-            "present": check_count("package present", 0, None),
-            "provide": check_count("package provide", 1, 2),
-            "require": check_count("package require", 1, None),
-            "unknown": check_count("package unknown", 1, None),
-            "vcompare": check_count("package vcompare", 2, 2),
-            "versions": check_count("package versions", 1, 1),
-            "vsatisfies": check_count("package vsatisfies", 2, None),
-            "prefer": check_count("package prefer", 1, 1),
-        },
-    },
-    "pid": check_count("pid", 0, 1),
-    "pkg::create": check_count("pkg::create", 2, None),
-    "pkg_mkIndex": check_count("pkg_mkIndex", 1, None),
-    "proc": _proc,
-    "puts": {
-        "positionals": [
-            {"name": "-nonewline", "value": {"type": "any"}, "required": False},
-            {"name": "channelId", "value": {"type": "any"}, "required": False},
-            {"name": "string", "value": {"type": "any"}, "required": True},
-        ],
-    },
-    "pwd": check_count("pwd", 0, 0),
-    "read": check_count("read", 1, 2),
-    "regexp": check_count("regexp", 2, None),
-    "regsub": check_count("regsub", 3, None),
-    "rename": check_count("rename", 2, 2),
-    "return": _return,
-    # TODO: check subcommands
-    "safe": check_count("safe", 1, None),
-    "scan": check_count("scan", 2, None),
-    "seek": check_count("seek", 2, 3),
-    "set": check_count("set", 1, 2),
-    "socket": check_count("socket", 2, None),
-    "source": check_count("source", 1, 3),
-    "split": check_count("split", 1, 2),
-    # TODO: check subcommands
-    "string": check_count("string", 2, None),
-    "subst": check_count("subst", 1, 4),
-    "switch": _switch,
-    "tailcall": check_count("tailcall", 1, None),
-    "tcl::prefix": {
-        "subcommands": {
-            "all": check_count("tcl::prefix all", 2, 2),
-            "longest": check_count("tcl::prefix longest", 2, 2),
-            "match": check_count("tcl::prefix match", 2, None),
-        },
-    },
-    "tell": check_count("tell", 1, 1),
-    "throw": check_count("throw", 2, 2),
-    "time": _time,
-    "timerate": _timerate,
-    "tcl::tm::path": {
-        "subcommands": {
-            "add": check_count("tcl::tm::path add"),
-            "remove": check_count("tcl::tm::path remove"),
-            "list": check_count("tcl::tm::path list", 0, 0),
-        },
-    },
-    "tcl::tm::roots": check_count("tcl::tm::roots"),
-    # TODO: check subcommands
-    "trace": check_count("trace", 2, None),
-    "try": _try,
-    "unload": check_count("unload", 1, 6),
-    "unset": check_count("unset"),
-    "update": check_count("update", 0, 1),
-    "uplevel": check_count("uplevel", 1, None),
-    "upvar": check_count("upvar", 2, None),
-    "variable": check_count("variable", 1, None),
-    "vwait": check_count("vwait", 1, 1),
-    "while": _while,
-    "yield": {
-        "positionals": [
-            {"name": "value", "value": {"type": "any"}, "required": False},
-        ]
-    },
-    "yieldto": {
-        "positionals": [
-            {"name": "command", "value": {"type": "any"}, "required": True},
-            {"name": "arg", "value": {"type": "variadic"}, "required": False},
-        ]
-    },
-    # TODO: check subcommands
-    "zlib": check_count("zlib", 3, None),
-})
diff --git a/server/libs/tclint/commands/checks.py b/server/libs/tclint/commands/checks.py
deleted file mode 100644
index 911f58e..0000000
--- a/server/libs/tclint/commands/checks.py
+++ /dev/null
@@ -1,240 +0,0 @@
-"""Helpers for checking command arguments."""
-
-from collections.abc import Callable
-from typing import List, Optional, Union
-
-from tclint.syntax_tree import ArgExpansion, QuotedWord, BracedWord, BareWord, Node
-
-
-class CommandArgError(Exception):
-    pass
-
-
-def arg_count(args, parser):
-    # TODO: graceful handling of argsub going into things with recursive parsing.
-    # if the argsub happens to be "concrete", we can technically do the right
-    # thing (although this should probably be flagged as a readability issue...)
-    # otherwise, we should flag that the non-concrete argsub is not okay for
-    # these cases. however, I think its not okay-ness doesn't need to be absolute, e.g.
-    # I think we could allow:
-    #
-    #  catch {puts "my script"} {*}$catchopts
-    #
-
-    arg_count = 0
-    has_arg_expansion = False
-    for arg in args:
-        if isinstance(arg, ArgExpansion):
-            if arg.contents is None:
-                has_arg_expansion = True
-                continue
-            arg_count += len(parser.parse_list(arg.contents))
-        else:
-            arg_count += 1
-
-    return arg_count, has_arg_expansion
-
-
-def check_count(command, min=None, max=None, args_name="args"):
-    def check(args, parser):
-        if min is None and max is None:
-            return None
-
-        count, has_arg_expansion = arg_count(args, parser)
-
-        if not has_arg_expansion and min == max and count != min:
-            raise CommandArgError(
-                f"wrong # of {args_name} for {command}: got {count}, expected {min}"
-            )
-
-        if not has_arg_expansion and min is not None and count < min:
-            raise CommandArgError(
-                f"not enough {args_name} for {command}: got {count}, expected at least"
-                f" {min}"
-            )
-
-        if max is not None and count > max:
-            raise CommandArgError(
-                f"too many {args_name} for {command}: got {count}, expected no more"
-                f" than {max}"
-            )
-
-        return None
-
-    return check
-
-
-def eval(args, parser, command):
-    if len(args) > 1 and any(isinstance(arg, (QuotedWord, BracedWord)) for arg in args):
-        # Slightly odd restriction, but our syntax tree doesn't have a great way
-        # to handle this case. We require each command argument to correspond to
-        # one child node, but multiple quoted or braced word arguments can be
-        # combined into a single subcommand when interpreted eval-style. This
-        # requirement exists to facilitate style checking, if we had a separate
-        # CST for style checks and AST for logical checks we may be able to
-        # handle it.
-
-        raise CommandArgError(
-            f"unable to parse multiple {command} arguments when one includes a braced"
-            " or quoted word"
-        )
-
-    # Construct the body of the eval taking whitespace into account to ensure we get
-    # style checking.
-
-    eval_script = ""
-    prev_arg_end_pos = None
-    for arg in args:
-        contents = arg.contents
-        if contents is None:
-            # TODO: flag sort of eval-specific violation? Common patterns will
-            # often trigger this, and it seems useful to be able to turn it off
-            raise CommandArgError(
-                f"{command} received an argument with a substitution, unable to parse"
-                " its arguments"
-            )
-
-        if prev_arg_end_pos is not None:
-            if prev_arg_end_pos[0] != arg.line:
-                # If we have multiple args on the same line, we know there must be a
-                # backslash newline. Add it so the parsing works.
-                eval_script += "\\\n" * (arg.line - prev_arg_end_pos[0])
-                eval_script += " " * (arg.col - 1)
-            else:
-                eval_script += " " * (arg.col - prev_arg_end_pos[1])
-        eval_script += contents
-
-        prev_arg_end_pos = arg.end_pos
-
-    script = parser.parse(eval_script, pos=(args[0].pos))
-    script.end_pos = args[-1].end_pos
-
-    return [script]
-
-
-def check_command(
-    command: str, args: List[Node], parser, command_spec: Union[Callable, dict, None]
-) -> Optional[List[Node]]:
-    if command_spec is None:
-        return None
-
-    if isinstance(command_spec, dict):
-        return check_arg_spec(command, args, parser, command_spec)
-
-    return command_spec(args, parser)
-
-
-def check_arg_spec(
-    command: str, args: List[Node], parser, arg_spec: dict
-) -> Optional[List[Node]]:
-    if "subcommands" in arg_spec:
-        subcommands = arg_spec["subcommands"]
-        try:
-            subcommand = args[0].contents
-        except IndexError:
-            subcommand = None
-
-        if subcommand in subcommands:
-            new_args = check_command(
-                f"{command} {subcommand}", args[1:], parser, subcommands[subcommand]
-            )
-            if new_args is None:
-                return new_args
-            return args[0:1] + new_args
-
-        if "" in subcommands:
-            return check_command(command, args, parser, subcommands[""])
-
-        if subcommand is not None:
-            msg = f"invalid subcommand for {command}: got {subcommand}"
-        else:
-            msg = f"no subcommand provided for {command}"
-
-        raise CommandArgError(f"{msg}, expected one of {', '.join(subcommands.keys())}")
-
-    switches = arg_spec["switches"]
-    args_allowed = set(switches)
-    args_required = {switch for switch in switches if switches[switch]["required"]}
-    positional_args = []
-
-    args = list(args)
-    while len(args) > 0:
-        arg = args.pop(0)
-
-        # To facilitate better error messages, we expect that switches are always
-        # specified as BareWords that start with "-" or ">". This lets us throw an
-        # error when a switch-like thing doesn't match any supported arguments,
-        # rather than counting it towards the positional arguments (which usually
-        # ends up in a vague "too many arguments" error). To make tclint interpret a
-        # switch-like word as a positional argument, users should wrap it in "", and
-        # any switches should be BareWords.
-        contents = arg.contents
-        if not (isinstance(arg, BareWord) and contents and contents[0] in {"-", ">"}):
-            positional_args.append(arg)
-            continue
-
-        # TODO check required arguments
-        if contents in args_allowed:
-            if switches[contents]["value"]:
-                try:
-                    args.pop(0)
-                except IndexError:
-                    raise CommandArgError(
-                        f"invalid arguments for {command}: expected value after"
-                        f" {contents}"
-                    )
-            if not switches[contents]["repeated"]:
-                args_allowed.remove(contents)
-            if contents in args_required:
-                args_required.remove(contents)
-        elif contents in arg_spec:
-            raise CommandArgError(f"duplicate argument for {command}: {contents}")
-        else:
-            prefix_matches = []
-            for switch in switches:
-                if switch.startswith(contents):
-                    prefix_matches.append(switch)
-
-            if len(prefix_matches) == 1:
-                raise CommandArgError(
-                    f"shortened argument for {command}: expand {contents} to"
-                    f" {prefix_matches[0]}"
-                )
-
-            if len(prefix_matches) > 1:
-                raise CommandArgError(
-                    f"ambiguous argument for {command}: {contents} could be any of"
-                    f" {', '.join(prefix_matches)}"
-                )
-
-            raise CommandArgError(f"unrecognized argument for {command}: {contents}")
-
-    if len(args_required) > 1:
-        raise CommandArgError(
-            f"missing required arguments for {command}: {', '.join(args_required)}"
-        )
-    elif len(args_required) == 1:
-        raise CommandArgError(
-            f"missing required argument for {command}: {args_required.pop()}"
-        )
-
-    min_positionals = 0
-    max_positionals: Optional[int] = 0
-    for positional in arg_spec["positionals"]:
-        if positional["value"]["type"] == "variadic":
-            max_positionals = None
-
-        if positional["required"]:
-            min_positionals += 1
-        if max_positionals is not None:
-            max_positionals += 1
-
-    check = check_count(
-        command,
-        min=min_positionals,
-        max=max_positionals,
-        args_name="positional args",
-    )
-    check(positional_args, None)
-
-    return None
diff --git a/server/libs/tclint/commands/plugins.py b/server/libs/tclint/commands/plugins.py
deleted file mode 100644
index 276a7d4..0000000
--- a/server/libs/tclint/commands/plugins.py
+++ /dev/null
@@ -1,86 +0,0 @@
-from importlib_metadata import entry_points
-import json
-import pathlib
-from typing import Dict, Optional
-from types import ModuleType
-
-import voluptuous
-
-from tclint.commands.schema import schema as command_schema
-
-
-class _PluginManager:
-    def __init__(self):
-        self._loaded = {}
-        self._installed = {}
-        self._loaded_specs = {}
-        for plugin in entry_points(group="tclint.plugins"):
-            if plugin.name in self._installed:
-                print(f"Warning: found duplicate definitions for plugin {plugin.name}")
-            self._installed[plugin.name] = plugin
-
-    def load(self, name: str) -> Optional[Dict]:
-        if name in self._loaded:
-            return self._loaded[name]
-
-        mod = self._load(name)
-        self._loaded[name] = mod
-        return mod
-
-    def load_from_spec(self, path: pathlib.Path) -> Optional[Dict]:
-        if path in self._loaded_specs:
-            return self._loaded_specs[path]
-
-        spec = self._load_from_spec(path)
-        self._loaded_specs[path] = spec
-        return spec
-
-    def _load_from_spec(self, path: pathlib.Path) -> Optional[Dict]:
-        try:
-            with open(path.expanduser(), "r") as f:
-                spec = json.load(f)
-        except (FileNotFoundError, RuntimeError):
-            print(f"Warning: command spec {path} not found, skipping...")
-            return None
-
-        try:
-            # Apply defaults and validate the spec.
-            spec = command_schema(spec)
-        except voluptuous.Invalid as e:
-            print(f"Warning: invalid command spec {path}: {e}")
-            return None
-
-        return spec["commands"]
-
-    def get_mod(self, name: str) -> Optional[ModuleType]:
-        if name not in self._installed:
-            print(f"Warning: plugin {name} is not installed")
-            return None
-
-        plugin = self._installed[name]
-
-        try:
-            module = plugin.load()
-        except Exception as e:
-            print(f"Warning: error loading plugin {name}: {e}")
-            return None
-
-        return module
-
-    def _load(self, name: str):
-        module = self.get_mod(name)
-        if module is None:
-            print(f"Skipping requested plugin {name}")
-            return None
-
-        if not hasattr(module, "commands"):
-            print(f"Warning: skipping plugin {name} since it does not define commands")
-            return None
-
-        return getattr(module, "commands")
-
-
-# TODO: we'll probably want to construct this in the tclint entry point and pass
-# it around rather than using a singleton instance, but this made for an easier
-# refactor.
-PluginManager = _PluginManager()
diff --git a/server/libs/tclint/commands/schema.py b/server/libs/tclint/commands/schema.py
deleted file mode 100644
index 7662a10..0000000
--- a/server/libs/tclint/commands/schema.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from collections.abc import Callable
-from voluptuous import Schema, Optional, Or, Self
-
-# Need to define this as a Schema with required=True to ensure that this requirement
-# persists through the Or in the main schema definition.
-_command_args = Schema(
-    {
-        Optional("positionals", default=[]): [
-            {
-                "name": str,
-                "required": bool,
-                "value": Or({"type": "any"}, {"type": "variadic"}),
-            }
-        ],
-        Optional("switches", default={}): {
-            Optional(str): {
-                "required": bool,
-                "repeated": bool,
-                "value": Or({"type": "any"}, None),
-                Optional("metavar"): str,
-            }
-        },
-    },
-    required=True,
-)
-
-commands_schema = Schema(
-    {Optional(str): Or(_command_args, None, {"subcommands": Self}, Callable)},
-    required=True,
-)
-
-schema = Schema(
-    {"name": str, "commands": commands_schema},
-    required=True,
-)
diff --git a/server/libs/tclint/comments.py b/server/libs/tclint/comments.py
deleted file mode 100644
index d7b878d..0000000
--- a/server/libs/tclint/comments.py
+++ /dev/null
@@ -1,91 +0,0 @@
-from collections import defaultdict
-
-from tclint.syntax_tree import Visitor
-from tclint.violations import ALL_RULES, Rule
-
-
-class CommentVisitor(Visitor):
-    """Scans the tree for lint waiver comments."""
-
-    def __init__(self):
-        # line -> [rule]
-        self.ignore_lines = defaultdict(set)
-
-        self._disable_regions = {
-            # rule -> line
-        }
-
-    def run(self, tree, path):
-        self._path = path
-        tree.accept(self, recurse=True)
-
-        # resolve remaining disabled regions
-        last_line = tree.end_pos[0]
-        for rule, start_line in self._disable_regions.items():
-            for line in range(start_line, last_line + 1):
-                self.ignore_lines[line].add(rule)
-
-        return self.ignore_lines
-
-    def visit_comment(self, comment):
-        contents = comment.value.strip()
-
-        if not contents.startswith("tclint-"):
-            return
-
-        split = contents.split(" ", 1)
-
-        command = split[0]
-
-        rule_strs = []
-        if len(split) > 1:
-            rest = split[-1]
-            rule_strs = rest.split("--", 1)[0]
-            rule_strs = rule_strs.replace(" ", "")
-            rule_strs = rule_strs.split(",")
-
-        rules = []
-        if not rule_strs:
-            # default if no rules specified is all violation types
-            rules = ALL_RULES
-        else:
-            for rule in rule_strs:
-                try:
-                    rules.append(Rule(rule))
-                except ValueError:
-                    self._warning(
-                        f"unknown rule '{rule}' provided to '{command}'", comment.pos
-                    )
-
-        if command == "tclint-disable":
-            for rule in rules:
-                # if in dictionary, already disabled - this has no effect
-                if rule not in self._disable_regions:
-                    self._disable_regions[rule] = comment.line
-        elif command == "tclint-disable-line":
-            line = comment.line
-            self.ignore_lines[line].update(rules)
-        elif command == "tclint-disable-next-line":
-            line = comment.line + 1
-            self.ignore_lines[line].update(rules)
-        elif command == "tclint-enable":
-            for rule in rules:
-                if rule in self._disable_regions:
-                    disable_start_line = self._disable_regions[rule]
-                    disable_end_line = comment.line
-
-                    for line in range(disable_start_line, disable_end_line + 1):
-                        self.ignore_lines[line].add(rule)
-
-                    del self._disable_regions[rule]
-        else:
-            self._warning(
-                f"comment starts with '{command}', which looks like a tclint keyword."
-                " Is this a typo?",
-                comment.pos,
-            )
-
-    def _warning(self, message, pos):
-        # TODO: formal warning mechanism
-        prefix = self._path if self._path is not None else "(stdin)"
-        print(f"Warning: {prefix}:{pos[0]}:{pos[1]}: {message}")
diff --git a/server/libs/tclint/config.py b/server/libs/tclint/config.py
deleted file mode 100644
index f8be7bc..0000000
--- a/server/libs/tclint/config.py
+++ /dev/null
@@ -1,427 +0,0 @@
-import argparse
-import pathlib
-from typing import Union, List
-from typing import Optional as OptionalType
-import dataclasses
-import sys
-
-if sys.version_info >= (3, 11):
-    import tomllib
-else:
-    import tomli as tomllib
-
-from voluptuous import Schema, Optional, And, Coerce, Invalid, Range
-
-from tclint.violations import Rule
-
-
-@dataclasses.dataclass
-class Config:
-    """This dataclass defines the supported Config fields and their default
-    values. It provides an external interface for accessing config values.
-
-    The type annotations defined here are fairly loose - more specific type
-    validation (and normalization) is defined by `validators` below.
-    """
-
-    exclude: List[str] = dataclasses.field(default_factory=list)
-    ignore: List[Rule] = dataclasses.field(default_factory=list)
-    commands: OptionalType[pathlib.Path] = dataclasses.field(default=None)
-    extensions: List[str] = dataclasses.field(
-        default_factory=lambda: ["tcl", "sdc", "xdc", "upf"]
-    )
-    style_indent: OptionalType[Union[str, int]] = dataclasses.field(default=None)
-    style_line_length: int = dataclasses.field(default=100)
-    style_max_blank_lines: int = dataclasses.field(default=2)
-    style_indent_namespace_eval: bool = dataclasses.field(default=True)
-    style_spaces_in_braces: bool = dataclasses.field(default=False)
-
-    def apply_cli_args(self, args):
-        args_dict = vars(args)
-        for field in dataclasses.fields(self):
-            if field.name in args_dict and args_dict[field.name] is not None:
-                setattr(self, field.name, args_dict[field.name])
-
-        # Special arguments that aren't handled automatically
-        if "extend_exclude" in args_dict and args_dict["extend_exclude"] is not None:
-            self.exclude.extend(args_dict["extend_exclude"])
-
-        if "extend_ignore" in args_dict and args_dict["extend_ignore"] is not None:
-            self.ignore.extend(args_dict["extend_ignore"])
-
-    def get_indent(self) -> str:
-        """Get indent setting as string.
-
-        This helper does two things. One, it's a helpful utility to factor out the logic
-        required for calculating the indent. Two, it lets us ergonomically store if the
-        indentation is not set in style_indent, which the LSP relies on.
-        """
-        if self.style_indent is None:
-            # Default indent
-            return " " * 4
-        elif self.style_indent == "tab":
-            return "\t"
-        elif isinstance(self.style_indent, int):
-            return " " * self.style_indent
-
-        # Should be unreachable, validated on ingestion of config
-        raise ValueError(
-            f"unexpected value for config.style_indent: {self.style_indent}"
-        )
-
-
-# Validators using `voluptuous` library that check and normalize config inputs.
-# Used for checking both config files as well as config-related CLI args.
-
-# Using these for CLI args adds a constraint that all non-boolean validators
-# need to be able to normalize a value from a string. This means one could put
-# e.g. a string representation of a list into a .toml config file, but we shouldn't
-# document this, since it won't be considered stable behavior.
-
-
-def _str2list(s):
-    """Handles string-to-list normalization."""
-    if isinstance(s, str):
-        if s == "":
-            return []
-        return [v.strip() for v in s.split(",")]
-    return s
-
-
-_VALIDATORS = {
-    # note: it's ok if paths don't exist - allows for generic
-    # configurations with directories like .git/ excluded
-    "exclude": _str2list,
-    "ignore": And(
-        _str2list,
-        [
-            Coerce(Rule, msg="invalid rule ID"),
-        ],
-    ),
-    "commands": Coerce(pathlib.Path),
-    "extensions": _str2list,
-    "style_indent": Coerce(
-        lambda v: v if v == "tab" else int(v), msg="expected integer or 'tab'"
-    ),
-    "style_line_length": Coerce(int),
-    "style_max_blank_lines": And(
-        Coerce(int),
-        # we could technically support i >= 0, but I think 0 would be a weird
-        # setting and this lets us ignore pluralizing the violation message :)
-        Range(min=1),
-    ),
-    "style_indent_namespace_eval": bool,
-    "style_spaces_in_braces": bool,
-}
-
-
-def _validate_config(config):
-    """Validates dictionary read from TOML config file. Individual value validators
-    are implemented in the global dict, this defines the actual structure of the
-    schema."""
-
-    base_config = {
-        Optional("ignore"): _VALIDATORS["ignore"],
-        Optional("commands"): _VALIDATORS["commands"],
-        Optional("style"): {
-            Optional("indent"): _VALIDATORS["style_indent"],
-            Optional("line-length"): _VALIDATORS["style_line_length"],
-            Optional("max-blank-lines"): _VALIDATORS["style_max_blank_lines"],
-            Optional("indent-namespace-eval"): _VALIDATORS[
-                "style_indent_namespace_eval"
-            ],
-            Optional("spaces-in-braces"): _VALIDATORS["style_spaces_in_braces"],
-        },
-    }
-
-    schema = Schema({
-        # exclude and extensions can only be used in global context
-        Optional("exclude"): _VALIDATORS["exclude"],
-        Optional("extensions"): _VALIDATORS["extensions"],
-        **base_config,
-        Optional("fileset"): Schema(
-            [{"paths": [Coerce(pathlib.Path)], **base_config}], required=True
-        ),
-    })
-
-    try:
-        return schema(config)
-    except Invalid as e:
-        if not e.path:
-            raise ConfigError(e.error_message)
-
-        # Stringify error path to my own taste.
-        path = []
-        for item in e.path:
-            if isinstance(item, int):
-                # Brackets around indices
-                if len(path) > 0:
-                    path[-1] += f"[{item}]"
-                else:
-                    path.append(f"[{item}]")
-            else:
-                path.append(str(item))
-
-        raise ConfigError(f"{e.error_message} ({'.'.join(path)})")
-
-
-def _validator(key):
-    def func(s):
-        try:
-            return Schema(_VALIDATORS[key])(s)
-        except Invalid as e:
-            raise argparse.ArgumentTypeError(str(e))
-
-    return func
-
-
-def _add_bool(group, parser, dest, yes_flag, no_flag):
-    mutex_group = group.add_mutually_exclusive_group(required=False)
-    mutex_group.add_argument(yes_flag, dest=dest, action="store_true")
-    mutex_group.add_argument(no_flag, dest=dest, action="store_false")
-    parser.set_defaults(**{dest: None})
-
-
-def setup_common_config_cli_args(config_group):
-    config_group.add_argument(
-        "--exclude", type=_validator("exclude"), metavar='"path1, path2, ..."'
-    )
-    config_group.add_argument(
-        "--extend-exclude", type=_validator("exclude"), metavar='"path1, path2, ..."'
-    )
-    config_group.add_argument(
-        "--extensions", type=_validator("extensions"), metavar='"tcl, xdc, ..."'
-    )
-    config_group.add_argument(
-        "--commands", type=_validator("commands"), metavar=""
-    )
-
-
-def setup_config_cli_args(parser):
-    """This method defines config-related CLI arguments.
-
-    The destvars of these switches should match the fields of Config.
-    """
-    config_group = parser.add_argument_group("configuration arguments")
-
-    config_group.add_argument(
-        "--ignore", type=_validator("ignore"), metavar='"rule1, rule2, ..."'
-    )
-    config_group.add_argument(
-        "--extend-ignore", type=_validator("ignore"), metavar='"rule1, rule2, ..."'
-    )
-    setup_common_config_cli_args(config_group)
-    config_group.add_argument(
-        "--style-line-length",
-        type=_validator("style_line_length"),
-        metavar="",
-    )
-
-
-def setup_tclfmt_config_cli_args(parser):
-    """This method defines the subset of config-related CLI arguments used by tclfmt.
-
-    The destvars of these switches should match the fields of Config.
-    """
-    config_group = parser.add_argument_group("configuration arguments")
-
-    setup_common_config_cli_args(config_group)
-
-    config_group.add_argument(
-        "--indent",
-        type=_validator("style_indent"),
-        metavar="",
-        dest="style_indent",
-    )
-    config_group.add_argument(
-        "--max-blank-lines",
-        type=_validator("style_max_blank_lines"),
-        metavar="",
-        dest="style_max_blank_lines",
-    )
-    _add_bool(
-        config_group,
-        parser,
-        "style_indent_namespace_eval",
-        "--indent-namespace-eval",
-        "--no-indent-namespace-eval",
-    )
-    _add_bool(
-        config_group,
-        parser,
-        "style_spaces_in_braces",
-        "--spaces-in-braces",
-        "--no-spaces-in-braces",
-    )
-
-
-def _flatten(d, prefix=None):
-    """Flattens TOML config dictionary structure to match the flat set of fields
-    expected by Config dataclass."""
-    if prefix is None:
-        prefix = []
-
-    flat = {}
-    for k, v in d.items():
-        if isinstance(v, dict):
-            flat.update(_flatten(v, prefix=prefix + [k]))
-        else:
-            flat["_".join(prefix + [k]).replace("-", "_")] = v
-
-    return flat
-
-
-class RunConfig:
-    """Class that holds information about both global and fileset configs. User
-    code can get a Config object that applies to a particular file by calling
-    get_from_path() and supplying that file's path."""
-
-    def __init__(self, global_config=None, fileset_configs=None):
-        if global_config is not None:
-            self._global_config = global_config
-        else:
-            self._global_config = Config()
-
-        self._fileset_configs = [
-            # ([pathlib.Path...], Config])
-        ]
-        if fileset_configs is not None:
-            self._fileset_configs = fileset_configs
-
-    @property
-    def exclude(self):
-        return self._global_config.exclude
-
-    @property
-    def extensions(self):
-        return self._global_config.extensions
-
-    @classmethod
-    def from_dict(cls, config_dict: dict, root: pathlib.Path):
-        config_dict = _validate_config(config_dict)
-        try:
-            fileset_config_dicts = config_dict.pop("fileset")
-        except KeyError:
-            fileset_config_dicts = []
-
-        config_dict = _flatten(config_dict)
-        global_config = Config(**config_dict)
-
-        fileset_configs = []
-        for fileset_config in fileset_config_dicts:
-            paths = []
-            for path in fileset_config.pop("paths"):
-                if not path.is_absolute():
-                    path = root / path
-                paths.append(path.resolve())
-
-            fileset_config = _flatten(fileset_config)
-
-            # pull in default values from global config
-            full_fileset_config = config_dict.copy()
-            full_fileset_config.update(fileset_config)
-
-            fileset_configs.append((paths, Config(**full_fileset_config)))
-
-        return cls(global_config, fileset_configs)
-
-    @classmethod
-    def from_path(cls, path: Union[str, pathlib.Path], root: pathlib.Path):
-        path = pathlib.Path(path)
-
-        if not path.exists():
-            raise FileNotFoundError
-
-        with open(path, "rb") as f:
-            try:
-                data = tomllib.load(f)
-            except tomllib.TOMLDecodeError as e:
-                raise ConfigError(f"{path}: {e}")
-
-        try:
-            return cls.from_dict(data, root)
-        except ConfigError as e:
-            raise ConfigError(f"{path}: {e}")
-
-    @classmethod
-    def from_pyproject(cls, directory=None):
-        if directory is None:
-            directory = pathlib.Path(".")
-        else:
-            directory = pathlib.Path(directory)
-
-        path = directory / "pyproject.toml"
-
-        if not path.exists():
-            raise FileNotFoundError
-
-        with open(path, "rb") as f:
-            data = tomllib.load(f)
-
-        tclint_config = data.get("tool", {})["tclint"]
-
-        try:
-            return cls.from_dict(tclint_config, directory)
-        except ConfigError as e:
-            raise ConfigError(f"pyproject.toml: {e}")
-
-    def get_for_path(self, path) -> Config:
-        if path is None:
-            return self._global_config
-
-        path = path.resolve()
-        for fileset_paths, config in self._fileset_configs:
-            for fileset_path in fileset_paths:
-                if path.is_relative_to(fileset_path):
-                    return config
-
-        return self._global_config
-
-    def apply_cli_args(self, args):
-        self._global_config.apply_cli_args(args)
-        for _, fileset_config in self._fileset_configs:
-            fileset_config.apply_cli_args(args)
-
-
-class ConfigError(Exception):
-    pass
-
-
-DEFAULT_CONFIGS = ("tclint.toml", ".tclint")
-
-
-def get_config(
-    config_path: OptionalType[pathlib.Path], root: pathlib.Path
-) -> OptionalType[RunConfig]:
-    """Loads a config file.
-
-    If `config_path` is supplied, attempts to read config file from this path. If the
-    path can't be found, raises a ConfigError.
-
-    Otherwise, attempts to read config from `root`/{tclint.toml, .tclint,
-    pyproject.toml} (in that order). If none of these files can be found, returns None.
-
-    `root` is also used to resolve some relative paths in the config file.
-    """
-    # user-supplied
-    if config_path is not None:
-        try:
-            return RunConfig.from_path(config_path, root)
-        except FileNotFoundError:
-            raise ConfigError(f"path {config_path} doesn't exist")
-
-    for path in DEFAULT_CONFIGS:
-        try:
-            return RunConfig.from_path(root / path, root)
-        except FileNotFoundError:
-            pass
-
-    try:
-        return RunConfig.from_pyproject(directory=root)
-    except ConfigError as e:
-        raise e
-    except (FileNotFoundError, tomllib.TOMLDecodeError, KeyError):
-        # just skip if file doesn't exist, contains TOML errors, or tclint key not found
-        pass
-
-    return None
diff --git a/server/libs/tclint/format.py b/server/libs/tclint/format.py
deleted file mode 100644
index cb01b7a..0000000
--- a/server/libs/tclint/format.py
+++ /dev/null
@@ -1,480 +0,0 @@
-import dataclasses
-import itertools
-import textwrap
-from typing import List, Tuple, Union
-import sys
-
-from tclint.syntax_tree import (
-    Node,
-    Script,
-    Command,
-    Comment,
-    CommandSub,
-    BareWord,
-    QuotedWord,
-    BracedWord,
-    CompoundBareWord,
-    VarSub,
-    ArgExpansion,
-    Expression,
-    BracedExpression,
-    ParenExpression,
-    UnaryOp,
-    BinaryOp,
-    TernaryOp,
-    Function,
-)
-from tclint.parser import Parser
-from tclint.syntax_tree import List as ListNode
-
-
-@dataclasses.dataclass
-class LiteralBlock:
-    block: List[str]
-    pos: Tuple[int, int]
-    end_pos: Tuple[int, int]
-
-
-@dataclasses.dataclass
-class FormatterOpts:
-    indent: str
-    spaces_in_braces: bool
-    max_blank_lines: int
-    indent_namespace_eval: bool
-
-
-class Formatter:
-    def __init__(self, opts: FormatterOpts):
-        self.opts = opts
-
-    def _indent(self, lines: List[str], indent: str) -> List[str]:
-        indented = []
-        for line in lines:
-            if line == "":
-                indented.append("")
-            else:
-                indented.append(indent + line)
-
-        return indented
-
-    def _brace(self, lines: List[str]) -> List[str]:
-        spaces_in_braces = " " if self.opts.spaces_in_braces else ""
-        if lines == [""]:
-            return ["{" + spaces_in_braces + "}"]
-
-        braced_lines = lines[:]
-        braced_lines[0] = "{" + spaces_in_braces + lines[0]
-        braced_lines[-1] += spaces_in_braces + "}"
-        return braced_lines
-
-    def format(self, *nodes: Union[Node, LiteralBlock]) -> List[str]:
-        formatted = []
-        for node in nodes:
-            if isinstance(node, Script):
-                formatted += self.format_script(node)
-            elif isinstance(node, Command):
-                formatted += self.format_command(node)
-            elif isinstance(node, Comment):
-                formatted += self.format_comment(node)
-            elif isinstance(node, CommandSub):
-                formatted += self.format_command_sub(node)
-            elif isinstance(node, BareWord):
-                formatted += self.format_bare_word(node)
-            elif isinstance(node, QuotedWord):
-                formatted += self.format_quoted_word(node)
-            elif isinstance(node, BracedWord):
-                formatted += self.format_braced_word(node)
-            elif isinstance(node, CompoundBareWord):
-                formatted += self.format_compound_bare_word(node)
-            elif isinstance(node, VarSub):
-                formatted += self.format_var_sub(node)
-            elif isinstance(node, ArgExpansion):
-                formatted += self.format_arg_expansion(node)
-            elif isinstance(node, ListNode):
-                formatted += self.format_list(node)
-            elif isinstance(node, Expression):
-                formatted += self.format_expression(node)
-            elif isinstance(node, BracedExpression):
-                formatted += self.format_braced_expression(node)
-            elif isinstance(node, ParenExpression):
-                formatted += self.format_paren_expression(node)
-            elif isinstance(node, UnaryOp):
-                formatted += self.format_unary_op(node)
-            elif isinstance(node, BinaryOp):
-                formatted += self.format_binary_op(node)
-            elif isinstance(node, TernaryOp):
-                formatted += self.format_ternary_op(node)
-            elif isinstance(node, Function):
-                formatted += self.format_function(node)
-            elif isinstance(node, LiteralBlock):
-                formatted += node.block
-            else:
-                assert False, f"unrecognized node: {type(node)}"
-
-        return formatted
-
-    def format_top(self, script: str, parser: Parser) -> str:
-        tree = parser.parse(script)
-        self.script = script.split("\n")
-        return "\n".join(self.format_script_contents(tree)) + "\n"
-
-    def format_partial(self, script: str, parser: Parser) -> str:
-        """Formats a partial Tcl script.
-
-        This function formats a partial script according to the gofmt partial formatting
-        rules, "[preserving] leading indentation as well as leading and trailing spaces"
-        (ref: https://pkg.go.dev/cmd/gofmt#pkg-overview). Unlike Go, we have no way of
-        detecting if a given script is a program fragment, hence the distinct method
-        from `format_top` .
-        """
-        leading = "".join(itertools.takewhile(str.isspace, script))
-        try:
-            leading, indent = leading.rsplit("\n", 1)
-            leading += "\n"
-        except ValueError:
-            leading, indent = "", leading
-        trailing = "".join(itertools.takewhile(str.isspace, reversed(script)))[::-1]
-
-        script = script.strip()
-        tree = parser.parse(script)
-        self.script = script.split("\n")
-
-        formatted = "\n".join(self.format_script_contents(tree))
-
-        return leading + textwrap.indent(formatted, indent) + trailing
-
-    def format_script_contents(self, script: Union[Script, CommandSub]) -> List[str]:
-        to_format = []
-        skip_formatting_start = None
-        for child in script.children:
-            if skip_formatting_start is None:
-                to_format.append(child)
-
-            if isinstance(child, Comment):
-                if child.value.strip() == "tclfmt-disable":
-                    if skip_formatting_start is not None:
-                        print(
-                            "Warning: encountered 'tclint-disable' while formatting is"
-                            " already disabled, ignoring...",
-                            file=sys.stderr,
-                        )
-                    else:
-                        skip_formatting_start = child.pos[0]
-                elif child.value.strip() == "tclfmt-enable":
-                    if skip_formatting_start is None:
-                        print(
-                            "Warning: encountered 'tclint-enable' while formatting is"
-                            " already disabled, ignoring...",
-                            file=sys.stderr,
-                        )
-                    else:
-                        skip_formatting_end = child.pos[0]
-                        block = self.script[skip_formatting_start:skip_formatting_end]
-                        to_format.append(
-                            LiteralBlock(
-                                block,
-                                pos=(skip_formatting_start + 1, 1),
-                                end_pos=(skip_formatting_end, 1),
-                            )
-                        )
-                        skip_formatting_start = None
-
-        if skip_formatting_start is not None:
-            print("Warning: missing 'tclint-enable'", file=sys.stderr)
-            to_format.append(
-                LiteralBlock(
-                    self.script[skip_formatting_start:],
-                    pos=(skip_formatting_start + 1, 1),
-                    end_pos=script.end_pos,
-                )
-            )
-
-        formatted = [""]
-        last_line = None
-        for child in to_format:
-            if last_line is not None:
-                if last_line == child.pos[0]:
-                    if isinstance(child, Comment):
-                        formatted[-1] += " ;"
-                    else:
-                        formatted[-1] += "; "
-                else:
-                    newlines = child.pos[0] - last_line
-                    newlines = min(newlines, self.opts.max_blank_lines + 1)
-                    formatted.extend([""] * newlines)
-            last_line = child.end_pos[0]
-
-            lines = self.format(child)
-            formatted[-1] += lines[0]
-            formatted.extend(lines[1:])
-
-        return formatted
-
-    def format_script(self, script: Script, should_indent=True) -> List[str]:
-        lines = self.format_script_contents(script)
-        if script.pos[0] == script.end_pos[0]:
-            return self._brace(lines)
-
-        # Usually, we enforce that multi-line scripts start on a new line after the open
-        # brace. However, if a comment was originally on the same line as the open brace
-        # we preserve it, since it's probably meant to be associated with this line
-        # (e.g. a tclint-disable-line).
-        open_brace = "{"
-        if (
-            len(script.children) > 0
-            and isinstance(script.children[0], Comment)
-            and script.pos[0] == script.children[0].pos[0]
-        ):
-            open_brace += " " + lines[0]
-            lines = lines[1:]
-
-        if should_indent:
-            return [open_brace] + self._indent(lines, self.opts.indent) + ["}"]
-        else:
-            return [open_brace] + lines + ["}"]
-
-    def format_command(self, command: Command) -> List[str]:
-        is_namespace_eval = (
-            command.routine.contents == "namespace"
-            and len(command.args) > 0
-            and command.args[0].contents == "eval"
-        )
-        should_indent = not is_namespace_eval or self.opts.indent_namespace_eval
-
-        hanging_indent = False
-        formatted = self.format(command.routine)
-        last_line = command.routine.end_pos[0]
-        for child in command.args:
-            if isinstance(child, Script):
-                child_lines = self.format_script(child, should_indent=should_indent)
-            else:
-                child_lines = self.format(child)
-
-            if last_line == child.pos[0]:
-                formatted[-1] += " "
-                formatted[-1] += child_lines[0]
-            else:
-                formatted[-1] += " \\"
-                formatted.append(self.opts.indent + child_lines[0])
-                hanging_indent = True
-
-            if hanging_indent:
-                formatted.extend(self._indent(child_lines[1:], self.opts.indent))
-            else:
-                formatted.extend(child_lines[1:])
-
-            last_line = child.end_pos[0]
-
-        return formatted
-
-    def format_comment(self, comment: Comment) -> List[str]:
-        return [f"#{comment.value}"]
-
-    def format_command_sub(self, command_sub):
-        if len(command_sub.children) == 0:
-            return ["[]"]
-
-        formatted = []
-        contents = self.format_script_contents(command_sub)
-        if len(command_sub.children) > 1 and len(contents) > 1:
-            formatted.append("[")
-            formatted.extend(self._indent(contents, self.opts.indent))
-            formatted.append("]")
-        else:
-            formatted.append("[" + contents[0])
-            formatted.extend(contents[1:])
-            formatted[-1] += "]"
-
-        return formatted
-
-    def format_bare_word(self, word) -> List[str]:
-        # Property enforced by parser
-        assert word.contents is not None
-        return [word.contents]
-
-    def format_quoted_word(self, word) -> List[str]:
-        if word.contents is not None:
-            return [f'"{word.contents}"']
-
-        formatted = ""
-        for child in word.children:
-            formatted += "\n".join(self.format(child))
-
-        return [f'"{formatted}"']
-
-    def format_braced_word(self, word) -> List[str]:
-        assert word.contents is not None
-        return [f"{{{word.contents}}}"]
-
-    def format_compound_bare_word(self, word) -> List[str]:
-        formatted = [""]
-        for child in word.children:
-            child_lines = self.format(child)
-            formatted[-1] += child_lines[0]
-            formatted.extend(child_lines[1:])
-
-        return formatted
-
-    def format_var_sub(self, varsub) -> List[str]:
-        # We might be able to make the formatter infer whether braces are required, and
-        # remove them from the syntax tree. For now it's easier to just mimic the
-        # original format.
-        if varsub.braced:
-            formatted = [f"${{{varsub.value}}}"]
-        else:
-            formatted = [f"${varsub.value}"]
-
-        if varsub.children:
-            # We just concatenate everything as is, since changes in whitespace are
-            # semantically meaningful in this context. Any newlines are captured by
-            # BareWords.
-            formatted[-1] += "("
-            for child in varsub.children:
-                child_lines = self.format(child)
-                formatted[-1] += child_lines[0]
-                formatted.extend(child_lines[1:])
-            formatted[-1] += ")"
-
-        return formatted
-
-    def format_arg_expansion(self, arg_expansion) -> List[str]:
-        lines = self.format(arg_expansion.list)
-        lines[0] = "{*}" + lines[0]
-
-        return lines
-
-    def format_list(self, list_node) -> List[str]:
-        # Similar to Script, but the contents are a bit more straightforward.
-        contents = [""]
-        last_line = None
-        for child in list_node.children:
-            if last_line is not None:
-                if last_line == child.pos[0]:
-                    contents[-1] += " "
-                else:
-                    newlines = child.pos[0] - last_line
-                    newlines = min(newlines, 3)
-                    contents.extend([""] * newlines)
-
-            lines = self.format(child)
-            contents[-1] += lines[0]
-            contents.extend(lines[1:])
-
-            last_line = child.end_pos[0]
-
-        if list_node.pos[0] == list_node.end_pos[0]:
-            return self._brace(contents)
-
-        return ["{"] + self._indent(contents, self.opts.indent) + ["}"]
-
-    def format_expression(self, expr) -> List[str]:
-        formatted = [""]
-        for child in expr.children:
-            lines = self.format(child)
-            formatted[-1] += lines[0]
-            for line in lines[1:]:
-                formatted[-1] += " \\"
-                formatted += self._indent([line], self.opts.indent)
-
-        # Trick: we know there are quotes around the expression if the start of the
-        # expression is a different column than its first child.
-        quoted = expr.pos[1] != expr.children[0].pos[1]
-        if quoted:
-            formatted[0] = '"' + formatted[0]
-            formatted[-1] += '"'
-
-        return formatted
-
-    def format_braced_expression(self, expr) -> List[str]:
-        formatted = [""]
-        for child in expr.children:
-            lines = self.format(child)
-            formatted[-1] += lines[0]
-            formatted.extend(lines[1:])
-
-        if expr.pos[0] == expr.end_pos[0]:
-            return self._brace(formatted)
-
-        return ["{"] + self._indent(formatted, self.opts.indent) + ["}"]
-
-    def format_paren_expression(self, expr) -> List[str]:
-        body = expr.body
-
-        formatted = ["("]
-        lines = self.format(body)
-        if expr.pos[0] != body.pos[0]:
-            formatted.extend(lines)
-        else:
-            formatted[-1] += lines[0]
-            formatted.extend(lines[1:])
-
-        formatted = formatted[0:1] + self._indent(formatted[1:], self.opts.indent)
-
-        if expr.end_pos[0] != body.end_pos[0]:
-            formatted.append(")")
-        else:
-            formatted[-1] += ")"
-
-        return formatted
-
-    def format_unary_op(self, expr):
-        op = self.format(expr.operator)
-        assert len(op) == 1
-
-        lines = self.format(expr.operand)
-        lines[0] = op[0] + lines[0]
-        return lines
-
-    def _format_op(self, expr) -> List[str]:
-        nodes = expr.children
-        formatted = self.format(nodes[0])
-
-        last = nodes[0]
-        for next in nodes[1:]:
-            lines = self.format(next)
-            if last.end_pos[0] != next.pos[0]:
-                formatted.extend(lines)
-            else:
-                formatted[-1] += " "
-                formatted[-1] += lines[0]
-                formatted.extend(lines[1:])
-            last = next
-
-        return formatted
-
-    def format_binary_op(self, expr) -> List[str]:
-        return self._format_op(expr)
-
-    def format_ternary_op(self, expr) -> List[str]:
-        return self._format_op(expr)
-
-    def format_function(self, function):
-        name = self.format(function.name)
-        assert len(name) == 1
-        name = name[0]
-
-        formatted = [f"{name}("]
-
-        last = function.name
-        for i, child in enumerate(function.args):
-            if i > 0:
-                formatted[-1] += ","
-            lines = self.format(child)
-            if last.end_pos[0] != child.pos[0]:
-                formatted.extend(lines)
-            else:
-                if i > 0:
-                    formatted[-1] += " "
-                formatted[-1] += lines[0]
-                formatted.extend(lines[1:])
-            last = child
-
-        # indent any continuation lines, but we leave the closing paren dedented
-        formatted = formatted[0:1] + self._indent(formatted[1:], self.opts.indent)
-
-        if last.end_pos[0] != function.end_pos[0]:
-            formatted.append(")")
-        else:
-            formatted[-1] += ")"
-
-        return formatted
diff --git a/server/libs/tclint/lexer.py b/server/libs/tclint/lexer.py
deleted file mode 100644
index dc18312..0000000
--- a/server/libs/tclint/lexer.py
+++ /dev/null
@@ -1,243 +0,0 @@
-import ply.lex as lex
-from typing import Tuple
-
-TOK_BACKSLASH_NEWLINE = "BACKSLASH_NEWLINE"
-TOK_BACKSLASH_SUB = "BACKSLASH_SUB"
-TOK_NEWLINE = "NEWLINE"
-TOK_SEMI = "SEMI"
-TOK_WS = "WS"
-TOK_QUOTE = "QUOTE"
-TOK_ARG_EXPANSION = "ARG_EXPANSION"
-TOK_LBRACE = "LBRACE"
-TOK_RBRACE = "RBRACE"
-TOK_STAR = "STAR"
-TOK_LBRACKET = "LBRACKET"
-TOK_RBRACKET = "RBRACKET"
-TOK_DOLLAR = "DOLLAR"
-TOK_LPAREN = "LPAREN"
-TOK_RPAREN = "RPAREN"
-TOK_HASH = "HASH"
-TOK_ALPHA_CHARS = "ALPHA_CHARS"
-TOK_NUM_CHARS = "NUM_CHARS"
-TOK_NAMESPACE_SEP = "NAMESPACE_SEP"
-TOK_CHAR = "CHAR"
-TOK_CONTENTS = "CONTENTS"
-TOK_EOF = None
-
-STATE_BRACEDWORD = "bracedword"
-
-
-class TclSyntaxError(Exception):
-    def __init__(self, message, start: Tuple[int, int], end: Tuple[int, int]):
-        super().__init__(message)
-        self.start = start
-        self.end = end
-
-
-class _LexTable:
-    tokens = (
-        TOK_BACKSLASH_NEWLINE,
-        TOK_BACKSLASH_SUB,
-        TOK_NEWLINE,
-        TOK_SEMI,
-        TOK_WS,
-        TOK_QUOTE,
-        TOK_ARG_EXPANSION,
-        TOK_LBRACE,
-        TOK_RBRACE,
-        TOK_STAR,
-        TOK_LBRACKET,
-        TOK_RBRACKET,
-        TOK_DOLLAR,
-        TOK_LPAREN,
-        TOK_RPAREN,
-        TOK_HASH,
-        TOK_ALPHA_CHARS,
-        TOK_NUM_CHARS,
-        TOK_NAMESPACE_SEP,
-        TOK_CHAR,
-        TOK_CONTENTS,
-    )
-
-    # This defines a conditional lexing state for parsing braced words. This is a
-    # performance optimization; since there are few special characters in this context,
-    # we can use a smaller set of tokens to parse them faster. This has a large impact
-    # since most Tcl programs have a large number of braced words. Any token with
-    # `bracedword` in its name is included in this state. Tokens that are included in
-    # this state and the default state also include `INITIAL` in their name.
-    states = ((STATE_BRACEDWORD, "exclusive"),)
-
-    def _tok(self, t):
-        pos = (t.lexer.lineno, t.lexer.colno)
-        t.lexer.lineno += t.value.count("\n")
-        index = t.value.rfind("\n")
-        if index == -1:
-            t.lexer.colno += len(t.value)
-        else:
-            remaining = t.value[index + 1 :]
-            t.lexer.colno = len(remaining) + 1
-
-        t.value = (t.value, pos)
-        return t
-
-    # Priority important
-    def t_bracedword_INITIAL_BACKSLASH_NEWLINE(self, t):
-        r"\\\n"
-        return self._tok(t)
-
-    # Priority important
-    def t_bracedword_INITIAL_BACKSLASH_SUB(self, t):
-        r"\\."
-        return self._tok(t)
-
-    def t_NEWLINE(self, t):
-        r"\n"
-        return self._tok(t)
-
-    def t_SEMI(self, t):
-        r";"
-        return self._tok(t)
-
-    # TODO: should use \s?
-    def t_WS(self, t):
-        r"[\t\v\f\r ]+"
-        return self._tok(t)
-
-    def t_QUOTE(self, t):
-        r'"'
-        return self._tok(t)
-
-    # Must be higher priority than LBRACE
-    def t_ARG_EXPANSION(self, t):
-        r"\{\*\}"
-        return self._tok(t)
-
-    def t_bracedword_INITIAL_LBRACE(self, t):
-        r"\{"
-        return self._tok(t)
-
-    def t_bracedword_INITIAL_RBRACE(self, t):
-        r"\}"
-        return self._tok(t)
-
-    def t_STAR(self, t):
-        r"\*"
-        return self._tok(t)
-
-    def t_LBRACKET(self, t):
-        r"\["
-        return self._tok(t)
-
-    def t_RBRACKET(self, t):
-        r"\]"
-        return self._tok(t)
-
-    def t_DOLLAR(self, t):
-        r"\$"
-        return self._tok(t)
-
-    def t_LPAREN(self, t):
-        r"\("
-        return self._tok(t)
-
-    def t_RPAREN(self, t):
-        r"\)"
-        return self._tok(t)
-
-    def t_HASH(self, t):
-        r"\#"
-        return self._tok(t)
-
-    # Valid non-numeric chars in variable names
-    def t_ALPHA_CHARS(self, t):
-        r"[A-Za-z_]+"
-        return self._tok(t)
-
-    # Valid numeric chars in variable names
-    # This is split up from the above to facilitate expression parsing, since
-    # e.g. 1eq1 can't be a single token.
-    def t_NUM_CHARS(self, t):
-        r"[0-9]+"
-        return self._tok(t)
-
-    def t_NAMESPACE_SEP(self, t):
-        r"::+"
-        return self._tok(t)
-
-    def t_bracedword_CONTENTS(self, t):
-        r"[^{}\\]+"
-        return self._tok(t)
-
-    # Catch-all. TODO: inefficient, should probably munch multiple chars
-    def t_CHAR(self, t):
-        r"."
-        return self._tok(t)
-
-    # Error handling rule
-    # TODO: do we need this? since we have a catch-all...
-    # there is a warning
-    def t_bracedword_INITIAL_error(self, t):
-        print("Illegal character '%s'" % t.value[0])
-        t.lexer.skip(1)
-
-    def __init__(self):
-        self.lexer = lex.lex(object=self)
-        self.lexer.lineno = 1
-        self.lexer.colno = 1
-
-    def new_lexer(self, pos=None):
-        lexer = self.lexer.clone()
-        lexer.lineno = 1
-        lexer.colno = 1
-
-        if pos is not None:
-            line, col = pos
-            lexer.lineno = line
-            lexer.colno = col
-
-        return lexer
-
-
-# Calling `lex.lex()` performs an expensive reflection process to generate the lexer.
-# This singleton class holds a preinitialized lexer that can then be cloned to create
-# individual instances.
-LexTable = _LexTable()
-
-
-class Lexer:
-    def __init__(self, pos=None):
-        self.lexer = LexTable.new_lexer(pos)
-        self.current = None
-
-    def input(self, text):
-        self.lexer.input(text)
-        self.current = self.lexer.token()
-
-    def type(self):
-        if self.current is None:
-            return TOK_EOF
-        return self.current.type
-
-    def value(self):
-        if self.current is None:
-            return None
-        return self.current.value[0]
-
-    def pos(self):
-        if self.current is None:
-            return (self.lexer.lineno, self.lexer.colno)
-        return self.current.value[1]
-
-    def next(self):
-        self.current = self.lexer.token()
-
-    def expect(self, *tokens, message, pos):
-        if self.type() not in tokens:
-            self.next()  # munch another token to update position
-            raise TclSyntaxError(message, pos, self.pos())
-
-        self.next()
-
-    def assert_(self, *tokens):
-        assert self.current.type in tokens
-        self.next()
diff --git a/server/libs/tclint/parser.py b/server/libs/tclint/parser.py
deleted file mode 100644
index b429838..0000000
--- a/server/libs/tclint/parser.py
+++ /dev/null
@@ -1,900 +0,0 @@
-import string
-import re
-
-from tclint.lexer import (
-    Lexer,
-    TclSyntaxError,
-    STATE_BRACEDWORD,
-    TOK_BACKSLASH_NEWLINE,
-    TOK_NEWLINE,
-    TOK_SEMI,
-    TOK_WS,
-    TOK_QUOTE,
-    TOK_ARG_EXPANSION,
-    TOK_LBRACE,
-    TOK_RBRACE,
-    TOK_LBRACKET,
-    TOK_RBRACKET,
-    TOK_DOLLAR,
-    TOK_LPAREN,
-    TOK_RPAREN,
-    TOK_HASH,
-    TOK_ALPHA_CHARS,
-    TOK_NUM_CHARS,
-    TOK_NAMESPACE_SEP,
-    TOK_EOF,
-)
-from tclint.syntax_tree import (
-    Script,
-    Comment,
-    Command,
-    CommandSub,
-    ArgExpansion,
-    VarSub,
-    BareWord,
-    BracedWord,
-    QuotedWord,
-    CompoundBareWord,
-    List,
-    Expression,
-    BracedExpression,
-    ParenExpression,
-    UnaryOp,
-    BinaryOp,
-    TernaryOp,
-    Function,
-)
-from tclint.commands import CommandArgError, get_commands
-from tclint.commands.checks import check_command
-from tclint.violations import Rule, Violation
-
-
-def _strip_ws(parse_func):
-    """Decorator used by expression parser for stripping whitespace around a node."""
-
-    def func(parser, ts):
-        while ts.type() in {TOK_WS, TOK_BACKSLASH_NEWLINE, TOK_NEWLINE}:
-            ts.next()
-
-        node = parse_func(parser, ts)
-
-        while ts.type() in {TOK_WS, TOK_BACKSLASH_NEWLINE, TOK_NEWLINE}:
-            ts.next()
-
-        return node
-
-    return func
-
-
-class _Word:
-    """Helper class for constructing Word nodes out of multiple segments."""
-
-    def __init__(self):
-        self.segments = []
-        self.current_segment = ""
-        self.current_start = None
-
-    def add_tok(self, tok):
-        if self.current_start is None:
-            self.current_start = tok.value[1]
-        self.current_segment += tok.value[0]
-
-    def add_node(self, node):
-        if self.current_segment != "":
-            self.segments.append(
-                BareWord(self.current_segment, pos=self.current_start, end_pos=node.pos)
-            )
-            self.current_segment = ""
-            self.current_start = None
-        self.segments.append(node)
-
-    def resolve(self, end_pos):
-        if self.current_segment:
-            self.segments.append(
-                BareWord(self.current_segment, pos=self.current_start, end_pos=end_pos)
-            )
-
-        return self.segments
-
-
-class Parser:
-    def __init__(self, debug=False, command_plugins=None):
-        self._debug = debug
-        self._debug_indent = 0
-        # TODO: better way to handle this?
-        self.violations = []
-
-        if command_plugins is None:
-            command_plugins = []
-        self._commands = get_commands(command_plugins)
-
-    def debug(self, *msg):
-        if self._debug:
-            print("  " * self._debug_indent, end="")
-            print(*msg)
-
-    def parse(self, script, pos=None):
-        lexer = Lexer(pos=pos)
-        lexer.input(script)
-        tree = self._parse_script(lexer, in_command_sub=False)
-        assert (
-            lexer.type() == TOK_EOF
-        ), "Didn't reach EOF parsing script, please file a bug report."
-
-        return tree
-
-    def _parse_command_args(self, routine, args):
-        """Since many built-in Tcl commands take in Tcl scripts or expressions
-        as arguments, building a complete parse tree requires checking command
-        names and possibly parsing their arguments.
-
-        The node of any argument that gets parsed by this method is replaced with
-        the parse tree of that argument. Since this process requires checking
-        the arguments provided to these commands, this method may report lint
-        violations.
-
-        This parsing process is analogous to how the Tcl interpreter interprets
-        scripts, and better handles weird edge cases compared to a traditional
-        parsing technique. For example, this may look like valid Tcl:
-
-        proc foo {a} {
-            # output }
-            puts "}"
-        }
-
-        But really, it is invalid since the } in the comment terminates the body
-        of the proc - Tcl blindly constructs the body of the proc until it
-        reaches the first }. tclint handles this correctly.
-        """
-        if routine not in self._commands:
-            return args
-
-        spec = self._commands[routine]
-
-        try:
-            new_args = check_command(routine, args, self, spec)
-        except TclSyntaxError as e:
-            raise e
-        except CommandArgError as e:
-            raise e
-        except Exception:
-            if self._debug:
-                raise
-            raise CommandArgError(
-                f"error parsing command arguments, possibly malformed {routine} command"
-            )
-
-        if new_args is None:
-            return args
-
-        return new_args
-
-    def parse_script(self, node):
-        if node.contents is None:
-            raise CommandArgError(
-                "expected braced word or word without substitutions in argument"
-                " interpreted as script"
-            )
-
-        script = self.parse(node.contents, pos=node.contents_pos)
-        if isinstance(node, BracedWord):
-            script.braced = True
-
-        script.line = node.line
-        script.col = node.col
-        script.end_pos = node.end_pos
-
-        return script
-
-    def _parse_script(self, ts, in_command_sub):
-        self.debug(f"parse_script({ts.current})")
-        self._debug_indent += 1
-        pos = ts.pos()
-
-        if in_command_sub:
-            script = CommandSub(pos=pos)
-        else:
-            script = Script(pos=pos)
-
-        while ts.type() is not TOK_EOF:
-            if ts.type() in {TOK_WS, TOK_BACKSLASH_NEWLINE}:
-                # strip whitespace at start of command
-                ts.next()
-                continue
-
-            if ts.type() == TOK_HASH:
-                script.add(self.parse_comment(ts))
-            else:
-                cmd = self.parse_command(ts, in_command_sub=in_command_sub)
-                if cmd is not None:
-                    script.add(cmd)
-
-            # when in command sub mode, a script is terminated by ]
-            if in_command_sub and ts.type() == TOK_RBRACKET:
-                return script
-
-            ts.expect(
-                TOK_EOF,
-                TOK_NEWLINE,
-                TOK_SEMI,
-                message=f"expected newline or semicolon, got {ts.value()}",
-                pos=ts.pos(),
-            )
-
-        if in_command_sub and ts.type() is TOK_EOF:
-            raise TclSyntaxError(
-                "reached EOF without finding end of command substitution", pos, ts.pos()
-            )
-
-        self._debug_indent -= 1
-
-        script.end_pos = ts.pos()
-
-        return script
-
-    def parse_comment(self, ts):
-        self.debug(f"parse_comment({ts.current})")
-        pos = ts.pos()
-
-        ts.assert_(TOK_HASH)
-
-        value = ""
-        while ts.type() not in {TOK_NEWLINE, TOK_EOF}:
-            value += ts.value()
-            ts.next()
-
-        # Stripping trailing whitespace from comments here allows tclfmt to clean it up
-        # without affecting the AST.
-        value = value.rstrip()
-
-        return Comment(value, pos=pos, end_pos=ts.pos())
-
-    def parse_command(self, ts, in_command_sub):
-        self.debug(f"parse_command({ts.current})")
-        self._debug_indent += 1
-        pos = ts.pos()
-
-        routine = self.parse_word(ts, in_command_sub)
-        if routine is None:
-            self._debug_indent -= 1
-            return None
-
-        args = []
-        while True:
-            if ts.type() not in {TOK_WS, TOK_BACKSLASH_NEWLINE}:
-                break
-
-            while ts.type() in {TOK_WS, TOK_BACKSLASH_NEWLINE}:
-                ts.next()
-
-            word = self.parse_word(ts, in_command_sub)
-            if word is None:
-                break
-
-            args.append(word)
-
-        self._debug_indent -= 1
-
-        try:
-            parsed_args = self._parse_command_args(routine.contents, args)
-        except CommandArgError as e:
-            self.violations.append(Violation(Rule.COMMAND_ARGS, str(e), pos, ts.pos()))
-            parsed_args = args
-
-        children = [routine, *parsed_args]
-        # We need to inherit end pos of last child to prevent us from counting
-        # extra whitespace at end of command, which is important for
-        # spaces-in-braces check.
-        return Command(*children, pos=pos, end_pos=children[-1].end_pos)
-
-    def parse_word(self, ts, in_command_sub):
-        self.debug(f"parse_word({ts.current})")
-        if ts.type() == TOK_ARG_EXPANSION:
-            return self.parse_arg_expansion(ts, in_command_sub)
-        elif ts.type() == TOK_LBRACE:
-            return self.parse_braced_word(ts)
-        elif ts.type() == TOK_QUOTE:
-            return self.parse_quoted_word(ts)
-        else:
-            return self.parse_bare_word(ts, in_command_sub)
-
-    def parse_arg_expansion(self, ts, in_command_sub):
-        self.debug(f"parse_arg_expansion({ts.current})")
-        pos = ts.pos()
-
-        ts.assert_(TOK_ARG_EXPANSION)
-
-        delimiters = [TOK_WS, TOK_BACKSLASH_NEWLINE, TOK_NEWLINE, TOK_SEMI, TOK_EOF]
-        if in_command_sub:
-            delimiters.append(TOK_RBRACKET)
-
-        # Arg expansion is just a regular braced word if followed by whitespace,
-        # or other word boundaries such as semicolon or right bracket
-        # (in command substitution)
-        if ts.type() in delimiters:
-            return BracedWord("*", pos=pos, end_pos=ts.pos())
-
-        return ArgExpansion(
-            self.parse_word(ts, in_command_sub), pos=pos, end_pos=ts.pos()
-        )
-
-    def parse_quoted_word(self, ts):
-        self.debug(f"parse_quoted_word({ts.current})")
-        self._debug_indent += 1
-        pos = ts.pos()
-
-        ts.assert_(TOK_QUOTE)
-
-        word = _Word()
-        while ts.type() not in {TOK_QUOTE, TOK_EOF}:
-            if ts.type() == TOK_DOLLAR:
-                dollar_tok = ts.current
-                var_sub = self.parse_var_sub(ts)
-                if var_sub:
-                    word.add_node(var_sub)
-                else:
-                    word.add_tok(dollar_tok)
-            elif ts.type() == TOK_LBRACKET:
-                command_sub = self.parse_command_sub(ts)
-                word.add_node(command_sub)
-            else:
-                word.add_tok(ts.current)
-                ts.next()
-
-        res = word.resolve(ts.pos())
-
-        ts.expect(
-            TOK_QUOTE, message="reached EOF without finding match for quote", pos=pos
-        )
-
-        self._debug_indent -= 1
-
-        if not res:
-            res = []
-
-        return QuotedWord(*res, pos=pos, end_pos=ts.pos())
-
-    def parse_braced_word(self, ts):
-        self.debug(f"parse_braced_word({ts.current})")
-        pos = ts.pos()
-
-        ts.lexer.push_state(STATE_BRACEDWORD)
-
-        ts.assert_(TOK_LBRACE)
-
-        word = ""
-        # store position for each brace we want to match, facilitating good
-        # error messages
-        expected_braces = [pos]
-        while True:
-            toktype = ts.type()
-            if toktype == TOK_EOF:
-                raise TclSyntaxError(
-                    "reached EOF without finding match for brace",
-                    expected_braces[-1],
-                    ts.pos(),
-                )
-
-            if toktype == TOK_LBRACE:
-                expected_braces.append(ts.pos())
-            elif toktype == TOK_RBRACE:
-                try:
-                    expected_braces.pop()
-                except IndexError:
-                    start = ts.pos()
-                    ts.next()
-                    end = ts.pos()
-                    raise TclSyntaxError(
-                        "found closing brace without matching open brace", start, end
-                    )
-
-                if len(expected_braces) == 0:
-                    ts.lexer.pop_state()
-                    ts.next()
-                    break
-            word += ts.value()
-            ts.next()
-
-        end_pos = ts.pos()
-        return BracedWord(word, pos=pos, end_pos=end_pos)
-
-    def parse_bare_word(self, ts, in_command_sub):
-        self.debug(f"parse_bare_word({ts.current})")
-        self._debug_indent += 1
-        pos = ts.pos()
-
-        word = _Word()
-        delimiters = [TOK_WS, TOK_BACKSLASH_NEWLINE, TOK_NEWLINE, TOK_SEMI, TOK_EOF]
-
-        # In command sub mode, words are ended by ]
-        if in_command_sub:
-            delimiters.append(TOK_RBRACKET)
-
-        while ts.type() not in delimiters:
-            if ts.type() == TOK_DOLLAR:
-                dollar_tok = ts.current
-                var_sub = self.parse_var_sub(ts)
-                if var_sub:
-                    word.add_node(var_sub)
-                else:
-                    word.add_tok(dollar_tok)
-            elif ts.type() == TOK_LBRACKET:
-                command_sub = self.parse_command_sub(ts)
-                word.add_node(command_sub)
-            else:
-                word.add_tok(ts.current)
-                ts.next()
-
-        res = word.resolve(ts.pos())
-
-        self._debug_indent -= 1
-
-        if not res:
-            return None
-        if len(res) == 1:
-            return res[0]
-        return CompoundBareWord(*res, pos=pos, end_pos=ts.pos())
-
-    def parse_var_sub(self, ts):
-        self.debug(f"parse_var_sub({ts.current})")
-        pos = ts.pos()
-
-        ts.assert_(TOK_DOLLAR)
-
-        var = ""
-        if ts.type() == TOK_LBRACE:
-            brace_pos = ts.pos()
-            ts.next()
-            while ts.type() != TOK_RBRACE:
-                if ts.type() is TOK_EOF:
-                    raise TclSyntaxError(
-                        "reached EOF without finding match for brace",
-                        brace_pos,
-                        ts.pos(),
-                    )
-                var += ts.value()
-                ts.next()
-            ts.next()
-
-            return VarSub(var, pos=pos, end_pos=ts.pos(), braced=True)
-
-        while ts.type() in {TOK_ALPHA_CHARS, TOK_NUM_CHARS, TOK_NAMESPACE_SEP}:
-            var += ts.value()
-            ts.next()
-
-        if not var:
-            return None
-
-        index_nodes = []
-        if ts.type() == TOK_LPAREN:
-            paren_pos = ts.pos()
-            index = _Word()
-            ts.next()
-            while ts.type() != TOK_RPAREN:
-                if ts.type() == TOK_EOF:
-                    raise TclSyntaxError(
-                        "reached EOF without finding match for paren",
-                        paren_pos,
-                        ts.pos(),
-                    )
-                if ts.type() == TOK_DOLLAR:
-                    dollar_tok = ts.current
-                    var_sub = self.parse_var_sub(ts)
-                    if var_sub:
-                        index.add_node(var_sub)
-                    else:
-                        index.add_tok(dollar_tok)
-                elif ts.type() == TOK_LBRACKET:
-                    command_sub = self.parse_command_sub(ts)
-                    index.add_node(command_sub)
-                else:
-                    index.add_tok(ts.current)
-                    ts.next()
-
-            index_nodes = index.resolve(ts.pos())
-            ts.next()
-
-        var_sub = VarSub(var, pos=pos, end_pos=ts.pos())
-
-        for index_segment in index_nodes:
-            var_sub.add(index_segment)
-
-        return var_sub
-
-    def parse_command_sub(self, ts):
-        self.debug(f"parse_command_sub({ts.current})")
-        self._debug_indent += 1
-
-        pos = ts.pos()
-        ts.assert_(TOK_LBRACKET)
-
-        script = self._parse_script(ts, in_command_sub=True)
-
-        ts.assert_(TOK_RBRACKET)
-        end_pos = ts.pos()
-
-        script.line = pos[0]
-        script.col = pos[1]
-        script.end_pos = end_pos
-
-        self._debug_indent -= 1
-        return script
-
-    def parse_list(self, node):
-        """Parse contents of node as Tcl list. This is a distinct entry point
-        that doesn't get used when generating the main syntax tree, but is used
-        in command-specific argument parsing.
-        """
-        if isinstance(node, List):
-            return node
-
-        if node.contents is None:
-            raise CommandArgError(
-                "expected braced word or word without substitutions in argument"
-                " interpreted as list"
-            )
-
-        ts = Lexer(pos=node.contents_pos)
-        ts.input(node.contents)
-
-        DELIMITERS = {TOK_WS, TOK_BACKSLASH_NEWLINE, TOK_NEWLINE}
-
-        list_node = List(pos=node.pos, end_pos=node.end_pos)
-        while ts.type() is not TOK_EOF:
-            while ts.type() in DELIMITERS:
-                ts.next()
-
-            if ts.type() is TOK_EOF:
-                break
-
-            if ts.type() == TOK_LBRACE:
-                # we can reuse parse_braced_word, since it doesn't use
-                # substitutions in any case
-                list_node.add(self.parse_braced_word(ts))
-            elif ts.type() == TOK_QUOTE:
-                quote_word_pos = ts.pos()
-
-                ts.assert_(TOK_QUOTE)
-
-                bare_word_pos = ts.pos()
-                contents = ""
-                while ts.type() not in {TOK_QUOTE, TOK_EOF}:
-                    contents += ts.value()
-                    ts.next()
-                word = BareWord(contents, pos=bare_word_pos, end_pos=ts.pos())
-
-                ts.expect(
-                    TOK_QUOTE,
-                    message="reached EOF without finding match for quote",
-                    pos=quote_word_pos,
-                )
-
-                list_node.add(QuotedWord(word, pos=quote_word_pos, end_pos=ts.pos()))
-            else:
-                pos = ts.pos()
-                contents = ""
-                while ts.type() not in {*DELIMITERS, TOK_EOF}:
-                    contents += ts.value()
-                    ts.next()
-                list_node.add(BareWord(contents, pos=pos, end_pos=ts.pos()))
-
-        return list_node
-
-    def parse_expression(self, node):
-        if node.contents is None:
-            raise CommandArgError(
-                "expected braced word or word without substitutions in argument"
-                " interpreted as expr"
-            )
-
-        ts = Lexer(pos=node.contents_pos)
-        ts.input(node.contents)
-
-        contents = self._parse_expression(ts)
-        ts.expect(
-            TOK_EOF,
-            message=f"expected end of expression, got {ts.value()}",
-            pos=ts.pos(),
-        )
-        if isinstance(node, BracedWord):
-            return BracedExpression(contents, pos=node.pos, end_pos=node.end_pos)
-
-        return Expression(contents, pos=node.pos, end_pos=node.end_pos)
-
-    @_strip_ws
-    def _parse_expression(self, ts):
-        op1 = self._parse_operand(ts)
-        expr = op1
-
-        # last condition is hack to break out of expression in case we're in ternary op
-        if ts.type() not in {TOK_EOF, TOK_RPAREN} and ts.value() not in {":", ","}:
-            if ts.value() == "?":
-                # weird hack to record operator
-                start = ts.pos()
-                ts.next()
-                q = BareWord("?", pos=start, end_pos=ts.pos())
-
-                op2 = self._parse_expression(ts)
-                if ts.value() != ":":
-                    start = ts.pos()
-                    ts.next()
-                    end = ts.pos()
-                    raise TclSyntaxError(
-                        "expected ':' to continue ternary expression", start, end
-                    )
-
-                # weird hack again
-                start = ts.pos()
-                ts.next()
-                colon = BareWord(":", pos=start, end_pos=ts.pos())
-
-                op3 = self._parse_expression(ts)
-                expr = TernaryOp(
-                    op1, q, op2, colon, op3, pos=op1.pos, end_pos=op3.end_pos
-                )
-            else:
-                operator = self._parse_operator(ts)
-                op2 = self._parse_expression(ts)
-                expr = BinaryOp(op1, operator, op2, pos=op1.pos, end_pos=op2.end_pos)
-
-            if ts.type() != TOK_RPAREN and ts.value() not in {":", ","}:
-                ts.expect(TOK_EOF, message="expected end of expression", pos=ts.pos())
-
-        return expr
-
-    @_strip_ws
-    def _parse_operand(self, ts):
-        if ts.type() == TOK_DOLLAR:
-            return self.parse_var_sub(ts)
-        if ts.type() == TOK_QUOTE:
-            return self.parse_quoted_word(ts)
-        if ts.type() == TOK_LBRACE:
-            return self.parse_braced_word(ts)
-        if ts.type() == TOK_LBRACKET:
-            return self.parse_command_sub(ts)
-        if ts.type() == TOK_LPAREN:
-            start = ts.pos()
-            ts.next()
-            expr = self._parse_expression(ts)
-            ts.expect(
-                TOK_RPAREN,
-                message="reached EOF without finding match for paren",
-                pos=expr.pos,
-            )
-            end = ts.pos()
-            return ParenExpression(expr, start, end)
-        if ts.value() in {"-", "+", "~", "!"}:
-            operator_val = ts.value()
-            operator_pos = ts.pos()
-            ts.next()
-            operator = BareWord(operator_val, pos=operator_pos, end_pos=ts.pos())
-            operand = self._parse_operand(ts)
-            # Since _parse_operand() munches whitespace after the operand, we
-            # set the end of the UnaryOp to the end of the operand rather than
-            # ts.pos(). Otherwise, the bounds of the UnaryOp would include all
-            # that whitespace.
-            return UnaryOp(operator, operand, pos=operator_pos, end_pos=operand.end_pos)
-
-        # If none of these, collect tokens that may comprise an operand
-        operand = ""
-        operand_pos = ts.pos()
-
-        # First, we want to check for numeric operands (either ints or numeric
-        # floats) by consuming tokens as long as they comprise the prefix of a
-        # numeric operand
-        while ts.type() != TOK_EOF and (
-            _is_int_prefix(operand + ts.value())
-            or _is_float_prefix(operand + ts.value())
-        ):
-            operand += ts.value()
-            ts.next()
-
-        # Next, we check if we've consumed an entire numeric literal. If so, we
-        # move on. If not, we keep consuming tokens that may correspond to a
-        # valid bareword (pretty much just alphanumeric chars).
-        if not (_is_int_literal(operand) or _is_float_literal(operand)):
-            while ts.type() in {TOK_ALPHA_CHARS, TOK_NUM_CHARS}:
-                operand += ts.value()
-                ts.next()
-
-        # The above method is a little hacky. Note that it doesn't parse things
-        # exactly the same as Tcl. E.g. if a script includes `expr {1foo}`,
-        # tclint will report an invalid operator "foo", whereas tclsh will
-        # report an invalid bareword "1foo". Despite reporting them differently
-        # both tools should still catch the same syntax errors, since there are
-        # no legal barewords that begin with a numeric literal prefix, and tclsh
-        # will stop parsing numeric operands if they're actually followed by a
-        # legal operator (e.g. `expr {1eq1}` will be handled properly).
-
-        is_func = _is_function(operand)
-
-        if not (
-            _is_int_literal(operand)
-            or _is_float_literal(operand)
-            or _is_bool_literal(operand)
-            or is_func
-        ):
-            raise TclSyntaxError(
-                f"invalid bareword in expression: {operand}", operand_pos, ts.pos()
-            )
-
-        node = BareWord(operand, pos=operand_pos, end_pos=ts.pos())
-
-        if is_func:
-            node = self._parse_function(ts, node)
-
-        return node
-
-    def _parse_operator(self, ts):
-        pos = ts.pos()
-
-        # hacky logic to handle parsing legal operators
-
-        if ts.value() in {"*", "&", "|"}:
-            # one or two of these characters are legal operators
-            operator = ts.value()
-            ts.next()
-            if ts.value() == operator:
-                operator += ts.value()
-                ts.next()
-        elif ts.value() in {"<", ">"}:
-            operator = ts.value()
-            ts.next()
-            if ts.value() in {operator, "="}:
-                operator += ts.value()
-                ts.next()
-        elif ts.value() in {"=", "!"}:
-            operator = ts.value()
-            ts.next()
-            if ts.value() != "=":
-                raise TclSyntaxError(
-                    f"invalid operator in expression: {operator}", pos, ts.pos()
-                )
-            operator += ts.value()
-            ts.next()
-        elif ts.value() in {"*", "/", "%", "+", "-", "^", "eq", "ne", "in", "ni"}:
-            operator = ts.value()
-            ts.next()
-        else:
-            raise TclSyntaxError(
-                f"invalid operator in expression: {ts.value()}", pos, ts.pos()
-            )
-
-        return BareWord(operator, pos=pos, end_pos=ts.pos())
-
-    def _parse_function(self, ts, name):
-        while ts.type() in {TOK_WS, TOK_BACKSLASH_NEWLINE}:
-            ts.next()
-
-        ts.expect(
-            TOK_LPAREN,
-            message="expected open paren after function name",
-            pos=name.pos,
-        )
-
-        delims = {TOK_RPAREN, TOK_EOF}
-
-        arguments = []
-        if ts.type() not in delims:
-            arguments.append(self._parse_expression(ts))
-
-        while ts.type() not in delims:
-            if ts.value() != ",":
-                start = ts.pos()
-                ts.next()
-                end = ts.pos()
-                raise TclSyntaxError(
-                    "expected comma between function arguments", start, end
-                )
-            ts.next()
-
-            arguments.append(self._parse_expression(ts))
-
-        ts.expect(
-            TOK_RPAREN,
-            message="expected close paren after function arguments",
-            pos=name.pos,
-        )
-        return Function(name, *arguments, pos=name.pos, end_pos=ts.pos())
-
-
-def _all(_list, non_empty=False):
-    """Like all(), but if non_empty is True, list must also have at least 1 element."""
-    if non_empty and len(_list) == 0:
-        return False
-    return all(_list)
-
-
-def _is_int(operand, full=False):
-    """Returns whether operand is a valid Tcl integer literal.
-
-    If full is False, will also return True if operand is the prefix of an
-    integer literal.  An empty string is not a valid full literal, but is a
-    valid prefix.
-    """
-    # prefixes
-    if operand.startswith("0b"):
-        return _all([digit in "01" for digit in operand[2:]], non_empty=full)
-    if operand.startswith("0o"):
-        return _all(
-            [digit in string.octdigits for digit in operand[2:]], non_empty=full
-        )
-    if operand.startswith("0x"):
-        return _all(
-            [digit in string.hexdigits for digit in operand[2:]], non_empty=full
-        )
-    if operand.startswith("0"):
-        # fun fact: apparently a lone 0 prefix is interpreted as octal
-        return _all(
-            [digit in string.octdigits for digit in operand[1:]], non_empty=full
-        )
-
-    return _all([digit in string.digits for digit in operand], non_empty=full)
-
-
-def _is_int_literal(operand):
-    return _is_int(operand, full=True)
-
-
-def _is_int_prefix(operand):
-    return _is_int(operand, full=False)
-
-
-def _is_float_literal(operand):
-    if operand.lower() in {"nan", "inf"}:
-        return True
-
-    return (
-        operand != "" and re.fullmatch(r"\d*\.?\d*([Ee][+-]?\d+)?", operand) is not None
-    )
-
-
-def _is_float_prefix(operand):
-    """Returns whether operand is the prefix of a valid numeric float literal."""
-    return re.fullmatch(r"\d*\.?\d*([Ee][+-]?)?\d*", operand) is not None
-
-
-def _is_bool_literal(operand):
-    return operand in {"false", "no", "off", "true", "yes", "on"}
-
-
-# map of function names to # arguments accepted
-# None indicates 1 or more arguments
-# TODO: use these values in an actual separate check. they might want to live elsewhere
-_FUNCTIONS = {
-    "abs": 1,
-    "acos": 1,
-    "asin": 1,
-    "atan": 1,
-    "atan2": 2,
-    "bool": 1,
-    "ceil": 1,
-    "cos": 1,
-    "cosh": 1,
-    "double": 1,
-    "entier": 1,
-    "exp": 1,
-    "floor": 1,
-    "fmod": 2,
-    "hypot": 2,
-    "int": 1,
-    "isqrt": 1,
-    "log": 1,
-    "log10": 1,
-    "max": None,
-    "min": None,
-    "pow": 2,
-    "rand": 0,
-    "round": 1,
-    "sin": 1,
-    "sinh": 1,
-    "sqrt": 1,
-    "srand": 1,
-    "tan": 1,
-    "tanh": 1,
-    "wide": 1,
-}
-
-
-def _is_function(operand):
-    return operand in _FUNCTIONS.keys()
diff --git a/server/libs/tclint/syntax_tree.py b/server/libs/tclint/syntax_tree.py
deleted file mode 100644
index d11f6df..0000000
--- a/server/libs/tclint/syntax_tree.py
+++ /dev/null
@@ -1,438 +0,0 @@
-"""Classes for representing and interacting with Tcl syntax trees. """
-
-
-class Visitor:
-    """Abstract base class for Visitors that operate on syntax tree."""
-
-    def visit_script(self, script):
-        pass
-
-    def visit_comment(self, comment):
-        pass
-
-    def visit_command(self, command):
-        pass
-
-    def visit_command_sub(self, command_sub):
-        pass
-
-    def visit_bare_word(self, word):
-        pass
-
-    def visit_braced_word(self, word):
-        pass
-
-    def visit_quoted_word(self, word):
-        pass
-
-    def visit_compound_bare_word(self, word):
-        pass
-
-    def visit_var_sub(self, var_sub):
-        pass
-
-    def visit_arg_expansion(self, arg_expansion):
-        pass
-
-    def visit_list(self, list):
-        pass
-
-    def visit_expression(self, expression):
-        pass
-
-    def visit_braced_expression(self, expression):
-        pass
-
-    def visit_paren_expression(self, expression):
-        pass
-
-    def visit_unary_op(self, unary_op):
-        pass
-
-    def visit_binary_op(self, binary_op):
-        pass
-
-    def visit_ternary_op(self, ternary_op):
-        pass
-
-    def visit_function(self, function):
-        pass
-
-
-class Node:
-    """
-    Invariants:
-    - self.value is some sort of base Python type
-    - self.children is a list of Node types
-    """
-
-    def __init__(self, *init, pos=None, end_pos=None):
-        """pos: line, column of first character of parsed region (1-indexed)
-        end_pos: line, column of first character after parsed region (1-indexed)
-        """
-        self.line = None
-        self.col = None
-        if pos is not None:
-            self.line, self.col = pos
-        self.end_pos = end_pos
-
-        self.value = None
-        if len(init) > 0 and not isinstance(init[0], Node):
-            self.value = init[0]
-            init = init[1:]
-
-        if not all(isinstance(v, Node) for v in init):
-            raise TypeError("Children must be Node instances")
-
-        self.children = list(init)
-
-    def add(self, node):
-        self.children.append(node)
-
-    @property
-    def contents(self):
-        """This is overloaded by word Nodes that may have concrete contents.
-
-        TODO: I prefer the name value, but that's currently taken...
-        """
-        return None
-
-    @property
-    def contents_pos(self):
-        """This is overloaded by word Nodes that may have concrete contents.
-
-        Returns the position at which the contents start.
-
-        TODO: consider combining with with `contents`?
-        """
-        return None
-
-    def _pos_str(self):
-        start_pos_str = "?"
-        if self.pos is not None:
-            start_pos_str = f"{self.pos[0]}:{self.pos[1]}"
-        end_pos_str = "?"
-        if self.end_pos is not None:
-            end_pos_str = f"{self.end_pos[0]}:{self.end_pos[1]}"
-
-        return f"  # {start_pos_str}-{end_pos_str}"
-
-    def _make_str(self, indent=None, positions=False):
-        if indent is not None:
-            s = "  " * indent
-        else:
-            s = ""
-
-        s += self.__class__.__name__
-        s += "("
-
-        if self.value:
-            s += repr(self.value)
-            if self.children:
-                s += ", "
-
-        if positions and self.children:
-            s += self._pos_str()
-
-        for i, child in enumerate(self.children):
-            if indent is not None:
-                s += "\n"
-            s += child._make_str(
-                indent=None if indent is None else indent + 1, positions=positions
-            )
-            if i < len(self.children) - 1:
-                s += ", "
-        s += ")"
-
-        if positions and not self.children:
-            s += self._pos_str()
-
-        return s
-
-    def pretty(self, positions=False):
-        return self._make_str(indent=0, positions=positions)
-
-    def __str__(self):
-        return self._make_str()
-
-    def __eq__(self, other):
-        if type(self) is not type(other):
-            return False
-
-        if self.value != other.value:
-            return False
-
-        if len(self.children) != len(other.children):
-            return False
-        for my_child, other_child in zip(self.children, other.children):
-            if my_child != other_child:
-                return False
-
-        return True
-
-    def diff(self, other, indent_depth=0):
-        lines = []
-        indent = "  " * indent_depth
-
-        my_cls = self.__class__.__name__
-        other_cls = other.__class__.__name__
-
-        if my_cls != other_cls:
-            lines += [f"{indent}-{my_cls}("]
-            lines += [f"{indent}+{other_cls}("]
-            return lines
-
-        if self.value != other.value:
-            lines += [f'{indent}-{my_cls}("{self.value}"']
-            lines += [f'{indent}+{other_cls}("{other.value}"']
-            return lines
-
-        if len(self.children) != len(other.children):
-            my_children = ",".join([
-                child.__class__.__name__ for child in self.children
-            ])
-            other_children = ",".join([
-                child.__class__.__name__ for child in other.children
-            ])
-
-            lines += [f"{indent}-{my_cls}({my_children})"]
-            lines += [f"{indent}+{other_cls}({other_children})"]
-            return lines
-
-        if self.value is not None:
-            lines += [f"{indent}{my_cls}({self.value}"]
-        else:
-            lines += [f"{indent}{my_cls}("]
-
-        for my_child, other_child in zip(self.children, other.children):
-            lines += my_child.diff(other_child, indent_depth=indent_depth + 1)
-
-        lines += [f"{indent})"]
-
-        return lines
-
-    @property
-    def pos(self):
-        if self.line is None or self.col is None:
-            return None
-
-        return (self.line, self.col)
-
-    def _recurse(self, visitor):
-        for child in self.children:
-            child.accept(visitor, recurse=True)
-
-
-class Script(Node):
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        # hack for spaces-in-braces check
-        self.braced = False
-
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_script(self)
-
-
-class Comment(Node):
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_comment(self)
-
-
-class Command(Node):
-    def __init__(self, routine, *args, pos=None, end_pos=None):
-        self.routine = routine
-        self.args = args
-        super().__init__(routine, *args, pos=pos, end_pos=end_pos)
-
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_command(self)
-
-
-class CommandSub(Node):
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_command_sub(self)
-
-
-class BareWord(Node):
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_bare_word(self)
-
-    @property
-    def contents(self):
-        return self.value
-
-    @property
-    def contents_pos(self):
-        return self.pos
-
-
-class BracedWord(Node):
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_braced_word(self)
-
-    @property
-    def contents(self):
-        return self.value
-
-    @property
-    def contents_pos(self):
-        return (self.line, self.col + 1)
-
-
-class QuotedWord(Node):
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_quoted_word(self)
-
-    @property
-    def contents(self):
-        """A QuotedWord with concrete contents is put in the tree as
-        QuotedWord(BareWord()), so return contents of its child."""
-        if len(self.children) > 1:
-            return None
-        if len(self.children) == 0:
-            # weird special case to handle blank quoted string ("") - it doesn't
-            # make sense to put in a child, but setting/returning the value is
-            # also inconsistent
-            return ""
-
-        return self.children[0].contents
-
-    @property
-    def contents_pos(self):
-        if self.contents is None:
-            return None
-        return (self.line, self.col + 1)
-
-
-class CompoundBareWord(Node):
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_compound_bare_word(self)
-
-
-class VarSub(Node):
-    def __init__(self, *args, braced=False, **kwargs):
-        self.braced = braced
-        return super().__init__(*args, **kwargs)
-
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_var_sub(self)
-
-
-class ArgExpansion(Node):
-    def __init__(self, list, pos=None, end_pos=None):
-        self.list = list
-        super().__init__(list, pos=pos, end_pos=end_pos)
-
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_arg_expansion(self)
-
-
-class List(Node):
-    """This Node currently exists exclusively for implementing the switch
-    command in a way that facilitates style checks. Might be nice to find
-    another way to handle this that doesn't require a special Node."""
-
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_list(self)
-
-
-class Expression(Node):
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_expression(self)
-
-
-class BracedExpression(Node):
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_braced_expression(self)
-
-
-class ParenExpression(Node):
-    def __init__(self, body: Expression, pos=None, end_pos=None):
-        self.body = body
-        super().__init__(body, pos=pos, end_pos=end_pos)
-
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_paren_expression(self)
-
-
-class UnaryOp(Node):
-    def __init__(self, operator, operand, pos=None, end_pos=None):
-        self.operator = operator
-        self.operand = operand
-        super().__init__(operator, operand, pos=pos, end_pos=end_pos)
-
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_unary_op(self)
-
-
-class BinaryOp(Node):
-    def __init__(self, operator1, operand, operator2, pos=None, end_pos=None):
-        self.operator1 = operator1
-        self.operand = operand
-        self.operator2 = operator2
-        super().__init__(operator1, operand, operator2, pos=pos, end_pos=end_pos)
-
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_binary_op(self)
-
-
-class TernaryOp(Node):
-    def __init__(self, condition, question, true, colon, false, pos=None, end_pos=None):
-        self.condition = condition
-        self.question = question
-        self.true = true
-        self.colon = colon
-        self.false = false
-
-        super().__init__(
-            condition, question, true, colon, false, pos=pos, end_pos=end_pos
-        )
-
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_ternary_op(self)
-
-
-class Function(Node):
-    def __init__(self, name, *args, pos=None, end_pos=None):
-        self.name = name
-        self.args = args
-        super().__init__(name, *args, pos=pos, end_pos=end_pos)
-
-    def accept(self, visitor, recurse=False):
-        if recurse:
-            self._recurse(visitor)
-        visitor.visit_function(self)
diff --git a/server/libs/tclint/violations.py b/server/libs/tclint/violations.py
deleted file mode 100644
index 8b08329..0000000
--- a/server/libs/tclint/violations.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from enum import Enum
-from typing import Tuple
-
-
-class Rule(Enum):
-    """This enum serves a few purposes:
-
-    1) define symbols for rule IDs to be used in code
-    2) map these symbols to names in the UI
-    3) collect all rule IDs/provide validation for IDs
-    """
-
-    LINE_LENGTH = "line-length"
-    TRAILING_WHITESPACE = "trailing-whitespace"
-    COMMAND_ARGS = "command-args"
-    REDEFINED_BUILTIN = "redefined-builtin"
-    UNBRACED_EXPR = "unbraced-expr"
-    REDUNDANT_EXPR = "redundant-expr"
-
-    def __str__(self):
-        return self.value
-
-
-ALL_RULES = [rule for rule in Rule]
-
-
-class Violation:
-    def __init__(
-        self, id: Rule, message: str, start: Tuple[int, int], end: Tuple[int, int]
-    ):
-        self.id = id
-        self.message = message
-        self.start = start
-        self.end = end
-
-    def __lt__(self, other):
-        return self.start < other.start
-
-    def __str__(self):
-        line, col = self.start
-        rule = str(self.id)
-
-        return f"{line}:{col}: {self.message} [{rule}]"
-
-    @classmethod
-    def create(cls, id):
-        def func(message: str, start: Tuple[int, int], end: Tuple[int, int]):
-            return cls(id, message, start, end)
-
-        return func
diff --git a/server/libs/typing_extensions-4.14.1.dist-info/INSTALLER b/server/libs/typing_extensions-4.14.1.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/server/libs/typing_extensions-4.14.1.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/server/libs/typing_extensions-4.14.1.dist-info/METADATA b/server/libs/typing_extensions-4.14.1.dist-info/METADATA
deleted file mode 100644
index b1fe93f..0000000
--- a/server/libs/typing_extensions-4.14.1.dist-info/METADATA
+++ /dev/null
@@ -1,68 +0,0 @@
-Metadata-Version: 2.4
-Name: typing_extensions
-Version: 4.14.1
-Summary: Backported and Experimental Type Hints for Python 3.9+
-Keywords: annotations,backport,checker,checking,function,hinting,hints,type,typechecking,typehinting,typehints,typing
-Author-email: "Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee" 
-Requires-Python: >=3.9
-Description-Content-Type: text/markdown
-License-Expression: PSF-2.0
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Console
-Classifier: Intended Audience :: Developers
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: 3.12
-Classifier: Programming Language :: Python :: 3.13
-Classifier: Programming Language :: Python :: 3.14
-Classifier: Topic :: Software Development
-License-File: LICENSE
-Project-URL: Bug Tracker, https://github.com/python/typing_extensions/issues
-Project-URL: Changes, https://github.com/python/typing_extensions/blob/main/CHANGELOG.md
-Project-URL: Documentation, https://typing-extensions.readthedocs.io/
-Project-URL: Home, https://github.com/python/typing_extensions
-Project-URL: Q & A, https://github.com/python/typing/discussions
-Project-URL: Repository, https://github.com/python/typing_extensions
-
-# Typing Extensions
-
-[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing)
-
-[Documentation](https://typing-extensions.readthedocs.io/en/latest/#) –
-[PyPI](https://pypi.org/project/typing-extensions/)
-
-## Overview
-
-The `typing_extensions` module serves two related purposes:
-
-- Enable use of new type system features on older Python versions. For example,
-  `typing.TypeGuard` is new in Python 3.10, but `typing_extensions` allows
-  users on previous Python versions to use it too.
-- Enable experimentation with new type system PEPs before they are accepted and
-  added to the `typing` module.
-
-`typing_extensions` is treated specially by static type checkers such as
-mypy and pyright. Objects defined in `typing_extensions` are treated the same
-way as equivalent forms in `typing`.
-
-`typing_extensions` uses
-[Semantic Versioning](https://semver.org/). The
-major version will be incremented only for backwards-incompatible changes.
-Therefore, it's safe to depend
-on `typing_extensions` like this: `typing_extensions >=x.y, <(x+1)`,
-where `x.y` is the first version that includes all features you need.
-
-## Included items
-
-See [the documentation](https://typing-extensions.readthedocs.io/en/latest/#) for a
-complete listing of module contents.
-
-## Contributing
-
-See [CONTRIBUTING.md](https://github.com/python/typing_extensions/blob/main/CONTRIBUTING.md)
-for how to contribute to `typing_extensions`.
-
diff --git a/server/libs/typing_extensions-4.14.1.dist-info/RECORD b/server/libs/typing_extensions-4.14.1.dist-info/RECORD
deleted file mode 100644
index a371f3a..0000000
--- a/server/libs/typing_extensions-4.14.1.dist-info/RECORD
+++ /dev/null
@@ -1,8 +0,0 @@
-__pycache__/typing_extensions.cpython-311.pyc,,
-typing_extensions-4.14.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-typing_extensions-4.14.1.dist-info/METADATA,sha256=8LS3enF0w3KyL4WYimlFfskcnkARg-sv_L6tHbPMS5s,2995
-typing_extensions-4.14.1.dist-info/RECORD,,
-typing_extensions-4.14.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-typing_extensions-4.14.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
-typing_extensions-4.14.1.dist-info/licenses/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936
-typing_extensions.py,sha256=Fh0lt5ZCgnzs7tyAhHOAfL0Zr829KYUxiR543ClwVgw,157408
diff --git a/server/libs/typing_extensions-4.14.1.dist-info/REQUESTED b/server/libs/typing_extensions-4.14.1.dist-info/REQUESTED
deleted file mode 100644
index e69de29..0000000
diff --git a/server/libs/typing_extensions-4.14.1.dist-info/WHEEL b/server/libs/typing_extensions-4.14.1.dist-info/WHEEL
deleted file mode 100644
index d8b9936..0000000
--- a/server/libs/typing_extensions-4.14.1.dist-info/WHEEL
+++ /dev/null
@@ -1,4 +0,0 @@
-Wheel-Version: 1.0
-Generator: flit 3.12.0
-Root-Is-Purelib: true
-Tag: py3-none-any
diff --git a/server/libs/typing_extensions-4.14.1.dist-info/licenses/LICENSE b/server/libs/typing_extensions-4.14.1.dist-info/licenses/LICENSE
deleted file mode 100644
index f26bcf4..0000000
--- a/server/libs/typing_extensions-4.14.1.dist-info/licenses/LICENSE
+++ /dev/null
@@ -1,279 +0,0 @@
-A. HISTORY OF THE SOFTWARE
-==========================
-
-Python was created in the early 1990s by Guido van Rossum at Stichting
-Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands
-as a successor of a language called ABC.  Guido remains Python's
-principal author, although it includes many contributions from others.
-
-In 1995, Guido continued his work on Python at the Corporation for
-National Research Initiatives (CNRI, see https://www.cnri.reston.va.us)
-in Reston, Virginia where he released several versions of the
-software.
-
-In May 2000, Guido and the Python core development team moved to
-BeOpen.com to form the BeOpen PythonLabs team.  In October of the same
-year, the PythonLabs team moved to Digital Creations, which became
-Zope Corporation.  In 2001, the Python Software Foundation (PSF, see
-https://www.python.org/psf/) was formed, a non-profit organization
-created specifically to own Python-related Intellectual Property.
-Zope Corporation was a sponsoring member of the PSF.
-
-All Python releases are Open Source (see https://opensource.org for
-the Open Source Definition).  Historically, most, but not all, Python
-releases have also been GPL-compatible; the table below summarizes
-the various releases.
-
-    Release         Derived     Year        Owner       GPL-
-                    from                                compatible? (1)
-
-    0.9.0 thru 1.2              1991-1995   CWI         yes
-    1.3 thru 1.5.2  1.2         1995-1999   CNRI        yes
-    1.6             1.5.2       2000        CNRI        no
-    2.0             1.6         2000        BeOpen.com  no
-    1.6.1           1.6         2001        CNRI        yes (2)
-    2.1             2.0+1.6.1   2001        PSF         no
-    2.0.1           2.0+1.6.1   2001        PSF         yes
-    2.1.1           2.1+2.0.1   2001        PSF         yes
-    2.1.2           2.1.1       2002        PSF         yes
-    2.1.3           2.1.2       2002        PSF         yes
-    2.2 and above   2.1.1       2001-now    PSF         yes
-
-Footnotes:
-
-(1) GPL-compatible doesn't mean that we're distributing Python under
-    the GPL.  All Python licenses, unlike the GPL, let you distribute
-    a modified version without making your changes open source.  The
-    GPL-compatible licenses make it possible to combine Python with
-    other software that is released under the GPL; the others don't.
-
-(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
-    because its license has a choice of law clause.  According to
-    CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
-    is "not incompatible" with the GPL.
-
-Thanks to the many outside volunteers who have worked under Guido's
-direction to make these releases possible.
-
-
-B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
-===============================================================
-
-Python software and documentation are licensed under the
-Python Software Foundation License Version 2.
-
-Starting with Python 3.8.6, examples, recipes, and other code in
-the documentation are dual licensed under the PSF License Version 2
-and the Zero-Clause BSD license.
-
-Some software incorporated into Python is under different licenses.
-The licenses are listed with code falling under that license.
-
-
-PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
---------------------------------------------
-
-1. This LICENSE AGREEMENT is between the Python Software Foundation
-("PSF"), and the Individual or Organization ("Licensee") accessing and
-otherwise using this software ("Python") in source or binary form and
-its associated documentation.
-
-2. Subject to the terms and conditions of this License Agreement, PSF hereby
-grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
-analyze, test, perform and/or display publicly, prepare derivative works,
-distribute, and otherwise use Python alone or in any derivative version,
-provided, however, that PSF's License Agreement and PSF's notice of copyright,
-i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation;
-All Rights Reserved" are retained in Python alone or in any derivative version
-prepared by Licensee.
-
-3. In the event Licensee prepares a derivative work that is based on
-or incorporates Python or any part thereof, and wants to make
-the derivative work available to others as provided herein, then
-Licensee hereby agrees to include in any such work a brief summary of
-the changes made to Python.
-
-4. PSF is making Python available to Licensee on an "AS IS"
-basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
-IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
-DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
-FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
-INFRINGE ANY THIRD PARTY RIGHTS.
-
-5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
-FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
-A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
-OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
-
-6. This License Agreement will automatically terminate upon a material
-breach of its terms and conditions.
-
-7. Nothing in this License Agreement shall be deemed to create any
-relationship of agency, partnership, or joint venture between PSF and
-Licensee.  This License Agreement does not grant permission to use PSF
-trademarks or trade name in a trademark sense to endorse or promote
-products or services of Licensee, or any third party.
-
-8. By copying, installing or otherwise using Python, Licensee
-agrees to be bound by the terms and conditions of this License
-Agreement.
-
-
-BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
--------------------------------------------
-
-BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
-
-1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
-office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
-Individual or Organization ("Licensee") accessing and otherwise using
-this software in source or binary form and its associated
-documentation ("the Software").
-
-2. Subject to the terms and conditions of this BeOpen Python License
-Agreement, BeOpen hereby grants Licensee a non-exclusive,
-royalty-free, world-wide license to reproduce, analyze, test, perform
-and/or display publicly, prepare derivative works, distribute, and
-otherwise use the Software alone or in any derivative version,
-provided, however, that the BeOpen Python License is retained in the
-Software, alone or in any derivative version prepared by Licensee.
-
-3. BeOpen is making the Software available to Licensee on an "AS IS"
-basis.  BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
-IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
-DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
-FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
-INFRINGE ANY THIRD PARTY RIGHTS.
-
-4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
-SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
-AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
-DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
-
-5. This License Agreement will automatically terminate upon a material
-breach of its terms and conditions.
-
-6. This License Agreement shall be governed by and interpreted in all
-respects by the law of the State of California, excluding conflict of
-law provisions.  Nothing in this License Agreement shall be deemed to
-create any relationship of agency, partnership, or joint venture
-between BeOpen and Licensee.  This License Agreement does not grant
-permission to use BeOpen trademarks or trade names in a trademark
-sense to endorse or promote products or services of Licensee, or any
-third party.  As an exception, the "BeOpen Python" logos available at
-http://www.pythonlabs.com/logos.html may be used according to the
-permissions granted on that web page.
-
-7. By copying, installing or otherwise using the software, Licensee
-agrees to be bound by the terms and conditions of this License
-Agreement.
-
-
-CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
----------------------------------------
-
-1. This LICENSE AGREEMENT is between the Corporation for National
-Research Initiatives, having an office at 1895 Preston White Drive,
-Reston, VA 20191 ("CNRI"), and the Individual or Organization
-("Licensee") accessing and otherwise using Python 1.6.1 software in
-source or binary form and its associated documentation.
-
-2. Subject to the terms and conditions of this License Agreement, CNRI
-hereby grants Licensee a nonexclusive, royalty-free, world-wide
-license to reproduce, analyze, test, perform and/or display publicly,
-prepare derivative works, distribute, and otherwise use Python 1.6.1
-alone or in any derivative version, provided, however, that CNRI's
-License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
-1995-2001 Corporation for National Research Initiatives; All Rights
-Reserved" are retained in Python 1.6.1 alone or in any derivative
-version prepared by Licensee.  Alternately, in lieu of CNRI's License
-Agreement, Licensee may substitute the following text (omitting the
-quotes): "Python 1.6.1 is made available subject to the terms and
-conditions in CNRI's License Agreement.  This Agreement together with
-Python 1.6.1 may be located on the internet using the following
-unique, persistent identifier (known as a handle): 1895.22/1013.  This
-Agreement may also be obtained from a proxy server on the internet
-using the following URL: http://hdl.handle.net/1895.22/1013".
-
-3. In the event Licensee prepares a derivative work that is based on
-or incorporates Python 1.6.1 or any part thereof, and wants to make
-the derivative work available to others as provided herein, then
-Licensee hereby agrees to include in any such work a brief summary of
-the changes made to Python 1.6.1.
-
-4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
-basis.  CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
-IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
-DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
-FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
-INFRINGE ANY THIRD PARTY RIGHTS.
-
-5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
-1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
-A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
-OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
-
-6. This License Agreement will automatically terminate upon a material
-breach of its terms and conditions.
-
-7. This License Agreement shall be governed by the federal
-intellectual property law of the United States, including without
-limitation the federal copyright law, and, to the extent such
-U.S. federal law does not apply, by the law of the Commonwealth of
-Virginia, excluding Virginia's conflict of law provisions.
-Notwithstanding the foregoing, with regard to derivative works based
-on Python 1.6.1 that incorporate non-separable material that was
-previously distributed under the GNU General Public License (GPL), the
-law of the Commonwealth of Virginia shall govern this License
-Agreement only as to issues arising under or with respect to
-Paragraphs 4, 5, and 7 of this License Agreement.  Nothing in this
-License Agreement shall be deemed to create any relationship of
-agency, partnership, or joint venture between CNRI and Licensee.  This
-License Agreement does not grant permission to use CNRI trademarks or
-trade name in a trademark sense to endorse or promote products or
-services of Licensee, or any third party.
-
-8. By clicking on the "ACCEPT" button where indicated, or by copying,
-installing or otherwise using Python 1.6.1, Licensee agrees to be
-bound by the terms and conditions of this License Agreement.
-
-        ACCEPT
-
-
-CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
---------------------------------------------------
-
-Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
-The Netherlands.  All rights reserved.
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the name of Stichting Mathematisch
-Centrum or CWI not be used in advertising or publicity pertaining to
-distribution of the software without specific, written prior
-permission.
-
-STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
-THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
-FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION
-----------------------------------------------------------------------
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
diff --git a/server/libs/typing_extensions.py b/server/libs/typing_extensions.py
deleted file mode 100644
index efa09d5..0000000
--- a/server/libs/typing_extensions.py
+++ /dev/null
@@ -1,4244 +0,0 @@
-import abc
-import builtins
-import collections
-import collections.abc
-import contextlib
-import enum
-import functools
-import inspect
-import io
-import keyword
-import operator
-import sys
-import types as _types
-import typing
-import warnings
-
-if sys.version_info >= (3, 14):
-    import annotationlib
-
-__all__ = [
-    # Super-special typing primitives.
-    'Any',
-    'ClassVar',
-    'Concatenate',
-    'Final',
-    'LiteralString',
-    'ParamSpec',
-    'ParamSpecArgs',
-    'ParamSpecKwargs',
-    'Self',
-    'Type',
-    'TypeVar',
-    'TypeVarTuple',
-    'Unpack',
-
-    # ABCs (from collections.abc).
-    'Awaitable',
-    'AsyncIterator',
-    'AsyncIterable',
-    'Coroutine',
-    'AsyncGenerator',
-    'AsyncContextManager',
-    'Buffer',
-    'ChainMap',
-
-    # Concrete collection types.
-    'ContextManager',
-    'Counter',
-    'Deque',
-    'DefaultDict',
-    'NamedTuple',
-    'OrderedDict',
-    'TypedDict',
-
-    # Structural checks, a.k.a. protocols.
-    'SupportsAbs',
-    'SupportsBytes',
-    'SupportsComplex',
-    'SupportsFloat',
-    'SupportsIndex',
-    'SupportsInt',
-    'SupportsRound',
-    'Reader',
-    'Writer',
-
-    # One-off things.
-    'Annotated',
-    'assert_never',
-    'assert_type',
-    'clear_overloads',
-    'dataclass_transform',
-    'deprecated',
-    'Doc',
-    'evaluate_forward_ref',
-    'get_overloads',
-    'final',
-    'Format',
-    'get_annotations',
-    'get_args',
-    'get_origin',
-    'get_original_bases',
-    'get_protocol_members',
-    'get_type_hints',
-    'IntVar',
-    'is_protocol',
-    'is_typeddict',
-    'Literal',
-    'NewType',
-    'overload',
-    'override',
-    'Protocol',
-    'Sentinel',
-    'reveal_type',
-    'runtime',
-    'runtime_checkable',
-    'Text',
-    'TypeAlias',
-    'TypeAliasType',
-    'TypeForm',
-    'TypeGuard',
-    'TypeIs',
-    'TYPE_CHECKING',
-    'Never',
-    'NoReturn',
-    'ReadOnly',
-    'Required',
-    'NotRequired',
-    'NoDefault',
-    'NoExtraItems',
-
-    # Pure aliases, have always been in typing
-    'AbstractSet',
-    'AnyStr',
-    'BinaryIO',
-    'Callable',
-    'Collection',
-    'Container',
-    'Dict',
-    'ForwardRef',
-    'FrozenSet',
-    'Generator',
-    'Generic',
-    'Hashable',
-    'IO',
-    'ItemsView',
-    'Iterable',
-    'Iterator',
-    'KeysView',
-    'List',
-    'Mapping',
-    'MappingView',
-    'Match',
-    'MutableMapping',
-    'MutableSequence',
-    'MutableSet',
-    'Optional',
-    'Pattern',
-    'Reversible',
-    'Sequence',
-    'Set',
-    'Sized',
-    'TextIO',
-    'Tuple',
-    'Union',
-    'ValuesView',
-    'cast',
-    'no_type_check',
-    'no_type_check_decorator',
-]
-
-# for backward compatibility
-PEP_560 = True
-GenericMeta = type
-_PEP_696_IMPLEMENTED = sys.version_info >= (3, 13, 0, "beta")
-
-# Added with bpo-45166 to 3.10.1+ and some 3.9 versions
-_FORWARD_REF_HAS_CLASS = "__forward_is_class__" in typing.ForwardRef.__slots__
-
-# The functions below are modified copies of typing internal helpers.
-# They are needed by _ProtocolMeta and they provide support for PEP 646.
-
-
-class _Sentinel:
-    def __repr__(self):
-        return ""
-
-
-_marker = _Sentinel()
-
-
-if sys.version_info >= (3, 10):
-    def _should_collect_from_parameters(t):
-        return isinstance(
-            t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType)
-        )
-else:
-    def _should_collect_from_parameters(t):
-        return isinstance(t, (typing._GenericAlias, _types.GenericAlias))
-
-
-NoReturn = typing.NoReturn
-
-# Some unconstrained type variables.  These are used by the container types.
-# (These are not for export.)
-T = typing.TypeVar('T')  # Any type.
-KT = typing.TypeVar('KT')  # Key type.
-VT = typing.TypeVar('VT')  # Value type.
-T_co = typing.TypeVar('T_co', covariant=True)  # Any type covariant containers.
-T_contra = typing.TypeVar('T_contra', contravariant=True)  # Ditto contravariant.
-
-
-if sys.version_info >= (3, 11):
-    from typing import Any
-else:
-
-    class _AnyMeta(type):
-        def __instancecheck__(self, obj):
-            if self is Any:
-                raise TypeError("typing_extensions.Any cannot be used with isinstance()")
-            return super().__instancecheck__(obj)
-
-        def __repr__(self):
-            if self is Any:
-                return "typing_extensions.Any"
-            return super().__repr__()
-
-    class Any(metaclass=_AnyMeta):
-        """Special type indicating an unconstrained type.
-        - Any is compatible with every type.
-        - Any assumed to have all methods.
-        - All values assumed to be instances of Any.
-        Note that all the above statements are true from the point of view of
-        static type checkers. At runtime, Any should not be used with instance
-        checks.
-        """
-        def __new__(cls, *args, **kwargs):
-            if cls is Any:
-                raise TypeError("Any cannot be instantiated")
-            return super().__new__(cls, *args, **kwargs)
-
-
-ClassVar = typing.ClassVar
-
-# Vendored from cpython typing._SpecialFrom
-# Having a separate class means that instances will not be rejected by
-# typing._type_check.
-class _SpecialForm(typing._Final, _root=True):
-    __slots__ = ('_name', '__doc__', '_getitem')
-
-    def __init__(self, getitem):
-        self._getitem = getitem
-        self._name = getitem.__name__
-        self.__doc__ = getitem.__doc__
-
-    def __getattr__(self, item):
-        if item in {'__name__', '__qualname__'}:
-            return self._name
-
-        raise AttributeError(item)
-
-    def __mro_entries__(self, bases):
-        raise TypeError(f"Cannot subclass {self!r}")
-
-    def __repr__(self):
-        return f'typing_extensions.{self._name}'
-
-    def __reduce__(self):
-        return self._name
-
-    def __call__(self, *args, **kwds):
-        raise TypeError(f"Cannot instantiate {self!r}")
-
-    def __or__(self, other):
-        return typing.Union[self, other]
-
-    def __ror__(self, other):
-        return typing.Union[other, self]
-
-    def __instancecheck__(self, obj):
-        raise TypeError(f"{self} cannot be used with isinstance()")
-
-    def __subclasscheck__(self, cls):
-        raise TypeError(f"{self} cannot be used with issubclass()")
-
-    @typing._tp_cache
-    def __getitem__(self, parameters):
-        return self._getitem(self, parameters)
-
-
-# Note that inheriting from this class means that the object will be
-# rejected by typing._type_check, so do not use it if the special form
-# is arguably valid as a type by itself.
-class _ExtensionsSpecialForm(typing._SpecialForm, _root=True):
-    def __repr__(self):
-        return 'typing_extensions.' + self._name
-
-
-Final = typing.Final
-
-if sys.version_info >= (3, 11):
-    final = typing.final
-else:
-    # @final exists in 3.8+, but we backport it for all versions
-    # before 3.11 to keep support for the __final__ attribute.
-    # See https://bugs.python.org/issue46342
-    def final(f):
-        """This decorator can be used to indicate to type checkers that
-        the decorated method cannot be overridden, and decorated class
-        cannot be subclassed. For example:
-
-            class Base:
-                @final
-                def done(self) -> None:
-                    ...
-            class Sub(Base):
-                def done(self) -> None:  # Error reported by type checker
-                    ...
-            @final
-            class Leaf:
-                ...
-            class Other(Leaf):  # Error reported by type checker
-                ...
-
-        There is no runtime checking of these properties. The decorator
-        sets the ``__final__`` attribute to ``True`` on the decorated object
-        to allow runtime introspection.
-        """
-        try:
-            f.__final__ = True
-        except (AttributeError, TypeError):
-            # Skip the attribute silently if it is not writable.
-            # AttributeError happens if the object has __slots__ or a
-            # read-only property, TypeError if it's a builtin class.
-            pass
-        return f
-
-
-def IntVar(name):
-    return typing.TypeVar(name)
-
-
-# A Literal bug was fixed in 3.11.0, 3.10.1 and 3.9.8
-if sys.version_info >= (3, 10, 1):
-    Literal = typing.Literal
-else:
-    def _flatten_literal_params(parameters):
-        """An internal helper for Literal creation: flatten Literals among parameters"""
-        params = []
-        for p in parameters:
-            if isinstance(p, _LiteralGenericAlias):
-                params.extend(p.__args__)
-            else:
-                params.append(p)
-        return tuple(params)
-
-    def _value_and_type_iter(params):
-        for p in params:
-            yield p, type(p)
-
-    class _LiteralGenericAlias(typing._GenericAlias, _root=True):
-        def __eq__(self, other):
-            if not isinstance(other, _LiteralGenericAlias):
-                return NotImplemented
-            these_args_deduped = set(_value_and_type_iter(self.__args__))
-            other_args_deduped = set(_value_and_type_iter(other.__args__))
-            return these_args_deduped == other_args_deduped
-
-        def __hash__(self):
-            return hash(frozenset(_value_and_type_iter(self.__args__)))
-
-    class _LiteralForm(_ExtensionsSpecialForm, _root=True):
-        def __init__(self, doc: str):
-            self._name = 'Literal'
-            self._doc = self.__doc__ = doc
-
-        def __getitem__(self, parameters):
-            if not isinstance(parameters, tuple):
-                parameters = (parameters,)
-
-            parameters = _flatten_literal_params(parameters)
-
-            val_type_pairs = list(_value_and_type_iter(parameters))
-            try:
-                deduped_pairs = set(val_type_pairs)
-            except TypeError:
-                # unhashable parameters
-                pass
-            else:
-                # similar logic to typing._deduplicate on Python 3.9+
-                if len(deduped_pairs) < len(val_type_pairs):
-                    new_parameters = []
-                    for pair in val_type_pairs:
-                        if pair in deduped_pairs:
-                            new_parameters.append(pair[0])
-                            deduped_pairs.remove(pair)
-                    assert not deduped_pairs, deduped_pairs
-                    parameters = tuple(new_parameters)
-
-            return _LiteralGenericAlias(self, parameters)
-
-    Literal = _LiteralForm(doc="""\
-                           A type that can be used to indicate to type checkers
-                           that the corresponding value has a value literally equivalent
-                           to the provided parameter. For example:
-
-                               var: Literal[4] = 4
-
-                           The type checker understands that 'var' is literally equal to
-                           the value 4 and no other value.
-
-                           Literal[...] cannot be subclassed. There is no runtime
-                           checking verifying that the parameter is actually a value
-                           instead of a type.""")
-
-
-_overload_dummy = typing._overload_dummy
-
-
-if hasattr(typing, "get_overloads"):  # 3.11+
-    overload = typing.overload
-    get_overloads = typing.get_overloads
-    clear_overloads = typing.clear_overloads
-else:
-    # {module: {qualname: {firstlineno: func}}}
-    _overload_registry = collections.defaultdict(
-        functools.partial(collections.defaultdict, dict)
-    )
-
-    def overload(func):
-        """Decorator for overloaded functions/methods.
-
-        In a stub file, place two or more stub definitions for the same
-        function in a row, each decorated with @overload.  For example:
-
-        @overload
-        def utf8(value: None) -> None: ...
-        @overload
-        def utf8(value: bytes) -> bytes: ...
-        @overload
-        def utf8(value: str) -> bytes: ...
-
-        In a non-stub file (i.e. a regular .py file), do the same but
-        follow it with an implementation.  The implementation should *not*
-        be decorated with @overload.  For example:
-
-        @overload
-        def utf8(value: None) -> None: ...
-        @overload
-        def utf8(value: bytes) -> bytes: ...
-        @overload
-        def utf8(value: str) -> bytes: ...
-        def utf8(value):
-            # implementation goes here
-
-        The overloads for a function can be retrieved at runtime using the
-        get_overloads() function.
-        """
-        # classmethod and staticmethod
-        f = getattr(func, "__func__", func)
-        try:
-            _overload_registry[f.__module__][f.__qualname__][
-                f.__code__.co_firstlineno
-            ] = func
-        except AttributeError:
-            # Not a normal function; ignore.
-            pass
-        return _overload_dummy
-
-    def get_overloads(func):
-        """Return all defined overloads for *func* as a sequence."""
-        # classmethod and staticmethod
-        f = getattr(func, "__func__", func)
-        if f.__module__ not in _overload_registry:
-            return []
-        mod_dict = _overload_registry[f.__module__]
-        if f.__qualname__ not in mod_dict:
-            return []
-        return list(mod_dict[f.__qualname__].values())
-
-    def clear_overloads():
-        """Clear all overloads in the registry."""
-        _overload_registry.clear()
-
-
-# This is not a real generic class.  Don't use outside annotations.
-Type = typing.Type
-
-# Various ABCs mimicking those in collections.abc.
-# A few are simply re-exported for completeness.
-Awaitable = typing.Awaitable
-Coroutine = typing.Coroutine
-AsyncIterable = typing.AsyncIterable
-AsyncIterator = typing.AsyncIterator
-Deque = typing.Deque
-DefaultDict = typing.DefaultDict
-OrderedDict = typing.OrderedDict
-Counter = typing.Counter
-ChainMap = typing.ChainMap
-Text = typing.Text
-TYPE_CHECKING = typing.TYPE_CHECKING
-
-
-if sys.version_info >= (3, 13, 0, "beta"):
-    from typing import AsyncContextManager, AsyncGenerator, ContextManager, Generator
-else:
-    def _is_dunder(attr):
-        return attr.startswith('__') and attr.endswith('__')
-
-
-    class _SpecialGenericAlias(typing._SpecialGenericAlias, _root=True):
-        def __init__(self, origin, nparams, *, inst=True, name=None, defaults=()):
-            super().__init__(origin, nparams, inst=inst, name=name)
-            self._defaults = defaults
-
-        def __setattr__(self, attr, val):
-            allowed_attrs = {'_name', '_inst', '_nparams', '_defaults'}
-            if _is_dunder(attr) or attr in allowed_attrs:
-                object.__setattr__(self, attr, val)
-            else:
-                setattr(self.__origin__, attr, val)
-
-        @typing._tp_cache
-        def __getitem__(self, params):
-            if not isinstance(params, tuple):
-                params = (params,)
-            msg = "Parameters to generic types must be types."
-            params = tuple(typing._type_check(p, msg) for p in params)
-            if (
-                self._defaults
-                and len(params) < self._nparams
-                and len(params) + len(self._defaults) >= self._nparams
-            ):
-                params = (*params, *self._defaults[len(params) - self._nparams:])
-            actual_len = len(params)
-
-            if actual_len != self._nparams:
-                if self._defaults:
-                    expected = f"at least {self._nparams - len(self._defaults)}"
-                else:
-                    expected = str(self._nparams)
-                if not self._nparams:
-                    raise TypeError(f"{self} is not a generic class")
-                raise TypeError(
-                    f"Too {'many' if actual_len > self._nparams else 'few'}"
-                    f" arguments for {self};"
-                    f" actual {actual_len}, expected {expected}"
-                )
-            return self.copy_with(params)
-
-    _NoneType = type(None)
-    Generator = _SpecialGenericAlias(
-        collections.abc.Generator, 3, defaults=(_NoneType, _NoneType)
-    )
-    AsyncGenerator = _SpecialGenericAlias(
-        collections.abc.AsyncGenerator, 2, defaults=(_NoneType,)
-    )
-    ContextManager = _SpecialGenericAlias(
-        contextlib.AbstractContextManager,
-        2,
-        name="ContextManager",
-        defaults=(typing.Optional[bool],)
-    )
-    AsyncContextManager = _SpecialGenericAlias(
-        contextlib.AbstractAsyncContextManager,
-        2,
-        name="AsyncContextManager",
-        defaults=(typing.Optional[bool],)
-    )
-
-
-_PROTO_ALLOWLIST = {
-    'collections.abc': [
-        'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable',
-        'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer',
-    ],
-    'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'],
-    'typing_extensions': ['Buffer'],
-}
-
-
-_EXCLUDED_ATTRS = frozenset(typing.EXCLUDED_ATTRIBUTES) | {
-    "__match_args__", "__protocol_attrs__", "__non_callable_proto_members__",
-    "__final__",
-}
-
-
-def _get_protocol_attrs(cls):
-    attrs = set()
-    for base in cls.__mro__[:-1]:  # without object
-        if base.__name__ in {'Protocol', 'Generic'}:
-            continue
-        annotations = getattr(base, '__annotations__', {})
-        for attr in (*base.__dict__, *annotations):
-            if (not attr.startswith('_abc_') and attr not in _EXCLUDED_ATTRS):
-                attrs.add(attr)
-    return attrs
-
-
-def _caller(depth=1, default='__main__'):
-    try:
-        return sys._getframemodulename(depth + 1) or default
-    except AttributeError:  # For platforms without _getframemodulename()
-        pass
-    try:
-        return sys._getframe(depth + 1).f_globals.get('__name__', default)
-    except (AttributeError, ValueError):  # For platforms without _getframe()
-        pass
-    return None
-
-
-# `__match_args__` attribute was removed from protocol members in 3.13,
-# we want to backport this change to older Python versions.
-if sys.version_info >= (3, 13):
-    Protocol = typing.Protocol
-else:
-    def _allow_reckless_class_checks(depth=2):
-        """Allow instance and class checks for special stdlib modules.
-        The abc and functools modules indiscriminately call isinstance() and
-        issubclass() on the whole MRO of a user class, which may contain protocols.
-        """
-        return _caller(depth) in {'abc', 'functools', None}
-
-    def _no_init(self, *args, **kwargs):
-        if type(self)._is_protocol:
-            raise TypeError('Protocols cannot be instantiated')
-
-    def _type_check_issubclass_arg_1(arg):
-        """Raise TypeError if `arg` is not an instance of `type`
-        in `issubclass(arg, )`.
-
-        In most cases, this is verified by type.__subclasscheck__.
-        Checking it again unnecessarily would slow down issubclass() checks,
-        so, we don't perform this check unless we absolutely have to.
-
-        For various error paths, however,
-        we want to ensure that *this* error message is shown to the user
-        where relevant, rather than a typing.py-specific error message.
-        """
-        if not isinstance(arg, type):
-            # Same error message as for issubclass(1, int).
-            raise TypeError('issubclass() arg 1 must be a class')
-
-    # Inheriting from typing._ProtocolMeta isn't actually desirable,
-    # but is necessary to allow typing.Protocol and typing_extensions.Protocol
-    # to mix without getting TypeErrors about "metaclass conflict"
-    class _ProtocolMeta(type(typing.Protocol)):
-        # This metaclass is somewhat unfortunate,
-        # but is necessary for several reasons...
-        #
-        # NOTE: DO NOT call super() in any methods in this class
-        # That would call the methods on typing._ProtocolMeta on Python <=3.11
-        # and those are slow
-        def __new__(mcls, name, bases, namespace, **kwargs):
-            if name == "Protocol" and len(bases) < 2:
-                pass
-            elif {Protocol, typing.Protocol} & set(bases):
-                for base in bases:
-                    if not (
-                        base in {object, typing.Generic, Protocol, typing.Protocol}
-                        or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, [])
-                        or is_protocol(base)
-                    ):
-                        raise TypeError(
-                            f"Protocols can only inherit from other protocols, "
-                            f"got {base!r}"
-                        )
-            return abc.ABCMeta.__new__(mcls, name, bases, namespace, **kwargs)
-
-        def __init__(cls, *args, **kwargs):
-            abc.ABCMeta.__init__(cls, *args, **kwargs)
-            if getattr(cls, "_is_protocol", False):
-                cls.__protocol_attrs__ = _get_protocol_attrs(cls)
-
-        def __subclasscheck__(cls, other):
-            if cls is Protocol:
-                return type.__subclasscheck__(cls, other)
-            if (
-                getattr(cls, '_is_protocol', False)
-                and not _allow_reckless_class_checks()
-            ):
-                if not getattr(cls, '_is_runtime_protocol', False):
-                    _type_check_issubclass_arg_1(other)
-                    raise TypeError(
-                        "Instance and class checks can only be used with "
-                        "@runtime_checkable protocols"
-                    )
-                if (
-                    # this attribute is set by @runtime_checkable:
-                    cls.__non_callable_proto_members__
-                    and cls.__dict__.get("__subclasshook__") is _proto_hook
-                ):
-                    _type_check_issubclass_arg_1(other)
-                    non_method_attrs = sorted(cls.__non_callable_proto_members__)
-                    raise TypeError(
-                        "Protocols with non-method members don't support issubclass()."
-                        f" Non-method members: {str(non_method_attrs)[1:-1]}."
-                    )
-            return abc.ABCMeta.__subclasscheck__(cls, other)
-
-        def __instancecheck__(cls, instance):
-            # We need this method for situations where attributes are
-            # assigned in __init__.
-            if cls is Protocol:
-                return type.__instancecheck__(cls, instance)
-            if not getattr(cls, "_is_protocol", False):
-                # i.e., it's a concrete subclass of a protocol
-                return abc.ABCMeta.__instancecheck__(cls, instance)
-
-            if (
-                not getattr(cls, '_is_runtime_protocol', False) and
-                not _allow_reckless_class_checks()
-            ):
-                raise TypeError("Instance and class checks can only be used with"
-                                " @runtime_checkable protocols")
-
-            if abc.ABCMeta.__instancecheck__(cls, instance):
-                return True
-
-            for attr in cls.__protocol_attrs__:
-                try:
-                    val = inspect.getattr_static(instance, attr)
-                except AttributeError:
-                    break
-                # this attribute is set by @runtime_checkable:
-                if val is None and attr not in cls.__non_callable_proto_members__:
-                    break
-            else:
-                return True
-
-            return False
-
-        def __eq__(cls, other):
-            # Hack so that typing.Generic.__class_getitem__
-            # treats typing_extensions.Protocol
-            # as equivalent to typing.Protocol
-            if abc.ABCMeta.__eq__(cls, other) is True:
-                return True
-            return cls is Protocol and other is typing.Protocol
-
-        # This has to be defined, or the abc-module cache
-        # complains about classes with this metaclass being unhashable,
-        # if we define only __eq__!
-        def __hash__(cls) -> int:
-            return type.__hash__(cls)
-
-    @classmethod
-    def _proto_hook(cls, other):
-        if not cls.__dict__.get('_is_protocol', False):
-            return NotImplemented
-
-        for attr in cls.__protocol_attrs__:
-            for base in other.__mro__:
-                # Check if the members appears in the class dictionary...
-                if attr in base.__dict__:
-                    if base.__dict__[attr] is None:
-                        return NotImplemented
-                    break
-
-                # ...or in annotations, if it is a sub-protocol.
-                annotations = getattr(base, '__annotations__', {})
-                if (
-                    isinstance(annotations, collections.abc.Mapping)
-                    and attr in annotations
-                    and is_protocol(other)
-                ):
-                    break
-            else:
-                return NotImplemented
-        return True
-
-    class Protocol(typing.Generic, metaclass=_ProtocolMeta):
-        __doc__ = typing.Protocol.__doc__
-        __slots__ = ()
-        _is_protocol = True
-        _is_runtime_protocol = False
-
-        def __init_subclass__(cls, *args, **kwargs):
-            super().__init_subclass__(*args, **kwargs)
-
-            # Determine if this is a protocol or a concrete subclass.
-            if not cls.__dict__.get('_is_protocol', False):
-                cls._is_protocol = any(b is Protocol for b in cls.__bases__)
-
-            # Set (or override) the protocol subclass hook.
-            if '__subclasshook__' not in cls.__dict__:
-                cls.__subclasshook__ = _proto_hook
-
-            # Prohibit instantiation for protocol classes
-            if cls._is_protocol and cls.__init__ is Protocol.__init__:
-                cls.__init__ = _no_init
-
-
-if sys.version_info >= (3, 13):
-    runtime_checkable = typing.runtime_checkable
-else:
-    def runtime_checkable(cls):
-        """Mark a protocol class as a runtime protocol.
-
-        Such protocol can be used with isinstance() and issubclass().
-        Raise TypeError if applied to a non-protocol class.
-        This allows a simple-minded structural check very similar to
-        one trick ponies in collections.abc such as Iterable.
-
-        For example::
-
-            @runtime_checkable
-            class Closable(Protocol):
-                def close(self): ...
-
-            assert isinstance(open('/some/file'), Closable)
-
-        Warning: this will check only the presence of the required methods,
-        not their type signatures!
-        """
-        if not issubclass(cls, typing.Generic) or not getattr(cls, '_is_protocol', False):
-            raise TypeError(f'@runtime_checkable can be only applied to protocol classes,'
-                            f' got {cls!r}')
-        cls._is_runtime_protocol = True
-
-        # typing.Protocol classes on <=3.11 break if we execute this block,
-        # because typing.Protocol classes on <=3.11 don't have a
-        # `__protocol_attrs__` attribute, and this block relies on the
-        # `__protocol_attrs__` attribute. Meanwhile, typing.Protocol classes on 3.12.2+
-        # break if we *don't* execute this block, because *they* assume that all
-        # protocol classes have a `__non_callable_proto_members__` attribute
-        # (which this block sets)
-        if isinstance(cls, _ProtocolMeta) or sys.version_info >= (3, 12, 2):
-            # PEP 544 prohibits using issubclass()
-            # with protocols that have non-method members.
-            # See gh-113320 for why we compute this attribute here,
-            # rather than in `_ProtocolMeta.__init__`
-            cls.__non_callable_proto_members__ = set()
-            for attr in cls.__protocol_attrs__:
-                try:
-                    is_callable = callable(getattr(cls, attr, None))
-                except Exception as e:
-                    raise TypeError(
-                        f"Failed to determine whether protocol member {attr!r} "
-                        "is a method member"
-                    ) from e
-                else:
-                    if not is_callable:
-                        cls.__non_callable_proto_members__.add(attr)
-
-        return cls
-
-
-# The "runtime" alias exists for backwards compatibility.
-runtime = runtime_checkable
-
-
-# Our version of runtime-checkable protocols is faster on Python <=3.11
-if sys.version_info >= (3, 12):
-    SupportsInt = typing.SupportsInt
-    SupportsFloat = typing.SupportsFloat
-    SupportsComplex = typing.SupportsComplex
-    SupportsBytes = typing.SupportsBytes
-    SupportsIndex = typing.SupportsIndex
-    SupportsAbs = typing.SupportsAbs
-    SupportsRound = typing.SupportsRound
-else:
-    @runtime_checkable
-    class SupportsInt(Protocol):
-        """An ABC with one abstract method __int__."""
-        __slots__ = ()
-
-        @abc.abstractmethod
-        def __int__(self) -> int:
-            pass
-
-    @runtime_checkable
-    class SupportsFloat(Protocol):
-        """An ABC with one abstract method __float__."""
-        __slots__ = ()
-
-        @abc.abstractmethod
-        def __float__(self) -> float:
-            pass
-
-    @runtime_checkable
-    class SupportsComplex(Protocol):
-        """An ABC with one abstract method __complex__."""
-        __slots__ = ()
-
-        @abc.abstractmethod
-        def __complex__(self) -> complex:
-            pass
-
-    @runtime_checkable
-    class SupportsBytes(Protocol):
-        """An ABC with one abstract method __bytes__."""
-        __slots__ = ()
-
-        @abc.abstractmethod
-        def __bytes__(self) -> bytes:
-            pass
-
-    @runtime_checkable
-    class SupportsIndex(Protocol):
-        __slots__ = ()
-
-        @abc.abstractmethod
-        def __index__(self) -> int:
-            pass
-
-    @runtime_checkable
-    class SupportsAbs(Protocol[T_co]):
-        """
-        An ABC with one abstract method __abs__ that is covariant in its return type.
-        """
-        __slots__ = ()
-
-        @abc.abstractmethod
-        def __abs__(self) -> T_co:
-            pass
-
-    @runtime_checkable
-    class SupportsRound(Protocol[T_co]):
-        """
-        An ABC with one abstract method __round__ that is covariant in its return type.
-        """
-        __slots__ = ()
-
-        @abc.abstractmethod
-        def __round__(self, ndigits: int = 0) -> T_co:
-            pass
-
-
-if hasattr(io, "Reader") and hasattr(io, "Writer"):
-    Reader = io.Reader
-    Writer = io.Writer
-else:
-    @runtime_checkable
-    class Reader(Protocol[T_co]):
-        """Protocol for simple I/O reader instances.
-
-        This protocol only supports blocking I/O.
-        """
-
-        __slots__ = ()
-
-        @abc.abstractmethod
-        def read(self, size: int = ..., /) -> T_co:
-            """Read data from the input stream and return it.
-
-            If *size* is specified, at most *size* items (bytes/characters) will be
-            read.
-            """
-
-    @runtime_checkable
-    class Writer(Protocol[T_contra]):
-        """Protocol for simple I/O writer instances.
-
-        This protocol only supports blocking I/O.
-        """
-
-        __slots__ = ()
-
-        @abc.abstractmethod
-        def write(self, data: T_contra, /) -> int:
-            """Write *data* to the output stream and return the number of items written."""  # noqa: E501
-
-
-_NEEDS_SINGLETONMETA = (
-    not hasattr(typing, "NoDefault") or not hasattr(typing, "NoExtraItems")
-)
-
-if _NEEDS_SINGLETONMETA:
-    class SingletonMeta(type):
-        def __setattr__(cls, attr, value):
-            # TypeError is consistent with the behavior of NoneType
-            raise TypeError(
-                f"cannot set {attr!r} attribute of immutable type {cls.__name__!r}"
-            )
-
-
-if hasattr(typing, "NoDefault"):
-    NoDefault = typing.NoDefault
-else:
-    class NoDefaultType(metaclass=SingletonMeta):
-        """The type of the NoDefault singleton."""
-
-        __slots__ = ()
-
-        def __new__(cls):
-            return globals().get("NoDefault") or object.__new__(cls)
-
-        def __repr__(self):
-            return "typing_extensions.NoDefault"
-
-        def __reduce__(self):
-            return "NoDefault"
-
-    NoDefault = NoDefaultType()
-    del NoDefaultType
-
-if hasattr(typing, "NoExtraItems"):
-    NoExtraItems = typing.NoExtraItems
-else:
-    class NoExtraItemsType(metaclass=SingletonMeta):
-        """The type of the NoExtraItems singleton."""
-
-        __slots__ = ()
-
-        def __new__(cls):
-            return globals().get("NoExtraItems") or object.__new__(cls)
-
-        def __repr__(self):
-            return "typing_extensions.NoExtraItems"
-
-        def __reduce__(self):
-            return "NoExtraItems"
-
-    NoExtraItems = NoExtraItemsType()
-    del NoExtraItemsType
-
-if _NEEDS_SINGLETONMETA:
-    del SingletonMeta
-
-
-# Update this to something like >=3.13.0b1 if and when
-# PEP 728 is implemented in CPython
-_PEP_728_IMPLEMENTED = False
-
-if _PEP_728_IMPLEMENTED:
-    # The standard library TypedDict in Python 3.9.0/1 does not honour the "total"
-    # keyword with old-style TypedDict().  See https://bugs.python.org/issue42059
-    # The standard library TypedDict below Python 3.11 does not store runtime
-    # information about optional and required keys when using Required or NotRequired.
-    # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11.
-    # Aaaand on 3.12 we add __orig_bases__ to TypedDict
-    # to enable better runtime introspection.
-    # On 3.13 we deprecate some odd ways of creating TypedDicts.
-    # Also on 3.13, PEP 705 adds the ReadOnly[] qualifier.
-    # PEP 728 (still pending) makes more changes.
-    TypedDict = typing.TypedDict
-    _TypedDictMeta = typing._TypedDictMeta
-    is_typeddict = typing.is_typeddict
-else:
-    # 3.10.0 and later
-    _TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters
-
-    def _get_typeddict_qualifiers(annotation_type):
-        while True:
-            annotation_origin = get_origin(annotation_type)
-            if annotation_origin is Annotated:
-                annotation_args = get_args(annotation_type)
-                if annotation_args:
-                    annotation_type = annotation_args[0]
-                else:
-                    break
-            elif annotation_origin is Required:
-                yield Required
-                annotation_type, = get_args(annotation_type)
-            elif annotation_origin is NotRequired:
-                yield NotRequired
-                annotation_type, = get_args(annotation_type)
-            elif annotation_origin is ReadOnly:
-                yield ReadOnly
-                annotation_type, = get_args(annotation_type)
-            else:
-                break
-
-    class _TypedDictMeta(type):
-
-        def __new__(cls, name, bases, ns, *, total=True, closed=None,
-                    extra_items=NoExtraItems):
-            """Create new typed dict class object.
-
-            This method is called when TypedDict is subclassed,
-            or when TypedDict is instantiated. This way
-            TypedDict supports all three syntax forms described in its docstring.
-            Subclasses and instances of TypedDict return actual dictionaries.
-            """
-            for base in bases:
-                if type(base) is not _TypedDictMeta and base is not typing.Generic:
-                    raise TypeError('cannot inherit from both a TypedDict type '
-                                    'and a non-TypedDict base class')
-            if closed is not None and extra_items is not NoExtraItems:
-                raise TypeError(f"Cannot combine closed={closed!r} and extra_items")
-
-            if any(issubclass(b, typing.Generic) for b in bases):
-                generic_base = (typing.Generic,)
-            else:
-                generic_base = ()
-
-            ns_annotations = ns.pop('__annotations__', None)
-
-            # typing.py generally doesn't let you inherit from plain Generic, unless
-            # the name of the class happens to be "Protocol"
-            tp_dict = type.__new__(_TypedDictMeta, "Protocol", (*generic_base, dict), ns)
-            tp_dict.__name__ = name
-            if tp_dict.__qualname__ == "Protocol":
-                tp_dict.__qualname__ = name
-
-            if not hasattr(tp_dict, '__orig_bases__'):
-                tp_dict.__orig_bases__ = bases
-
-            annotations = {}
-            own_annotate = None
-            if ns_annotations is not None:
-                own_annotations = ns_annotations
-            elif sys.version_info >= (3, 14):
-                if hasattr(annotationlib, "get_annotate_from_class_namespace"):
-                    own_annotate = annotationlib.get_annotate_from_class_namespace(ns)
-                else:
-                    # 3.14.0a7 and earlier
-                    own_annotate = ns.get("__annotate__")
-                if own_annotate is not None:
-                    own_annotations = annotationlib.call_annotate_function(
-                        own_annotate, Format.FORWARDREF, owner=tp_dict
-                    )
-                else:
-                    own_annotations = {}
-            else:
-                own_annotations = {}
-            msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
-            if _TAKES_MODULE:
-                own_checked_annotations = {
-                    n: typing._type_check(tp, msg, module=tp_dict.__module__)
-                    for n, tp in own_annotations.items()
-                }
-            else:
-                own_checked_annotations = {
-                    n: typing._type_check(tp, msg)
-                    for n, tp in own_annotations.items()
-                }
-            required_keys = set()
-            optional_keys = set()
-            readonly_keys = set()
-            mutable_keys = set()
-            extra_items_type = extra_items
-
-            for base in bases:
-                base_dict = base.__dict__
-
-                if sys.version_info <= (3, 14):
-                    annotations.update(base_dict.get('__annotations__', {}))
-                required_keys.update(base_dict.get('__required_keys__', ()))
-                optional_keys.update(base_dict.get('__optional_keys__', ()))
-                readonly_keys.update(base_dict.get('__readonly_keys__', ()))
-                mutable_keys.update(base_dict.get('__mutable_keys__', ()))
-
-            # This was specified in an earlier version of PEP 728. Support
-            # is retained for backwards compatibility, but only for Python
-            # 3.13 and lower.
-            if (closed and sys.version_info < (3, 14)
-                       and "__extra_items__" in own_checked_annotations):
-                annotation_type = own_checked_annotations.pop("__extra_items__")
-                qualifiers = set(_get_typeddict_qualifiers(annotation_type))
-                if Required in qualifiers:
-                    raise TypeError(
-                        "Special key __extra_items__ does not support "
-                        "Required"
-                    )
-                if NotRequired in qualifiers:
-                    raise TypeError(
-                        "Special key __extra_items__ does not support "
-                        "NotRequired"
-                    )
-                extra_items_type = annotation_type
-
-            annotations.update(own_checked_annotations)
-            for annotation_key, annotation_type in own_checked_annotations.items():
-                qualifiers = set(_get_typeddict_qualifiers(annotation_type))
-
-                if Required in qualifiers:
-                    required_keys.add(annotation_key)
-                elif NotRequired in qualifiers:
-                    optional_keys.add(annotation_key)
-                elif total:
-                    required_keys.add(annotation_key)
-                else:
-                    optional_keys.add(annotation_key)
-                if ReadOnly in qualifiers:
-                    mutable_keys.discard(annotation_key)
-                    readonly_keys.add(annotation_key)
-                else:
-                    mutable_keys.add(annotation_key)
-                    readonly_keys.discard(annotation_key)
-
-            if sys.version_info >= (3, 14):
-                def __annotate__(format):
-                    annos = {}
-                    for base in bases:
-                        if base is Generic:
-                            continue
-                        base_annotate = base.__annotate__
-                        if base_annotate is None:
-                            continue
-                        base_annos = annotationlib.call_annotate_function(
-                            base_annotate, format, owner=base)
-                        annos.update(base_annos)
-                    if own_annotate is not None:
-                        own = annotationlib.call_annotate_function(
-                            own_annotate, format, owner=tp_dict)
-                        if format != Format.STRING:
-                            own = {
-                                n: typing._type_check(tp, msg, module=tp_dict.__module__)
-                                for n, tp in own.items()
-                            }
-                    elif format == Format.STRING:
-                        own = annotationlib.annotations_to_string(own_annotations)
-                    elif format in (Format.FORWARDREF, Format.VALUE):
-                        own = own_checked_annotations
-                    else:
-                        raise NotImplementedError(format)
-                    annos.update(own)
-                    return annos
-
-                tp_dict.__annotate__ = __annotate__
-            else:
-                tp_dict.__annotations__ = annotations
-            tp_dict.__required_keys__ = frozenset(required_keys)
-            tp_dict.__optional_keys__ = frozenset(optional_keys)
-            tp_dict.__readonly_keys__ = frozenset(readonly_keys)
-            tp_dict.__mutable_keys__ = frozenset(mutable_keys)
-            tp_dict.__total__ = total
-            tp_dict.__closed__ = closed
-            tp_dict.__extra_items__ = extra_items_type
-            return tp_dict
-
-        __call__ = dict  # static method
-
-        def __subclasscheck__(cls, other):
-            # Typed dicts are only for static structural subtyping.
-            raise TypeError('TypedDict does not support instance and class checks')
-
-        __instancecheck__ = __subclasscheck__
-
-    _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {})
-
-    def _create_typeddict(
-        typename,
-        fields,
-        /,
-        *,
-        typing_is_inline,
-        total,
-        closed,
-        extra_items,
-        **kwargs,
-    ):
-        if fields is _marker or fields is None:
-            if fields is _marker:
-                deprecated_thing = (
-                    "Failing to pass a value for the 'fields' parameter"
-                )
-            else:
-                deprecated_thing = "Passing `None` as the 'fields' parameter"
-
-            example = f"`{typename} = TypedDict({typename!r}, {{}})`"
-            deprecation_msg = (
-                f"{deprecated_thing} is deprecated and will be disallowed in "
-                "Python 3.15. To create a TypedDict class with 0 fields "
-                "using the functional syntax, pass an empty dictionary, e.g. "
-            ) + example + "."
-            warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2)
-            # Support a field called "closed"
-            if closed is not False and closed is not True and closed is not None:
-                kwargs["closed"] = closed
-                closed = None
-            # Or "extra_items"
-            if extra_items is not NoExtraItems:
-                kwargs["extra_items"] = extra_items
-                extra_items = NoExtraItems
-            fields = kwargs
-        elif kwargs:
-            raise TypeError("TypedDict takes either a dict or keyword arguments,"
-                            " but not both")
-        if kwargs:
-            if sys.version_info >= (3, 13):
-                raise TypeError("TypedDict takes no keyword arguments")
-            warnings.warn(
-                "The kwargs-based syntax for TypedDict definitions is deprecated "
-                "in Python 3.11, will be removed in Python 3.13, and may not be "
-                "understood by third-party type checkers.",
-                DeprecationWarning,
-                stacklevel=2,
-            )
-
-        ns = {'__annotations__': dict(fields)}
-        module = _caller(depth=4 if typing_is_inline else 2)
-        if module is not None:
-            # Setting correct module is necessary to make typed dict classes
-            # pickleable.
-            ns['__module__'] = module
-
-        td = _TypedDictMeta(typename, (), ns, total=total, closed=closed,
-                            extra_items=extra_items)
-        td.__orig_bases__ = (TypedDict,)
-        return td
-
-    class _TypedDictSpecialForm(_SpecialForm, _root=True):
-        def __call__(
-            self,
-            typename,
-            fields=_marker,
-            /,
-            *,
-            total=True,
-            closed=None,
-            extra_items=NoExtraItems,
-            **kwargs
-        ):
-            return _create_typeddict(
-                typename,
-                fields,
-                typing_is_inline=False,
-                total=total,
-                closed=closed,
-                extra_items=extra_items,
-                **kwargs,
-            )
-
-        def __mro_entries__(self, bases):
-            return (_TypedDict,)
-
-    @_TypedDictSpecialForm
-    def TypedDict(self, args):
-        """A simple typed namespace. At runtime it is equivalent to a plain dict.
-
-        TypedDict creates a dictionary type such that a type checker will expect all
-        instances to have a certain set of keys, where each key is
-        associated with a value of a consistent type. This expectation
-        is not checked at runtime.
-
-        Usage::
-
-            class Point2D(TypedDict):
-                x: int
-                y: int
-                label: str
-
-            a: Point2D = {'x': 1, 'y': 2, 'label': 'good'}  # OK
-            b: Point2D = {'z': 3, 'label': 'bad'}           # Fails type check
-
-            assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
-
-        The type info can be accessed via the Point2D.__annotations__ dict, and
-        the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets.
-        TypedDict supports an additional equivalent form::
-
-            Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
-
-        By default, all keys must be present in a TypedDict. It is possible
-        to override this by specifying totality::
-
-            class Point2D(TypedDict, total=False):
-                x: int
-                y: int
-
-        This means that a Point2D TypedDict can have any of the keys omitted. A type
-        checker is only expected to support a literal False or True as the value of
-        the total argument. True is the default, and makes all items defined in the
-        class body be required.
-
-        The Required and NotRequired special forms can also be used to mark
-        individual keys as being required or not required::
-
-            class Point2D(TypedDict):
-                x: int  # the "x" key must always be present (Required is the default)
-                y: NotRequired[int]  # the "y" key can be omitted
-
-        See PEP 655 for more details on Required and NotRequired.
-        """
-        # This runs when creating inline TypedDicts:
-        if not isinstance(args, dict):
-            raise TypeError(
-                "TypedDict[...] should be used with a single dict argument"
-            )
-
-        return _create_typeddict(
-            "",
-            args,
-            typing_is_inline=True,
-            total=True,
-            closed=True,
-            extra_items=NoExtraItems,
-        )
-
-    _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta)
-
-    def is_typeddict(tp):
-        """Check if an annotation is a TypedDict class
-
-        For example::
-            class Film(TypedDict):
-                title: str
-                year: int
-
-            is_typeddict(Film)  # => True
-            is_typeddict(Union[list, str])  # => False
-        """
-        return isinstance(tp, _TYPEDDICT_TYPES)
-
-
-if hasattr(typing, "assert_type"):
-    assert_type = typing.assert_type
-
-else:
-    def assert_type(val, typ, /):
-        """Assert (to the type checker) that the value is of the given type.
-
-        When the type checker encounters a call to assert_type(), it
-        emits an error if the value is not of the specified type::
-
-            def greet(name: str) -> None:
-                assert_type(name, str)  # ok
-                assert_type(name, int)  # type checker error
-
-        At runtime this returns the first argument unchanged and otherwise
-        does nothing.
-        """
-        return val
-
-
-if hasattr(typing, "ReadOnly"):  # 3.13+
-    get_type_hints = typing.get_type_hints
-else:  # <=3.13
-    # replaces _strip_annotations()
-    def _strip_extras(t):
-        """Strips Annotated, Required and NotRequired from a given type."""
-        if isinstance(t, typing._AnnotatedAlias):
-            return _strip_extras(t.__origin__)
-        if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired, ReadOnly):
-            return _strip_extras(t.__args__[0])
-        if isinstance(t, typing._GenericAlias):
-            stripped_args = tuple(_strip_extras(a) for a in t.__args__)
-            if stripped_args == t.__args__:
-                return t
-            return t.copy_with(stripped_args)
-        if hasattr(_types, "GenericAlias") and isinstance(t, _types.GenericAlias):
-            stripped_args = tuple(_strip_extras(a) for a in t.__args__)
-            if stripped_args == t.__args__:
-                return t
-            return _types.GenericAlias(t.__origin__, stripped_args)
-        if hasattr(_types, "UnionType") and isinstance(t, _types.UnionType):
-            stripped_args = tuple(_strip_extras(a) for a in t.__args__)
-            if stripped_args == t.__args__:
-                return t
-            return functools.reduce(operator.or_, stripped_args)
-
-        return t
-
-    def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
-        """Return type hints for an object.
-
-        This is often the same as obj.__annotations__, but it handles
-        forward references encoded as string literals, adds Optional[t] if a
-        default value equal to None is set and recursively replaces all
-        'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T'
-        (unless 'include_extras=True').
-
-        The argument may be a module, class, method, or function. The annotations
-        are returned as a dictionary. For classes, annotations include also
-        inherited members.
-
-        TypeError is raised if the argument is not of a type that can contain
-        annotations, and an empty dictionary is returned if no annotations are
-        present.
-
-        BEWARE -- the behavior of globalns and localns is counterintuitive
-        (unless you are familiar with how eval() and exec() work).  The
-        search order is locals first, then globals.
-
-        - If no dict arguments are passed, an attempt is made to use the
-          globals from obj (or the respective module's globals for classes),
-          and these are also used as the locals.  If the object does not appear
-          to have globals, an empty dictionary is used.
-
-        - If one dict argument is passed, it is used for both globals and
-          locals.
-
-        - If two dict arguments are passed, they specify globals and
-          locals, respectively.
-        """
-        hint = typing.get_type_hints(
-            obj, globalns=globalns, localns=localns, include_extras=True
-        )
-        if sys.version_info < (3, 11):
-            _clean_optional(obj, hint, globalns, localns)
-        if include_extras:
-            return hint
-        return {k: _strip_extras(t) for k, t in hint.items()}
-
-    _NoneType = type(None)
-
-    def _could_be_inserted_optional(t):
-        """detects Union[..., None] pattern"""
-        if not isinstance(t, typing._UnionGenericAlias):
-            return False
-        # Assume if last argument is not None they are user defined
-        if t.__args__[-1] is not _NoneType:
-            return False
-        return True
-
-    # < 3.11
-    def _clean_optional(obj, hints, globalns=None, localns=None):
-        # reverts injected Union[..., None] cases from typing.get_type_hints
-        # when a None default value is used.
-        # see https://github.com/python/typing_extensions/issues/310
-        if not hints or isinstance(obj, type):
-            return
-        defaults = typing._get_defaults(obj)  # avoid accessing __annotations___
-        if not defaults:
-            return
-        original_hints = obj.__annotations__
-        for name, value in hints.items():
-            # Not a Union[..., None] or replacement conditions not fullfilled
-            if (not _could_be_inserted_optional(value)
-                or name not in defaults
-                or defaults[name] is not None
-            ):
-                continue
-            original_value = original_hints[name]
-            # value=NoneType should have caused a skip above but check for safety
-            if original_value is None:
-                original_value = _NoneType
-            # Forward reference
-            if isinstance(original_value, str):
-                if globalns is None:
-                    if isinstance(obj, _types.ModuleType):
-                        globalns = obj.__dict__
-                    else:
-                        nsobj = obj
-                        # Find globalns for the unwrapped object.
-                        while hasattr(nsobj, '__wrapped__'):
-                            nsobj = nsobj.__wrapped__
-                        globalns = getattr(nsobj, '__globals__', {})
-                    if localns is None:
-                        localns = globalns
-                elif localns is None:
-                    localns = globalns
-
-                original_value = ForwardRef(
-                    original_value,
-                    is_argument=not isinstance(obj, _types.ModuleType)
-                )
-            original_evaluated = typing._eval_type(original_value, globalns, localns)
-            # Compare if values differ. Note that even if equal
-            # value might be cached by typing._tp_cache contrary to original_evaluated
-            if original_evaluated != value or (
-                # 3.10: ForwardRefs of UnionType might be turned into _UnionGenericAlias
-                hasattr(_types, "UnionType")
-                and isinstance(original_evaluated, _types.UnionType)
-                and not isinstance(value, _types.UnionType)
-            ):
-                hints[name] = original_evaluated
-
-# Python 3.9 has get_origin() and get_args() but those implementations don't support
-# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do.
-if sys.version_info[:2] >= (3, 10):
-    get_origin = typing.get_origin
-    get_args = typing.get_args
-# 3.9
-else:
-    def get_origin(tp):
-        """Get the unsubscripted version of a type.
-
-        This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar
-        and Annotated. Return None for unsupported types. Examples::
-
-            get_origin(Literal[42]) is Literal
-            get_origin(int) is None
-            get_origin(ClassVar[int]) is ClassVar
-            get_origin(Generic) is Generic
-            get_origin(Generic[T]) is Generic
-            get_origin(Union[T, int]) is Union
-            get_origin(List[Tuple[T, T]][int]) == list
-            get_origin(P.args) is P
-        """
-        if isinstance(tp, typing._AnnotatedAlias):
-            return Annotated
-        if isinstance(tp, (typing._BaseGenericAlias, _types.GenericAlias,
-                           ParamSpecArgs, ParamSpecKwargs)):
-            return tp.__origin__
-        if tp is typing.Generic:
-            return typing.Generic
-        return None
-
-    def get_args(tp):
-        """Get type arguments with all substitutions performed.
-
-        For unions, basic simplifications used by Union constructor are performed.
-        Examples::
-            get_args(Dict[str, int]) == (str, int)
-            get_args(int) == ()
-            get_args(Union[int, Union[T, int], str][int]) == (int, str)
-            get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int])
-            get_args(Callable[[], T][int]) == ([], int)
-        """
-        if isinstance(tp, typing._AnnotatedAlias):
-            return (tp.__origin__, *tp.__metadata__)
-        if isinstance(tp, (typing._GenericAlias, _types.GenericAlias)):
-            res = tp.__args__
-            if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis:
-                res = (list(res[:-1]), res[-1])
-            return res
-        return ()
-
-
-# 3.10+
-if hasattr(typing, 'TypeAlias'):
-    TypeAlias = typing.TypeAlias
-# 3.9
-else:
-    @_ExtensionsSpecialForm
-    def TypeAlias(self, parameters):
-        """Special marker indicating that an assignment should
-        be recognized as a proper type alias definition by type
-        checkers.
-
-        For example::
-
-            Predicate: TypeAlias = Callable[..., bool]
-
-        It's invalid when used anywhere except as in the example above.
-        """
-        raise TypeError(f"{self} is not subscriptable")
-
-
-def _set_default(type_param, default):
-    type_param.has_default = lambda: default is not NoDefault
-    type_param.__default__ = default
-
-
-def _set_module(typevarlike):
-    # for pickling:
-    def_mod = _caller(depth=2)
-    if def_mod != 'typing_extensions':
-        typevarlike.__module__ = def_mod
-
-
-class _DefaultMixin:
-    """Mixin for TypeVarLike defaults."""
-
-    __slots__ = ()
-    __init__ = _set_default
-
-
-# Classes using this metaclass must provide a _backported_typevarlike ClassVar
-class _TypeVarLikeMeta(type):
-    def __instancecheck__(cls, __instance: Any) -> bool:
-        return isinstance(__instance, cls._backported_typevarlike)
-
-
-if _PEP_696_IMPLEMENTED:
-    from typing import TypeVar
-else:
-    # Add default and infer_variance parameters from PEP 696 and 695
-    class TypeVar(metaclass=_TypeVarLikeMeta):
-        """Type variable."""
-
-        _backported_typevarlike = typing.TypeVar
-
-        def __new__(cls, name, *constraints, bound=None,
-                    covariant=False, contravariant=False,
-                    default=NoDefault, infer_variance=False):
-            if hasattr(typing, "TypeAliasType"):
-                # PEP 695 implemented (3.12+), can pass infer_variance to typing.TypeVar
-                typevar = typing.TypeVar(name, *constraints, bound=bound,
-                                         covariant=covariant, contravariant=contravariant,
-                                         infer_variance=infer_variance)
-            else:
-                typevar = typing.TypeVar(name, *constraints, bound=bound,
-                                         covariant=covariant, contravariant=contravariant)
-                if infer_variance and (covariant or contravariant):
-                    raise ValueError("Variance cannot be specified with infer_variance.")
-                typevar.__infer_variance__ = infer_variance
-
-            _set_default(typevar, default)
-            _set_module(typevar)
-
-            def _tvar_prepare_subst(alias, args):
-                if (
-                    typevar.has_default()
-                    and alias.__parameters__.index(typevar) == len(args)
-                ):
-                    args += (typevar.__default__,)
-                return args
-
-            typevar.__typing_prepare_subst__ = _tvar_prepare_subst
-            return typevar
-
-        def __init_subclass__(cls) -> None:
-            raise TypeError(f"type '{__name__}.TypeVar' is not an acceptable base type")
-
-
-# Python 3.10+ has PEP 612
-if hasattr(typing, 'ParamSpecArgs'):
-    ParamSpecArgs = typing.ParamSpecArgs
-    ParamSpecKwargs = typing.ParamSpecKwargs
-# 3.9
-else:
-    class _Immutable:
-        """Mixin to indicate that object should not be copied."""
-        __slots__ = ()
-
-        def __copy__(self):
-            return self
-
-        def __deepcopy__(self, memo):
-            return self
-
-    class ParamSpecArgs(_Immutable):
-        """The args for a ParamSpec object.
-
-        Given a ParamSpec object P, P.args is an instance of ParamSpecArgs.
-
-        ParamSpecArgs objects have a reference back to their ParamSpec:
-
-        P.args.__origin__ is P
-
-        This type is meant for runtime introspection and has no special meaning to
-        static type checkers.
-        """
-        def __init__(self, origin):
-            self.__origin__ = origin
-
-        def __repr__(self):
-            return f"{self.__origin__.__name__}.args"
-
-        def __eq__(self, other):
-            if not isinstance(other, ParamSpecArgs):
-                return NotImplemented
-            return self.__origin__ == other.__origin__
-
-    class ParamSpecKwargs(_Immutable):
-        """The kwargs for a ParamSpec object.
-
-        Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs.
-
-        ParamSpecKwargs objects have a reference back to their ParamSpec:
-
-        P.kwargs.__origin__ is P
-
-        This type is meant for runtime introspection and has no special meaning to
-        static type checkers.
-        """
-        def __init__(self, origin):
-            self.__origin__ = origin
-
-        def __repr__(self):
-            return f"{self.__origin__.__name__}.kwargs"
-
-        def __eq__(self, other):
-            if not isinstance(other, ParamSpecKwargs):
-                return NotImplemented
-            return self.__origin__ == other.__origin__
-
-
-if _PEP_696_IMPLEMENTED:
-    from typing import ParamSpec
-
-# 3.10+
-elif hasattr(typing, 'ParamSpec'):
-
-    # Add default parameter - PEP 696
-    class ParamSpec(metaclass=_TypeVarLikeMeta):
-        """Parameter specification."""
-
-        _backported_typevarlike = typing.ParamSpec
-
-        def __new__(cls, name, *, bound=None,
-                    covariant=False, contravariant=False,
-                    infer_variance=False, default=NoDefault):
-            if hasattr(typing, "TypeAliasType"):
-                # PEP 695 implemented, can pass infer_variance to typing.TypeVar
-                paramspec = typing.ParamSpec(name, bound=bound,
-                                             covariant=covariant,
-                                             contravariant=contravariant,
-                                             infer_variance=infer_variance)
-            else:
-                paramspec = typing.ParamSpec(name, bound=bound,
-                                             covariant=covariant,
-                                             contravariant=contravariant)
-                paramspec.__infer_variance__ = infer_variance
-
-            _set_default(paramspec, default)
-            _set_module(paramspec)
-
-            def _paramspec_prepare_subst(alias, args):
-                params = alias.__parameters__
-                i = params.index(paramspec)
-                if i == len(args) and paramspec.has_default():
-                    args = [*args, paramspec.__default__]
-                if i >= len(args):
-                    raise TypeError(f"Too few arguments for {alias}")
-                # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612.
-                if len(params) == 1 and not typing._is_param_expr(args[0]):
-                    assert i == 0
-                    args = (args,)
-                # Convert lists to tuples to help other libraries cache the results.
-                elif isinstance(args[i], list):
-                    args = (*args[:i], tuple(args[i]), *args[i + 1:])
-                return args
-
-            paramspec.__typing_prepare_subst__ = _paramspec_prepare_subst
-            return paramspec
-
-        def __init_subclass__(cls) -> None:
-            raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type")
-
-# 3.9
-else:
-
-    # Inherits from list as a workaround for Callable checks in Python < 3.9.2.
-    class ParamSpec(list, _DefaultMixin):
-        """Parameter specification variable.
-
-        Usage::
-
-           P = ParamSpec('P')
-
-        Parameter specification variables exist primarily for the benefit of static
-        type checkers.  They are used to forward the parameter types of one
-        callable to another callable, a pattern commonly found in higher order
-        functions and decorators.  They are only valid when used in ``Concatenate``,
-        or s the first argument to ``Callable``. In Python 3.10 and higher,
-        they are also supported in user-defined Generics at runtime.
-        See class Generic for more information on generic types.  An
-        example for annotating a decorator::
-
-           T = TypeVar('T')
-           P = ParamSpec('P')
-
-           def add_logging(f: Callable[P, T]) -> Callable[P, T]:
-               '''A type-safe decorator to add logging to a function.'''
-               def inner(*args: P.args, **kwargs: P.kwargs) -> T:
-                   logging.info(f'{f.__name__} was called')
-                   return f(*args, **kwargs)
-               return inner
-
-           @add_logging
-           def add_two(x: float, y: float) -> float:
-               '''Add two numbers together.'''
-               return x + y
-
-        Parameter specification variables defined with covariant=True or
-        contravariant=True can be used to declare covariant or contravariant
-        generic types.  These keyword arguments are valid, but their actual semantics
-        are yet to be decided.  See PEP 612 for details.
-
-        Parameter specification variables can be introspected. e.g.:
-
-           P.__name__ == 'T'
-           P.__bound__ == None
-           P.__covariant__ == False
-           P.__contravariant__ == False
-
-        Note that only parameter specification variables defined in global scope can
-        be pickled.
-        """
-
-        # Trick Generic __parameters__.
-        __class__ = typing.TypeVar
-
-        @property
-        def args(self):
-            return ParamSpecArgs(self)
-
-        @property
-        def kwargs(self):
-            return ParamSpecKwargs(self)
-
-        def __init__(self, name, *, bound=None, covariant=False, contravariant=False,
-                     infer_variance=False, default=NoDefault):
-            list.__init__(self, [self])
-            self.__name__ = name
-            self.__covariant__ = bool(covariant)
-            self.__contravariant__ = bool(contravariant)
-            self.__infer_variance__ = bool(infer_variance)
-            if bound:
-                self.__bound__ = typing._type_check(bound, 'Bound must be a type.')
-            else:
-                self.__bound__ = None
-            _DefaultMixin.__init__(self, default)
-
-            # for pickling:
-            def_mod = _caller()
-            if def_mod != 'typing_extensions':
-                self.__module__ = def_mod
-
-        def __repr__(self):
-            if self.__infer_variance__:
-                prefix = ''
-            elif self.__covariant__:
-                prefix = '+'
-            elif self.__contravariant__:
-                prefix = '-'
-            else:
-                prefix = '~'
-            return prefix + self.__name__
-
-        def __hash__(self):
-            return object.__hash__(self)
-
-        def __eq__(self, other):
-            return self is other
-
-        def __reduce__(self):
-            return self.__name__
-
-        # Hack to get typing._type_check to pass.
-        def __call__(self, *args, **kwargs):
-            pass
-
-
-# 3.9
-if not hasattr(typing, 'Concatenate'):
-    # Inherits from list as a workaround for Callable checks in Python < 3.9.2.
-
-    # 3.9.0-1
-    if not hasattr(typing, '_type_convert'):
-        def _type_convert(arg, module=None, *, allow_special_forms=False):
-            """For converting None to type(None), and strings to ForwardRef."""
-            if arg is None:
-                return type(None)
-            if isinstance(arg, str):
-                if sys.version_info <= (3, 9, 6):
-                    return ForwardRef(arg)
-                if sys.version_info <= (3, 9, 7):
-                    return ForwardRef(arg, module=module)
-                return ForwardRef(arg, module=module, is_class=allow_special_forms)
-            return arg
-    else:
-        _type_convert = typing._type_convert
-
-    class _ConcatenateGenericAlias(list):
-
-        # Trick Generic into looking into this for __parameters__.
-        __class__ = typing._GenericAlias
-
-        def __init__(self, origin, args):
-            super().__init__(args)
-            self.__origin__ = origin
-            self.__args__ = args
-
-        def __repr__(self):
-            _type_repr = typing._type_repr
-            return (f'{_type_repr(self.__origin__)}'
-                    f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]')
-
-        def __hash__(self):
-            return hash((self.__origin__, self.__args__))
-
-        # Hack to get typing._type_check to pass in Generic.
-        def __call__(self, *args, **kwargs):
-            pass
-
-        @property
-        def __parameters__(self):
-            return tuple(
-                tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec))
-            )
-
-        # 3.9 used by __getitem__ below
-        def copy_with(self, params):
-            if isinstance(params[-1], _ConcatenateGenericAlias):
-                params = (*params[:-1], *params[-1].__args__)
-            elif isinstance(params[-1], (list, tuple)):
-                return (*params[:-1], *params[-1])
-            elif (not (params[-1] is ... or isinstance(params[-1], ParamSpec))):
-                raise TypeError("The last parameter to Concatenate should be a "
-                        "ParamSpec variable or ellipsis.")
-            return self.__class__(self.__origin__, params)
-
-        # 3.9; accessed during GenericAlias.__getitem__ when substituting
-        def __getitem__(self, args):
-            if self.__origin__ in (Generic, Protocol):
-                # Can't subscript Generic[...] or Protocol[...].
-                raise TypeError(f"Cannot subscript already-subscripted {self}")
-            if not self.__parameters__:
-                raise TypeError(f"{self} is not a generic class")
-
-            if not isinstance(args, tuple):
-                args = (args,)
-            args = _unpack_args(*(_type_convert(p) for p in args))
-            params = self.__parameters__
-            for param in params:
-                prepare = getattr(param, "__typing_prepare_subst__", None)
-                if prepare is not None:
-                    args = prepare(self, args)
-                # 3.9 & typing.ParamSpec
-                elif isinstance(param, ParamSpec):
-                    i = params.index(param)
-                    if (
-                        i == len(args)
-                        and getattr(param, '__default__', NoDefault) is not NoDefault
-                    ):
-                        args = [*args, param.__default__]
-                    if i >= len(args):
-                        raise TypeError(f"Too few arguments for {self}")
-                    # Special case for Z[[int, str, bool]] == Z[int, str, bool]
-                    if len(params) == 1 and not _is_param_expr(args[0]):
-                        assert i == 0
-                        args = (args,)
-                    elif (
-                        isinstance(args[i], list)
-                        # 3.9
-                        # This class inherits from list do not convert
-                        and not isinstance(args[i], _ConcatenateGenericAlias)
-                    ):
-                        args = (*args[:i], tuple(args[i]), *args[i + 1:])
-
-            alen = len(args)
-            plen = len(params)
-            if alen != plen:
-                raise TypeError(
-                    f"Too {'many' if alen > plen else 'few'} arguments for {self};"
-                    f" actual {alen}, expected {plen}"
-                )
-
-            subst = dict(zip(self.__parameters__, args))
-            # determine new args
-            new_args = []
-            for arg in self.__args__:
-                if isinstance(arg, type):
-                    new_args.append(arg)
-                    continue
-                if isinstance(arg, TypeVar):
-                    arg = subst[arg]
-                    if (
-                        (isinstance(arg, typing._GenericAlias) and _is_unpack(arg))
-                        or (
-                            hasattr(_types, "GenericAlias")
-                            and isinstance(arg, _types.GenericAlias)
-                            and getattr(arg, "__unpacked__", False)
-                        )
-                    ):
-                        raise TypeError(f"{arg} is not valid as type argument")
-
-                elif isinstance(arg,
-                    typing._GenericAlias
-                    if not hasattr(_types, "GenericAlias") else
-                    (typing._GenericAlias, _types.GenericAlias)
-                ):
-                    subparams = arg.__parameters__
-                    if subparams:
-                        subargs = tuple(subst[x] for x in subparams)
-                        arg = arg[subargs]
-                new_args.append(arg)
-            return self.copy_with(tuple(new_args))
-
-# 3.10+
-else:
-    _ConcatenateGenericAlias = typing._ConcatenateGenericAlias
-
-    # 3.10
-    if sys.version_info < (3, 11):
-
-        class _ConcatenateGenericAlias(typing._ConcatenateGenericAlias, _root=True):
-            # needed for checks in collections.abc.Callable to accept this class
-            __module__ = "typing"
-
-            def copy_with(self, params):
-                if isinstance(params[-1], (list, tuple)):
-                    return (*params[:-1], *params[-1])
-                if isinstance(params[-1], typing._ConcatenateGenericAlias):
-                    params = (*params[:-1], *params[-1].__args__)
-                elif not (params[-1] is ... or isinstance(params[-1], ParamSpec)):
-                    raise TypeError("The last parameter to Concatenate should be a "
-                            "ParamSpec variable or ellipsis.")
-                return super(typing._ConcatenateGenericAlias, self).copy_with(params)
-
-            def __getitem__(self, args):
-                value = super().__getitem__(args)
-                if isinstance(value, tuple) and any(_is_unpack(t) for t in value):
-                    return tuple(_unpack_args(*(n for n in value)))
-                return value
-
-
-# 3.9.2
-class _EllipsisDummy: ...
-
-
-# <=3.10
-def _create_concatenate_alias(origin, parameters):
-    if parameters[-1] is ... and sys.version_info < (3, 9, 2):
-        # Hack: Arguments must be types, replace it with one.
-        parameters = (*parameters[:-1], _EllipsisDummy)
-    if sys.version_info >= (3, 10, 3):
-        concatenate = _ConcatenateGenericAlias(origin, parameters,
-                                        _typevar_types=(TypeVar, ParamSpec),
-                                        _paramspec_tvars=True)
-    else:
-        concatenate = _ConcatenateGenericAlias(origin, parameters)
-    if parameters[-1] is not _EllipsisDummy:
-        return concatenate
-    # Remove dummy again
-    concatenate.__args__ = tuple(p if p is not _EllipsisDummy else ...
-                                    for p in concatenate.__args__)
-    if sys.version_info < (3, 10):
-        # backport needs __args__ adjustment only
-        return concatenate
-    concatenate.__parameters__ = tuple(p for p in concatenate.__parameters__
-                                        if p is not _EllipsisDummy)
-    return concatenate
-
-
-# <=3.10
-@typing._tp_cache
-def _concatenate_getitem(self, parameters):
-    if parameters == ():
-        raise TypeError("Cannot take a Concatenate of no types.")
-    if not isinstance(parameters, tuple):
-        parameters = (parameters,)
-    if not (parameters[-1] is ... or isinstance(parameters[-1], ParamSpec)):
-        raise TypeError("The last parameter to Concatenate should be a "
-                        "ParamSpec variable or ellipsis.")
-    msg = "Concatenate[arg, ...]: each arg must be a type."
-    parameters = (*(typing._type_check(p, msg) for p in parameters[:-1]),
-                    parameters[-1])
-    return _create_concatenate_alias(self, parameters)
-
-
-# 3.11+; Concatenate does not accept ellipsis in 3.10
-if sys.version_info >= (3, 11):
-    Concatenate = typing.Concatenate
-# <=3.10
-else:
-    @_ExtensionsSpecialForm
-    def Concatenate(self, parameters):
-        """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a
-        higher order function which adds, removes or transforms parameters of a
-        callable.
-
-        For example::
-
-           Callable[Concatenate[int, P], int]
-
-        See PEP 612 for detailed information.
-        """
-        return _concatenate_getitem(self, parameters)
-
-
-# 3.10+
-if hasattr(typing, 'TypeGuard'):
-    TypeGuard = typing.TypeGuard
-# 3.9
-else:
-    @_ExtensionsSpecialForm
-    def TypeGuard(self, parameters):
-        """Special typing form used to annotate the return type of a user-defined
-        type guard function.  ``TypeGuard`` only accepts a single type argument.
-        At runtime, functions marked this way should return a boolean.
-
-        ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static
-        type checkers to determine a more precise type of an expression within a
-        program's code flow.  Usually type narrowing is done by analyzing
-        conditional code flow and applying the narrowing to a block of code.  The
-        conditional expression here is sometimes referred to as a "type guard".
-
-        Sometimes it would be convenient to use a user-defined boolean function
-        as a type guard.  Such a function should use ``TypeGuard[...]`` as its
-        return type to alert static type checkers to this intention.
-
-        Using  ``-> TypeGuard`` tells the static type checker that for a given
-        function:
-
-        1. The return value is a boolean.
-        2. If the return value is ``True``, the type of its argument
-        is the type inside ``TypeGuard``.
-
-        For example::
-
-            def is_str(val: Union[str, float]):
-                # "isinstance" type guard
-                if isinstance(val, str):
-                    # Type of ``val`` is narrowed to ``str``
-                    ...
-                else:
-                    # Else, type of ``val`` is narrowed to ``float``.
-                    ...
-
-        Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower
-        form of ``TypeA`` (it can even be a wider form) and this may lead to
-        type-unsafe results.  The main reason is to allow for things like
-        narrowing ``List[object]`` to ``List[str]`` even though the latter is not
-        a subtype of the former, since ``List`` is invariant.  The responsibility of
-        writing type-safe type guards is left to the user.
-
-        ``TypeGuard`` also works with type variables.  For more information, see
-        PEP 647 (User-Defined Type Guards).
-        """
-        item = typing._type_check(parameters, f'{self} accepts only a single type.')
-        return typing._GenericAlias(self, (item,))
-
-
-# 3.13+
-if hasattr(typing, 'TypeIs'):
-    TypeIs = typing.TypeIs
-# <=3.12
-else:
-    @_ExtensionsSpecialForm
-    def TypeIs(self, parameters):
-        """Special typing form used to annotate the return type of a user-defined
-        type narrower function.  ``TypeIs`` only accepts a single type argument.
-        At runtime, functions marked this way should return a boolean.
-
-        ``TypeIs`` aims to benefit *type narrowing* -- a technique used by static
-        type checkers to determine a more precise type of an expression within a
-        program's code flow.  Usually type narrowing is done by analyzing
-        conditional code flow and applying the narrowing to a block of code.  The
-        conditional expression here is sometimes referred to as a "type guard".
-
-        Sometimes it would be convenient to use a user-defined boolean function
-        as a type guard.  Such a function should use ``TypeIs[...]`` as its
-        return type to alert static type checkers to this intention.
-
-        Using  ``-> TypeIs`` tells the static type checker that for a given
-        function:
-
-        1. The return value is a boolean.
-        2. If the return value is ``True``, the type of its argument
-        is the intersection of the type inside ``TypeIs`` and the argument's
-        previously known type.
-
-        For example::
-
-            def is_awaitable(val: object) -> TypeIs[Awaitable[Any]]:
-                return hasattr(val, '__await__')
-
-            def f(val: Union[int, Awaitable[int]]) -> int:
-                if is_awaitable(val):
-                    assert_type(val, Awaitable[int])
-                else:
-                    assert_type(val, int)
-
-        ``TypeIs`` also works with type variables.  For more information, see
-        PEP 742 (Narrowing types with TypeIs).
-        """
-        item = typing._type_check(parameters, f'{self} accepts only a single type.')
-        return typing._GenericAlias(self, (item,))
-
-
-# 3.14+?
-if hasattr(typing, 'TypeForm'):
-    TypeForm = typing.TypeForm
-# <=3.13
-else:
-    class _TypeFormForm(_ExtensionsSpecialForm, _root=True):
-        # TypeForm(X) is equivalent to X but indicates to the type checker
-        # that the object is a TypeForm.
-        def __call__(self, obj, /):
-            return obj
-
-    @_TypeFormForm
-    def TypeForm(self, parameters):
-        """A special form representing the value that results from the evaluation
-        of a type expression. This value encodes the information supplied in the
-        type expression, and it represents the type described by that type expression.
-
-        When used in a type expression, TypeForm describes a set of type form objects.
-        It accepts a single type argument, which must be a valid type expression.
-        ``TypeForm[T]`` describes the set of all type form objects that represent
-        the type T or types that are assignable to T.
-
-        Usage:
-
-            def cast[T](typ: TypeForm[T], value: Any) -> T: ...
-
-            reveal_type(cast(int, "x"))  # int
-
-        See PEP 747 for more information.
-        """
-        item = typing._type_check(parameters, f'{self} accepts only a single type.')
-        return typing._GenericAlias(self, (item,))
-
-
-
-
-if hasattr(typing, "LiteralString"):  # 3.11+
-    LiteralString = typing.LiteralString
-else:
-    @_SpecialForm
-    def LiteralString(self, params):
-        """Represents an arbitrary literal string.
-
-        Example::
-
-          from typing_extensions import LiteralString
-
-          def query(sql: LiteralString) -> ...:
-              ...
-
-          query("SELECT * FROM table")  # ok
-          query(f"SELECT * FROM {input()}")  # not ok
-
-        See PEP 675 for details.
-
-        """
-        raise TypeError(f"{self} is not subscriptable")
-
-
-if hasattr(typing, "Self"):  # 3.11+
-    Self = typing.Self
-else:
-    @_SpecialForm
-    def Self(self, params):
-        """Used to spell the type of "self" in classes.
-
-        Example::
-
-          from typing import Self
-
-          class ReturnsSelf:
-              def parse(self, data: bytes) -> Self:
-                  ...
-                  return self
-
-        """
-
-        raise TypeError(f"{self} is not subscriptable")
-
-
-if hasattr(typing, "Never"):  # 3.11+
-    Never = typing.Never
-else:
-    @_SpecialForm
-    def Never(self, params):
-        """The bottom type, a type that has no members.
-
-        This can be used to define a function that should never be
-        called, or a function that never returns::
-
-            from typing_extensions import Never
-
-            def never_call_me(arg: Never) -> None:
-                pass
-
-            def int_or_str(arg: int | str) -> None:
-                never_call_me(arg)  # type checker error
-                match arg:
-                    case int():
-                        print("It's an int")
-                    case str():
-                        print("It's a str")
-                    case _:
-                        never_call_me(arg)  # ok, arg is of type Never
-
-        """
-
-        raise TypeError(f"{self} is not subscriptable")
-
-
-if hasattr(typing, 'Required'):  # 3.11+
-    Required = typing.Required
-    NotRequired = typing.NotRequired
-else:  # <=3.10
-    @_ExtensionsSpecialForm
-    def Required(self, parameters):
-        """A special typing construct to mark a key of a total=False TypedDict
-        as required. For example:
-
-            class Movie(TypedDict, total=False):
-                title: Required[str]
-                year: int
-
-            m = Movie(
-                title='The Matrix',  # typechecker error if key is omitted
-                year=1999,
-            )
-
-        There is no runtime checking that a required key is actually provided
-        when instantiating a related TypedDict.
-        """
-        item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
-        return typing._GenericAlias(self, (item,))
-
-    @_ExtensionsSpecialForm
-    def NotRequired(self, parameters):
-        """A special typing construct to mark a key of a TypedDict as
-        potentially missing. For example:
-
-            class Movie(TypedDict):
-                title: str
-                year: NotRequired[int]
-
-            m = Movie(
-                title='The Matrix',  # typechecker error if key is omitted
-                year=1999,
-            )
-        """
-        item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
-        return typing._GenericAlias(self, (item,))
-
-
-if hasattr(typing, 'ReadOnly'):
-    ReadOnly = typing.ReadOnly
-else:  # <=3.12
-    @_ExtensionsSpecialForm
-    def ReadOnly(self, parameters):
-        """A special typing construct to mark an item of a TypedDict as read-only.
-
-        For example:
-
-            class Movie(TypedDict):
-                title: ReadOnly[str]
-                year: int
-
-            def mutate_movie(m: Movie) -> None:
-                m["year"] = 1992  # allowed
-                m["title"] = "The Matrix"  # typechecker error
-
-        There is no runtime checking for this property.
-        """
-        item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
-        return typing._GenericAlias(self, (item,))
-
-
-_UNPACK_DOC = """\
-Type unpack operator.
-
-The type unpack operator takes the child types from some container type,
-such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. For
-example:
-
-  # For some generic class `Foo`:
-  Foo[Unpack[tuple[int, str]]]  # Equivalent to Foo[int, str]
-
-  Ts = TypeVarTuple('Ts')
-  # Specifies that `Bar` is generic in an arbitrary number of types.
-  # (Think of `Ts` as a tuple of an arbitrary number of individual
-  #  `TypeVar`s, which the `Unpack` is 'pulling out' directly into the
-  #  `Generic[]`.)
-  class Bar(Generic[Unpack[Ts]]): ...
-  Bar[int]  # Valid
-  Bar[int, str]  # Also valid
-
-From Python 3.11, this can also be done using the `*` operator:
-
-    Foo[*tuple[int, str]]
-    class Bar(Generic[*Ts]): ...
-
-The operator can also be used along with a `TypedDict` to annotate
-`**kwargs` in a function signature. For instance:
-
-  class Movie(TypedDict):
-    name: str
-    year: int
-
-  # This function expects two keyword arguments - *name* of type `str` and
-  # *year* of type `int`.
-  def foo(**kwargs: Unpack[Movie]): ...
-
-Note that there is only some runtime checking of this operator. Not
-everything the runtime allows may be accepted by static type checkers.
-
-For more information, see PEP 646 and PEP 692.
-"""
-
-
-if sys.version_info >= (3, 12):  # PEP 692 changed the repr of Unpack[]
-    Unpack = typing.Unpack
-
-    def _is_unpack(obj):
-        return get_origin(obj) is Unpack
-
-else:  # <=3.11
-    class _UnpackSpecialForm(_ExtensionsSpecialForm, _root=True):
-        def __init__(self, getitem):
-            super().__init__(getitem)
-            self.__doc__ = _UNPACK_DOC
-
-    class _UnpackAlias(typing._GenericAlias, _root=True):
-        if sys.version_info < (3, 11):
-            # needed for compatibility with Generic[Unpack[Ts]]
-            __class__ = typing.TypeVar
-
-        @property
-        def __typing_unpacked_tuple_args__(self):
-            assert self.__origin__ is Unpack
-            assert len(self.__args__) == 1
-            arg, = self.__args__
-            if isinstance(arg, (typing._GenericAlias, _types.GenericAlias)):
-                if arg.__origin__ is not tuple:
-                    raise TypeError("Unpack[...] must be used with a tuple type")
-                return arg.__args__
-            return None
-
-        @property
-        def __typing_is_unpacked_typevartuple__(self):
-            assert self.__origin__ is Unpack
-            assert len(self.__args__) == 1
-            return isinstance(self.__args__[0], TypeVarTuple)
-
-        def __getitem__(self, args):
-            if self.__typing_is_unpacked_typevartuple__:
-                return args
-            return super().__getitem__(args)
-
-    @_UnpackSpecialForm
-    def Unpack(self, parameters):
-        item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
-        return _UnpackAlias(self, (item,))
-
-    def _is_unpack(obj):
-        return isinstance(obj, _UnpackAlias)
-
-
-def _unpack_args(*args):
-    newargs = []
-    for arg in args:
-        subargs = getattr(arg, '__typing_unpacked_tuple_args__', None)
-        if subargs is not None and (not (subargs and subargs[-1] is ...)):
-            newargs.extend(subargs)
-        else:
-            newargs.append(arg)
-    return newargs
-
-
-if _PEP_696_IMPLEMENTED:
-    from typing import TypeVarTuple
-
-elif hasattr(typing, "TypeVarTuple"):  # 3.11+
-
-    # Add default parameter - PEP 696
-    class TypeVarTuple(metaclass=_TypeVarLikeMeta):
-        """Type variable tuple."""
-
-        _backported_typevarlike = typing.TypeVarTuple
-
-        def __new__(cls, name, *, default=NoDefault):
-            tvt = typing.TypeVarTuple(name)
-            _set_default(tvt, default)
-            _set_module(tvt)
-
-            def _typevartuple_prepare_subst(alias, args):
-                params = alias.__parameters__
-                typevartuple_index = params.index(tvt)
-                for param in params[typevartuple_index + 1:]:
-                    if isinstance(param, TypeVarTuple):
-                        raise TypeError(
-                            f"More than one TypeVarTuple parameter in {alias}"
-                        )
-
-                alen = len(args)
-                plen = len(params)
-                left = typevartuple_index
-                right = plen - typevartuple_index - 1
-                var_tuple_index = None
-                fillarg = None
-                for k, arg in enumerate(args):
-                    if not isinstance(arg, type):
-                        subargs = getattr(arg, '__typing_unpacked_tuple_args__', None)
-                        if subargs and len(subargs) == 2 and subargs[-1] is ...:
-                            if var_tuple_index is not None:
-                                raise TypeError(
-                                    "More than one unpacked "
-                                    "arbitrary-length tuple argument"
-                                )
-                            var_tuple_index = k
-                            fillarg = subargs[0]
-                if var_tuple_index is not None:
-                    left = min(left, var_tuple_index)
-                    right = min(right, alen - var_tuple_index - 1)
-                elif left + right > alen:
-                    raise TypeError(f"Too few arguments for {alias};"
-                                    f" actual {alen}, expected at least {plen - 1}")
-                if left == alen - right and tvt.has_default():
-                    replacement = _unpack_args(tvt.__default__)
-                else:
-                    replacement = args[left: alen - right]
-
-                return (
-                    *args[:left],
-                    *([fillarg] * (typevartuple_index - left)),
-                    replacement,
-                    *([fillarg] * (plen - right - left - typevartuple_index - 1)),
-                    *args[alen - right:],
-                )
-
-            tvt.__typing_prepare_subst__ = _typevartuple_prepare_subst
-            return tvt
-
-        def __init_subclass__(self, *args, **kwds):
-            raise TypeError("Cannot subclass special typing classes")
-
-else:  # <=3.10
-    class TypeVarTuple(_DefaultMixin):
-        """Type variable tuple.
-
-        Usage::
-
-            Ts = TypeVarTuple('Ts')
-
-        In the same way that a normal type variable is a stand-in for a single
-        type such as ``int``, a type variable *tuple* is a stand-in for a *tuple*
-        type such as ``Tuple[int, str]``.
-
-        Type variable tuples can be used in ``Generic`` declarations.
-        Consider the following example::
-
-            class Array(Generic[*Ts]): ...
-
-        The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``,
-        where ``T1`` and ``T2`` are type variables. To use these type variables
-        as type parameters of ``Array``, we must *unpack* the type variable tuple using
-        the star operator: ``*Ts``. The signature of ``Array`` then behaves
-        as if we had simply written ``class Array(Generic[T1, T2]): ...``.
-        In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows
-        us to parameterise the class with an *arbitrary* number of type parameters.
-
-        Type variable tuples can be used anywhere a normal ``TypeVar`` can.
-        This includes class definitions, as shown above, as well as function
-        signatures and variable annotations::
-
-            class Array(Generic[*Ts]):
-
-                def __init__(self, shape: Tuple[*Ts]):
-                    self._shape: Tuple[*Ts] = shape
-
-                def get_shape(self) -> Tuple[*Ts]:
-                    return self._shape
-
-            shape = (Height(480), Width(640))
-            x: Array[Height, Width] = Array(shape)
-            y = abs(x)  # Inferred type is Array[Height, Width]
-            z = x + x   #        ...    is Array[Height, Width]
-            x.get_shape()  #     ...    is tuple[Height, Width]
-
-        """
-
-        # Trick Generic __parameters__.
-        __class__ = typing.TypeVar
-
-        def __iter__(self):
-            yield self.__unpacked__
-
-        def __init__(self, name, *, default=NoDefault):
-            self.__name__ = name
-            _DefaultMixin.__init__(self, default)
-
-            # for pickling:
-            def_mod = _caller()
-            if def_mod != 'typing_extensions':
-                self.__module__ = def_mod
-
-            self.__unpacked__ = Unpack[self]
-
-        def __repr__(self):
-            return self.__name__
-
-        def __hash__(self):
-            return object.__hash__(self)
-
-        def __eq__(self, other):
-            return self is other
-
-        def __reduce__(self):
-            return self.__name__
-
-        def __init_subclass__(self, *args, **kwds):
-            if '_root' not in kwds:
-                raise TypeError("Cannot subclass special typing classes")
-
-
-if hasattr(typing, "reveal_type"):  # 3.11+
-    reveal_type = typing.reveal_type
-else:  # <=3.10
-    def reveal_type(obj: T, /) -> T:
-        """Reveal the inferred type of a variable.
-
-        When a static type checker encounters a call to ``reveal_type()``,
-        it will emit the inferred type of the argument::
-
-            x: int = 1
-            reveal_type(x)
-
-        Running a static type checker (e.g., ``mypy``) on this example
-        will produce output similar to 'Revealed type is "builtins.int"'.
-
-        At runtime, the function prints the runtime type of the
-        argument and returns it unchanged.
-
-        """
-        print(f"Runtime type is {type(obj).__name__!r}", file=sys.stderr)
-        return obj
-
-
-if hasattr(typing, "_ASSERT_NEVER_REPR_MAX_LENGTH"):  # 3.11+
-    _ASSERT_NEVER_REPR_MAX_LENGTH = typing._ASSERT_NEVER_REPR_MAX_LENGTH
-else:  # <=3.10
-    _ASSERT_NEVER_REPR_MAX_LENGTH = 100
-
-
-if hasattr(typing, "assert_never"):  # 3.11+
-    assert_never = typing.assert_never
-else:  # <=3.10
-    def assert_never(arg: Never, /) -> Never:
-        """Assert to the type checker that a line of code is unreachable.
-
-        Example::
-
-            def int_or_str(arg: int | str) -> None:
-                match arg:
-                    case int():
-                        print("It's an int")
-                    case str():
-                        print("It's a str")
-                    case _:
-                        assert_never(arg)
-
-        If a type checker finds that a call to assert_never() is
-        reachable, it will emit an error.
-
-        At runtime, this throws an exception when called.
-
-        """
-        value = repr(arg)
-        if len(value) > _ASSERT_NEVER_REPR_MAX_LENGTH:
-            value = value[:_ASSERT_NEVER_REPR_MAX_LENGTH] + '...'
-        raise AssertionError(f"Expected code to be unreachable, but got: {value}")
-
-
-if sys.version_info >= (3, 12):  # 3.12+
-    # dataclass_transform exists in 3.11 but lacks the frozen_default parameter
-    dataclass_transform = typing.dataclass_transform
-else:  # <=3.11
-    def dataclass_transform(
-        *,
-        eq_default: bool = True,
-        order_default: bool = False,
-        kw_only_default: bool = False,
-        frozen_default: bool = False,
-        field_specifiers: typing.Tuple[
-            typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]],
-            ...
-        ] = (),
-        **kwargs: typing.Any,
-    ) -> typing.Callable[[T], T]:
-        """Decorator that marks a function, class, or metaclass as providing
-        dataclass-like behavior.
-
-        Example:
-
-            from typing_extensions import dataclass_transform
-
-            _T = TypeVar("_T")
-
-            # Used on a decorator function
-            @dataclass_transform()
-            def create_model(cls: type[_T]) -> type[_T]:
-                ...
-                return cls
-
-            @create_model
-            class CustomerModel:
-                id: int
-                name: str
-
-            # Used on a base class
-            @dataclass_transform()
-            class ModelBase: ...
-
-            class CustomerModel(ModelBase):
-                id: int
-                name: str
-
-            # Used on a metaclass
-            @dataclass_transform()
-            class ModelMeta(type): ...
-
-            class ModelBase(metaclass=ModelMeta): ...
-
-            class CustomerModel(ModelBase):
-                id: int
-                name: str
-
-        Each of the ``CustomerModel`` classes defined in this example will now
-        behave similarly to a dataclass created with the ``@dataclasses.dataclass``
-        decorator. For example, the type checker will synthesize an ``__init__``
-        method.
-
-        The arguments to this decorator can be used to customize this behavior:
-        - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be
-          True or False if it is omitted by the caller.
-        - ``order_default`` indicates whether the ``order`` parameter is
-          assumed to be True or False if it is omitted by the caller.
-        - ``kw_only_default`` indicates whether the ``kw_only`` parameter is
-          assumed to be True or False if it is omitted by the caller.
-        - ``frozen_default`` indicates whether the ``frozen`` parameter is
-          assumed to be True or False if it is omitted by the caller.
-        - ``field_specifiers`` specifies a static list of supported classes
-          or functions that describe fields, similar to ``dataclasses.field()``.
-
-        At runtime, this decorator records its arguments in the
-        ``__dataclass_transform__`` attribute on the decorated object.
-
-        See PEP 681 for details.
-
-        """
-        def decorator(cls_or_fn):
-            cls_or_fn.__dataclass_transform__ = {
-                "eq_default": eq_default,
-                "order_default": order_default,
-                "kw_only_default": kw_only_default,
-                "frozen_default": frozen_default,
-                "field_specifiers": field_specifiers,
-                "kwargs": kwargs,
-            }
-            return cls_or_fn
-        return decorator
-
-
-if hasattr(typing, "override"):  # 3.12+
-    override = typing.override
-else:  # <=3.11
-    _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any])
-
-    def override(arg: _F, /) -> _F:
-        """Indicate that a method is intended to override a method in a base class.
-
-        Usage:
-
-            class Base:
-                def method(self) -> None:
-                    pass
-
-            class Child(Base):
-                @override
-                def method(self) -> None:
-                    super().method()
-
-        When this decorator is applied to a method, the type checker will
-        validate that it overrides a method with the same name on a base class.
-        This helps prevent bugs that may occur when a base class is changed
-        without an equivalent change to a child class.
-
-        There is no runtime checking of these properties. The decorator
-        sets the ``__override__`` attribute to ``True`` on the decorated object
-        to allow runtime introspection.
-
-        See PEP 698 for details.
-
-        """
-        try:
-            arg.__override__ = True
-        except (AttributeError, TypeError):
-            # Skip the attribute silently if it is not writable.
-            # AttributeError happens if the object has __slots__ or a
-            # read-only property, TypeError if it's a builtin class.
-            pass
-        return arg
-
-
-# Python 3.13.3+ contains a fix for the wrapped __new__
-if sys.version_info >= (3, 13, 3):
-    deprecated = warnings.deprecated
-else:
-    _T = typing.TypeVar("_T")
-
-    class deprecated:
-        """Indicate that a class, function or overload is deprecated.
-
-        When this decorator is applied to an object, the type checker
-        will generate a diagnostic on usage of the deprecated object.
-
-        Usage:
-
-            @deprecated("Use B instead")
-            class A:
-                pass
-
-            @deprecated("Use g instead")
-            def f():
-                pass
-
-            @overload
-            @deprecated("int support is deprecated")
-            def g(x: int) -> int: ...
-            @overload
-            def g(x: str) -> int: ...
-
-        The warning specified by *category* will be emitted at runtime
-        on use of deprecated objects. For functions, that happens on calls;
-        for classes, on instantiation and on creation of subclasses.
-        If the *category* is ``None``, no warning is emitted at runtime.
-        The *stacklevel* determines where the
-        warning is emitted. If it is ``1`` (the default), the warning
-        is emitted at the direct caller of the deprecated object; if it
-        is higher, it is emitted further up the stack.
-        Static type checker behavior is not affected by the *category*
-        and *stacklevel* arguments.
-
-        The deprecation message passed to the decorator is saved in the
-        ``__deprecated__`` attribute on the decorated object.
-        If applied to an overload, the decorator
-        must be after the ``@overload`` decorator for the attribute to
-        exist on the overload as returned by ``get_overloads()``.
-
-        See PEP 702 for details.
-
-        """
-        def __init__(
-            self,
-            message: str,
-            /,
-            *,
-            category: typing.Optional[typing.Type[Warning]] = DeprecationWarning,
-            stacklevel: int = 1,
-        ) -> None:
-            if not isinstance(message, str):
-                raise TypeError(
-                    "Expected an object of type str for 'message', not "
-                    f"{type(message).__name__!r}"
-                )
-            self.message = message
-            self.category = category
-            self.stacklevel = stacklevel
-
-        def __call__(self, arg: _T, /) -> _T:
-            # Make sure the inner functions created below don't
-            # retain a reference to self.
-            msg = self.message
-            category = self.category
-            stacklevel = self.stacklevel
-            if category is None:
-                arg.__deprecated__ = msg
-                return arg
-            elif isinstance(arg, type):
-                import functools
-                from types import MethodType
-
-                original_new = arg.__new__
-
-                @functools.wraps(original_new)
-                def __new__(cls, /, *args, **kwargs):
-                    if cls is arg:
-                        warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
-                    if original_new is not object.__new__:
-                        return original_new(cls, *args, **kwargs)
-                    # Mirrors a similar check in object.__new__.
-                    elif cls.__init__ is object.__init__ and (args or kwargs):
-                        raise TypeError(f"{cls.__name__}() takes no arguments")
-                    else:
-                        return original_new(cls)
-
-                arg.__new__ = staticmethod(__new__)
-
-                original_init_subclass = arg.__init_subclass__
-                # We need slightly different behavior if __init_subclass__
-                # is a bound method (likely if it was implemented in Python)
-                if isinstance(original_init_subclass, MethodType):
-                    original_init_subclass = original_init_subclass.__func__
-
-                    @functools.wraps(original_init_subclass)
-                    def __init_subclass__(*args, **kwargs):
-                        warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
-                        return original_init_subclass(*args, **kwargs)
-
-                    arg.__init_subclass__ = classmethod(__init_subclass__)
-                # Or otherwise, which likely means it's a builtin such as
-                # object's implementation of __init_subclass__.
-                else:
-                    @functools.wraps(original_init_subclass)
-                    def __init_subclass__(*args, **kwargs):
-                        warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
-                        return original_init_subclass(*args, **kwargs)
-
-                    arg.__init_subclass__ = __init_subclass__
-
-                arg.__deprecated__ = __new__.__deprecated__ = msg
-                __init_subclass__.__deprecated__ = msg
-                return arg
-            elif callable(arg):
-                import asyncio.coroutines
-                import functools
-                import inspect
-
-                @functools.wraps(arg)
-                def wrapper(*args, **kwargs):
-                    warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
-                    return arg(*args, **kwargs)
-
-                if asyncio.coroutines.iscoroutinefunction(arg):
-                    if sys.version_info >= (3, 12):
-                        wrapper = inspect.markcoroutinefunction(wrapper)
-                    else:
-                        wrapper._is_coroutine = asyncio.coroutines._is_coroutine
-
-                arg.__deprecated__ = wrapper.__deprecated__ = msg
-                return wrapper
-            else:
-                raise TypeError(
-                    "@deprecated decorator with non-None category must be applied to "
-                    f"a class or callable, not {arg!r}"
-                )
-
-if sys.version_info < (3, 10):
-    def _is_param_expr(arg):
-        return arg is ... or isinstance(
-            arg, (tuple, list, ParamSpec, _ConcatenateGenericAlias)
-        )
-else:
-    def _is_param_expr(arg):
-        return arg is ... or isinstance(
-            arg,
-            (
-                tuple,
-                list,
-                ParamSpec,
-                _ConcatenateGenericAlias,
-                typing._ConcatenateGenericAlias,
-            ),
-        )
-
-
-# We have to do some monkey patching to deal with the dual nature of
-# Unpack/TypeVarTuple:
-# - We want Unpack to be a kind of TypeVar so it gets accepted in
-#   Generic[Unpack[Ts]]
-# - We want it to *not* be treated as a TypeVar for the purposes of
-#   counting generic parameters, so that when we subscript a generic,
-#   the runtime doesn't try to substitute the Unpack with the subscripted type.
-if not hasattr(typing, "TypeVarTuple"):
-    def _check_generic(cls, parameters, elen=_marker):
-        """Check correct count for parameters of a generic cls (internal helper).
-
-        This gives a nice error message in case of count mismatch.
-        """
-        # If substituting a single ParamSpec with multiple arguments
-        # we do not check the count
-        if (inspect.isclass(cls) and issubclass(cls, typing.Generic)
-            and len(cls.__parameters__) == 1
-            and isinstance(cls.__parameters__[0], ParamSpec)
-            and parameters
-            and not _is_param_expr(parameters[0])
-        ):
-            # Generic modifies parameters variable, but here we cannot do this
-            return
-
-        if not elen:
-            raise TypeError(f"{cls} is not a generic class")
-        if elen is _marker:
-            if not hasattr(cls, "__parameters__") or not cls.__parameters__:
-                raise TypeError(f"{cls} is not a generic class")
-            elen = len(cls.__parameters__)
-        alen = len(parameters)
-        if alen != elen:
-            expect_val = elen
-            if hasattr(cls, "__parameters__"):
-                parameters = [p for p in cls.__parameters__ if not _is_unpack(p)]
-                num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters)
-                if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples):
-                    return
-
-                # deal with TypeVarLike defaults
-                # required TypeVarLikes cannot appear after a defaulted one.
-                if alen < elen:
-                    # since we validate TypeVarLike default in _collect_type_vars
-                    # or _collect_parameters we can safely check parameters[alen]
-                    if (
-                        getattr(parameters[alen], '__default__', NoDefault)
-                        is not NoDefault
-                    ):
-                        return
-
-                    num_default_tv = sum(getattr(p, '__default__', NoDefault)
-                                         is not NoDefault for p in parameters)
-
-                    elen -= num_default_tv
-
-                    expect_val = f"at least {elen}"
-
-            things = "arguments" if sys.version_info >= (3, 10) else "parameters"
-            raise TypeError(f"Too {'many' if alen > elen else 'few'} {things}"
-                            f" for {cls}; actual {alen}, expected {expect_val}")
-else:
-    # Python 3.11+
-
-    def _check_generic(cls, parameters, elen):
-        """Check correct count for parameters of a generic cls (internal helper).
-
-        This gives a nice error message in case of count mismatch.
-        """
-        if not elen:
-            raise TypeError(f"{cls} is not a generic class")
-        alen = len(parameters)
-        if alen != elen:
-            expect_val = elen
-            if hasattr(cls, "__parameters__"):
-                parameters = [p for p in cls.__parameters__ if not _is_unpack(p)]
-
-                # deal with TypeVarLike defaults
-                # required TypeVarLikes cannot appear after a defaulted one.
-                if alen < elen:
-                    # since we validate TypeVarLike default in _collect_type_vars
-                    # or _collect_parameters we can safely check parameters[alen]
-                    if (
-                        getattr(parameters[alen], '__default__', NoDefault)
-                        is not NoDefault
-                    ):
-                        return
-
-                    num_default_tv = sum(getattr(p, '__default__', NoDefault)
-                                         is not NoDefault for p in parameters)
-
-                    elen -= num_default_tv
-
-                    expect_val = f"at least {elen}"
-
-            raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments"
-                            f" for {cls}; actual {alen}, expected {expect_val}")
-
-if not _PEP_696_IMPLEMENTED:
-    typing._check_generic = _check_generic
-
-
-def _has_generic_or_protocol_as_origin() -> bool:
-    try:
-        frame = sys._getframe(2)
-    # - Catch AttributeError: not all Python implementations have sys._getframe()
-    # - Catch ValueError: maybe we're called from an unexpected module
-    #   and the call stack isn't deep enough
-    except (AttributeError, ValueError):
-        return False  # err on the side of leniency
-    else:
-        # If we somehow get invoked from outside typing.py,
-        # also err on the side of leniency
-        if frame.f_globals.get("__name__") != "typing":
-            return False
-        origin = frame.f_locals.get("origin")
-        # Cannot use "in" because origin may be an object with a buggy __eq__ that
-        # throws an error.
-        return origin is typing.Generic or origin is Protocol or origin is typing.Protocol
-
-
-_TYPEVARTUPLE_TYPES = {TypeVarTuple, getattr(typing, "TypeVarTuple", None)}
-
-
-def _is_unpacked_typevartuple(x) -> bool:
-    if get_origin(x) is not Unpack:
-        return False
-    args = get_args(x)
-    return (
-        bool(args)
-        and len(args) == 1
-        and type(args[0]) in _TYPEVARTUPLE_TYPES
-    )
-
-
-# Python 3.11+ _collect_type_vars was renamed to _collect_parameters
-if hasattr(typing, '_collect_type_vars'):
-    def _collect_type_vars(types, typevar_types=None):
-        """Collect all type variable contained in types in order of
-        first appearance (lexicographic order). For example::
-
-            _collect_type_vars((T, List[S, T])) == (T, S)
-        """
-        if typevar_types is None:
-            typevar_types = typing.TypeVar
-        tvars = []
-
-        # A required TypeVarLike cannot appear after a TypeVarLike with a default
-        # if it was a direct call to `Generic[]` or `Protocol[]`
-        enforce_default_ordering = _has_generic_or_protocol_as_origin()
-        default_encountered = False
-
-        # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple
-        type_var_tuple_encountered = False
-
-        for t in types:
-            if _is_unpacked_typevartuple(t):
-                type_var_tuple_encountered = True
-            elif (
-                isinstance(t, typevar_types) and not isinstance(t, _UnpackAlias)
-                and t not in tvars
-            ):
-                if enforce_default_ordering:
-                    has_default = getattr(t, '__default__', NoDefault) is not NoDefault
-                    if has_default:
-                        if type_var_tuple_encountered:
-                            raise TypeError('Type parameter with a default'
-                                            ' follows TypeVarTuple')
-                        default_encountered = True
-                    elif default_encountered:
-                        raise TypeError(f'Type parameter {t!r} without a default'
-                                        ' follows type parameter with a default')
-
-                tvars.append(t)
-            if _should_collect_from_parameters(t):
-                tvars.extend([t for t in t.__parameters__ if t not in tvars])
-            elif isinstance(t, tuple):
-                # Collect nested type_vars
-                # tuple wrapped by  _prepare_paramspec_params(cls, params)
-                for x in t:
-                    for collected in _collect_type_vars([x]):
-                        if collected not in tvars:
-                            tvars.append(collected)
-        return tuple(tvars)
-
-    typing._collect_type_vars = _collect_type_vars
-else:
-    def _collect_parameters(args):
-        """Collect all type variables and parameter specifications in args
-        in order of first appearance (lexicographic order).
-
-        For example::
-
-            assert _collect_parameters((T, Callable[P, T])) == (T, P)
-        """
-        parameters = []
-
-        # A required TypeVarLike cannot appear after a TypeVarLike with default
-        # if it was a direct call to `Generic[]` or `Protocol[]`
-        enforce_default_ordering = _has_generic_or_protocol_as_origin()
-        default_encountered = False
-
-        # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple
-        type_var_tuple_encountered = False
-
-        for t in args:
-            if isinstance(t, type):
-                # We don't want __parameters__ descriptor of a bare Python class.
-                pass
-            elif isinstance(t, tuple):
-                # `t` might be a tuple, when `ParamSpec` is substituted with
-                # `[T, int]`, or `[int, *Ts]`, etc.
-                for x in t:
-                    for collected in _collect_parameters([x]):
-                        if collected not in parameters:
-                            parameters.append(collected)
-            elif hasattr(t, '__typing_subst__'):
-                if t not in parameters:
-                    if enforce_default_ordering:
-                        has_default = (
-                            getattr(t, '__default__', NoDefault) is not NoDefault
-                        )
-
-                        if type_var_tuple_encountered and has_default:
-                            raise TypeError('Type parameter with a default'
-                                            ' follows TypeVarTuple')
-
-                        if has_default:
-                            default_encountered = True
-                        elif default_encountered:
-                            raise TypeError(f'Type parameter {t!r} without a default'
-                                            ' follows type parameter with a default')
-
-                    parameters.append(t)
-            else:
-                if _is_unpacked_typevartuple(t):
-                    type_var_tuple_encountered = True
-                for x in getattr(t, '__parameters__', ()):
-                    if x not in parameters:
-                        parameters.append(x)
-
-        return tuple(parameters)
-
-    if not _PEP_696_IMPLEMENTED:
-        typing._collect_parameters = _collect_parameters
-
-# Backport typing.NamedTuple as it exists in Python 3.13.
-# In 3.11, the ability to define generic `NamedTuple`s was supported.
-# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8.
-# On 3.12, we added __orig_bases__ to call-based NamedTuples
-# On 3.13, we deprecated kwargs-based NamedTuples
-if sys.version_info >= (3, 13):
-    NamedTuple = typing.NamedTuple
-else:
-    def _make_nmtuple(name, types, module, defaults=()):
-        fields = [n for n, t in types]
-        annotations = {n: typing._type_check(t, f"field {n} annotation must be a type")
-                       for n, t in types}
-        nm_tpl = collections.namedtuple(name, fields,
-                                        defaults=defaults, module=module)
-        nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations
-        return nm_tpl
-
-    _prohibited_namedtuple_fields = typing._prohibited
-    _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'})
-
-    class _NamedTupleMeta(type):
-        def __new__(cls, typename, bases, ns):
-            assert _NamedTuple in bases
-            for base in bases:
-                if base is not _NamedTuple and base is not typing.Generic:
-                    raise TypeError(
-                        'can only inherit from a NamedTuple type and Generic')
-            bases = tuple(tuple if base is _NamedTuple else base for base in bases)
-            if "__annotations__" in ns:
-                types = ns["__annotations__"]
-            elif "__annotate__" in ns:
-                # TODO: Use inspect.VALUE here, and make the annotations lazily evaluated
-                types = ns["__annotate__"](1)
-            else:
-                types = {}
-            default_names = []
-            for field_name in types:
-                if field_name in ns:
-                    default_names.append(field_name)
-                elif default_names:
-                    raise TypeError(f"Non-default namedtuple field {field_name} "
-                                    f"cannot follow default field"
-                                    f"{'s' if len(default_names) > 1 else ''} "
-                                    f"{', '.join(default_names)}")
-            nm_tpl = _make_nmtuple(
-                typename, types.items(),
-                defaults=[ns[n] for n in default_names],
-                module=ns['__module__']
-            )
-            nm_tpl.__bases__ = bases
-            if typing.Generic in bases:
-                if hasattr(typing, '_generic_class_getitem'):  # 3.12+
-                    nm_tpl.__class_getitem__ = classmethod(typing._generic_class_getitem)
-                else:
-                    class_getitem = typing.Generic.__class_getitem__.__func__
-                    nm_tpl.__class_getitem__ = classmethod(class_getitem)
-            # update from user namespace without overriding special namedtuple attributes
-            for key, val in ns.items():
-                if key in _prohibited_namedtuple_fields:
-                    raise AttributeError("Cannot overwrite NamedTuple attribute " + key)
-                elif key not in _special_namedtuple_fields:
-                    if key not in nm_tpl._fields:
-                        setattr(nm_tpl, key, ns[key])
-                    try:
-                        set_name = type(val).__set_name__
-                    except AttributeError:
-                        pass
-                    else:
-                        try:
-                            set_name(val, nm_tpl, key)
-                        except BaseException as e:
-                            msg = (
-                                f"Error calling __set_name__ on {type(val).__name__!r} "
-                                f"instance {key!r} in {typename!r}"
-                            )
-                            # BaseException.add_note() existed on py311,
-                            # but the __set_name__ machinery didn't start
-                            # using add_note() until py312.
-                            # Making sure exceptions are raised in the same way
-                            # as in "normal" classes seems most important here.
-                            if sys.version_info >= (3, 12):
-                                e.add_note(msg)
-                                raise
-                            else:
-                                raise RuntimeError(msg) from e
-
-            if typing.Generic in bases:
-                nm_tpl.__init_subclass__()
-            return nm_tpl
-
-    _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {})
-
-    def _namedtuple_mro_entries(bases):
-        assert NamedTuple in bases
-        return (_NamedTuple,)
-
-    def NamedTuple(typename, fields=_marker, /, **kwargs):
-        """Typed version of namedtuple.
-
-        Usage::
-
-            class Employee(NamedTuple):
-                name: str
-                id: int
-
-        This is equivalent to::
-
-            Employee = collections.namedtuple('Employee', ['name', 'id'])
-
-        The resulting class has an extra __annotations__ attribute, giving a
-        dict that maps field names to types.  (The field names are also in
-        the _fields attribute, which is part of the namedtuple API.)
-        An alternative equivalent functional syntax is also accepted::
-
-            Employee = NamedTuple('Employee', [('name', str), ('id', int)])
-        """
-        if fields is _marker:
-            if kwargs:
-                deprecated_thing = "Creating NamedTuple classes using keyword arguments"
-                deprecation_msg = (
-                    "{name} is deprecated and will be disallowed in Python {remove}. "
-                    "Use the class-based or functional syntax instead."
-                )
-            else:
-                deprecated_thing = "Failing to pass a value for the 'fields' parameter"
-                example = f"`{typename} = NamedTuple({typename!r}, [])`"
-                deprecation_msg = (
-                    "{name} is deprecated and will be disallowed in Python {remove}. "
-                    "To create a NamedTuple class with 0 fields "
-                    "using the functional syntax, "
-                    "pass an empty list, e.g. "
-                ) + example + "."
-        elif fields is None:
-            if kwargs:
-                raise TypeError(
-                    "Cannot pass `None` as the 'fields' parameter "
-                    "and also specify fields using keyword arguments"
-                )
-            else:
-                deprecated_thing = "Passing `None` as the 'fields' parameter"
-                example = f"`{typename} = NamedTuple({typename!r}, [])`"
-                deprecation_msg = (
-                    "{name} is deprecated and will be disallowed in Python {remove}. "
-                    "To create a NamedTuple class with 0 fields "
-                    "using the functional syntax, "
-                    "pass an empty list, e.g. "
-                ) + example + "."
-        elif kwargs:
-            raise TypeError("Either list of fields or keywords"
-                            " can be provided to NamedTuple, not both")
-        if fields is _marker or fields is None:
-            warnings.warn(
-                deprecation_msg.format(name=deprecated_thing, remove="3.15"),
-                DeprecationWarning,
-                stacklevel=2,
-            )
-            fields = kwargs.items()
-        nt = _make_nmtuple(typename, fields, module=_caller())
-        nt.__orig_bases__ = (NamedTuple,)
-        return nt
-
-    NamedTuple.__mro_entries__ = _namedtuple_mro_entries
-
-
-if hasattr(collections.abc, "Buffer"):
-    Buffer = collections.abc.Buffer
-else:
-    class Buffer(abc.ABC):  # noqa: B024
-        """Base class for classes that implement the buffer protocol.
-
-        The buffer protocol allows Python objects to expose a low-level
-        memory buffer interface. Before Python 3.12, it is not possible
-        to implement the buffer protocol in pure Python code, or even
-        to check whether a class implements the buffer protocol. In
-        Python 3.12 and higher, the ``__buffer__`` method allows access
-        to the buffer protocol from Python code, and the
-        ``collections.abc.Buffer`` ABC allows checking whether a class
-        implements the buffer protocol.
-
-        To indicate support for the buffer protocol in earlier versions,
-        inherit from this ABC, either in a stub file or at runtime,
-        or use ABC registration. This ABC provides no methods, because
-        there is no Python-accessible methods shared by pre-3.12 buffer
-        classes. It is useful primarily for static checks.
-
-        """
-
-    # As a courtesy, register the most common stdlib buffer classes.
-    Buffer.register(memoryview)
-    Buffer.register(bytearray)
-    Buffer.register(bytes)
-
-
-# Backport of types.get_original_bases, available on 3.12+ in CPython
-if hasattr(_types, "get_original_bases"):
-    get_original_bases = _types.get_original_bases
-else:
-    def get_original_bases(cls, /):
-        """Return the class's "original" bases prior to modification by `__mro_entries__`.
-
-        Examples::
-
-            from typing import TypeVar, Generic
-            from typing_extensions import NamedTuple, TypedDict
-
-            T = TypeVar("T")
-            class Foo(Generic[T]): ...
-            class Bar(Foo[int], float): ...
-            class Baz(list[str]): ...
-            Eggs = NamedTuple("Eggs", [("a", int), ("b", str)])
-            Spam = TypedDict("Spam", {"a": int, "b": str})
-
-            assert get_original_bases(Bar) == (Foo[int], float)
-            assert get_original_bases(Baz) == (list[str],)
-            assert get_original_bases(Eggs) == (NamedTuple,)
-            assert get_original_bases(Spam) == (TypedDict,)
-            assert get_original_bases(int) == (object,)
-        """
-        try:
-            return cls.__dict__.get("__orig_bases__", cls.__bases__)
-        except AttributeError:
-            raise TypeError(
-                f'Expected an instance of type, not {type(cls).__name__!r}'
-            ) from None
-
-
-# NewType is a class on Python 3.10+, making it pickleable
-# The error message for subclassing instances of NewType was improved on 3.11+
-if sys.version_info >= (3, 11):
-    NewType = typing.NewType
-else:
-    class NewType:
-        """NewType creates simple unique types with almost zero
-        runtime overhead. NewType(name, tp) is considered a subtype of tp
-        by static type checkers. At runtime, NewType(name, tp) returns
-        a dummy callable that simply returns its argument. Usage::
-            UserId = NewType('UserId', int)
-            def name_by_id(user_id: UserId) -> str:
-                ...
-            UserId('user')          # Fails type check
-            name_by_id(42)          # Fails type check
-            name_by_id(UserId(42))  # OK
-            num = UserId(5) + 1     # type: int
-        """
-
-        def __call__(self, obj, /):
-            return obj
-
-        def __init__(self, name, tp):
-            self.__qualname__ = name
-            if '.' in name:
-                name = name.rpartition('.')[-1]
-            self.__name__ = name
-            self.__supertype__ = tp
-            def_mod = _caller()
-            if def_mod != 'typing_extensions':
-                self.__module__ = def_mod
-
-        def __mro_entries__(self, bases):
-            # We defined __mro_entries__ to get a better error message
-            # if a user attempts to subclass a NewType instance. bpo-46170
-            supercls_name = self.__name__
-
-            class Dummy:
-                def __init_subclass__(cls):
-                    subcls_name = cls.__name__
-                    raise TypeError(
-                        f"Cannot subclass an instance of NewType. "
-                        f"Perhaps you were looking for: "
-                        f"`{subcls_name} = NewType({subcls_name!r}, {supercls_name})`"
-                    )
-
-            return (Dummy,)
-
-        def __repr__(self):
-            return f'{self.__module__}.{self.__qualname__}'
-
-        def __reduce__(self):
-            return self.__qualname__
-
-        if sys.version_info >= (3, 10):
-            # PEP 604 methods
-            # It doesn't make sense to have these methods on Python <3.10
-
-            def __or__(self, other):
-                return typing.Union[self, other]
-
-            def __ror__(self, other):
-                return typing.Union[other, self]
-
-
-if sys.version_info >= (3, 14):
-    TypeAliasType = typing.TypeAliasType
-# <=3.13
-else:
-    if sys.version_info >= (3, 12):
-        # 3.12-3.13
-        def _is_unionable(obj):
-            """Corresponds to is_unionable() in unionobject.c in CPython."""
-            return obj is None or isinstance(obj, (
-                type,
-                _types.GenericAlias,
-                _types.UnionType,
-                typing.TypeAliasType,
-                TypeAliasType,
-            ))
-    else:
-        # <=3.11
-        def _is_unionable(obj):
-            """Corresponds to is_unionable() in unionobject.c in CPython."""
-            return obj is None or isinstance(obj, (
-                type,
-                _types.GenericAlias,
-                _types.UnionType,
-                TypeAliasType,
-            ))
-
-    if sys.version_info < (3, 10):
-        # Copied and pasted from https://github.com/python/cpython/blob/986a4e1b6fcae7fe7a1d0a26aea446107dd58dd2/Objects/genericaliasobject.c#L568-L582,
-        # so that we emulate the behaviour of `types.GenericAlias`
-        # on the latest versions of CPython
-        _ATTRIBUTE_DELEGATION_EXCLUSIONS = frozenset({
-            "__class__",
-            "__bases__",
-            "__origin__",
-            "__args__",
-            "__unpacked__",
-            "__parameters__",
-            "__typing_unpacked_tuple_args__",
-            "__mro_entries__",
-            "__reduce_ex__",
-            "__reduce__",
-            "__copy__",
-            "__deepcopy__",
-        })
-
-        class _TypeAliasGenericAlias(typing._GenericAlias, _root=True):
-            def __getattr__(self, attr):
-                if attr in _ATTRIBUTE_DELEGATION_EXCLUSIONS:
-                    return object.__getattr__(self, attr)
-                return getattr(self.__origin__, attr)
-
-
-    class TypeAliasType:
-        """Create named, parameterized type aliases.
-
-        This provides a backport of the new `type` statement in Python 3.12:
-
-            type ListOrSet[T] = list[T] | set[T]
-
-        is equivalent to:
-
-            T = TypeVar("T")
-            ListOrSet = TypeAliasType("ListOrSet", list[T] | set[T], type_params=(T,))
-
-        The name ListOrSet can then be used as an alias for the type it refers to.
-
-        The type_params argument should contain all the type parameters used
-        in the value of the type alias. If the alias is not generic, this
-        argument is omitted.
-
-        Static type checkers should only support type aliases declared using
-        TypeAliasType that follow these rules:
-
-        - The first argument (the name) must be a string literal.
-        - The TypeAliasType instance must be immediately assigned to a variable
-          of the same name. (For example, 'X = TypeAliasType("Y", int)' is invalid,
-          as is 'X, Y = TypeAliasType("X", int), TypeAliasType("Y", int)').
-
-        """
-
-        def __init__(self, name: str, value, *, type_params=()):
-            if not isinstance(name, str):
-                raise TypeError("TypeAliasType name must be a string")
-            if not isinstance(type_params, tuple):
-                raise TypeError("type_params must be a tuple")
-            self.__value__ = value
-            self.__type_params__ = type_params
-
-            default_value_encountered = False
-            parameters = []
-            for type_param in type_params:
-                if (
-                    not isinstance(type_param, (TypeVar, TypeVarTuple, ParamSpec))
-                    # <=3.11
-                    # Unpack Backport passes isinstance(type_param, TypeVar)
-                    or _is_unpack(type_param)
-                ):
-                    raise TypeError(f"Expected a type param, got {type_param!r}")
-                has_default = (
-                    getattr(type_param, '__default__', NoDefault) is not NoDefault
-                )
-                if default_value_encountered and not has_default:
-                    raise TypeError(f"non-default type parameter '{type_param!r}'"
-                                    " follows default type parameter")
-                if has_default:
-                    default_value_encountered = True
-                if isinstance(type_param, TypeVarTuple):
-                    parameters.extend(type_param)
-                else:
-                    parameters.append(type_param)
-            self.__parameters__ = tuple(parameters)
-            def_mod = _caller()
-            if def_mod != 'typing_extensions':
-                self.__module__ = def_mod
-            # Setting this attribute closes the TypeAliasType from further modification
-            self.__name__ = name
-
-        def __setattr__(self, name: str, value: object, /) -> None:
-            if hasattr(self, "__name__"):
-                self._raise_attribute_error(name)
-            super().__setattr__(name, value)
-
-        def __delattr__(self, name: str, /) -> Never:
-            self._raise_attribute_error(name)
-
-        def _raise_attribute_error(self, name: str) -> Never:
-            # Match the Python 3.12 error messages exactly
-            if name == "__name__":
-                raise AttributeError("readonly attribute")
-            elif name in {"__value__", "__type_params__", "__parameters__", "__module__"}:
-                raise AttributeError(
-                    f"attribute '{name}' of 'typing.TypeAliasType' objects "
-                    "is not writable"
-                )
-            else:
-                raise AttributeError(
-                    f"'typing.TypeAliasType' object has no attribute '{name}'"
-                )
-
-        def __repr__(self) -> str:
-            return self.__name__
-
-        if sys.version_info < (3, 11):
-            def _check_single_param(self, param, recursion=0):
-                # Allow [], [int], [int, str], [int, ...], [int, T]
-                if param is ...:
-                    return ...
-                if param is None:
-                    return None
-                # Note in <= 3.9 _ConcatenateGenericAlias inherits from list
-                if isinstance(param, list) and recursion == 0:
-                    return [self._check_single_param(arg, recursion+1)
-                            for arg in param]
-                return typing._type_check(
-                        param, f'Subscripting {self.__name__} requires a type.'
-                    )
-
-        def _check_parameters(self, parameters):
-            if sys.version_info < (3, 11):
-                return tuple(
-                    self._check_single_param(item)
-                    for item in parameters
-                )
-            return tuple(typing._type_check(
-                        item, f'Subscripting {self.__name__} requires a type.'
-                    )
-                    for item in parameters
-            )
-
-        def __getitem__(self, parameters):
-            if not self.__type_params__:
-                raise TypeError("Only generic type aliases are subscriptable")
-            if not isinstance(parameters, tuple):
-                parameters = (parameters,)
-            # Using 3.9 here will create problems with Concatenate
-            if sys.version_info >= (3, 10):
-                return _types.GenericAlias(self, parameters)
-            type_vars = _collect_type_vars(parameters)
-            parameters = self._check_parameters(parameters)
-            alias = _TypeAliasGenericAlias(self, parameters)
-            # alias.__parameters__ is not complete if Concatenate is present
-            # as it is converted to a list from which no parameters are extracted.
-            if alias.__parameters__ != type_vars:
-                alias.__parameters__ = type_vars
-            return alias
-
-        def __reduce__(self):
-            return self.__name__
-
-        def __init_subclass__(cls, *args, **kwargs):
-            raise TypeError(
-                "type 'typing_extensions.TypeAliasType' is not an acceptable base type"
-            )
-
-        # The presence of this method convinces typing._type_check
-        # that TypeAliasTypes are types.
-        def __call__(self):
-            raise TypeError("Type alias is not callable")
-
-        if sys.version_info >= (3, 10):
-            def __or__(self, right):
-                # For forward compatibility with 3.12, reject Unions
-                # that are not accepted by the built-in Union.
-                if not _is_unionable(right):
-                    return NotImplemented
-                return typing.Union[self, right]
-
-            def __ror__(self, left):
-                if not _is_unionable(left):
-                    return NotImplemented
-                return typing.Union[left, self]
-
-
-if hasattr(typing, "is_protocol"):
-    is_protocol = typing.is_protocol
-    get_protocol_members = typing.get_protocol_members
-else:
-    def is_protocol(tp: type, /) -> bool:
-        """Return True if the given type is a Protocol.
-
-        Example::
-
-            >>> from typing_extensions import Protocol, is_protocol
-            >>> class P(Protocol):
-            ...     def a(self) -> str: ...
-            ...     b: int
-            >>> is_protocol(P)
-            True
-            >>> is_protocol(int)
-            False
-        """
-        return (
-            isinstance(tp, type)
-            and getattr(tp, '_is_protocol', False)
-            and tp is not Protocol
-            and tp is not typing.Protocol
-        )
-
-    def get_protocol_members(tp: type, /) -> typing.FrozenSet[str]:
-        """Return the set of members defined in a Protocol.
-
-        Example::
-
-            >>> from typing_extensions import Protocol, get_protocol_members
-            >>> class P(Protocol):
-            ...     def a(self) -> str: ...
-            ...     b: int
-            >>> get_protocol_members(P)
-            frozenset({'a', 'b'})
-
-        Raise a TypeError for arguments that are not Protocols.
-        """
-        if not is_protocol(tp):
-            raise TypeError(f'{tp!r} is not a Protocol')
-        if hasattr(tp, '__protocol_attrs__'):
-            return frozenset(tp.__protocol_attrs__)
-        return frozenset(_get_protocol_attrs(tp))
-
-
-if hasattr(typing, "Doc"):
-    Doc = typing.Doc
-else:
-    class Doc:
-        """Define the documentation of a type annotation using ``Annotated``, to be
-         used in class attributes, function and method parameters, return values,
-         and variables.
-
-        The value should be a positional-only string literal to allow static tools
-        like editors and documentation generators to use it.
-
-        This complements docstrings.
-
-        The string value passed is available in the attribute ``documentation``.
-
-        Example::
-
-            >>> from typing_extensions import Annotated, Doc
-            >>> def hi(to: Annotated[str, Doc("Who to say hi to")]) -> None: ...
-        """
-        def __init__(self, documentation: str, /) -> None:
-            self.documentation = documentation
-
-        def __repr__(self) -> str:
-            return f"Doc({self.documentation!r})"
-
-        def __hash__(self) -> int:
-            return hash(self.documentation)
-
-        def __eq__(self, other: object) -> bool:
-            if not isinstance(other, Doc):
-                return NotImplemented
-            return self.documentation == other.documentation
-
-
-_CapsuleType = getattr(_types, "CapsuleType", None)
-
-if _CapsuleType is None:
-    try:
-        import _socket
-    except ImportError:
-        pass
-    else:
-        _CAPI = getattr(_socket, "CAPI", None)
-        if _CAPI is not None:
-            _CapsuleType = type(_CAPI)
-
-if _CapsuleType is not None:
-    CapsuleType = _CapsuleType
-    __all__.append("CapsuleType")
-
-
-if sys.version_info >= (3,14):
-    from annotationlib import Format, get_annotations
-else:
-    class Format(enum.IntEnum):
-        VALUE = 1
-        VALUE_WITH_FAKE_GLOBALS = 2
-        FORWARDREF = 3
-        STRING = 4
-
-    def get_annotations(obj, *, globals=None, locals=None, eval_str=False,
-                        format=Format.VALUE):
-        """Compute the annotations dict for an object.
-
-        obj may be a callable, class, or module.
-        Passing in an object of any other type raises TypeError.
-
-        Returns a dict.  get_annotations() returns a new dict every time
-        it's called; calling it twice on the same object will return two
-        different but equivalent dicts.
-
-        This is a backport of `inspect.get_annotations`, which has been
-        in the standard library since Python 3.10. See the standard library
-        documentation for more:
-
-            https://docs.python.org/3/library/inspect.html#inspect.get_annotations
-
-        This backport adds the *format* argument introduced by PEP 649. The
-        three formats supported are:
-        * VALUE: the annotations are returned as-is. This is the default and
-          it is compatible with the behavior on previous Python versions.
-        * FORWARDREF: return annotations as-is if possible, but replace any
-          undefined names with ForwardRef objects. The implementation proposed by
-          PEP 649 relies on language changes that cannot be backported; the
-          typing-extensions implementation simply returns the same result as VALUE.
-        * STRING: return annotations as strings, in a format close to the original
-          source. Again, this behavior cannot be replicated directly in a backport.
-          As an approximation, typing-extensions retrieves the annotations under
-          VALUE semantics and then stringifies them.
-
-        The purpose of this backport is to allow users who would like to use
-        FORWARDREF or STRING semantics once PEP 649 is implemented, but who also
-        want to support earlier Python versions, to simply write:
-
-            typing_extensions.get_annotations(obj, format=Format.FORWARDREF)
-
-        """
-        format = Format(format)
-        if format is Format.VALUE_WITH_FAKE_GLOBALS:
-            raise ValueError(
-                "The VALUE_WITH_FAKE_GLOBALS format is for internal use only"
-            )
-
-        if eval_str and format is not Format.VALUE:
-            raise ValueError("eval_str=True is only supported with format=Format.VALUE")
-
-        if isinstance(obj, type):
-            # class
-            obj_dict = getattr(obj, '__dict__', None)
-            if obj_dict and hasattr(obj_dict, 'get'):
-                ann = obj_dict.get('__annotations__', None)
-                if isinstance(ann, _types.GetSetDescriptorType):
-                    ann = None
-            else:
-                ann = None
-
-            obj_globals = None
-            module_name = getattr(obj, '__module__', None)
-            if module_name:
-                module = sys.modules.get(module_name, None)
-                if module:
-                    obj_globals = getattr(module, '__dict__', None)
-            obj_locals = dict(vars(obj))
-            unwrap = obj
-        elif isinstance(obj, _types.ModuleType):
-            # module
-            ann = getattr(obj, '__annotations__', None)
-            obj_globals = obj.__dict__
-            obj_locals = None
-            unwrap = None
-        elif callable(obj):
-            # this includes types.Function, types.BuiltinFunctionType,
-            # types.BuiltinMethodType, functools.partial, functools.singledispatch,
-            # "class funclike" from Lib/test/test_inspect... on and on it goes.
-            ann = getattr(obj, '__annotations__', None)
-            obj_globals = getattr(obj, '__globals__', None)
-            obj_locals = None
-            unwrap = obj
-        elif hasattr(obj, '__annotations__'):
-            ann = obj.__annotations__
-            obj_globals = obj_locals = unwrap = None
-        else:
-            raise TypeError(f"{obj!r} is not a module, class, or callable.")
-
-        if ann is None:
-            return {}
-
-        if not isinstance(ann, dict):
-            raise ValueError(f"{obj!r}.__annotations__ is neither a dict nor None")
-
-        if not ann:
-            return {}
-
-        if not eval_str:
-            if format is Format.STRING:
-                return {
-                    key: value if isinstance(value, str) else typing._type_repr(value)
-                    for key, value in ann.items()
-                }
-            return dict(ann)
-
-        if unwrap is not None:
-            while True:
-                if hasattr(unwrap, '__wrapped__'):
-                    unwrap = unwrap.__wrapped__
-                    continue
-                if isinstance(unwrap, functools.partial):
-                    unwrap = unwrap.func
-                    continue
-                break
-            if hasattr(unwrap, "__globals__"):
-                obj_globals = unwrap.__globals__
-
-        if globals is None:
-            globals = obj_globals
-        if locals is None:
-            locals = obj_locals or {}
-
-        # "Inject" type parameters into the local namespace
-        # (unless they are shadowed by assignments *in* the local namespace),
-        # as a way of emulating annotation scopes when calling `eval()`
-        if type_params := getattr(obj, "__type_params__", ()):
-            locals = {param.__name__: param for param in type_params} | locals
-
-        return_value = {key:
-            value if not isinstance(value, str) else eval(value, globals, locals)
-            for key, value in ann.items() }
-        return return_value
-
-
-if hasattr(typing, "evaluate_forward_ref"):
-    evaluate_forward_ref = typing.evaluate_forward_ref
-else:
-    # Implements annotationlib.ForwardRef.evaluate
-    def _eval_with_owner(
-        forward_ref, *, owner=None, globals=None, locals=None, type_params=None
-    ):
-        if forward_ref.__forward_evaluated__:
-            return forward_ref.__forward_value__
-        if getattr(forward_ref, "__cell__", None) is not None:
-            try:
-                value = forward_ref.__cell__.cell_contents
-            except ValueError:
-                pass
-            else:
-                forward_ref.__forward_evaluated__ = True
-                forward_ref.__forward_value__ = value
-                return value
-        if owner is None:
-            owner = getattr(forward_ref, "__owner__", None)
-
-        if (
-            globals is None
-            and getattr(forward_ref, "__forward_module__", None) is not None
-        ):
-            globals = getattr(
-                sys.modules.get(forward_ref.__forward_module__, None), "__dict__", None
-            )
-        if globals is None:
-            globals = getattr(forward_ref, "__globals__", None)
-        if globals is None:
-            if isinstance(owner, type):
-                module_name = getattr(owner, "__module__", None)
-                if module_name:
-                    module = sys.modules.get(module_name, None)
-                    if module:
-                        globals = getattr(module, "__dict__", None)
-            elif isinstance(owner, _types.ModuleType):
-                globals = getattr(owner, "__dict__", None)
-            elif callable(owner):
-                globals = getattr(owner, "__globals__", None)
-
-        # If we pass None to eval() below, the globals of this module are used.
-        if globals is None:
-            globals = {}
-
-        if locals is None:
-            locals = {}
-            if isinstance(owner, type):
-                locals.update(vars(owner))
-
-        if type_params is None and owner is not None:
-            # "Inject" type parameters into the local namespace
-            # (unless they are shadowed by assignments *in* the local namespace),
-            # as a way of emulating annotation scopes when calling `eval()`
-            type_params = getattr(owner, "__type_params__", None)
-
-        # type parameters require some special handling,
-        # as they exist in their own scope
-        # but `eval()` does not have a dedicated parameter for that scope.
-        # For classes, names in type parameter scopes should override
-        # names in the global scope (which here are called `localns`!),
-        # but should in turn be overridden by names in the class scope
-        # (which here are called `globalns`!)
-        if type_params is not None:
-            globals = dict(globals)
-            locals = dict(locals)
-            for param in type_params:
-                param_name = param.__name__
-                if (
-                    _FORWARD_REF_HAS_CLASS and not forward_ref.__forward_is_class__
-                ) or param_name not in globals:
-                    globals[param_name] = param
-                    locals.pop(param_name, None)
-
-        arg = forward_ref.__forward_arg__
-        if arg.isidentifier() and not keyword.iskeyword(arg):
-            if arg in locals:
-                value = locals[arg]
-            elif arg in globals:
-                value = globals[arg]
-            elif hasattr(builtins, arg):
-                return getattr(builtins, arg)
-            else:
-                raise NameError(arg)
-        else:
-            code = forward_ref.__forward_code__
-            value = eval(code, globals, locals)
-        forward_ref.__forward_evaluated__ = True
-        forward_ref.__forward_value__ = value
-        return value
-
-    def evaluate_forward_ref(
-        forward_ref,
-        *,
-        owner=None,
-        globals=None,
-        locals=None,
-        type_params=None,
-        format=None,
-        _recursive_guard=frozenset(),
-    ):
-        """Evaluate a forward reference as a type hint.
-
-        This is similar to calling the ForwardRef.evaluate() method,
-        but unlike that method, evaluate_forward_ref() also:
-
-        * Recursively evaluates forward references nested within the type hint.
-        * Rejects certain objects that are not valid type hints.
-        * Replaces type hints that evaluate to None with types.NoneType.
-        * Supports the *FORWARDREF* and *STRING* formats.
-
-        *forward_ref* must be an instance of ForwardRef. *owner*, if given,
-        should be the object that holds the annotations that the forward reference
-        derived from, such as a module, class object, or function. It is used to
-        infer the namespaces to use for looking up names. *globals* and *locals*
-        can also be explicitly given to provide the global and local namespaces.
-        *type_params* is a tuple of type parameters that are in scope when
-        evaluating the forward reference. This parameter must be provided (though
-        it may be an empty tuple) if *owner* is not given and the forward reference
-        does not already have an owner set. *format* specifies the format of the
-        annotation and is a member of the annotationlib.Format enum.
-
-        """
-        if format == Format.STRING:
-            return forward_ref.__forward_arg__
-        if forward_ref.__forward_arg__ in _recursive_guard:
-            return forward_ref
-
-        # Evaluate the forward reference
-        try:
-            value = _eval_with_owner(
-                forward_ref,
-                owner=owner,
-                globals=globals,
-                locals=locals,
-                type_params=type_params,
-            )
-        except NameError:
-            if format == Format.FORWARDREF:
-                return forward_ref
-            else:
-                raise
-
-        if isinstance(value, str):
-            value = ForwardRef(value)
-
-        # Recursively evaluate the type
-        if isinstance(value, ForwardRef):
-            if getattr(value, "__forward_module__", True) is not None:
-                globals = None
-            return evaluate_forward_ref(
-                value,
-                globals=globals,
-                locals=locals,
-                 type_params=type_params, owner=owner,
-                _recursive_guard=_recursive_guard, format=format
-            )
-        if sys.version_info < (3, 12, 5) and type_params:
-            # Make use of type_params
-            locals = dict(locals) if locals else {}
-            for tvar in type_params:
-                if tvar.__name__ not in locals:  # lets not overwrite something present
-                    locals[tvar.__name__] = tvar
-        if sys.version_info < (3, 12, 5):
-            return typing._eval_type(
-                value,
-                globals,
-                locals,
-                recursive_guard=_recursive_guard | {forward_ref.__forward_arg__},
-            )
-        else:
-            return typing._eval_type(
-                value,
-                globals,
-                locals,
-                type_params,
-                recursive_guard=_recursive_guard | {forward_ref.__forward_arg__},
-            )
-
-
-class Sentinel:
-    """Create a unique sentinel object.
-
-    *name* should be the name of the variable to which the return value shall be assigned.
-
-    *repr*, if supplied, will be used for the repr of the sentinel object.
-    If not provided, "" will be used.
-    """
-
-    def __init__(
-        self,
-        name: str,
-        repr: typing.Optional[str] = None,
-    ):
-        self._name = name
-        self._repr = repr if repr is not None else f'<{name}>'
-
-    def __repr__(self):
-        return self._repr
-
-    if sys.version_info < (3, 11):
-        # The presence of this method convinces typing._type_check
-        # that Sentinels are types.
-        def __call__(self, *args, **kwargs):
-            raise TypeError(f"{type(self).__name__!r} object is not callable")
-
-    if sys.version_info >= (3, 10):
-        def __or__(self, other):
-            return typing.Union[self, other]
-
-        def __ror__(self, other):
-            return typing.Union[other, self]
-
-    def __getstate__(self):
-        raise TypeError(f"Cannot pickle {type(self).__name__!r} object")
-
-
-# Aliases for items that are in typing in all supported versions.
-# We use hasattr() checks so this library will continue to import on
-# future versions of Python that may remove these names.
-_typing_names = [
-    "AbstractSet",
-    "AnyStr",
-    "BinaryIO",
-    "Callable",
-    "Collection",
-    "Container",
-    "Dict",
-    "FrozenSet",
-    "Hashable",
-    "IO",
-    "ItemsView",
-    "Iterable",
-    "Iterator",
-    "KeysView",
-    "List",
-    "Mapping",
-    "MappingView",
-    "Match",
-    "MutableMapping",
-    "MutableSequence",
-    "MutableSet",
-    "Optional",
-    "Pattern",
-    "Reversible",
-    "Sequence",
-    "Set",
-    "Sized",
-    "TextIO",
-    "Tuple",
-    "Union",
-    "ValuesView",
-    "cast",
-    "no_type_check",
-    "no_type_check_decorator",
-    # This is private, but it was defined by typing_extensions for a long time
-    # and some users rely on it.
-    "_AnnotatedAlias",
-]
-globals().update(
-    {name: getattr(typing, name) for name in _typing_names if hasattr(typing, name)}
-)
-# These are defined unconditionally because they are used in
-# typing-extensions itself.
-Generic = typing.Generic
-ForwardRef = typing.ForwardRef
-Annotated = typing.Annotated
diff --git a/server/libs/voluptuous-0.15.2.dist-info/COPYING b/server/libs/voluptuous-0.15.2.dist-info/COPYING
deleted file mode 100644
index a19b705..0000000
--- a/server/libs/voluptuous-0.15.2.dist-info/COPYING
+++ /dev/null
@@ -1,25 +0,0 @@
-Copyright (c) 2010, Alec Thomas
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- - Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
- - Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
- - Neither the name of SwapOff.org nor the names of its contributors may
-   be used to endorse or promote products derived from this software without
-   specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/server/libs/voluptuous-0.15.2.dist-info/INSTALLER b/server/libs/voluptuous-0.15.2.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/server/libs/voluptuous-0.15.2.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/server/libs/voluptuous-0.15.2.dist-info/METADATA b/server/libs/voluptuous-0.15.2.dist-info/METADATA
deleted file mode 100644
index 85d2ef1..0000000
--- a/server/libs/voluptuous-0.15.2.dist-info/METADATA
+++ /dev/null
@@ -1,743 +0,0 @@
-Metadata-Version: 2.1
-Name: voluptuous
-Version: 0.15.2
-Summary: Python data validation library
-Home-page: https://github.com/alecthomas/voluptuous
-Download-URL: https://pypi.python.org/pypi/voluptuous
-Author: Alec Thomas
-Author-email: alec@swapoff.org
-License: BSD-3-Clause
-Platform: any
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: 3.12
-Requires-Python: >=3.9
-Description-Content-Type: text/markdown
-License-File: COPYING
-
-
-# CONTRIBUTIONS ONLY
-
-**What does this mean?** I do not have time to fix issues myself. The only way fixes or new features will be added is by people submitting PRs.
-
-**Current status:** Voluptuous is largely feature stable. There hasn't been a need to add new features in a while, but there are some bugs that should be fixed.
-
-**Why?** I no longer use Voluptuous personally (in fact I no longer regularly write Python code). Rather than leave the project in a limbo of people filing issues and wondering why they're not being worked on, I believe this notice will more clearly set expectations.
-
-# Voluptuous is a Python data validation library
-
-[![image](https://img.shields.io/pypi/v/voluptuous.svg)](https://python.org/pypi/voluptuous)
-[![image](https://img.shields.io/pypi/l/voluptuous.svg)](https://python.org/pypi/voluptuous)
-[![image](https://img.shields.io/pypi/pyversions/voluptuous.svg)](https://python.org/pypi/voluptuous)
-[![Test status](https://github.com/alecthomas/voluptuous/actions/workflows/tests.yml/badge.svg)](https://github.com/alecthomas/voluptuous/actions/workflows/tests.yml)
-[![Coverage status](https://coveralls.io/repos/github/alecthomas/voluptuous/badge.svg?branch=master)](https://coveralls.io/github/alecthomas/voluptuous?branch=master)
-[![Gitter chat](https://badges.gitter.im/alecthomas.svg)](https://gitter.im/alecthomas/Lobby)
-
-Voluptuous, *despite* the name, is a Python data validation library. It
-is primarily intended for validating data coming into Python as JSON,
-YAML, etc.
-
-It has three goals:
-
-1. Simplicity.
-2. Support for complex data structures.
-3. Provide useful error messages.
-
-## Contact
-
-Voluptuous now has a mailing list! Send a mail to
-[](mailto:voluptuous@librelist.com) to subscribe. Instructions
-will follow.
-
-You can also contact me directly via [email](mailto:alec@swapoff.org) or
-[Twitter](https://twitter.com/alecthomas).
-
-To file a bug, create a [new issue](https://github.com/alecthomas/voluptuous/issues/new) on GitHub with a short example of how to replicate the issue.
-
-## Documentation
-
-The documentation is provided [here](http://alecthomas.github.io/voluptuous/).
-
-## Contribution to Documentation
-
-Documentation is built using `Sphinx`. You can install it by
-
-    pip install -r requirements.txt
-
-For building `sphinx-apidoc` from scratch you need to set PYTHONPATH to `voluptuous/voluptuous` repository.
-
-The documentation is provided [here.](http://alecthomas.github.io/voluptuous/)
-
-## Changelog
-
-See [CHANGELOG.md](https://github.com/alecthomas/voluptuous/blob/master/CHANGELOG.md).
-
-## Why use Voluptuous over another validation library?
-
-**Validators are simple callables:**
-No need to subclass anything, just use a function.
-
-**Errors are simple exceptions:**
-A validator can just `raise Invalid(msg)` and expect the user to get
-useful messages.
-
-**Schemas are basic Python data structures:**
-Should your data be a dictionary of integer keys to strings?
-`{int: str}` does what you expect. List of integers, floats or
-strings? `[int, float, str]`.
-
-**Designed from the ground up for validating more than just forms:**
-Nested data structures are treated in the same way as any other
-type. Need a list of dictionaries? `[{}]`
-
-**Consistency:**
-Types in the schema are checked as types. Values are compared as
-values. Callables are called to validate. Simple.
-
-## Show me an example
-
-Twitter's [user search API](https://dev.twitter.com/rest/reference/get/users/search) accepts
-query URLs like:
-
-```bash
-$ curl 'https://api.twitter.com/1.1/users/search.json?q=python&per_page=20&page=1'
-```
-
-To validate this we might use a schema like:
-
-```pycon
->>> from voluptuous import Schema
->>> schema = Schema({
-...   'q': str,
-...   'per_page': int,
-...   'page': int,
-... })
-```
-
-This schema very succinctly and roughly describes the data required by
-the API, and will work fine. But it has a few problems. Firstly, it
-doesn't fully express the constraints of the API. According to the API,
-`per_page` should be restricted to at most 20, defaulting to 5, for
-example. To describe the semantics of the API more accurately, our
-schema will need to be more thoroughly defined:
-
-```pycon
->>> from voluptuous import Required, All, Length, Range
->>> schema = Schema({
-...   Required('q'): All(str, Length(min=1)),
-...   Required('per_page', default=5): All(int, Range(min=1, max=20)),
-...   'page': All(int, Range(min=0)),
-... })
-```
-
-This schema fully enforces the interface defined in Twitter's
-documentation, and goes a little further for completeness.
-
-"q" is required:
-
-```pycon
->>> from voluptuous import MultipleInvalid, Invalid
->>> try:
-...   schema({})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "required key not provided @ data['q']"
-True
-```
-
-...must be a string:
-
-```pycon
->>> try:
-...   schema({'q': 123})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "expected str for dictionary value @ data['q']"
-True
-```
-
-...and must be at least one character in length:
-
-```pycon
->>> try:
-...   schema({'q': ''})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "length of value must be at least 1 for dictionary value @ data['q']"
-True
->>> schema({'q': '#topic'}) == {'q': '#topic', 'per_page': 5}
-True
-```
-
-"per\_page" is a positive integer no greater than 20:
-
-```pycon
->>> try:
-...   schema({'q': '#topic', 'per_page': 900})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "value must be at most 20 for dictionary value @ data['per_page']"
-True
->>> try:
-...   schema({'q': '#topic', 'per_page': -10})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "value must be at least 1 for dictionary value @ data['per_page']"
-True
-```
-
-"page" is an integer \>= 0:
-
-```pycon
->>> try:
-...   schema({'q': '#topic', 'per_page': 'one'})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc)
-"expected int for dictionary value @ data['per_page']"
->>> schema({'q': '#topic', 'page': 1}) == {'q': '#topic', 'page': 1, 'per_page': 5}
-True
-```
-
-## Defining schemas
-
-Schemas are nested data structures consisting of dictionaries, lists,
-scalars and *validators*. Each node in the input schema is pattern
-matched against corresponding nodes in the input data.
-
-### Literals
-
-Literals in the schema are matched using normal equality checks:
-
-```pycon
->>> schema = Schema(1)
->>> schema(1)
-1
->>> schema = Schema('a string')
->>> schema('a string')
-'a string'
-```
-
-### Types
-
-Types in the schema are matched by checking if the corresponding value
-is an instance of the type:
-
-```pycon
->>> schema = Schema(int)
->>> schema(1)
-1
->>> try:
-...   schema('one')
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "expected int"
-True
-```
-
-### URLs
-
-URLs in the schema are matched by using `urlparse` library.
-
-```pycon
->>> from voluptuous import Url
->>> schema = Schema(Url())
->>> schema('http://w3.org')
-'http://w3.org'
->>> try:
-...   schema('one')
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "expected a URL"
-True
-```
-
-### Lists
-
-Lists in the schema are treated as a set of valid values. Each element
-in the schema list is compared to each value in the input data:
-
-```pycon
->>> schema = Schema([1, 'a', 'string'])
->>> schema([1])
-[1]
->>> schema([1, 1, 1])
-[1, 1, 1]
->>> schema(['a', 1, 'string', 1, 'string'])
-['a', 1, 'string', 1, 'string']
-```
-
-However, an empty list (`[]`) is treated as is. If you want to specify a list that can
-contain anything, specify it as `list`:
-
-```pycon
->>> schema = Schema([])
->>> try:
-...   schema([1])
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "not a valid value @ data[1]"
-True
->>> schema([])
-[]
->>> schema = Schema(list)
->>> schema([])
-[]
->>> schema([1, 2])
-[1, 2]
-```
-
-### Sets and frozensets
-
-Sets and frozensets are treated as a set of valid values. Each element
-in the schema set is compared to each value in the input data:
-
-```pycon
->>> schema = Schema({42})
->>> schema({42}) == {42}
-True
->>> try:
-...   schema({43})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "invalid value in set"
-True
->>> schema = Schema({int})
->>> schema({1, 2, 3}) == {1, 2, 3}
-True
->>> schema = Schema({int, str})
->>> schema({1, 2, 'abc'}) == {1, 2, 'abc'}
-True
->>> schema = Schema(frozenset([int]))
->>> try:
-...   schema({3})
-...   raise AssertionError('Invalid not raised')
-... except Invalid as e:
-...   exc = e
->>> str(exc) == 'expected a frozenset'
-True
-```
-
-However, an empty set (`set()`) is treated as is. If you want to specify a set
-that can contain anything, specify it as `set`:
-
-```pycon
->>> schema = Schema(set())
->>> try:
-...   schema({1})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "invalid value in set"
-True
->>> schema(set()) == set()
-True
->>> schema = Schema(set)
->>> schema({1, 2}) == {1, 2}
-True
-```
-
-### Validation functions
-
-Validators are simple callables that raise an `Invalid` exception when
-they encounter invalid data. The criteria for determining validity is
-entirely up to the implementation; it may check that a value is a valid
-username with `pwd.getpwnam()`, it may check that a value is of a
-specific type, and so on.
-
-The simplest kind of validator is a Python function that raises
-ValueError when its argument is invalid. Conveniently, many builtin
-Python functions have this property. Here's an example of a date
-validator:
-
-```pycon
->>> from datetime import datetime
->>> def Date(fmt='%Y-%m-%d'):
-...   return lambda v: datetime.strptime(v, fmt)
-```
-
-```pycon
->>> schema = Schema(Date())
->>> schema('2013-03-03')
-datetime.datetime(2013, 3, 3, 0, 0)
->>> try:
-...   schema('2013-03')
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "not a valid value"
-True
-```
-
-In addition to simply determining if a value is valid, validators may
-mutate the value into a valid form. An example of this is the
-`Coerce(type)` function, which returns a function that coerces its
-argument to the given type:
-
-```python
-def Coerce(type, msg=None):
-    """Coerce a value to a type.
-
-    If the type constructor throws a ValueError, the value will be marked as
-    Invalid.
-    """
-    def f(v):
-        try:
-            return type(v)
-        except ValueError:
-            raise Invalid(msg or ('expected %s' % type.__name__))
-    return f
-```
-
-This example also shows a common idiom where an optional human-readable
-message can be provided. This can vastly improve the usefulness of the
-resulting error messages.
-
-### Dictionaries
-
-Each key-value pair in a schema dictionary is validated against each
-key-value pair in the corresponding data dictionary:
-
-```pycon
->>> schema = Schema({1: 'one', 2: 'two'})
->>> schema({1: 'one'})
-{1: 'one'}
-```
-
-#### Extra dictionary keys
-
-By default any additional keys in the data, not in the schema will
-trigger exceptions:
-
-```pycon
->>> schema = Schema({2: 3})
->>> try:
-...   schema({1: 2, 2: 3})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "extra keys not allowed @ data[1]"
-True
-```
-
-This behaviour can be altered on a per-schema basis. To allow
-additional keys use
-`Schema(..., extra=ALLOW_EXTRA)`:
-
-```pycon
->>> from voluptuous import ALLOW_EXTRA
->>> schema = Schema({2: 3}, extra=ALLOW_EXTRA)
->>> schema({1: 2, 2: 3})
-{1: 2, 2: 3}
-```
-
-To remove additional keys use
-`Schema(..., extra=REMOVE_EXTRA)`:
-
-```pycon
->>> from voluptuous import REMOVE_EXTRA
->>> schema = Schema({2: 3}, extra=REMOVE_EXTRA)
->>> schema({1: 2, 2: 3})
-{2: 3}
-```
-
-It can also be overridden per-dictionary by using the catch-all marker
-token `extra` as a key:
-
-```pycon
->>> from voluptuous import Extra
->>> schema = Schema({1: {Extra: object}})
->>> schema({1: {'foo': 'bar'}})
-{1: {'foo': 'bar'}}
-```
-
-#### Required dictionary keys
-
-By default, keys in the schema are not required to be in the data:
-
-```pycon
->>> schema = Schema({1: 2, 3: 4})
->>> schema({3: 4})
-{3: 4}
-```
-
-Similarly to how extra\_ keys work, this behaviour can be overridden
-per-schema:
-
-```pycon
->>> schema = Schema({1: 2, 3: 4}, required=True)
->>> try:
-...   schema({3: 4})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "required key not provided @ data[1]"
-True
-```
-
-And per-key, with the marker token `Required(key)`:
-
-```pycon
->>> schema = Schema({Required(1): 2, 3: 4})
->>> try:
-...   schema({3: 4})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "required key not provided @ data[1]"
-True
->>> schema({1: 2})
-{1: 2}
-```
-
-#### Optional dictionary keys
-
-If a schema has `required=True`, keys may be individually marked as
-optional using the marker token `Optional(key)`:
-
-```pycon
->>> from voluptuous import Optional
->>> schema = Schema({1: 2, Optional(3): 4}, required=True)
->>> try:
-...   schema({})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "required key not provided @ data[1]"
-True
->>> schema({1: 2})
-{1: 2}
->>> try:
-...   schema({1: 2, 4: 5})
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "extra keys not allowed @ data[4]"
-True
-```
-
-```pycon
->>> schema({1: 2, 3: 4})
-{1: 2, 3: 4}
-```
-
-### Recursive / nested schema
-
-You can use `voluptuous.Self` to define a nested schema:
-
-```pycon
->>> from voluptuous import Schema, Self
->>> recursive = Schema({"more": Self, "value": int})
->>> recursive({"more": {"value": 42}, "value": 41}) == {'more': {'value': 42}, 'value': 41}
-True
-```
-
-### Extending an existing Schema
-
-Often it comes handy to have a base `Schema` that is extended with more
-requirements. In that case you can use `Schema.extend` to create a new
-`Schema`:
-
-```pycon
->>> from voluptuous import Schema
->>> person = Schema({'name': str})
->>> person_with_age = person.extend({'age': int})
->>> sorted(list(person_with_age.schema.keys()))
-['age', 'name']
-```
-
-The original `Schema` remains unchanged.
-
-### Objects
-
-Each key-value pair in a schema dictionary is validated against each
-attribute-value pair in the corresponding object:
-
-```pycon
->>> from voluptuous import Object
->>> class Structure(object):
-...     def __init__(self, q=None):
-...         self.q = q
-...     def __repr__(self):
-...         return ''.format(self)
-...
->>> schema = Schema(Object({'q': 'one'}, cls=Structure))
->>> schema(Structure(q='one'))
-
-```
-
-### Allow None values
-
-To allow value to be None as well, use Any:
-
-```pycon
->>> from voluptuous import Any
-
->>> schema = Schema(Any(None, int))
->>> schema(None)
->>> schema(5)
-5
-```
-
-## Error reporting
-
-Validators must throw an `Invalid` exception if invalid data is passed
-to them. All other exceptions are treated as errors in the validator and
-will not be caught.
-
-Each `Invalid` exception has an associated `path` attribute representing
-the path in the data structure to our currently validating value, as well
-as an `error_message` attribute that contains the message of the original
-exception. This is especially useful when you want to catch `Invalid`
-exceptions and give some feedback to the user, for instance in the context of
-an HTTP API.
-
-```pycon
->>> def validate_email(email):
-...     """Validate email."""
-...     if not "@" in email:
-...         raise Invalid("This email is invalid.")
-...     return email
->>> schema = Schema({"email": validate_email})
->>> exc = None
->>> try:
-...     schema({"email": "whatever"})
-... except MultipleInvalid as e:
-...     exc = e
->>> str(exc)
-"This email is invalid. for dictionary value @ data['email']"
->>> exc.path
-['email']
->>> exc.msg
-'This email is invalid.'
->>> exc.error_message
-'This email is invalid.'
-```
-
-The `path` attribute is used during error reporting, but also during matching
-to determine whether an error should be reported to the user or if the next
-match should be attempted. This is determined by comparing the depth of the
-path where the check is, to the depth of the path where the error occurred. If
-the error is more than one level deeper, it is reported.
-
-The upshot of this is that *matching is depth-first and fail-fast*.
-
-To illustrate this, here is an example schema:
-
-```pycon
->>> schema = Schema([[2, 3], 6])
-```
-
-Each value in the top-level list is matched depth-first in-order. Given
-input data of `[[6]]`, the inner list will match the first element of
-the schema, but the literal `6` will not match any of the elements of
-that list. This error will be reported back to the user immediately. No
-backtracking is attempted:
-
-```pycon
->>> try:
-...   schema([[6]])
-...   raise AssertionError('MultipleInvalid not raised')
-... except MultipleInvalid as e:
-...   exc = e
->>> str(exc) == "not a valid value @ data[0][0]"
-True
-```
-
-If we pass the data `[6]`, the `6` is not a list type and so will not
-recurse into the first element of the schema. Matching will continue on
-to the second element in the schema, and succeed:
-
-```pycon
->>> schema([6])
-[6]
-```
-
-## Multi-field validation
-
-Validation rules that involve multiple fields can be implemented as
-custom validators. It's recommended to use `All()` to do a two-pass
-validation - the first pass checking the basic structure of the data,
-and only after that, the second pass applying your cross-field
-validator:
-
-```python
-def passwords_must_match(passwords):
-    if passwords['password'] != passwords['password_again']:
-        raise Invalid('passwords must match')
-    return passwords
-
-schema = Schema(All(
-    # First "pass" for field types
-    {'password': str, 'password_again': str},
-    # Follow up the first "pass" with your multi-field rules
-    passwords_must_match
-))
-
-# valid
-schema({'password': '123', 'password_again': '123'})
-
-# raises MultipleInvalid: passwords must match
-schema({'password': '123', 'password_again': 'and now for something completely different'})
-
-```
-
-With this structure, your multi-field validator will run with
-pre-validated data from the first "pass" and so will not have to do
-its own type checking on its inputs.
-
-The flipside is that if the first "pass" of validation fails, your
-cross-field validator will not run:
-
-```python
-# raises Invalid because password_again is not a string
-# passwords_must_match() will not run because first-pass validation already failed
-schema({'password': '123', 'password_again': 1337})
-```
-
-## Running tests
-
-Voluptuous is using `pytest`:
-
-```bash
-$ pip install pytest
-$ pytest
-```
-
-To also include a coverage report:
-
-```bash
-$ pip install pytest pytest-cov coverage>=3.0
-$ pytest --cov=voluptuous voluptuous/tests/
-```
-
-## Other libraries and inspirations
-
-Voluptuous is heavily inspired by
-[Validino](http://code.google.com/p/validino/), and to a lesser extent,
-[jsonvalidator](http://code.google.com/p/jsonvalidator/) and
-[json\_schema](http://blog.sendapatch.se/category/json_schema.html).
-
-[pytest-voluptuous](https://github.com/F-Secure/pytest-voluptuous) is a
-[pytest](https://github.com/pytest-dev/pytest) plugin that helps in
-using voluptuous validators in `assert`s.
-
-I greatly prefer the light-weight style promoted by these libraries to
-the complexity of libraries like FormEncode.
-
diff --git a/server/libs/voluptuous-0.15.2.dist-info/RECORD b/server/libs/voluptuous-0.15.2.dist-info/RECORD
deleted file mode 100644
index 07b7692..0000000
--- a/server/libs/voluptuous-0.15.2.dist-info/RECORD
+++ /dev/null
@@ -1,20 +0,0 @@
-voluptuous-0.15.2.dist-info/COPYING,sha256=JHtJdren-k2J2Vh8qlCVVh60bcVFfyJ59ipitUUq3qk,1486
-voluptuous-0.15.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-voluptuous-0.15.2.dist-info/METADATA,sha256=skO8Rp2Rq3VpxIPpE5LWhWiiWWXWHf9HL_-TFOkEz60,20641
-voluptuous-0.15.2.dist-info/RECORD,,
-voluptuous-0.15.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-voluptuous-0.15.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
-voluptuous-0.15.2.dist-info/top_level.txt,sha256=TTdVb7M-vndb67UqTmAxuVjpAUakrlAWJYqvo3w4Iqc,11
-voluptuous/__init__.py,sha256=6_S65O_9lnoewl5dQSLIz_BKrsfxmOK-lG_i3Djd8Z8,2227
-voluptuous/__pycache__/__init__.cpython-311.pyc,,
-voluptuous/__pycache__/error.cpython-311.pyc,,
-voluptuous/__pycache__/humanize.cpython-311.pyc,,
-voluptuous/__pycache__/schema_builder.cpython-311.pyc,,
-voluptuous/__pycache__/util.cpython-311.pyc,,
-voluptuous/__pycache__/validators.cpython-311.pyc,,
-voluptuous/error.py,sha256=qipmadJhLycX4zIju6j8T8rjJHiiELVDv3CSoBCDnwM,4606
-voluptuous/humanize.py,sha256=CWBrrE6fK73iOM19w1CK9_f_Qrc92u2PQIjngG8-EC0,1905
-voluptuous/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-voluptuous/schema_builder.py,sha256=QDt5o1ZtLdqTtOd5IVzKczNBPftLKGk77Cz4UFJUD0g,43730
-voluptuous/util.py,sha256=BNxkVJZ6qbg8pDWY_TOMloLLgNgzixV1ZQ9rhTdbFgs,3174
-voluptuous/validators.py,sha256=wp3fmKr-KC7saw8aeUWw1CLOoxwrcj8YiteXJN9eUIQ,36501
diff --git a/server/libs/voluptuous-0.15.2.dist-info/REQUESTED b/server/libs/voluptuous-0.15.2.dist-info/REQUESTED
deleted file mode 100644
index e69de29..0000000
diff --git a/server/libs/voluptuous-0.15.2.dist-info/WHEEL b/server/libs/voluptuous-0.15.2.dist-info/WHEEL
deleted file mode 100644
index bab98d6..0000000
--- a/server/libs/voluptuous-0.15.2.dist-info/WHEEL
+++ /dev/null
@@ -1,5 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.43.0)
-Root-Is-Purelib: true
-Tag: py3-none-any
-
diff --git a/server/libs/voluptuous-0.15.2.dist-info/top_level.txt b/server/libs/voluptuous-0.15.2.dist-info/top_level.txt
deleted file mode 100644
index 55356d5..0000000
--- a/server/libs/voluptuous-0.15.2.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-voluptuous
diff --git a/server/libs/voluptuous/__init__.py b/server/libs/voluptuous/__init__.py
deleted file mode 100644
index d030b35..0000000
--- a/server/libs/voluptuous/__init__.py
+++ /dev/null
@@ -1,88 +0,0 @@
-"""Schema validation for Python data structures.
-
-Given eg. a nested data structure like this:
-
-    {
-        'exclude': ['Users', 'Uptime'],
-        'include': [],
-        'set': {
-            'snmp_community': 'public',
-            'snmp_timeout': 15,
-            'snmp_version': '2c',
-        },
-        'targets': {
-            'localhost': {
-                'exclude': ['Uptime'],
-                'features': {
-                    'Uptime': {
-                        'retries': 3,
-                    },
-                    'Users': {
-                        'snmp_community': 'monkey',
-                        'snmp_port': 15,
-                    },
-                },
-                'include': ['Users'],
-                'set': {
-                    'snmp_community': 'monkeys',
-                },
-            },
-        },
-    }
-
-A schema like this:
-
-    >>> settings = {
-    ...   'snmp_community': str,
-    ...   'retries': int,
-    ...   'snmp_version': All(Coerce(str), Any('3', '2c', '1')),
-    ... }
-    >>> features = ['Ping', 'Uptime', 'Http']
-    >>> schema = Schema({
-    ...    'exclude': features,
-    ...    'include': features,
-    ...    'set': settings,
-    ...    'targets': {
-    ...      'exclude': features,
-    ...      'include': features,
-    ...      'features': {
-    ...        str: settings,
-    ...      },
-    ...    },
-    ... })
-
-Validate like so:
-
-    >>> schema({
-    ...   'set': {
-    ...     'snmp_community': 'public',
-    ...     'snmp_version': '2c',
-    ...   },
-    ...   'targets': {
-    ...     'exclude': ['Ping'],
-    ...     'features': {
-    ...       'Uptime': {'retries': 3},
-    ...       'Users': {'snmp_community': 'monkey'},
-    ...     },
-    ...   },
-    ... }) == {
-    ...   'set': {'snmp_version': '2c', 'snmp_community': 'public'},
-    ...   'targets': {
-    ...     'exclude': ['Ping'],
-    ...     'features': {'Uptime': {'retries': 3},
-    ...                  'Users': {'snmp_community': 'monkey'}}}}
-    True
-"""
-
-# flake8: noqa
-# fmt: off
-from voluptuous.schema_builder import *
-from voluptuous.util import *
-from voluptuous.validators import *
-
-from voluptuous.error import *  # isort: skip
-
-# fmt: on
-
-__version__ = '0.15.2'
-__author__ = 'alecthomas'
diff --git a/server/libs/voluptuous/error.py b/server/libs/voluptuous/error.py
deleted file mode 100644
index 9dab943..0000000
--- a/server/libs/voluptuous/error.py
+++ /dev/null
@@ -1,219 +0,0 @@
-# fmt: off
-import typing
-
-# fmt: on
-
-
-class Error(Exception):
-    """Base validation exception."""
-
-
-class SchemaError(Error):
-    """An error was encountered in the schema."""
-
-
-class Invalid(Error):
-    """The data was invalid.
-
-    :attr msg: The error message.
-    :attr path: The path to the error, as a list of keys in the source data.
-    :attr error_message: The actual error message that was raised, as a
-        string.
-
-    """
-
-    def __init__(
-        self,
-        message: str,
-        path: typing.Optional[typing.List[typing.Hashable]] = None,
-        error_message: typing.Optional[str] = None,
-        error_type: typing.Optional[str] = None,
-    ) -> None:
-        Error.__init__(self, message)
-        self._path = path or []
-        self._error_message = error_message or message
-        self.error_type = error_type
-
-    @property
-    def msg(self) -> str:
-        return self.args[0]
-
-    @property
-    def path(self) -> typing.List[typing.Hashable]:
-        return self._path
-
-    @property
-    def error_message(self) -> str:
-        return self._error_message
-
-    def __str__(self) -> str:
-        path = ' @ data[%s]' % ']['.join(map(repr, self.path)) if self.path else ''
-        output = Exception.__str__(self)
-        if self.error_type:
-            output += ' for ' + self.error_type
-        return output + path
-
-    def prepend(self, path: typing.List[typing.Hashable]) -> None:
-        self._path = path + self.path
-
-
-class MultipleInvalid(Invalid):
-    def __init__(self, errors: typing.Optional[typing.List[Invalid]] = None) -> None:
-        self.errors = errors[:] if errors else []
-
-    def __repr__(self) -> str:
-        return 'MultipleInvalid(%r)' % self.errors
-
-    @property
-    def msg(self) -> str:
-        return self.errors[0].msg
-
-    @property
-    def path(self) -> typing.List[typing.Hashable]:
-        return self.errors[0].path
-
-    @property
-    def error_message(self) -> str:
-        return self.errors[0].error_message
-
-    def add(self, error: Invalid) -> None:
-        self.errors.append(error)
-
-    def __str__(self) -> str:
-        return str(self.errors[0])
-
-    def prepend(self, path: typing.List[typing.Hashable]) -> None:
-        for error in self.errors:
-            error.prepend(path)
-
-
-class RequiredFieldInvalid(Invalid):
-    """Required field was missing."""
-
-
-class ObjectInvalid(Invalid):
-    """The value we found was not an object."""
-
-
-class DictInvalid(Invalid):
-    """The value found was not a dict."""
-
-
-class ExclusiveInvalid(Invalid):
-    """More than one value found in exclusion group."""
-
-
-class InclusiveInvalid(Invalid):
-    """Not all values found in inclusion group."""
-
-
-class SequenceTypeInvalid(Invalid):
-    """The type found is not a sequence type."""
-
-
-class TypeInvalid(Invalid):
-    """The value was not of required type."""
-
-
-class ValueInvalid(Invalid):
-    """The value was found invalid by evaluation function."""
-
-
-class ContainsInvalid(Invalid):
-    """List does not contain item"""
-
-
-class ScalarInvalid(Invalid):
-    """Scalars did not match."""
-
-
-class CoerceInvalid(Invalid):
-    """Impossible to coerce value to type."""
-
-
-class AnyInvalid(Invalid):
-    """The value did not pass any validator."""
-
-
-class AllInvalid(Invalid):
-    """The value did not pass all validators."""
-
-
-class MatchInvalid(Invalid):
-    """The value does not match the given regular expression."""
-
-
-class RangeInvalid(Invalid):
-    """The value is not in given range."""
-
-
-class TrueInvalid(Invalid):
-    """The value is not True."""
-
-
-class FalseInvalid(Invalid):
-    """The value is not False."""
-
-
-class BooleanInvalid(Invalid):
-    """The value is not a boolean."""
-
-
-class UrlInvalid(Invalid):
-    """The value is not a URL."""
-
-
-class EmailInvalid(Invalid):
-    """The value is not an email address."""
-
-
-class FileInvalid(Invalid):
-    """The value is not a file."""
-
-
-class DirInvalid(Invalid):
-    """The value is not a directory."""
-
-
-class PathInvalid(Invalid):
-    """The value is not a path."""
-
-
-class LiteralInvalid(Invalid):
-    """The literal values do not match."""
-
-
-class LengthInvalid(Invalid):
-    pass
-
-
-class DatetimeInvalid(Invalid):
-    """The value is not a formatted datetime string."""
-
-
-class DateInvalid(Invalid):
-    """The value is not a formatted date string."""
-
-
-class InInvalid(Invalid):
-    pass
-
-
-class NotInInvalid(Invalid):
-    pass
-
-
-class ExactSequenceInvalid(Invalid):
-    pass
-
-
-class NotEnoughValid(Invalid):
-    """The value did not pass enough validations."""
-
-    pass
-
-
-class TooManyValid(Invalid):
-    """The value passed more than expected validations."""
-
-    pass
diff --git a/server/libs/voluptuous/humanize.py b/server/libs/voluptuous/humanize.py
deleted file mode 100644
index eabfd02..0000000
--- a/server/libs/voluptuous/humanize.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# fmt: off
-import typing
-
-from voluptuous import Invalid, MultipleInvalid
-from voluptuous.error import Error
-from voluptuous.schema_builder import Schema
-
-# fmt: on
-
-MAX_VALIDATION_ERROR_ITEM_LENGTH = 500
-
-
-def _nested_getitem(
-    data: typing.Any, path: typing.List[typing.Hashable]
-) -> typing.Optional[typing.Any]:
-    for item_index in path:
-        try:
-            data = data[item_index]
-        except (KeyError, IndexError, TypeError):
-            # The index is not present in the dictionary, list or other
-            # indexable or data is not subscriptable
-            return None
-    return data
-
-
-def humanize_error(
-    data,
-    validation_error: Invalid,
-    max_sub_error_length: int = MAX_VALIDATION_ERROR_ITEM_LENGTH,
-) -> str:
-    """Provide a more helpful + complete validation error message than that provided automatically
-    Invalid and MultipleInvalid do not include the offending value in error messages,
-    and MultipleInvalid.__str__ only provides the first error.
-    """
-    if isinstance(validation_error, MultipleInvalid):
-        return '\n'.join(
-            sorted(
-                humanize_error(data, sub_error, max_sub_error_length)
-                for sub_error in validation_error.errors
-            )
-        )
-    else:
-        offending_item_summary = repr(_nested_getitem(data, validation_error.path))
-        if len(offending_item_summary) > max_sub_error_length:
-            offending_item_summary = (
-                offending_item_summary[: max_sub_error_length - 3] + '...'
-            )
-        return '%s. Got %s' % (validation_error, offending_item_summary)
-
-
-def validate_with_humanized_errors(
-    data, schema: Schema, max_sub_error_length: int = MAX_VALIDATION_ERROR_ITEM_LENGTH
-) -> typing.Any:
-    try:
-        return schema(data)
-    except (Invalid, MultipleInvalid) as e:
-        raise Error(humanize_error(data, e, max_sub_error_length))
diff --git a/server/libs/voluptuous/py.typed b/server/libs/voluptuous/py.typed
deleted file mode 100644
index e69de29..0000000
diff --git a/server/libs/voluptuous/schema_builder.py b/server/libs/voluptuous/schema_builder.py
deleted file mode 100644
index cdeb514..0000000
--- a/server/libs/voluptuous/schema_builder.py
+++ /dev/null
@@ -1,1315 +0,0 @@
-# fmt: off
-from __future__ import annotations
-
-import collections
-import inspect
-import itertools
-import re
-import sys
-import typing
-from collections.abc import Generator
-from contextlib import contextmanager
-from functools import cache, wraps
-
-from voluptuous import error as er
-from voluptuous.error import Error
-
-# fmt: on
-
-# options for extra keys
-PREVENT_EXTRA = 0  # any extra key not in schema will raise an error
-ALLOW_EXTRA = 1  # extra keys not in schema will be included in output
-REMOVE_EXTRA = 2  # extra keys not in schema will be excluded from output
-
-
-def _isnamedtuple(obj):
-    return isinstance(obj, tuple) and hasattr(obj, '_fields')
-
-
-class Undefined(object):
-    def __nonzero__(self):
-        return False
-
-    def __repr__(self):
-        return '...'
-
-
-UNDEFINED = Undefined()
-
-
-def Self() -> None:
-    raise er.SchemaError('"Self" should never be called')
-
-
-DefaultFactory = typing.Union[Undefined, typing.Callable[[], typing.Any]]
-
-
-def default_factory(value) -> DefaultFactory:
-    if value is UNDEFINED or callable(value):
-        return value
-    return lambda: value
-
-
-@contextmanager
-def raises(
-    exc, msg: typing.Optional[str] = None, regex: typing.Optional[re.Pattern] = None
-) -> Generator[None, None, None]:
-    try:
-        yield
-    except exc as e:
-        if msg is not None:
-            assert str(e) == msg, '%r != %r' % (str(e), msg)
-        if regex is not None:
-            assert re.search(regex, str(e)), '%r does not match %r' % (str(e), regex)
-    else:
-        raise AssertionError(f"Did not raise exception {exc.__name__}")
-
-
-def Extra(_) -> None:
-    """Allow keys in the data that are not present in the schema."""
-    raise er.SchemaError('"Extra" should never be called')
-
-
-# As extra() is never called there's no way to catch references to the
-# deprecated object, so we just leave an alias here instead.
-extra = Extra
-
-primitive_types = (bool, bytes, int, str, float, complex)
-
-# fmt: off
-Schemable = typing.Union[
-    'Schema', 'Object',
-    collections.abc.Mapping,
-    list, tuple, frozenset, set,
-    bool, bytes, int, str, float, complex,
-    type, object, dict, None, typing.Callable
-]
-# fmt: on
-
-
-class Schema(object):
-    """A validation schema.
-
-    The schema is a Python tree-like structure where nodes are pattern
-    matched against corresponding trees of values.
-
-    Nodes can be values, in which case a direct comparison is used, types,
-    in which case an isinstance() check is performed, or callables, which will
-    validate and optionally convert the value.
-
-    We can equate schemas also.
-
-    For Example:
-
-            >>> v = Schema({Required('a'): str})
-            >>> v1 = Schema({Required('a'): str})
-            >>> v2 = Schema({Required('b'): str})
-            >>> assert v == v1
-            >>> assert v != v2
-
-    """
-
-    _extra_to_name = {
-        REMOVE_EXTRA: 'REMOVE_EXTRA',
-        ALLOW_EXTRA: 'ALLOW_EXTRA',
-        PREVENT_EXTRA: 'PREVENT_EXTRA',
-    }
-
-    def __init__(
-        self, schema: Schemable, required: bool = False, extra: int = PREVENT_EXTRA
-    ) -> None:
-        """Create a new Schema.
-
-        :param schema: Validation schema. See :module:`voluptuous` for details.
-        :param required: Keys defined in the schema must be in the data.
-        :param extra: Specify how extra keys in the data are treated:
-            - :const:`~voluptuous.PREVENT_EXTRA`: to disallow any undefined
-              extra keys (raise ``Invalid``).
-            - :const:`~voluptuous.ALLOW_EXTRA`: to include undefined extra
-              keys in the output.
-            - :const:`~voluptuous.REMOVE_EXTRA`: to exclude undefined extra keys
-              from the output.
-            - Any value other than the above defaults to
-              :const:`~voluptuous.PREVENT_EXTRA`
-        """
-        self.schema: typing.Any = schema
-        self.required = required
-        self.extra = int(extra)  # ensure the value is an integer
-        self._compiled = self._compile(schema)
-
-    @classmethod
-    def infer(cls, data, **kwargs) -> Schema:
-        """Create a Schema from concrete data (e.g. an API response).
-
-        For example, this will take a dict like:
-
-        {
-            'foo': 1,
-            'bar': {
-                'a': True,
-                'b': False
-            },
-            'baz': ['purple', 'monkey', 'dishwasher']
-        }
-
-        And return a Schema:
-
-        {
-            'foo': int,
-            'bar': {
-                'a': bool,
-                'b': bool
-            },
-            'baz': [str]
-        }
-
-        Note: only very basic inference is supported.
-        """
-
-        def value_to_schema_type(value):
-            if isinstance(value, dict):
-                if len(value) == 0:
-                    return dict
-                return {k: value_to_schema_type(v) for k, v in value.items()}
-            if isinstance(value, list):
-                if len(value) == 0:
-                    return list
-                else:
-                    return [value_to_schema_type(v) for v in value]
-            return type(value)
-
-        return cls(value_to_schema_type(data), **kwargs)
-
-    def __eq__(self, other):
-        if not isinstance(other, Schema):
-            return False
-        return other.schema == self.schema
-
-    def __ne__(self, other):
-        return not (self == other)
-
-    def __str__(self):
-        return str(self.schema)
-
-    def __repr__(self):
-        return "" % (
-            self.schema,
-            self._extra_to_name.get(self.extra, '??'),
-            self.required,
-            id(self),
-        )
-
-    def __call__(self, data):
-        """Validate data against this schema."""
-        try:
-            return self._compiled([], data)
-        except er.MultipleInvalid:
-            raise
-        except er.Invalid as e:
-            raise er.MultipleInvalid([e])
-            # return self.validate([], self.schema, data)
-
-    def _compile(self, schema):
-        if schema is Extra:
-            return lambda _, v: v
-        if schema is Self:
-            return lambda p, v: self._compiled(p, v)
-        elif hasattr(schema, "__voluptuous_compile__"):
-            return schema.__voluptuous_compile__(self)
-        if isinstance(schema, Object):
-            return self._compile_object(schema)
-        if isinstance(schema, collections.abc.Mapping):
-            return self._compile_dict(schema)
-        elif isinstance(schema, list):
-            return self._compile_list(schema)
-        elif isinstance(schema, tuple):
-            return self._compile_tuple(schema)
-        elif isinstance(schema, (frozenset, set)):
-            return self._compile_set(schema)
-        type_ = type(schema)
-        if inspect.isclass(schema):
-            type_ = schema
-        if type_ in (*primitive_types, object, type(None)) or callable(schema):
-            return _compile_scalar(schema)
-        raise er.SchemaError('unsupported schema data type %r' % type(schema).__name__)
-
-    def _compile_mapping(self, schema, invalid_msg=None):
-        """Create validator for given mapping."""
-        invalid_msg = invalid_msg or 'mapping value'
-
-        # Keys that may be required
-        all_required_keys = set(
-            key
-            for key in schema
-            if key is not Extra
-            and (
-                (self.required and not isinstance(key, (Optional, Remove)))
-                or isinstance(key, Required)
-            )
-        )
-
-        # Keys that may have defaults
-        all_default_keys = set(
-            key
-            for key in schema
-            if isinstance(key, Required) or isinstance(key, Optional)
-        )
-
-        _compiled_schema = {}
-        for skey, svalue in schema.items():
-            new_key = self._compile(skey)
-            new_value = self._compile(svalue)
-            _compiled_schema[skey] = (new_key, new_value)
-
-        candidates = list(_iterate_mapping_candidates(_compiled_schema))
-
-        # After we have the list of candidates in the correct order, we want to apply some optimization so that each
-        # key in the data being validated will be matched against the relevant schema keys only.
-        # No point in matching against different keys
-        additional_candidates = []
-        candidates_by_key = {}
-        for skey, (ckey, cvalue) in candidates:
-            if type(skey) in primitive_types:
-                candidates_by_key.setdefault(skey, []).append((skey, (ckey, cvalue)))
-            elif isinstance(skey, Marker) and type(skey.schema) in primitive_types:
-                candidates_by_key.setdefault(skey.schema, []).append(
-                    (skey, (ckey, cvalue))
-                )
-            else:
-                # These are wildcards such as 'int', 'str', 'Remove' and others which should be applied to all keys
-                additional_candidates.append((skey, (ckey, cvalue)))
-
-        def validate_mapping(path, iterable, out):
-            required_keys = all_required_keys.copy()
-
-            # Build a map of all provided key-value pairs.
-            # The type(out) is used to retain ordering in case a ordered
-            # map type is provided as input.
-            key_value_map = type(out)()
-            for key, value in iterable:
-                key_value_map[key] = value
-
-            # Insert default values for non-existing keys.
-            for key in all_default_keys:
-                if (
-                    not isinstance(key.default, Undefined)
-                    and key.schema not in key_value_map
-                ):
-                    # A default value has been specified for this missing
-                    # key, insert it.
-                    key_value_map[key.schema] = key.default()
-
-            errors = []
-            for key, value in key_value_map.items():
-                key_path = path + [key]
-                remove_key = False
-
-                # Optimization. Validate against the matching key first, then fallback to the rest
-                relevant_candidates = itertools.chain(
-                    candidates_by_key.get(key, []), additional_candidates
-                )
-
-                # compare each given key/value against all compiled key/values
-                # schema key, (compiled key, compiled value)
-                error = None
-                for skey, (ckey, cvalue) in relevant_candidates:
-                    try:
-                        new_key = ckey(key_path, key)
-                    except er.Invalid as e:
-                        if len(e.path) > len(key_path):
-                            raise
-                        if not error or len(e.path) > len(error.path):
-                            error = e
-                        continue
-                    # Backtracking is not performed once a key is selected, so if
-                    # the value is invalid we immediately throw an exception.
-                    exception_errors = []
-                    # check if the key is marked for removal
-                    is_remove = new_key is Remove
-                    try:
-                        cval = cvalue(key_path, value)
-                        # include if it's not marked for removal
-                        if not is_remove:
-                            out[new_key] = cval
-                        else:
-                            remove_key = True
-                            continue
-                    except er.MultipleInvalid as e:
-                        exception_errors.extend(e.errors)
-                    except er.Invalid as e:
-                        exception_errors.append(e)
-
-                    if exception_errors:
-                        if is_remove or remove_key:
-                            continue
-                        for err in exception_errors:
-                            if len(err.path) <= len(key_path):
-                                err.error_type = invalid_msg
-                            errors.append(err)
-                        # If there is a validation error for a required
-                        # key, this means that the key was provided.
-                        # Discard the required key so it does not
-                        # create an additional, noisy exception.
-                        required_keys.discard(skey)
-                        break
-
-                    # Key and value okay, mark as found in case it was
-                    # a Required() field.
-                    required_keys.discard(skey)
-
-                    break
-                else:
-                    if remove_key:
-                        # remove key
-                        continue
-                    elif self.extra == ALLOW_EXTRA:
-                        out[key] = value
-                    elif error:
-                        errors.append(error)
-                    elif self.extra != REMOVE_EXTRA:
-                        errors.append(er.Invalid('extra keys not allowed', key_path))
-                        # else REMOVE_EXTRA: ignore the key so it's removed from output
-
-            # for any required keys left that weren't found and don't have defaults:
-            for key in required_keys:
-                msg = (
-                    key.msg
-                    if hasattr(key, 'msg') and key.msg
-                    else 'required key not provided'
-                )
-                errors.append(er.RequiredFieldInvalid(msg, path + [key]))
-            if errors:
-                raise er.MultipleInvalid(errors)
-
-            return out
-
-        return validate_mapping
-
-    def _compile_object(self, schema):
-        """Validate an object.
-
-        Has the same behavior as dictionary validator but work with object
-        attributes.
-
-        For example:
-
-            >>> class Structure(object):
-            ...     def __init__(self, one=None, three=None):
-            ...         self.one = one
-            ...         self.three = three
-            ...
-            >>> validate = Schema(Object({'one': 'two', 'three': 'four'}, cls=Structure))
-            >>> with raises(er.MultipleInvalid, "not a valid value for object value @ data['one']"):
-            ...   validate(Structure(one='three'))
-
-        """
-        base_validate = self._compile_mapping(schema, invalid_msg='object value')
-
-        def validate_object(path, data):
-            if schema.cls is not UNDEFINED and not isinstance(data, schema.cls):
-                raise er.ObjectInvalid('expected a {0!r}'.format(schema.cls), path)
-            iterable = _iterate_object(data)
-            iterable = filter(lambda item: item[1] is not None, iterable)
-            out = base_validate(path, iterable, {})
-            return type(data)(**out)
-
-        return validate_object
-
-    def _compile_dict(self, schema):
-        """Validate a dictionary.
-
-        A dictionary schema can contain a set of values, or at most one
-        validator function/type.
-
-        A dictionary schema will only validate a dictionary:
-
-            >>> validate = Schema({})
-            >>> with raises(er.MultipleInvalid, 'expected a dictionary'):
-            ...   validate([])
-
-        An invalid dictionary value:
-
-            >>> validate = Schema({'one': 'two', 'three': 'four'})
-            >>> with raises(er.MultipleInvalid, "not a valid value for dictionary value @ data['one']"):
-            ...   validate({'one': 'three'})
-
-        An invalid key:
-
-            >>> with raises(er.MultipleInvalid, "extra keys not allowed @ data['two']"):
-            ...   validate({'two': 'three'})
-
-
-        Validation function, in this case the "int" type:
-
-            >>> validate = Schema({'one': 'two', 'three': 'four', int: str})
-
-        Valid integer input:
-
-            >>> validate({10: 'twenty'})
-            {10: 'twenty'}
-
-        By default, a "type" in the schema (in this case "int") will be used
-        purely to validate that the corresponding value is of that type. It
-        will not Coerce the value:
-
-            >>> with raises(er.MultipleInvalid, "extra keys not allowed @ data['10']"):
-            ...   validate({'10': 'twenty'})
-
-        Wrap them in the Coerce() function to achieve this:
-            >>> from voluptuous import Coerce
-            >>> validate = Schema({'one': 'two', 'three': 'four',
-            ...                    Coerce(int): str})
-            >>> validate({'10': 'twenty'})
-            {10: 'twenty'}
-
-        Custom message for required key
-
-            >>> validate = Schema({Required('one', 'required'): 'two'})
-            >>> with raises(er.MultipleInvalid, "required @ data['one']"):
-            ...   validate({})
-
-        (This is to avoid unexpected surprises.)
-
-        Multiple errors for nested field in a dict:
-
-        >>> validate = Schema({
-        ...     'adict': {
-        ...         'strfield': str,
-        ...         'intfield': int
-        ...     }
-        ... })
-        >>> try:
-        ...     validate({
-        ...         'adict': {
-        ...             'strfield': 123,
-        ...             'intfield': 'one'
-        ...         }
-        ...     })
-        ... except er.MultipleInvalid as e:
-        ...     print(sorted(str(i) for i in e.errors)) # doctest: +NORMALIZE_WHITESPACE
-        ["expected int for dictionary value @ data['adict']['intfield']",
-         "expected str for dictionary value @ data['adict']['strfield']"]
-
-        """
-        base_validate = self._compile_mapping(schema, invalid_msg='dictionary value')
-
-        groups_of_exclusion = {}
-        groups_of_inclusion = {}
-        for node in schema:
-            if isinstance(node, Exclusive):
-                g = groups_of_exclusion.setdefault(node.group_of_exclusion, [])
-                g.append(node)
-            elif isinstance(node, Inclusive):
-                g = groups_of_inclusion.setdefault(node.group_of_inclusion, [])
-                g.append(node)
-
-        def validate_dict(path, data):
-            if not isinstance(data, dict):
-                raise er.DictInvalid('expected a dictionary', path)
-
-            errors = []
-            for label, group in groups_of_exclusion.items():
-                exists = False
-                for exclusive in group:
-                    if exclusive.schema in data:
-                        if exists:
-                            msg = (
-                                exclusive.msg
-                                if hasattr(exclusive, 'msg') and exclusive.msg
-                                else "two or more values in the same group of exclusion '%s'"
-                                % label
-                            )
-                            next_path = path + [VirtualPathComponent(label)]
-                            errors.append(er.ExclusiveInvalid(msg, next_path))
-                            break
-                        exists = True
-
-            if errors:
-                raise er.MultipleInvalid(errors)
-
-            for label, group in groups_of_inclusion.items():
-                included = [node.schema in data for node in group]
-                if any(included) and not all(included):
-                    msg = (
-                        "some but not all values in the same group of inclusion '%s'"
-                        % label
-                    )
-                    for g in group:
-                        if hasattr(g, 'msg') and g.msg:
-                            msg = g.msg
-                            break
-                    next_path = path + [VirtualPathComponent(label)]
-                    errors.append(er.InclusiveInvalid(msg, next_path))
-                    break
-
-            if errors:
-                raise er.MultipleInvalid(errors)
-
-            out = data.__class__()
-            return base_validate(path, data.items(), out)
-
-        return validate_dict
-
-    def _compile_sequence(self, schema, seq_type):
-        """Validate a sequence type.
-
-        This is a sequence of valid values or validators tried in order.
-
-        >>> validator = Schema(['one', 'two', int])
-        >>> validator(['one'])
-        ['one']
-        >>> with raises(er.MultipleInvalid, 'expected int @ data[0]'):
-        ...   validator([3.5])
-        >>> validator([1])
-        [1]
-        """
-        _compiled = [self._compile(s) for s in schema]
-        seq_type_name = seq_type.__name__
-
-        def validate_sequence(path, data):
-            if not isinstance(data, seq_type):
-                raise er.SequenceTypeInvalid('expected a %s' % seq_type_name, path)
-
-            # Empty seq schema, reject any data.
-            if not schema:
-                if data:
-                    raise er.MultipleInvalid(
-                        [er.ValueInvalid('not a valid value', path if path else data)]
-                    )
-                return data
-
-            out = []
-            invalid = None
-            errors = []
-            index_path = UNDEFINED
-            for i, value in enumerate(data):
-                index_path = path + [i]
-                invalid = None
-                for validate in _compiled:
-                    try:
-                        cval = validate(index_path, value)
-                        if cval is not Remove:  # do not include Remove values
-                            out.append(cval)
-                        break
-                    except er.Invalid as e:
-                        if len(e.path) > len(index_path):
-                            raise
-                        invalid = e
-                else:
-                    errors.append(invalid)
-            if errors:
-                raise er.MultipleInvalid(errors)
-
-            if _isnamedtuple(data):
-                return type(data)(*out)
-            else:
-                return type(data)(out)
-
-        return validate_sequence
-
-    def _compile_tuple(self, schema):
-        """Validate a tuple.
-
-        A tuple is a sequence of valid values or validators tried in order.
-
-        >>> validator = Schema(('one', 'two', int))
-        >>> validator(('one',))
-        ('one',)
-        >>> with raises(er.MultipleInvalid, 'expected int @ data[0]'):
-        ...   validator((3.5,))
-        >>> validator((1,))
-        (1,)
-        """
-        return self._compile_sequence(schema, tuple)
-
-    def _compile_list(self, schema):
-        """Validate a list.
-
-        A list is a sequence of valid values or validators tried in order.
-
-        >>> validator = Schema(['one', 'two', int])
-        >>> validator(['one'])
-        ['one']
-        >>> with raises(er.MultipleInvalid, 'expected int @ data[0]'):
-        ...   validator([3.5])
-        >>> validator([1])
-        [1]
-        """
-        return self._compile_sequence(schema, list)
-
-    def _compile_set(self, schema):
-        """Validate a set.
-
-        A set is an unordered collection of unique elements.
-
-        >>> validator = Schema({int})
-        >>> validator(set([42])) == set([42])
-        True
-        >>> with raises(er.Invalid, 'expected a set'):
-        ...   validator(42)
-        >>> with raises(er.MultipleInvalid, 'invalid value in set'):
-        ...   validator(set(['a']))
-        """
-        type_ = type(schema)
-        type_name = type_.__name__
-
-        def validate_set(path, data):
-            if not isinstance(data, type_):
-                raise er.Invalid('expected a %s' % type_name, path)
-
-            _compiled = [self._compile(s) for s in schema]
-            errors = []
-            for value in data:
-                for validate in _compiled:
-                    try:
-                        validate(path, value)
-                        break
-                    except er.Invalid:
-                        pass
-                else:
-                    invalid = er.Invalid('invalid value in %s' % type_name, path)
-                    errors.append(invalid)
-
-            if errors:
-                raise er.MultipleInvalid(errors)
-
-            return data
-
-        return validate_set
-
-    def extend(
-        self,
-        schema: Schemable,
-        required: typing.Optional[bool] = None,
-        extra: typing.Optional[int] = None,
-    ) -> Schema:
-        """Create a new `Schema` by merging this and the provided `schema`.
-
-        Neither this `Schema` nor the provided `schema` are modified. The
-        resulting `Schema` inherits the `required` and `extra` parameters of
-        this, unless overridden.
-
-        Both schemas must be dictionary-based.
-
-        :param schema: dictionary to extend this `Schema` with
-        :param required: if set, overrides `required` of this `Schema`
-        :param extra: if set, overrides `extra` of this `Schema`
-        """
-
-        assert isinstance(self.schema, dict) and isinstance(
-            schema, dict
-        ), 'Both schemas must be dictionary-based'
-
-        result = self.schema.copy()
-
-        # returns the key that may have been passed as an argument to Marker constructor
-        def key_literal(key):
-            return key.schema if isinstance(key, Marker) else key
-
-        # build a map that takes the key literals to the needed objects
-        # literal -> Required|Optional|literal
-        result_key_map = dict((key_literal(key), key) for key in result)
-
-        # for each item in the extension schema, replace duplicates
-        # or add new keys
-        for key, value in schema.items():
-            # if the key is already in the dictionary, we need to replace it
-            # transform key to literal before checking presence
-            if key_literal(key) in result_key_map:
-                result_key = result_key_map[key_literal(key)]
-                result_value = result[result_key]
-
-                # if both are dictionaries, we need to extend recursively
-                # create the new extended sub schema, then remove the old key and add the new one
-                if isinstance(result_value, dict) and isinstance(value, dict):
-                    new_value = Schema(result_value).extend(value).schema
-                    del result[result_key]
-                    result[key] = new_value
-                # one or the other or both are not sub-schemas, simple replacement is fine
-                # remove old key and add new one
-                else:
-                    del result[result_key]
-                    result[key] = value
-
-            # key is new and can simply be added
-            else:
-                result[key] = value
-
-        # recompile and send old object
-        result_cls = type(self)
-        result_required = required if required is not None else self.required
-        result_extra = extra if extra is not None else self.extra
-        return result_cls(result, required=result_required, extra=result_extra)
-
-
-def _compile_scalar(schema):
-    """A scalar value.
-
-    The schema can either be a value or a type.
-
-    >>> _compile_scalar(int)([], 1)
-    1
-    >>> with raises(er.Invalid, 'expected float'):
-    ...   _compile_scalar(float)([], '1')
-
-    Callables have
-    >>> _compile_scalar(lambda v: float(v))([], '1')
-    1.0
-
-    As a convenience, ValueError's are trapped:
-
-    >>> with raises(er.Invalid, 'not a valid value'):
-    ...   _compile_scalar(lambda v: float(v))([], 'a')
-    """
-    if inspect.isclass(schema):
-
-        def validate_instance(path, data):
-            if isinstance(data, schema):
-                return data
-            else:
-                msg = 'expected %s' % schema.__name__
-                raise er.TypeInvalid(msg, path)
-
-        return validate_instance
-
-    if callable(schema):
-
-        def validate_callable(path, data):
-            try:
-                return schema(data)
-            except ValueError:
-                raise er.ValueInvalid('not a valid value', path)
-            except er.Invalid as e:
-                e.prepend(path)
-                raise
-
-        return validate_callable
-
-    def validate_value(path, data):
-        if data != schema:
-            raise er.ScalarInvalid('not a valid value', path)
-        return data
-
-    return validate_value
-
-
-def _compile_itemsort():
-    '''return sort function of mappings'''
-
-    def is_extra(key_):
-        return key_ is Extra
-
-    def is_remove(key_):
-        return isinstance(key_, Remove)
-
-    def is_marker(key_):
-        return isinstance(key_, Marker)
-
-    def is_type(key_):
-        return inspect.isclass(key_)
-
-    def is_callable(key_):
-        return callable(key_)
-
-    # priority list for map sorting (in order of checking)
-    # We want Extra to match last, because it's a catch-all. On the other hand,
-    # Remove markers should match first (since invalid values will not
-    # raise an Error, instead the validator will check if other schemas match
-    # the same value).
-    priority = [
-        (1, is_remove),  # Remove highest priority after values
-        (2, is_marker),  # then other Markers
-        (4, is_type),  # types/classes lowest before Extra
-        (3, is_callable),  # callables after markers
-        (5, is_extra),  # Extra lowest priority
-    ]
-
-    def item_priority(item_):
-        key_ = item_[0]
-        for i, check_ in priority:
-            if check_(key_):
-                return i
-        # values have highest priorities
-        return 0
-
-    return item_priority
-
-
-_sort_item = _compile_itemsort()
-
-
-def _iterate_mapping_candidates(schema):
-    """Iterate over schema in a meaningful order."""
-    # Without this, Extra might appear first in the iterator, and fail to
-    # validate a key even though it's a Required that has its own validation,
-    # generating a false positive.
-    return sorted(schema.items(), key=_sort_item)
-
-
-def _iterate_object(obj):
-    """Return iterator over object attributes. Respect objects with
-    defined __slots__.
-
-    """
-    d = {}
-    try:
-        d = vars(obj)
-    except TypeError:
-        # maybe we have named tuple here?
-        if hasattr(obj, '_asdict'):
-            d = obj._asdict()
-    for item in d.items():
-        yield item
-    try:
-        slots = obj.__slots__
-    except AttributeError:
-        pass
-    else:
-        for key in slots:
-            if key != '__dict__':
-                yield (key, getattr(obj, key))
-
-
-class Msg(object):
-    """Report a user-friendly message if a schema fails to validate.
-
-    >>> validate = Schema(
-    ...   Msg(['one', 'two', int],
-    ...       'should be one of "one", "two" or an integer'))
-    >>> with raises(er.MultipleInvalid, 'should be one of "one", "two" or an integer'):
-    ...   validate(['three'])
-
-    Messages are only applied to invalid direct descendants of the schema:
-
-    >>> validate = Schema(Msg([['one', 'two', int]], 'not okay!'))
-    >>> with raises(er.MultipleInvalid, 'expected int @ data[0][0]'):
-    ...   validate([['three']])
-
-    The type which is thrown can be overridden but needs to be a subclass of Invalid
-
-    >>> with raises(er.SchemaError, 'Msg can only use subclases of Invalid as custom class'):
-    ...   validate = Schema(Msg([int], 'should be int', cls=KeyError))
-
-    If you do use a subclass of Invalid, that error will be thrown (wrapped in a MultipleInvalid)
-
-    >>> validate = Schema(Msg([['one', 'two', int]], 'not okay!', cls=er.RangeInvalid))
-    >>> try:
-    ...  validate(['three'])
-    ... except er.MultipleInvalid as e:
-    ...   assert isinstance(e.errors[0], er.RangeInvalid)
-    """
-
-    def __init__(
-        self,
-        schema: Schemable,
-        msg: str,
-        cls: typing.Optional[typing.Type[Error]] = None,
-    ) -> None:
-        if cls and not issubclass(cls, er.Invalid):
-            raise er.SchemaError(
-                "Msg can only use subclases of Invalid as custom class"
-            )
-        self._schema = schema
-        self.schema = Schema(schema)
-        self.msg = msg
-        self.cls = cls
-
-    def __call__(self, v):
-        try:
-            return self.schema(v)
-        except er.Invalid as e:
-            if len(e.path) > 1:
-                raise e
-            else:
-                raise (self.cls or er.Invalid)(self.msg)
-
-    def __repr__(self):
-        return 'Msg(%s, %s, cls=%s)' % (self._schema, self.msg, self.cls)
-
-
-class Object(dict):
-    """Indicate that we should work with attributes, not keys."""
-
-    def __init__(self, schema: typing.Any, cls: object = UNDEFINED) -> None:
-        self.cls = cls
-        super(Object, self).__init__(schema)
-
-
-class VirtualPathComponent(str):
-    def __str__(self):
-        return '<' + self + '>'
-
-    def __repr__(self):
-        return self.__str__()
-
-
-class Marker(object):
-    """Mark nodes for special treatment.
-
-    `description` is an optional field, unused by Voluptuous itself, but can be
-    introspected by any external tool, for example to generate schema documentation.
-    """
-
-    __slots__ = ('schema', '_schema', 'msg', 'description', '__hash__')
-
-    def __init__(
-        self,
-        schema_: Schemable,
-        msg: typing.Optional[str] = None,
-        description: typing.Any | None = None,
-    ) -> None:
-        self.schema: typing.Any = schema_
-        self._schema = Schema(schema_)
-        self.msg = msg
-        self.description = description
-        self.__hash__ = cache(lambda: hash(schema_))  # type: ignore[method-assign]
-
-    def __call__(self, v):
-        try:
-            return self._schema(v)
-        except er.Invalid as e:
-            if not self.msg or len(e.path) > 1:
-                raise
-            raise er.Invalid(self.msg)
-
-    def __str__(self):
-        return str(self.schema)
-
-    def __repr__(self):
-        return repr(self.schema)
-
-    def __lt__(self, other):
-        if isinstance(other, Marker):
-            return self.schema < other.schema
-        return self.schema < other
-
-    def __eq__(self, other):
-        return self.schema == other
-
-    def __ne__(self, other):
-        return not (self.schema == other)
-
-
-class Optional(Marker):
-    """Mark a node in the schema as optional, and optionally provide a default
-
-    >>> schema = Schema({Optional('key'): str})
-    >>> schema({})
-    {}
-    >>> schema = Schema({Optional('key', default='value'): str})
-    >>> schema({})
-    {'key': 'value'}
-    >>> schema = Schema({Optional('key', default=list): list})
-    >>> schema({})
-    {'key': []}
-
-    If 'required' flag is set for an entire schema, optional keys aren't required
-
-    >>> schema = Schema({
-    ...    Optional('key'): str,
-    ...    'key2': str
-    ... }, required=True)
-    >>> schema({'key2':'value'})
-    {'key2': 'value'}
-    """
-
-    def __init__(
-        self,
-        schema: Schemable,
-        msg: typing.Optional[str] = None,
-        default: typing.Any = UNDEFINED,
-        description: typing.Any | None = None,
-    ) -> None:
-        super(Optional, self).__init__(schema, msg=msg, description=description)
-        self.default = default_factory(default)
-
-
-class Exclusive(Optional):
-    """Mark a node in the schema as exclusive.
-
-    Exclusive keys inherited from Optional:
-
-    >>> schema = Schema({Exclusive('alpha', 'angles'): int, Exclusive('beta', 'angles'): int})
-    >>> schema({'alpha': 30})
-    {'alpha': 30}
-
-    Keys inside a same group of exclusion cannot be together, it only makes sense for dictionaries:
-
-    >>> with raises(er.MultipleInvalid, "two or more values in the same group of exclusion 'angles' @ data[]"):
-    ...   schema({'alpha': 30, 'beta': 45})
-
-    For example, API can provides multiple types of authentication, but only one works in the same time:
-
-    >>> msg = 'Please, use only one type of authentication at the same time.'
-    >>> schema = Schema({
-    ... Exclusive('classic', 'auth', msg=msg):{
-    ...     Required('email'): str,
-    ...     Required('password'): str
-    ...     },
-    ... Exclusive('internal', 'auth', msg=msg):{
-    ...     Required('secret_key'): str
-    ...     },
-    ... Exclusive('social', 'auth', msg=msg):{
-    ...     Required('social_network'): str,
-    ...     Required('token'): str
-    ...     }
-    ... })
-
-    >>> with raises(er.MultipleInvalid, "Please, use only one type of authentication at the same time. @ data[]"):
-    ...     schema({'classic': {'email': 'foo@example.com', 'password': 'bar'},
-    ...             'social': {'social_network': 'barfoo', 'token': 'tEMp'}})
-    """
-
-    def __init__(
-        self,
-        schema: Schemable,
-        group_of_exclusion: str,
-        msg: typing.Optional[str] = None,
-        description: typing.Any | None = None,
-    ) -> None:
-        super(Exclusive, self).__init__(schema, msg=msg, description=description)
-        self.group_of_exclusion = group_of_exclusion
-
-
-class Inclusive(Optional):
-    """Mark a node in the schema as inclusive.
-
-    Inclusive keys inherited from Optional:
-
-    >>> schema = Schema({
-    ...     Inclusive('filename', 'file'): str,
-    ...     Inclusive('mimetype', 'file'): str
-    ... })
-    >>> data = {'filename': 'dog.jpg', 'mimetype': 'image/jpeg'}
-    >>> data == schema(data)
-    True
-
-    Keys inside a same group of inclusive must exist together, it only makes sense for dictionaries:
-
-    >>> with raises(er.MultipleInvalid, "some but not all values in the same group of inclusion 'file' @ data[]"):
-    ...     schema({'filename': 'dog.jpg'})
-
-    If none of the keys in the group are present, it is accepted:
-
-    >>> schema({})
-    {}
-
-    For example, API can return 'height' and 'width' together, but not separately.
-
-    >>> msg = "Height and width must exist together"
-    >>> schema = Schema({
-    ...     Inclusive('height', 'size', msg=msg): int,
-    ...     Inclusive('width', 'size', msg=msg): int
-    ... })
-
-    >>> with raises(er.MultipleInvalid, msg + " @ data[]"):
-    ...     schema({'height': 100})
-
-    >>> with raises(er.MultipleInvalid, msg + " @ data[]"):
-    ...     schema({'width': 100})
-
-    >>> data = {'height': 100, 'width': 100}
-    >>> data == schema(data)
-    True
-    """
-
-    def __init__(
-        self,
-        schema: Schemable,
-        group_of_inclusion: str,
-        msg: typing.Optional[str] = None,
-        description: typing.Any | None = None,
-        default: typing.Any = UNDEFINED,
-    ) -> None:
-        super(Inclusive, self).__init__(
-            schema, msg=msg, default=default, description=description
-        )
-        self.group_of_inclusion = group_of_inclusion
-
-
-class Required(Marker):
-    """Mark a node in the schema as being required, and optionally provide a default value.
-
-    >>> schema = Schema({Required('key'): str})
-    >>> with raises(er.MultipleInvalid, "required key not provided @ data['key']"):
-    ...   schema({})
-
-    >>> schema = Schema({Required('key', default='value'): str})
-    >>> schema({})
-    {'key': 'value'}
-    >>> schema = Schema({Required('key', default=list): list})
-    >>> schema({})
-    {'key': []}
-    """
-
-    def __init__(
-        self,
-        schema: Schemable,
-        msg: typing.Optional[str] = None,
-        default: typing.Any = UNDEFINED,
-        description: typing.Any | None = None,
-    ) -> None:
-        super(Required, self).__init__(schema, msg=msg, description=description)
-        self.default = default_factory(default)
-
-
-class Remove(Marker):
-    """Mark a node in the schema to be removed and excluded from the validated
-    output. Keys that fail validation will not raise ``Invalid``. Instead, these
-    keys will be treated as extras.
-
-    >>> schema = Schema({str: int, Remove(int): str})
-    >>> with raises(er.MultipleInvalid, "extra keys not allowed @ data[1]"):
-    ...    schema({'keep': 1, 1: 1.0})
-    >>> schema({1: 'red', 'red': 1, 2: 'green'})
-    {'red': 1}
-    >>> schema = Schema([int, Remove(float), Extra])
-    >>> schema([1, 2, 3, 4.0, 5, 6.0, '7'])
-    [1, 2, 3, 5, '7']
-    """
-
-    def __init__(
-        self,
-        schema_: Schemable,
-        msg: typing.Optional[str] = None,
-        description: typing.Any | None = None,
-    ) -> None:
-        super().__init__(schema_, msg, description)
-        self.__hash__ = cache(lambda: object.__hash__(self))  # type: ignore[method-assign]
-
-    def __call__(self, schema: Schemable):
-        super(Remove, self).__call__(schema)
-        return self.__class__
-
-    def __repr__(self):
-        return "Remove(%r)" % (self.schema,)
-
-
-def message(
-    default: typing.Optional[str] = None,
-    cls: typing.Optional[typing.Type[Error]] = None,
-) -> typing.Callable:
-    """Convenience decorator to allow functions to provide a message.
-
-    Set a default message:
-
-        >>> @message('not an integer')
-        ... def isint(v):
-        ...   return int(v)
-
-        >>> validate = Schema(isint())
-        >>> with raises(er.MultipleInvalid, 'not an integer'):
-        ...   validate('a')
-
-    The message can be overridden on a per validator basis:
-
-        >>> validate = Schema(isint('bad'))
-        >>> with raises(er.MultipleInvalid, 'bad'):
-        ...   validate('a')
-
-    The class thrown too:
-
-        >>> class IntegerInvalid(er.Invalid): pass
-        >>> validate = Schema(isint('bad', clsoverride=IntegerInvalid))
-        >>> try:
-        ...  validate('a')
-        ... except er.MultipleInvalid as e:
-        ...   assert isinstance(e.errors[0], IntegerInvalid)
-    """
-    if cls and not issubclass(cls, er.Invalid):
-        raise er.SchemaError(
-            "message can only use subclases of Invalid as custom class"
-        )
-
-    def decorator(f):
-        @wraps(f)
-        def check(msg=None, clsoverride=None):
-            @wraps(f)
-            def wrapper(*args, **kwargs):
-                try:
-                    return f(*args, **kwargs)
-                except ValueError:
-                    raise (clsoverride or cls or er.ValueInvalid)(
-                        msg or default or 'invalid value'
-                    )
-
-            return wrapper
-
-        return check
-
-    return decorator
-
-
-def _args_to_dict(func, args):
-    """Returns argument names as values as key-value pairs."""
-    if sys.version_info >= (3, 0):
-        arg_count = func.__code__.co_argcount
-        arg_names = func.__code__.co_varnames[:arg_count]
-    else:
-        arg_count = func.func_code.co_argcount
-        arg_names = func.func_code.co_varnames[:arg_count]
-
-    arg_value_list = list(args)
-    arguments = dict(
-        (arg_name, arg_value_list[i])
-        for i, arg_name in enumerate(arg_names)
-        if i < len(arg_value_list)
-    )
-    return arguments
-
-
-def _merge_args_with_kwargs(args_dict, kwargs_dict):
-    """Merge args with kwargs."""
-    ret = args_dict.copy()
-    ret.update(kwargs_dict)
-    return ret
-
-
-def validate(*a, **kw) -> typing.Callable:
-    """Decorator for validating arguments of a function against a given schema.
-
-    Set restrictions for arguments:
-
-        >>> @validate(arg1=int, arg2=int)
-        ... def foo(arg1, arg2):
-        ...   return arg1 * arg2
-
-    Set restriction for returned value:
-
-        >>> @validate(arg=int, __return__=int)
-        ... def bar(arg1):
-        ...   return arg1 * 2
-
-    """
-    RETURNS_KEY = '__return__'
-
-    def validate_schema_decorator(func):
-        returns_defined = False
-        returns = None
-
-        schema_args_dict = _args_to_dict(func, a)
-        schema_arguments = _merge_args_with_kwargs(schema_args_dict, kw)
-
-        if RETURNS_KEY in schema_arguments:
-            returns_defined = True
-            returns = schema_arguments[RETURNS_KEY]
-            del schema_arguments[RETURNS_KEY]
-
-        input_schema = (
-            Schema(schema_arguments, extra=ALLOW_EXTRA)
-            if len(schema_arguments) != 0
-            else lambda x: x
-        )
-        output_schema = Schema(returns) if returns_defined else lambda x: x
-
-        @wraps(func)
-        def func_wrapper(*args, **kwargs):
-            args_dict = _args_to_dict(func, args)
-            arguments = _merge_args_with_kwargs(args_dict, kwargs)
-            validated_arguments = input_schema(arguments)
-            output = func(**validated_arguments)
-            return output_schema(output)
-
-        return func_wrapper
-
-    return validate_schema_decorator
diff --git a/server/libs/voluptuous/util.py b/server/libs/voluptuous/util.py
deleted file mode 100644
index 0bf9302..0000000
--- a/server/libs/voluptuous/util.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# F401: "imported but unused"
-# fmt: off
-import typing
-
-from voluptuous import validators  # noqa: F401
-from voluptuous.error import Invalid, LiteralInvalid, TypeInvalid  # noqa: F401
-from voluptuous.schema_builder import DefaultFactory  # noqa: F401
-from voluptuous.schema_builder import Schema, default_factory, raises  # noqa: F401
-
-# fmt: on
-
-__author__ = 'tusharmakkar08'
-
-
-def Lower(v: str) -> str:
-    """Transform a string to lower case.
-
-    >>> s = Schema(Lower)
-    >>> s('HI')
-    'hi'
-    """
-    return str(v).lower()
-
-
-def Upper(v: str) -> str:
-    """Transform a string to upper case.
-
-    >>> s = Schema(Upper)
-    >>> s('hi')
-    'HI'
-    """
-    return str(v).upper()
-
-
-def Capitalize(v: str) -> str:
-    """Capitalise a string.
-
-    >>> s = Schema(Capitalize)
-    >>> s('hello world')
-    'Hello world'
-    """
-    return str(v).capitalize()
-
-
-def Title(v: str) -> str:
-    """Title case a string.
-
-    >>> s = Schema(Title)
-    >>> s('hello world')
-    'Hello World'
-    """
-    return str(v).title()
-
-
-def Strip(v: str) -> str:
-    """Strip whitespace from a string.
-
-    >>> s = Schema(Strip)
-    >>> s('  hello world  ')
-    'hello world'
-    """
-    return str(v).strip()
-
-
-class DefaultTo(object):
-    """Sets a value to default_value if none provided.
-
-    >>> s = Schema(DefaultTo(42))
-    >>> s(None)
-    42
-    >>> s = Schema(DefaultTo(list))
-    >>> s(None)
-    []
-    """
-
-    def __init__(self, default_value, msg: typing.Optional[str] = None) -> None:
-        self.default_value = default_factory(default_value)
-        self.msg = msg
-
-    def __call__(self, v):
-        if v is None:
-            v = self.default_value()
-        return v
-
-    def __repr__(self):
-        return 'DefaultTo(%s)' % (self.default_value(),)
-
-
-class SetTo(object):
-    """Set a value, ignoring any previous value.
-
-    >>> s = Schema(validators.Any(int, SetTo(42)))
-    >>> s(2)
-    2
-    >>> s("foo")
-    42
-    """
-
-    def __init__(self, value) -> None:
-        self.value = default_factory(value)
-
-    def __call__(self, v):
-        return self.value()
-
-    def __repr__(self):
-        return 'SetTo(%s)' % (self.value(),)
-
-
-class Set(object):
-    """Convert a list into a set.
-
-    >>> s = Schema(Set())
-    >>> s([]) == set([])
-    True
-    >>> s([1, 2]) == set([1, 2])
-    True
-    >>> with raises(Invalid, regex="^cannot be presented as set: "):
-    ...   s([set([1, 2]), set([3, 4])])
-    """
-
-    def __init__(self, msg: typing.Optional[str] = None) -> None:
-        self.msg = msg
-
-    def __call__(self, v):
-        try:
-            set_v = set(v)
-        except Exception as e:
-            raise TypeInvalid(self.msg or 'cannot be presented as set: {0}'.format(e))
-        return set_v
-
-    def __repr__(self):
-        return 'Set()'
-
-
-class Literal(object):
-    def __init__(self, lit) -> None:
-        self.lit = lit
-
-    def __call__(self, value, msg: typing.Optional[str] = None):
-        if self.lit != value:
-            raise LiteralInvalid(msg or '%s not match for %s' % (value, self.lit))
-        else:
-            return self.lit
-
-    def __str__(self):
-        return str(self.lit)
-
-    def __repr__(self):
-        return repr(self.lit)
diff --git a/server/libs/voluptuous/validators.py b/server/libs/voluptuous/validators.py
deleted file mode 100644
index d385260..0000000
--- a/server/libs/voluptuous/validators.py
+++ /dev/null
@@ -1,1248 +0,0 @@
-# fmt: off
-from __future__ import annotations
-
-import datetime
-import os
-import re
-import sys
-import typing
-from decimal import Decimal, InvalidOperation
-from functools import wraps
-
-from voluptuous.error import (
-    AllInvalid, AnyInvalid, BooleanInvalid, CoerceInvalid, ContainsInvalid, DateInvalid,
-    DatetimeInvalid, DirInvalid, EmailInvalid, ExactSequenceInvalid, FalseInvalid,
-    FileInvalid, InInvalid, Invalid, LengthInvalid, MatchInvalid, MultipleInvalid,
-    NotEnoughValid, NotInInvalid, PathInvalid, RangeInvalid, TooManyValid, TrueInvalid,
-    TypeInvalid, UrlInvalid,
-)
-
-# F401: flake8 complains about 'raises' not being used, but it is used in doctests
-from voluptuous.schema_builder import Schema, Schemable, message, raises  # noqa: F401
-
-if typing.TYPE_CHECKING:
-    from _typeshed import SupportsAllComparisons
-
-# fmt: on
-
-
-Enum: typing.Union[type, None]
-try:
-    from enum import Enum
-except ImportError:
-    Enum = None
-
-
-if sys.version_info >= (3,):
-    import urllib.parse as urlparse
-
-    basestring = str
-else:
-    import urlparse
-
-# Taken from https://github.com/kvesteri/validators/blob/master/validators/email.py
-# fmt: off
-USER_REGEX = re.compile(
-    # start anchor, because fullmatch is not available in python 2.7
-    "(?:"
-    # dot-atom
-    r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+"
-    r"(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$"
-    # quoted-string
-    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|'
-    r"""\\[\001-\011\013\014\016-\177])*"$)"""
-    # end anchor, because fullmatch is not available in python 2.7
-    r")\Z",
-    re.IGNORECASE,
-)
-DOMAIN_REGEX = re.compile(
-    # start anchor, because fullmatch is not available in python 2.7
-    "(?:"
-    # domain
-    r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+'
-    # tld
-    r'(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?$)'
-    # literal form, ipv4 address (SMTP 4.1.3)
-    r'|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)'
-    r'(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$'
-    # end anchor, because fullmatch is not available in python 2.7
-    r")\Z",
-    re.IGNORECASE,
-)
-# fmt: on
-
-__author__ = 'tusharmakkar08'
-
-
-def truth(f: typing.Callable) -> typing.Callable:
-    """Convenience decorator to convert truth functions into validators.
-
-    >>> @truth
-    ... def isdir(v):
-    ...   return os.path.isdir(v)
-    >>> validate = Schema(isdir)
-    >>> validate('/')
-    '/'
-    >>> with raises(MultipleInvalid, 'not a valid value'):
-    ...   validate('/notavaliddir')
-    """
-
-    @wraps(f)
-    def check(v):
-        t = f(v)
-        if not t:
-            raise ValueError
-        return v
-
-    return check
-
-
-class Coerce(object):
-    """Coerce a value to a type.
-
-    If the type constructor throws a ValueError or TypeError, the value
-    will be marked as Invalid.
-
-    Default behavior:
-
-        >>> validate = Schema(Coerce(int))
-        >>> with raises(MultipleInvalid, 'expected int'):
-        ...   validate(None)
-        >>> with raises(MultipleInvalid, 'expected int'):
-        ...   validate('foo')
-
-    With custom message:
-
-        >>> validate = Schema(Coerce(int, "moo"))
-        >>> with raises(MultipleInvalid, 'moo'):
-        ...   validate('foo')
-    """
-
-    def __init__(
-        self,
-        type: typing.Union[type, typing.Callable],
-        msg: typing.Optional[str] = None,
-    ) -> None:
-        self.type = type
-        self.msg = msg
-        self.type_name = type.__name__
-
-    def __call__(self, v):
-        try:
-            return self.type(v)
-        except (ValueError, TypeError, InvalidOperation):
-            msg = self.msg or ('expected %s' % self.type_name)
-            if not self.msg and Enum and issubclass(self.type, Enum):
-                msg += " or one of %s" % str([e.value for e in self.type])[1:-1]
-            raise CoerceInvalid(msg)
-
-    def __repr__(self):
-        return 'Coerce(%s, msg=%r)' % (self.type_name, self.msg)
-
-
-@message('value was not true', cls=TrueInvalid)
-@truth
-def IsTrue(v):
-    """Assert that a value is true, in the Python sense.
-
-    >>> validate = Schema(IsTrue())
-
-    "In the Python sense" means that implicitly false values, such as empty
-    lists, dictionaries, etc. are treated as "false":
-
-    >>> with raises(MultipleInvalid, "value was not true"):
-    ...   validate([])
-    >>> validate([1])
-    [1]
-    >>> with raises(MultipleInvalid, "value was not true"):
-    ...   validate(False)
-
-    ...and so on.
-
-    >>> try:
-    ...  validate([])
-    ... except MultipleInvalid as e:
-    ...   assert isinstance(e.errors[0], TrueInvalid)
-    """
-    return v
-
-
-@message('value was not false', cls=FalseInvalid)
-def IsFalse(v):
-    """Assert that a value is false, in the Python sense.
-
-    (see :func:`IsTrue` for more detail)
-
-    >>> validate = Schema(IsFalse())
-    >>> validate([])
-    []
-    >>> with raises(MultipleInvalid, "value was not false"):
-    ...   validate(True)
-
-    >>> try:
-    ...  validate(True)
-    ... except MultipleInvalid as e:
-    ...   assert isinstance(e.errors[0], FalseInvalid)
-    """
-    if v:
-        raise ValueError
-    return v
-
-
-@message('expected boolean', cls=BooleanInvalid)
-def Boolean(v):
-    """Convert human-readable boolean values to a bool.
-
-    Accepted values are 1, true, yes, on, enable, and their negatives.
-    Non-string values are cast to bool.
-
-    >>> validate = Schema(Boolean())
-    >>> validate(True)
-    True
-    >>> validate("1")
-    True
-    >>> validate("0")
-    False
-    >>> with raises(MultipleInvalid, "expected boolean"):
-    ...   validate('moo')
-    >>> try:
-    ...  validate('moo')
-    ... except MultipleInvalid as e:
-    ...   assert isinstance(e.errors[0], BooleanInvalid)
-    """
-    if isinstance(v, basestring):
-        v = v.lower()
-        if v in ('1', 'true', 'yes', 'on', 'enable'):
-            return True
-        if v in ('0', 'false', 'no', 'off', 'disable'):
-            return False
-        raise ValueError
-    return bool(v)
-
-
-class _WithSubValidators(object):
-    """Base class for validators that use sub-validators.
-
-    Special class to use as a parent class for validators using sub-validators.
-    This class provides the `__voluptuous_compile__` method so the
-    sub-validators are compiled by the parent `Schema`.
-    """
-
-    def __init__(
-        self, *validators, msg=None, required=False, discriminant=None, **kwargs
-    ) -> None:
-        self.validators = validators
-        self.msg = msg
-        self.required = required
-        self.discriminant = discriminant
-
-    def __voluptuous_compile__(self, schema: Schema) -> typing.Callable:
-        self._compiled = []
-        old_required = schema.required
-        self.schema = schema
-        for v in self.validators:
-            schema.required = self.required
-            self._compiled.append(schema._compile(v))
-        schema.required = old_required
-        return self._run
-
-    def _run(self, path: typing.List[typing.Hashable], value):
-        if self.discriminant is not None:
-            self._compiled = [
-                self.schema._compile(v)
-                for v in self.discriminant(value, self.validators)
-            ]
-
-        return self._exec(self._compiled, value, path)
-
-    def __call__(self, v):
-        return self._exec((Schema(val) for val in self.validators), v)
-
-    def __repr__(self):
-        return '%s(%s, msg=%r)' % (
-            self.__class__.__name__,
-            ", ".join(repr(v) for v in self.validators),
-            self.msg,
-        )
-
-    def _exec(
-        self,
-        funcs: typing.Iterable,
-        v,
-        path: typing.Optional[typing.List[typing.Hashable]] = None,
-    ):
-        raise NotImplementedError()
-
-
-class Any(_WithSubValidators):
-    """Use the first validated value.
-
-    :param msg: Message to deliver to user if validation fails.
-    :param kwargs: All other keyword arguments are passed to the sub-schema constructors.
-    :returns: Return value of the first validator that passes.
-
-    >>> validate = Schema(Any('true', 'false',
-    ...                       All(Any(int, bool), Coerce(bool))))
-    >>> validate('true')
-    'true'
-    >>> validate(1)
-    True
-    >>> with raises(MultipleInvalid, "not a valid value"):
-    ...   validate('moo')
-
-    msg argument is used
-
-    >>> validate = Schema(Any(1, 2, 3, msg="Expected 1 2 or 3"))
-    >>> validate(1)
-    1
-    >>> with raises(MultipleInvalid, "Expected 1 2 or 3"):
-    ...   validate(4)
-    """
-
-    def _exec(self, funcs, v, path=None):
-        error = None
-        for func in funcs:
-            try:
-                if path is None:
-                    return func(v)
-                else:
-                    return func(path, v)
-            except Invalid as e:
-                if error is None or len(e.path) > len(error.path):
-                    error = e
-        else:
-            if error:
-                raise error if self.msg is None else AnyInvalid(self.msg, path=path)
-            raise AnyInvalid(self.msg or 'no valid value found', path=path)
-
-
-# Convenience alias
-Or = Any
-
-
-class Union(_WithSubValidators):
-    """Use the first validated value among those selected by discriminant.
-
-    :param msg: Message to deliver to user if validation fails.
-    :param discriminant(value, validators): Returns the filtered list of validators based on the value.
-    :param kwargs: All other keyword arguments are passed to the sub-schema constructors.
-    :returns: Return value of the first validator that passes.
-
-    >>> validate = Schema(Union({'type':'a', 'a_val':'1'},{'type':'b', 'b_val':'2'},
-    ...                         discriminant=lambda val, alt: filter(
-    ...                         lambda v : v['type'] == val['type'] , alt)))
-    >>> validate({'type':'a', 'a_val':'1'}) == {'type':'a', 'a_val':'1'}
-    True
-    >>> with raises(MultipleInvalid, "not a valid value for dictionary value @ data['b_val']"):
-    ...   validate({'type':'b', 'b_val':'5'})
-
-    ```discriminant({'type':'b', 'a_val':'5'}, [{'type':'a', 'a_val':'1'},{'type':'b', 'b_val':'2'}])``` is invoked
-
-    Without the discriminant, the exception would be "extra keys not allowed @ data['b_val']"
-    """
-
-    def _exec(self, funcs, v, path=None):
-        error = None
-        for func in funcs:
-            try:
-                if path is None:
-                    return func(v)
-                else:
-                    return func(path, v)
-            except Invalid as e:
-                if error is None or len(e.path) > len(error.path):
-                    error = e
-        else:
-            if error:
-                raise error if self.msg is None else AnyInvalid(self.msg, path=path)
-            raise AnyInvalid(self.msg or 'no valid value found', path=path)
-
-
-# Convenience alias
-Switch = Union
-
-
-class All(_WithSubValidators):
-    """Value must pass all validators.
-
-    The output of each validator is passed as input to the next.
-
-    :param msg: Message to deliver to user if validation fails.
-    :param kwargs: All other keyword arguments are passed to the sub-schema constructors.
-
-    >>> validate = Schema(All('10', Coerce(int)))
-    >>> validate('10')
-    10
-    """
-
-    def _exec(self, funcs, v, path=None):
-        try:
-            for func in funcs:
-                if path is None:
-                    v = func(v)
-                else:
-                    v = func(path, v)
-        except Invalid as e:
-            raise e if self.msg is None else AllInvalid(self.msg, path=path)
-        return v
-
-
-# Convenience alias
-And = All
-
-
-class Match(object):
-    """Value must be a string that matches the regular expression.
-
-    >>> validate = Schema(Match(r'^0x[A-F0-9]+$'))
-    >>> validate('0x123EF4')
-    '0x123EF4'
-    >>> with raises(MultipleInvalid, 'does not match regular expression ^0x[A-F0-9]+$'):
-    ...   validate('123EF4')
-
-    >>> with raises(MultipleInvalid, 'expected string or buffer'):
-    ...   validate(123)
-
-    Pattern may also be a compiled regular expression:
-
-    >>> validate = Schema(Match(re.compile(r'0x[A-F0-9]+', re.I)))
-    >>> validate('0x123ef4')
-    '0x123ef4'
-    """
-
-    def __init__(
-        self, pattern: typing.Union[re.Pattern, str], msg: typing.Optional[str] = None
-    ) -> None:
-        if isinstance(pattern, basestring):
-            pattern = re.compile(pattern)
-        self.pattern = pattern
-        self.msg = msg
-
-    def __call__(self, v):
-        try:
-            match = self.pattern.match(v)
-        except TypeError:
-            raise MatchInvalid("expected string or buffer")
-        if not match:
-            raise MatchInvalid(
-                self.msg
-                or 'does not match regular expression {}'.format(self.pattern.pattern)
-            )
-        return v
-
-    def __repr__(self):
-        return 'Match(%r, msg=%r)' % (self.pattern.pattern, self.msg)
-
-
-class Replace(object):
-    """Regex substitution.
-
-    >>> validate = Schema(All(Replace('you', 'I'),
-    ...                       Replace('hello', 'goodbye')))
-    >>> validate('you say hello')
-    'I say goodbye'
-    """
-
-    def __init__(
-        self,
-        pattern: typing.Union[re.Pattern, str],
-        substitution: str,
-        msg: typing.Optional[str] = None,
-    ) -> None:
-        if isinstance(pattern, basestring):
-            pattern = re.compile(pattern)
-        self.pattern = pattern
-        self.substitution = substitution
-        self.msg = msg
-
-    def __call__(self, v):
-        return self.pattern.sub(self.substitution, v)
-
-    def __repr__(self):
-        return 'Replace(%r, %r, msg=%r)' % (
-            self.pattern.pattern,
-            self.substitution,
-            self.msg,
-        )
-
-
-def _url_validation(v: str) -> urlparse.ParseResult:
-    parsed = urlparse.urlparse(v)
-    if not parsed.scheme or not parsed.netloc:
-        raise UrlInvalid("must have a URL scheme and host")
-    return parsed
-
-
-@message('expected an email address', cls=EmailInvalid)
-def Email(v):
-    """Verify that the value is an email address or not.
-
-    >>> s = Schema(Email())
-    >>> with raises(MultipleInvalid, 'expected an email address'):
-    ...   s("a.com")
-    >>> with raises(MultipleInvalid, 'expected an email address'):
-    ...   s("a@.com")
-    >>> with raises(MultipleInvalid, 'expected an email address'):
-    ...   s("a@.com")
-    >>> s('t@x.com')
-    't@x.com'
-    """
-    try:
-        if not v or "@" not in v:
-            raise EmailInvalid("Invalid email address")
-        user_part, domain_part = v.rsplit('@', 1)
-
-        if not (USER_REGEX.match(user_part) and DOMAIN_REGEX.match(domain_part)):
-            raise EmailInvalid("Invalid email address")
-        return v
-    except:  # noqa: E722
-        raise ValueError
-
-
-@message('expected a fully qualified domain name URL', cls=UrlInvalid)
-def FqdnUrl(v):
-    """Verify that the value is a fully qualified domain name URL.
-
-    >>> s = Schema(FqdnUrl())
-    >>> with raises(MultipleInvalid, 'expected a fully qualified domain name URL'):
-    ...   s("http://localhost/")
-    >>> s('http://w3.org')
-    'http://w3.org'
-    """
-    try:
-        parsed_url = _url_validation(v)
-        if "." not in parsed_url.netloc:
-            raise UrlInvalid("must have a domain name in URL")
-        return v
-    except:  # noqa: E722
-        raise ValueError
-
-
-@message('expected a URL', cls=UrlInvalid)
-def Url(v):
-    """Verify that the value is a URL.
-
-    >>> s = Schema(Url())
-    >>> with raises(MultipleInvalid, 'expected a URL'):
-    ...   s(1)
-    >>> s('http://w3.org')
-    'http://w3.org'
-    """
-    try:
-        _url_validation(v)
-        return v
-    except:  # noqa: E722
-        raise ValueError
-
-
-@message('Not a file', cls=FileInvalid)
-@truth
-def IsFile(v):
-    """Verify the file exists.
-
-    >>> os.path.basename(IsFile()(__file__)).startswith('validators.py')
-    True
-    >>> with raises(FileInvalid, 'Not a file'):
-    ...   IsFile()("random_filename_goes_here.py")
-    >>> with raises(FileInvalid, 'Not a file'):
-    ...   IsFile()(None)
-    """
-    try:
-        if v:
-            v = str(v)
-            return os.path.isfile(v)
-        else:
-            raise FileInvalid('Not a file')
-    except TypeError:
-        raise FileInvalid('Not a file')
-
-
-@message('Not a directory', cls=DirInvalid)
-@truth
-def IsDir(v):
-    """Verify the directory exists.
-
-    >>> IsDir()('/')
-    '/'
-    >>> with raises(DirInvalid, 'Not a directory'):
-    ...   IsDir()(None)
-    """
-    try:
-        if v:
-            v = str(v)
-            return os.path.isdir(v)
-        else:
-            raise DirInvalid("Not a directory")
-    except TypeError:
-        raise DirInvalid("Not a directory")
-
-
-@message('path does not exist', cls=PathInvalid)
-@truth
-def PathExists(v):
-    """Verify the path exists, regardless of its type.
-
-    >>> os.path.basename(PathExists()(__file__)).startswith('validators.py')
-    True
-    >>> with raises(Invalid, 'path does not exist'):
-    ...   PathExists()("random_filename_goes_here.py")
-    >>> with raises(PathInvalid, 'Not a Path'):
-    ...   PathExists()(None)
-    """
-    try:
-        if v:
-            v = str(v)
-            return os.path.exists(v)
-        else:
-            raise PathInvalid("Not a Path")
-    except TypeError:
-        raise PathInvalid("Not a Path")
-
-
-def Maybe(validator: Schemable, msg: typing.Optional[str] = None):
-    """Validate that the object matches given validator or is None.
-
-    :raises Invalid: If the value does not match the given validator and is not
-        None.
-
-    >>> s = Schema(Maybe(int))
-    >>> s(10)
-    10
-    >>> with raises(Invalid):
-    ...  s("string")
-
-    """
-    return Any(None, validator, msg=msg)
-
-
-class Range(object):
-    """Limit a value to a range.
-
-    Either min or max may be omitted.
-    Either min or max can be excluded from the range of accepted values.
-
-    :raises Invalid: If the value is outside the range.
-
-    >>> s = Schema(Range(min=1, max=10, min_included=False))
-    >>> s(5)
-    5
-    >>> s(10)
-    10
-    >>> with raises(MultipleInvalid, 'value must be at most 10'):
-    ...   s(20)
-    >>> with raises(MultipleInvalid, 'value must be higher than 1'):
-    ...   s(1)
-    >>> with raises(MultipleInvalid, 'value must be lower than 10'):
-    ...   Schema(Range(max=10, max_included=False))(20)
-    """
-
-    def __init__(
-        self,
-        min: SupportsAllComparisons | None = None,
-        max: SupportsAllComparisons | None = None,
-        min_included: bool = True,
-        max_included: bool = True,
-        msg: typing.Optional[str] = None,
-    ) -> None:
-        self.min = min
-        self.max = max
-        self.min_included = min_included
-        self.max_included = max_included
-        self.msg = msg
-
-    def __call__(self, v):
-        try:
-            if self.min_included:
-                if self.min is not None and not v >= self.min:
-                    raise RangeInvalid(
-                        self.msg or 'value must be at least %s' % self.min
-                    )
-            else:
-                if self.min is not None and not v > self.min:
-                    raise RangeInvalid(
-                        self.msg or 'value must be higher than %s' % self.min
-                    )
-            if self.max_included:
-                if self.max is not None and not v <= self.max:
-                    raise RangeInvalid(
-                        self.msg or 'value must be at most %s' % self.max
-                    )
-            else:
-                if self.max is not None and not v < self.max:
-                    raise RangeInvalid(
-                        self.msg or 'value must be lower than %s' % self.max
-                    )
-
-            return v
-
-        # Objects that lack a partial ordering, e.g. None or strings will raise TypeError
-        except TypeError:
-            raise RangeInvalid(
-                self.msg or 'invalid value or type (must have a partial ordering)'
-            )
-
-    def __repr__(self):
-        return 'Range(min=%r, max=%r, min_included=%r, max_included=%r, msg=%r)' % (
-            self.min,
-            self.max,
-            self.min_included,
-            self.max_included,
-            self.msg,
-        )
-
-
-class Clamp(object):
-    """Clamp a value to a range.
-
-    Either min or max may be omitted.
-
-    >>> s = Schema(Clamp(min=0, max=1))
-    >>> s(0.5)
-    0.5
-    >>> s(5)
-    1
-    >>> s(-1)
-    0
-    """
-
-    def __init__(
-        self,
-        min: SupportsAllComparisons | None = None,
-        max: SupportsAllComparisons | None = None,
-        msg: typing.Optional[str] = None,
-    ) -> None:
-        self.min = min
-        self.max = max
-        self.msg = msg
-
-    def __call__(self, v):
-        try:
-            if self.min is not None and v < self.min:
-                v = self.min
-            if self.max is not None and v > self.max:
-                v = self.max
-            return v
-
-        # Objects that lack a partial ordering, e.g. None or strings will raise TypeError
-        except TypeError:
-            raise RangeInvalid(
-                self.msg or 'invalid value or type (must have a partial ordering)'
-            )
-
-    def __repr__(self):
-        return 'Clamp(min=%s, max=%s)' % (self.min, self.max)
-
-
-class Length(object):
-    """The length of a value must be in a certain range."""
-
-    def __init__(
-        self,
-        min: SupportsAllComparisons | None = None,
-        max: SupportsAllComparisons | None = None,
-        msg: typing.Optional[str] = None,
-    ) -> None:
-        self.min = min
-        self.max = max
-        self.msg = msg
-
-    def __call__(self, v):
-        try:
-            if self.min is not None and len(v) < self.min:
-                raise LengthInvalid(
-                    self.msg or 'length of value must be at least %s' % self.min
-                )
-            if self.max is not None and len(v) > self.max:
-                raise LengthInvalid(
-                    self.msg or 'length of value must be at most %s' % self.max
-                )
-            return v
-
-        # Objects that have no length e.g. None or strings will raise TypeError
-        except TypeError:
-            raise RangeInvalid(self.msg or 'invalid value or type')
-
-    def __repr__(self):
-        return 'Length(min=%s, max=%s)' % (self.min, self.max)
-
-
-class Datetime(object):
-    """Validate that the value matches the datetime format."""
-
-    DEFAULT_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
-
-    def __init__(
-        self, format: typing.Optional[str] = None, msg: typing.Optional[str] = None
-    ) -> None:
-        self.format = format or self.DEFAULT_FORMAT
-        self.msg = msg
-
-    def __call__(self, v):
-        try:
-            datetime.datetime.strptime(v, self.format)
-        except (TypeError, ValueError):
-            raise DatetimeInvalid(
-                self.msg or 'value does not match expected format %s' % self.format
-            )
-        return v
-
-    def __repr__(self):
-        return 'Datetime(format=%s)' % self.format
-
-
-class Date(Datetime):
-    """Validate that the value matches the date format."""
-
-    DEFAULT_FORMAT = '%Y-%m-%d'
-
-    def __call__(self, v):
-        try:
-            datetime.datetime.strptime(v, self.format)
-        except (TypeError, ValueError):
-            raise DateInvalid(
-                self.msg or 'value does not match expected format %s' % self.format
-            )
-        return v
-
-    def __repr__(self):
-        return 'Date(format=%s)' % self.format
-
-
-class In(object):
-    """Validate that a value is in a collection."""
-
-    def __init__(
-        self, container: typing.Container, msg: typing.Optional[str] = None
-    ) -> None:
-        self.container = container
-        self.msg = msg
-
-    def __call__(self, v):
-        try:
-            check = v not in self.container
-        except TypeError:
-            check = True
-        if check:
-            try:
-                raise InInvalid(
-                    self.msg or f'value must be one of {sorted(self.container)}'
-                )
-            except TypeError:
-                raise InInvalid(
-                    self.msg
-                    or f'value must be one of {sorted(self.container, key=str)}'
-                )
-        return v
-
-    def __repr__(self):
-        return 'In(%s)' % (self.container,)
-
-
-class NotIn(object):
-    """Validate that a value is not in a collection."""
-
-    def __init__(
-        self, container: typing.Iterable, msg: typing.Optional[str] = None
-    ) -> None:
-        self.container = container
-        self.msg = msg
-
-    def __call__(self, v):
-        try:
-            check = v in self.container
-        except TypeError:
-            check = True
-        if check:
-            try:
-                raise NotInInvalid(
-                    self.msg or f'value must not be one of {sorted(self.container)}'
-                )
-            except TypeError:
-                raise NotInInvalid(
-                    self.msg
-                    or f'value must not be one of {sorted(self.container, key=str)}'
-                )
-        return v
-
-    def __repr__(self):
-        return 'NotIn(%s)' % (self.container,)
-
-
-class Contains(object):
-    """Validate that the given schema element is in the sequence being validated.
-
-    >>> s = Contains(1)
-    >>> s([3, 2, 1])
-    [3, 2, 1]
-    >>> with raises(ContainsInvalid, 'value is not allowed'):
-    ...   s([3, 2])
-    """
-
-    def __init__(self, item, msg: typing.Optional[str] = None) -> None:
-        self.item = item
-        self.msg = msg
-
-    def __call__(self, v):
-        try:
-            check = self.item not in v
-        except TypeError:
-            check = True
-        if check:
-            raise ContainsInvalid(self.msg or 'value is not allowed')
-        return v
-
-    def __repr__(self):
-        return 'Contains(%s)' % (self.item,)
-
-
-class ExactSequence(object):
-    """Matches each element in a sequence against the corresponding element in
-    the validators.
-
-    :param msg: Message to deliver to user if validation fails.
-    :param kwargs: All other keyword arguments are passed to the sub-schema
-        constructors.
-
-    >>> from voluptuous import Schema, ExactSequence
-    >>> validate = Schema(ExactSequence([str, int, list, list]))
-    >>> validate(['hourly_report', 10, [], []])
-    ['hourly_report', 10, [], []]
-    >>> validate(('hourly_report', 10, [], []))
-    ('hourly_report', 10, [], [])
-    """
-
-    def __init__(
-        self,
-        validators: typing.Iterable[Schemable],
-        msg: typing.Optional[str] = None,
-        **kwargs,
-    ) -> None:
-        self.validators = validators
-        self.msg = msg
-        self._schemas = [Schema(val, **kwargs) for val in validators]
-
-    def __call__(self, v):
-        if not isinstance(v, (list, tuple)) or len(v) != len(self._schemas):
-            raise ExactSequenceInvalid(self.msg)
-        try:
-            v = type(v)(schema(x) for x, schema in zip(v, self._schemas))
-        except Invalid as e:
-            raise e if self.msg is None else ExactSequenceInvalid(self.msg)
-        return v
-
-    def __repr__(self):
-        return 'ExactSequence([%s])' % ", ".join(repr(v) for v in self.validators)
-
-
-class Unique(object):
-    """Ensure an iterable does not contain duplicate items.
-
-    Only iterables convertible to a set are supported (native types and
-    objects with correct __eq__).
-
-    JSON does not support set, so they need to be presented as arrays.
-    Unique allows ensuring that such array does not contain dupes.
-
-    >>> s = Schema(Unique())
-    >>> s([])
-    []
-    >>> s([1, 2])
-    [1, 2]
-    >>> with raises(Invalid, 'contains duplicate items: [1]'):
-    ...   s([1, 1, 2])
-    >>> with raises(Invalid, "contains duplicate items: ['one']"):
-    ...   s(['one', 'two', 'one'])
-    >>> with raises(Invalid, regex="^contains unhashable elements: "):
-    ...   s([set([1, 2]), set([3, 4])])
-    >>> s('abc')
-    'abc'
-    >>> with raises(Invalid, regex="^contains duplicate items: "):
-    ...   s('aabbc')
-    """
-
-    def __init__(self, msg: typing.Optional[str] = None) -> None:
-        self.msg = msg
-
-    def __call__(self, v):
-        try:
-            set_v = set(v)
-        except TypeError as e:
-            raise TypeInvalid(self.msg or 'contains unhashable elements: {0}'.format(e))
-        if len(set_v) != len(v):
-            seen = set()
-            dupes = list(set(x for x in v if x in seen or seen.add(x)))
-            raise Invalid(self.msg or 'contains duplicate items: {0}'.format(dupes))
-        return v
-
-    def __repr__(self):
-        return 'Unique()'
-
-
-class Equal(object):
-    """Ensure that value matches target.
-
-    >>> s = Schema(Equal(1))
-    >>> s(1)
-    1
-    >>> with raises(Invalid):
-    ...    s(2)
-
-    Validators are not supported, match must be exact:
-
-    >>> s = Schema(Equal(str))
-    >>> with raises(Invalid):
-    ...     s('foo')
-    """
-
-    def __init__(self, target, msg: typing.Optional[str] = None) -> None:
-        self.target = target
-        self.msg = msg
-
-    def __call__(self, v):
-        if v != self.target:
-            raise Invalid(
-                self.msg
-                or 'Values are not equal: value:{} != target:{}'.format(v, self.target)
-            )
-        return v
-
-    def __repr__(self):
-        return 'Equal({})'.format(self.target)
-
-
-class Unordered(object):
-    """Ensures sequence contains values in unspecified order.
-
-    >>> s = Schema(Unordered([2, 1]))
-    >>> s([2, 1])
-    [2, 1]
-    >>> s([1, 2])
-    [1, 2]
-    >>> s = Schema(Unordered([str, int]))
-    >>> s(['foo', 1])
-    ['foo', 1]
-    >>> s([1, 'foo'])
-    [1, 'foo']
-    """
-
-    def __init__(
-        self,
-        validators: typing.Iterable[Schemable],
-        msg: typing.Optional[str] = None,
-        **kwargs,
-    ) -> None:
-        self.validators = validators
-        self.msg = msg
-        self._schemas = [Schema(val, **kwargs) for val in validators]
-
-    def __call__(self, v):
-        if not isinstance(v, (list, tuple)):
-            raise Invalid(self.msg or 'Value {} is not sequence!'.format(v))
-
-        if len(v) != len(self._schemas):
-            raise Invalid(
-                self.msg
-                or 'List lengths differ, value:{} != target:{}'.format(
-                    len(v), len(self._schemas)
-                )
-            )
-
-        consumed = set()
-        missing = []
-        for index, value in enumerate(v):
-            found = False
-            for i, s in enumerate(self._schemas):
-                if i in consumed:
-                    continue
-                try:
-                    s(value)
-                except Invalid:
-                    pass
-                else:
-                    found = True
-                    consumed.add(i)
-                    break
-            if not found:
-                missing.append((index, value))
-
-        if len(missing) == 1:
-            el = missing[0]
-            raise Invalid(
-                self.msg
-                or 'Element #{} ({}) is not valid against any validator'.format(
-                    el[0], el[1]
-                )
-            )
-        elif missing:
-            raise MultipleInvalid(
-                [
-                    Invalid(
-                        self.msg
-                        or 'Element #{} ({}) is not valid against any validator'.format(
-                            el[0], el[1]
-                        )
-                    )
-                    for el in missing
-                ]
-            )
-        return v
-
-    def __repr__(self):
-        return 'Unordered([{}])'.format(", ".join(repr(v) for v in self.validators))
-
-
-class Number(object):
-    """
-    Verify the number of digits that are present in the number(Precision),
-    and the decimal places(Scale).
-
-    :raises Invalid: If the value does not match the provided Precision and Scale.
-
-    >>> schema = Schema(Number(precision=6, scale=2))
-    >>> schema('1234.01')
-    '1234.01'
-    >>> schema = Schema(Number(precision=6, scale=2, yield_decimal=True))
-    >>> schema('1234.01')
-    Decimal('1234.01')
-    """
-
-    def __init__(
-        self,
-        precision: typing.Optional[int] = None,
-        scale: typing.Optional[int] = None,
-        msg: typing.Optional[str] = None,
-        yield_decimal: bool = False,
-    ) -> None:
-        self.precision = precision
-        self.scale = scale
-        self.msg = msg
-        self.yield_decimal = yield_decimal
-
-    def __call__(self, v):
-        """
-        :param v: is a number enclosed with string
-        :return: Decimal number
-        """
-        precision, scale, decimal_num = self._get_precision_scale(v)
-
-        if (
-            self.precision is not None
-            and self.scale is not None
-            and precision != self.precision
-            and scale != self.scale
-        ):
-            raise Invalid(
-                self.msg
-                or "Precision must be equal to %s, and Scale must be equal to %s"
-                % (self.precision, self.scale)
-            )
-        else:
-            if self.precision is not None and precision != self.precision:
-                raise Invalid(
-                    self.msg or "Precision must be equal to %s" % self.precision
-                )
-
-            if self.scale is not None and scale != self.scale:
-                raise Invalid(self.msg or "Scale must be equal to %s" % self.scale)
-
-        if self.yield_decimal:
-            return decimal_num
-        else:
-            return v
-
-    def __repr__(self):
-        return 'Number(precision=%s, scale=%s, msg=%s)' % (
-            self.precision,
-            self.scale,
-            self.msg,
-        )
-
-    def _get_precision_scale(self, number) -> typing.Tuple[int, int, Decimal]:
-        """
-        :param number:
-        :return: tuple(precision, scale, decimal_number)
-        """
-        try:
-            decimal_num = Decimal(number)
-        except InvalidOperation:
-            raise Invalid(self.msg or 'Value must be a number enclosed with string')
-
-        exp = decimal_num.as_tuple().exponent
-        if isinstance(exp, int):
-            return (len(decimal_num.as_tuple().digits), -exp, decimal_num)
-        else:
-            # TODO: handle infinity and NaN
-            # raise Invalid(self.msg or 'Value has no precision')
-            raise TypeError("infinity and NaN have no precision")
-
-
-class SomeOf(_WithSubValidators):
-    """Value must pass at least some validations, determined by the given parameter.
-    Optionally, number of passed validations can be capped.
-
-    The output of each validator is passed as input to the next.
-
-    :param min_valid: Minimum number of valid schemas.
-    :param validators: List of schemas or validators to match input against.
-    :param max_valid: Maximum number of valid schemas.
-    :param msg: Message to deliver to user if validation fails.
-    :param kwargs: All other keyword arguments are passed to the sub-schema constructors.
-
-    :raises NotEnoughValid: If the minimum number of validations isn't met.
-    :raises TooManyValid: If the maximum number of validations is exceeded.
-
-    >>> validate = Schema(SomeOf(min_valid=2, validators=[Range(1, 5), Any(float, int), 6.6]))
-    >>> validate(6.6)
-    6.6
-    >>> validate(3)
-    3
-    >>> with raises(MultipleInvalid, 'value must be at most 5, not a valid value'):
-    ...     validate(6.2)
-    """
-
-    def __init__(
-        self,
-        validators: typing.List[Schemable],
-        min_valid: typing.Optional[int] = None,
-        max_valid: typing.Optional[int] = None,
-        **kwargs,
-    ) -> None:
-        assert min_valid is not None or max_valid is not None, (
-            'when using "%s" you should specify at least one of min_valid and max_valid'
-            % (type(self).__name__,)
-        )
-        self.min_valid = min_valid or 0
-        self.max_valid = max_valid or len(validators)
-        super(SomeOf, self).__init__(*validators, **kwargs)
-
-    def _exec(self, funcs, v, path=None):
-        errors = []
-        funcs = list(funcs)
-        for func in funcs:
-            try:
-                if path is None:
-                    v = func(v)
-                else:
-                    v = func(path, v)
-            except Invalid as e:
-                errors.append(e)
-
-        passed_count = len(funcs) - len(errors)
-        if self.min_valid <= passed_count <= self.max_valid:
-            return v
-
-        msg = self.msg
-        if not msg:
-            msg = ', '.join(map(str, errors))
-
-        if passed_count > self.max_valid:
-            raise TooManyValid(msg)
-        raise NotEnoughValid(msg)
-
-    def __repr__(self):
-        return 'SomeOf(min_valid=%s, validators=[%s], max_valid=%s, msg=%r)' % (
-            self.min_valid,
-            ", ".join(repr(v) for v in self.validators),
-            self.max_valid,
-            self.msg,
-        )
diff --git a/server/libs/zipp-3.23.0.dist-info/INSTALLER b/server/libs/zipp-3.23.0.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/server/libs/zipp-3.23.0.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/server/libs/zipp-3.23.0.dist-info/METADATA b/server/libs/zipp-3.23.0.dist-info/METADATA
deleted file mode 100644
index 6420117..0000000
--- a/server/libs/zipp-3.23.0.dist-info/METADATA
+++ /dev/null
@@ -1,106 +0,0 @@
-Metadata-Version: 2.4
-Name: zipp
-Version: 3.23.0
-Summary: Backport of pathlib-compatible object wrapper for zip files
-Author-email: "Jason R. Coombs" 
-License-Expression: MIT
-Project-URL: Source, https://github.com/jaraco/zipp
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3 :: Only
-Requires-Python: >=3.9
-Description-Content-Type: text/x-rst
-License-File: LICENSE
-Provides-Extra: test
-Requires-Dist: pytest!=8.1.*,>=6; extra == "test"
-Requires-Dist: jaraco.itertools; extra == "test"
-Requires-Dist: jaraco.functools; extra == "test"
-Requires-Dist: more_itertools; extra == "test"
-Requires-Dist: big-O; extra == "test"
-Requires-Dist: pytest-ignore-flaky; extra == "test"
-Requires-Dist: jaraco.test; extra == "test"
-Provides-Extra: doc
-Requires-Dist: sphinx>=3.5; extra == "doc"
-Requires-Dist: jaraco.packaging>=9.3; extra == "doc"
-Requires-Dist: rst.linker>=1.9; extra == "doc"
-Requires-Dist: furo; extra == "doc"
-Requires-Dist: sphinx-lint; extra == "doc"
-Requires-Dist: jaraco.tidelift>=1.4; extra == "doc"
-Provides-Extra: check
-Requires-Dist: pytest-checkdocs>=2.4; extra == "check"
-Requires-Dist: pytest-ruff>=0.2.1; sys_platform != "cygwin" and extra == "check"
-Provides-Extra: cover
-Requires-Dist: pytest-cov; extra == "cover"
-Provides-Extra: enabler
-Requires-Dist: pytest-enabler>=2.2; extra == "enabler"
-Provides-Extra: type
-Requires-Dist: pytest-mypy; extra == "type"
-Dynamic: license-file
-
-.. image:: https://img.shields.io/pypi/v/zipp.svg
-   :target: https://pypi.org/project/zipp
-
-.. image:: https://img.shields.io/pypi/pyversions/zipp.svg
-
-.. image:: https://github.com/jaraco/zipp/actions/workflows/main.yml/badge.svg
-   :target: https://github.com/jaraco/zipp/actions?query=workflow%3A%22tests%22
-   :alt: tests
-
-.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
-    :target: https://github.com/astral-sh/ruff
-    :alt: Ruff
-
-.. image:: https://readthedocs.org/projects/zipp/badge/?version=latest
-..    :target: https://zipp.readthedocs.io/en/latest/?badge=latest
-
-.. image:: https://img.shields.io/badge/skeleton-2025-informational
-   :target: https://blog.jaraco.com/skeleton
-
-.. image:: https://tidelift.com/badges/package/pypi/zipp
-   :target: https://tidelift.com/subscription/pkg/pypi-zipp?utm_source=pypi-zipp&utm_medium=readme
-
-
-A pathlib-compatible Zipfile object wrapper. Official backport of the standard library
-`Path object `_.
-
-
-Compatibility
-=============
-
-New features are introduced in this third-party library and later merged
-into CPython. The following table indicates which versions of this library
-were contributed to different versions in the standard library:
-
-.. list-table::
-   :header-rows: 1
-
-   * - zipp
-     - stdlib
-   * - 3.18
-     - 3.13
-   * - 3.16
-     - 3.12
-   * - 3.5
-     - 3.11
-   * - 3.2
-     - 3.10
-   * - 3.3 ??
-     - 3.9
-   * - 1.0
-     - 3.8
-
-
-Usage
-=====
-
-Use ``zipp.Path`` in place of ``zipfile.Path`` on any Python.
-
-For Enterprise
-==============
-
-Available as part of the Tidelift Subscription.
-
-This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.
-
-`Learn more `_.
diff --git a/server/libs/zipp-3.23.0.dist-info/RECORD b/server/libs/zipp-3.23.0.dist-info/RECORD
deleted file mode 100644
index 08332d5..0000000
--- a/server/libs/zipp-3.23.0.dist-info/RECORD
+++ /dev/null
@@ -1,21 +0,0 @@
-zipp-3.23.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-zipp-3.23.0.dist-info/METADATA,sha256=vdZ9TRbPC_O4k-fRjNPS13StuC837Zhbx3cMYHIms1s,3563
-zipp-3.23.0.dist-info/RECORD,,
-zipp-3.23.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-zipp-3.23.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
-zipp-3.23.0.dist-info/licenses/LICENSE,sha256=WlfLTbheKi3YjCkGKJCK3VfjRRRJ4KmnH9-zh3b9dZ0,1076
-zipp-3.23.0.dist-info/top_level.txt,sha256=iAbdoSHfaGqBfVb2XuR9JqSQHCoOsOtG6y9C_LSpqFw,5
-zipp/__init__.py,sha256=ieXh9GIMdABjKRX_JUJtP9k5wdBLK4Mt5X4nszSkmYE,11976
-zipp/__pycache__/__init__.cpython-311.pyc,,
-zipp/__pycache__/_functools.cpython-311.pyc,,
-zipp/__pycache__/glob.cpython-311.pyc,,
-zipp/_functools.py,sha256=f6Kt9LxZ4TE-cY1lJVdXSId3memSXmH9IdgMbU-_x2k,575
-zipp/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-zipp/compat/__pycache__/__init__.cpython-311.pyc,,
-zipp/compat/__pycache__/overlay.cpython-311.pyc,,
-zipp/compat/__pycache__/py310.cpython-311.pyc,,
-zipp/compat/__pycache__/py313.cpython-311.pyc,,
-zipp/compat/overlay.py,sha256=oEIGAnbr8yGjuKTrVSO2ByewPui71uppbX18BLnYTKE,783
-zipp/compat/py310.py,sha256=S7i6N9mToEn3asNb2ILyjnzvITOXrATD_J4emjyBbDU,256
-zipp/compat/py313.py,sha256=RndvDNtuY7H2D9ecnnzcPBMZ8mZc42gmXD_IwQAXXAE,654
-zipp/glob.py,sha256=DLV9LBsDxA6YVW82e3-tkoNrus1h4R-j3BR6VqS0AzE,3382
diff --git a/server/libs/zipp-3.23.0.dist-info/REQUESTED b/server/libs/zipp-3.23.0.dist-info/REQUESTED
deleted file mode 100644
index e69de29..0000000
diff --git a/server/libs/zipp-3.23.0.dist-info/WHEEL b/server/libs/zipp-3.23.0.dist-info/WHEEL
deleted file mode 100644
index e7fa31b..0000000
--- a/server/libs/zipp-3.23.0.dist-info/WHEEL
+++ /dev/null
@@ -1,5 +0,0 @@
-Wheel-Version: 1.0
-Generator: setuptools (80.9.0)
-Root-Is-Purelib: true
-Tag: py3-none-any
-
diff --git a/server/libs/zipp-3.23.0.dist-info/licenses/LICENSE b/server/libs/zipp-3.23.0.dist-info/licenses/LICENSE
deleted file mode 100644
index f60bd57..0000000
--- a/server/libs/zipp-3.23.0.dist-info/licenses/LICENSE
+++ /dev/null
@@ -1,18 +0,0 @@
-MIT License
-
-Copyright (c) 2025 
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
-associated documentation files (the "Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
-following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial
-portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
-LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
-EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/server/libs/zipp-3.23.0.dist-info/top_level.txt b/server/libs/zipp-3.23.0.dist-info/top_level.txt
deleted file mode 100644
index e82f676..0000000
--- a/server/libs/zipp-3.23.0.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-zipp
diff --git a/server/libs/zipp/__init__.py b/server/libs/zipp/__init__.py
deleted file mode 100644
index ed5b214..0000000
--- a/server/libs/zipp/__init__.py
+++ /dev/null
@@ -1,456 +0,0 @@
-"""
-A Path-like interface for zipfiles.
-
-This codebase is shared between zipfile.Path in the stdlib
-and zipp in PyPI. See
-https://github.com/python/importlib_metadata/wiki/Development-Methodology
-for more detail.
-"""
-
-import functools
-import io
-import itertools
-import pathlib
-import posixpath
-import re
-import stat
-import sys
-import zipfile
-
-from ._functools import save_method_args
-from .compat.py310 import text_encoding
-from .glob import Translator
-
-__all__ = ['Path']
-
-
-def _parents(path):
-    """
-    Given a path with elements separated by
-    posixpath.sep, generate all parents of that path.
-
-    >>> list(_parents('b/d'))
-    ['b']
-    >>> list(_parents('/b/d/'))
-    ['/b']
-    >>> list(_parents('b/d/f/'))
-    ['b/d', 'b']
-    >>> list(_parents('b'))
-    []
-    >>> list(_parents(''))
-    []
-    """
-    return itertools.islice(_ancestry(path), 1, None)
-
-
-def _ancestry(path):
-    """
-    Given a path with elements separated by
-    posixpath.sep, generate all elements of that path.
-
-    >>> list(_ancestry('b/d'))
-    ['b/d', 'b']
-    >>> list(_ancestry('/b/d/'))
-    ['/b/d', '/b']
-    >>> list(_ancestry('b/d/f/'))
-    ['b/d/f', 'b/d', 'b']
-    >>> list(_ancestry('b'))
-    ['b']
-    >>> list(_ancestry(''))
-    []
-
-    Multiple separators are treated like a single.
-
-    >>> list(_ancestry('//b//d///f//'))
-    ['//b//d///f', '//b//d', '//b']
-    """
-    path = path.rstrip(posixpath.sep)
-    while path.rstrip(posixpath.sep):
-        yield path
-        path, tail = posixpath.split(path)
-
-
-_dedupe = dict.fromkeys
-"""Deduplicate an iterable in original order"""
-
-
-def _difference(minuend, subtrahend):
-    """
-    Return items in minuend not in subtrahend, retaining order
-    with O(1) lookup.
-    """
-    return itertools.filterfalse(set(subtrahend).__contains__, minuend)
-
-
-class InitializedState:
-    """
-    Mix-in to save the initialization state for pickling.
-    """
-
-    @save_method_args
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-
-    def __getstate__(self):
-        return self._saved___init__.args, self._saved___init__.kwargs
-
-    def __setstate__(self, state):
-        args, kwargs = state
-        super().__init__(*args, **kwargs)
-
-
-class CompleteDirs(InitializedState, zipfile.ZipFile):
-    """
-    A ZipFile subclass that ensures that implied directories
-    are always included in the namelist.
-
-    >>> list(CompleteDirs._implied_dirs(['foo/bar.txt', 'foo/bar/baz.txt']))
-    ['foo/', 'foo/bar/']
-    >>> list(CompleteDirs._implied_dirs(['foo/bar.txt', 'foo/bar/baz.txt', 'foo/bar/']))
-    ['foo/']
-    """
-
-    @staticmethod
-    def _implied_dirs(names):
-        parents = itertools.chain.from_iterable(map(_parents, names))
-        as_dirs = (p + posixpath.sep for p in parents)
-        return _dedupe(_difference(as_dirs, names))
-
-    def namelist(self):
-        names = super().namelist()
-        return names + list(self._implied_dirs(names))
-
-    def _name_set(self):
-        return set(self.namelist())
-
-    def resolve_dir(self, name):
-        """
-        If the name represents a directory, return that name
-        as a directory (with the trailing slash).
-        """
-        names = self._name_set()
-        dirname = name + '/'
-        dir_match = name not in names and dirname in names
-        return dirname if dir_match else name
-
-    def getinfo(self, name):
-        """
-        Supplement getinfo for implied dirs.
-        """
-        try:
-            return super().getinfo(name)
-        except KeyError:
-            if not name.endswith('/') or name not in self._name_set():
-                raise
-            return zipfile.ZipInfo(filename=name)
-
-    @classmethod
-    def make(cls, source):
-        """
-        Given a source (filename or zipfile), return an
-        appropriate CompleteDirs subclass.
-        """
-        if isinstance(source, CompleteDirs):
-            return source
-
-        if not isinstance(source, zipfile.ZipFile):
-            return cls(source)
-
-        # Only allow for FastLookup when supplied zipfile is read-only
-        if 'r' not in source.mode:
-            cls = CompleteDirs
-
-        source.__class__ = cls
-        return source
-
-    @classmethod
-    def inject(cls, zf: zipfile.ZipFile) -> zipfile.ZipFile:
-        """
-        Given a writable zip file zf, inject directory entries for
-        any directories implied by the presence of children.
-        """
-        for name in cls._implied_dirs(zf.namelist()):
-            zf.writestr(name, b"")
-        return zf
-
-
-class FastLookup(CompleteDirs):
-    """
-    ZipFile subclass to ensure implicit
-    dirs exist and are resolved rapidly.
-    """
-
-    def namelist(self):
-        return self._namelist
-
-    @functools.cached_property
-    def _namelist(self):
-        return super().namelist()
-
-    def _name_set(self):
-        return self._name_set_prop
-
-    @functools.cached_property
-    def _name_set_prop(self):
-        return super()._name_set()
-
-
-def _extract_text_encoding(encoding=None, *args, **kwargs):
-    # compute stack level so that the caller of the caller sees any warning.
-    is_pypy = sys.implementation.name == 'pypy'
-    # PyPy no longer special cased after 7.3.19 (or maybe 7.3.18)
-    # See jaraco/zipp#143
-    is_old_pypi = is_pypy and sys.pypy_version_info < (7, 3, 19)
-    stack_level = 3 + is_old_pypi
-    return text_encoding(encoding, stack_level), args, kwargs
-
-
-class Path:
-    """
-    A :class:`importlib.resources.abc.Traversable` interface for zip files.
-
-    Implements many of the features users enjoy from
-    :class:`pathlib.Path`.
-
-    Consider a zip file with this structure::
-
-        .
-        ├── a.txt
-        └── b
-            ├── c.txt
-            └── d
-                └── e.txt
-
-    >>> data = io.BytesIO()
-    >>> zf = zipfile.ZipFile(data, 'w')
-    >>> zf.writestr('a.txt', 'content of a')
-    >>> zf.writestr('b/c.txt', 'content of c')
-    >>> zf.writestr('b/d/e.txt', 'content of e')
-    >>> zf.filename = 'mem/abcde.zip'
-
-    Path accepts the zipfile object itself or a filename
-
-    >>> path = Path(zf)
-
-    From there, several path operations are available.
-
-    Directory iteration (including the zip file itself):
-
-    >>> a, b = path.iterdir()
-    >>> a
-    Path('mem/abcde.zip', 'a.txt')
-    >>> b
-    Path('mem/abcde.zip', 'b/')
-
-    name property:
-
-    >>> b.name
-    'b'
-
-    join with divide operator:
-
-    >>> c = b / 'c.txt'
-    >>> c
-    Path('mem/abcde.zip', 'b/c.txt')
-    >>> c.name
-    'c.txt'
-
-    Read text:
-
-    >>> c.read_text(encoding='utf-8')
-    'content of c'
-
-    existence:
-
-    >>> c.exists()
-    True
-    >>> (b / 'missing.txt').exists()
-    False
-
-    Coercion to string:
-
-    >>> import os
-    >>> str(c).replace(os.sep, posixpath.sep)
-    'mem/abcde.zip/b/c.txt'
-
-    At the root, ``name``, ``filename``, and ``parent``
-    resolve to the zipfile.
-
-    >>> str(path)
-    'mem/abcde.zip/'
-    >>> path.name
-    'abcde.zip'
-    >>> path.filename == pathlib.Path('mem/abcde.zip')
-    True
-    >>> str(path.parent)
-    'mem'
-
-    If the zipfile has no filename, such attributes are not
-    valid and accessing them will raise an Exception.
-
-    >>> zf.filename = None
-    >>> path.name
-    Traceback (most recent call last):
-    ...
-    TypeError: ...
-
-    >>> path.filename
-    Traceback (most recent call last):
-    ...
-    TypeError: ...
-
-    >>> path.parent
-    Traceback (most recent call last):
-    ...
-    TypeError: ...
-
-    # workaround python/cpython#106763
-    >>> pass
-    """
-
-    __repr = "{self.__class__.__name__}({self.root.filename!r}, {self.at!r})"
-
-    def __init__(self, root, at=""):
-        """
-        Construct a Path from a ZipFile or filename.
-
-        Note: When the source is an existing ZipFile object,
-        its type (__class__) will be mutated to a
-        specialized type. If the caller wishes to retain the
-        original type, the caller should either create a
-        separate ZipFile object or pass a filename.
-        """
-        self.root = FastLookup.make(root)
-        self.at = at
-
-    def __eq__(self, other):
-        """
-        >>> Path(zipfile.ZipFile(io.BytesIO(), 'w')) == 'foo'
-        False
-        """
-        if self.__class__ is not other.__class__:
-            return NotImplemented
-        return (self.root, self.at) == (other.root, other.at)
-
-    def __hash__(self):
-        return hash((self.root, self.at))
-
-    def open(self, mode='r', *args, pwd=None, **kwargs):
-        """
-        Open this entry as text or binary following the semantics
-        of ``pathlib.Path.open()`` by passing arguments through
-        to io.TextIOWrapper().
-        """
-        if self.is_dir():
-            raise IsADirectoryError(self)
-        zip_mode = mode[0]
-        if zip_mode == 'r' and not self.exists():
-            raise FileNotFoundError(self)
-        stream = self.root.open(self.at, zip_mode, pwd=pwd)
-        if 'b' in mode:
-            if args or kwargs:
-                raise ValueError("encoding args invalid for binary operation")
-            return stream
-        # Text mode:
-        encoding, args, kwargs = _extract_text_encoding(*args, **kwargs)
-        return io.TextIOWrapper(stream, encoding, *args, **kwargs)
-
-    def _base(self):
-        return pathlib.PurePosixPath(self.at) if self.at else self.filename
-
-    @property
-    def name(self):
-        return self._base().name
-
-    @property
-    def suffix(self):
-        return self._base().suffix
-
-    @property
-    def suffixes(self):
-        return self._base().suffixes
-
-    @property
-    def stem(self):
-        return self._base().stem
-
-    @property
-    def filename(self):
-        return pathlib.Path(self.root.filename).joinpath(self.at)
-
-    def read_text(self, *args, **kwargs):
-        encoding, args, kwargs = _extract_text_encoding(*args, **kwargs)
-        with self.open('r', encoding, *args, **kwargs) as strm:
-            return strm.read()
-
-    def read_bytes(self):
-        with self.open('rb') as strm:
-            return strm.read()
-
-    def _is_child(self, path):
-        return posixpath.dirname(path.at.rstrip("/")) == self.at.rstrip("/")
-
-    def _next(self, at):
-        return self.__class__(self.root, at)
-
-    def is_dir(self):
-        return not self.at or self.at.endswith("/")
-
-    def is_file(self):
-        return self.exists() and not self.is_dir()
-
-    def exists(self):
-        return self.at in self.root._name_set()
-
-    def iterdir(self):
-        if not self.is_dir():
-            raise ValueError("Can't listdir a file")
-        subs = map(self._next, self.root.namelist())
-        return filter(self._is_child, subs)
-
-    def match(self, path_pattern):
-        return pathlib.PurePosixPath(self.at).match(path_pattern)
-
-    def is_symlink(self):
-        """
-        Return whether this path is a symlink.
-        """
-        info = self.root.getinfo(self.at)
-        mode = info.external_attr >> 16
-        return stat.S_ISLNK(mode)
-
-    def glob(self, pattern):
-        if not pattern:
-            raise ValueError(f"Unacceptable pattern: {pattern!r}")
-
-        prefix = re.escape(self.at)
-        tr = Translator(seps='/')
-        matches = re.compile(prefix + tr.translate(pattern)).fullmatch
-        return map(self._next, filter(matches, self.root.namelist()))
-
-    def rglob(self, pattern):
-        return self.glob(f'**/{pattern}')
-
-    def relative_to(self, other, *extra):
-        return posixpath.relpath(str(self), str(other.joinpath(*extra)))
-
-    def __str__(self):
-        return posixpath.join(self.root.filename, self.at)
-
-    def __repr__(self):
-        return self.__repr.format(self=self)
-
-    def joinpath(self, *other):
-        next = posixpath.join(self.at, *other)
-        return self._next(self.root.resolve_dir(next))
-
-    __truediv__ = joinpath
-
-    @property
-    def parent(self):
-        if not self.at:
-            return self.filename.parent
-        parent_at = posixpath.dirname(self.at.rstrip('/'))
-        if parent_at:
-            parent_at += '/'
-        return self._next(parent_at)
diff --git a/server/libs/zipp/_functools.py b/server/libs/zipp/_functools.py
deleted file mode 100644
index 7390be2..0000000
--- a/server/libs/zipp/_functools.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import collections
-import functools
-
-
-# from jaraco.functools 4.0.2
-def save_method_args(method):
-    """
-    Wrap a method such that when it is called, the args and kwargs are
-    saved on the method.
-    """
-    args_and_kwargs = collections.namedtuple('args_and_kwargs', 'args kwargs')  # noqa: PYI024
-
-    @functools.wraps(method)
-    def wrapper(self, /, *args, **kwargs):
-        attr_name = '_saved_' + method.__name__
-        attr = args_and_kwargs(args, kwargs)
-        setattr(self, attr_name, attr)
-        return method(self, *args, **kwargs)
-
-    return wrapper
diff --git a/server/libs/zipp/compat/__init__.py b/server/libs/zipp/compat/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/server/libs/zipp/compat/overlay.py b/server/libs/zipp/compat/overlay.py
deleted file mode 100644
index 5a97ee7..0000000
--- a/server/libs/zipp/compat/overlay.py
+++ /dev/null
@@ -1,37 +0,0 @@
-"""
-Expose zipp.Path as .zipfile.Path.
-
-Includes everything else in ``zipfile`` to match future usage. Just
-use:
-
->>> from zipp.compat.overlay import zipfile
-
-in place of ``import zipfile``.
-
-Relative imports are supported too.
-
->>> from zipp.compat.overlay.zipfile import ZipInfo
-
-The ``zipfile`` object added to ``sys.modules`` needs to be
-hashable (#126).
-
->>> _ = hash(sys.modules['zipp.compat.overlay.zipfile'])
-"""
-
-import importlib
-import sys
-import types
-
-import zipp
-
-
-class HashableNamespace(types.SimpleNamespace):
-    def __hash__(self):
-        return hash(tuple(vars(self)))
-
-
-zipfile = HashableNamespace(**vars(importlib.import_module('zipfile')))
-zipfile.Path = zipp.Path
-zipfile._path = zipp
-
-sys.modules[__name__ + '.zipfile'] = zipfile  # type: ignore[assignment]
diff --git a/server/libs/zipp/compat/py310.py b/server/libs/zipp/compat/py310.py
deleted file mode 100644
index e1e7ec2..0000000
--- a/server/libs/zipp/compat/py310.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import io
-import sys
-
-
-def _text_encoding(encoding, stacklevel=2, /):  # pragma: no cover
-    return encoding
-
-
-text_encoding = (
-    io.text_encoding  # type: ignore[unused-ignore, attr-defined]
-    if sys.version_info > (3, 10)
-    else _text_encoding
-)
diff --git a/server/libs/zipp/compat/py313.py b/server/libs/zipp/compat/py313.py
deleted file mode 100644
index ae45869..0000000
--- a/server/libs/zipp/compat/py313.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import functools
-import sys
-
-
-# from jaraco.functools 4.1
-def identity(x):
-    return x
-
-
-# from jaraco.functools 4.1
-def apply(transform):
-    def wrap(func):
-        return functools.wraps(func)(compose(transform, func))
-
-    return wrap
-
-
-# from jaraco.functools 4.1
-def compose(*funcs):
-    def compose_two(f1, f2):
-        return lambda *args, **kwargs: f1(f2(*args, **kwargs))
-
-    return functools.reduce(compose_two, funcs)
-
-
-def replace(pattern):
-    r"""
-    >>> replace(r'foo\z')
-    'foo\\Z'
-    """
-    return pattern[:-2] + pattern[-2:].replace(r'\z', r'\Z')
-
-
-legacy_end_marker = apply(replace) if sys.version_info < (3, 14) else identity
diff --git a/server/libs/zipp/glob.py b/server/libs/zipp/glob.py
deleted file mode 100644
index 1b4ffb3..0000000
--- a/server/libs/zipp/glob.py
+++ /dev/null
@@ -1,116 +0,0 @@
-import os
-import re
-
-from .compat.py313 import legacy_end_marker
-
-_default_seps = os.sep + str(os.altsep) * bool(os.altsep)
-
-
-class Translator:
-    """
-    >>> Translator('xyz')
-    Traceback (most recent call last):
-    ...
-    AssertionError: Invalid separators
-
-    >>> Translator('')
-    Traceback (most recent call last):
-    ...
-    AssertionError: Invalid separators
-    """
-
-    seps: str
-
-    def __init__(self, seps: str = _default_seps):
-        assert seps and set(seps) <= set(_default_seps), "Invalid separators"
-        self.seps = seps
-
-    def translate(self, pattern):
-        """
-        Given a glob pattern, produce a regex that matches it.
-        """
-        return self.extend(self.match_dirs(self.translate_core(pattern)))
-
-    @legacy_end_marker
-    def extend(self, pattern):
-        r"""
-        Extend regex for pattern-wide concerns.
-
-        Apply '(?s:)' to create a non-matching group that
-        matches newlines (valid on Unix).
-
-        Append '\z' to imply fullmatch even when match is used.
-        """
-        return rf'(?s:{pattern})\z'
-
-    def match_dirs(self, pattern):
-        """
-        Ensure that zipfile.Path directory names are matched.
-
-        zipfile.Path directory names always end in a slash.
-        """
-        return rf'{pattern}[/]?'
-
-    def translate_core(self, pattern):
-        r"""
-        Given a glob pattern, produce a regex that matches it.
-
-        >>> t = Translator()
-        >>> t.translate_core('*.txt').replace('\\\\', '')
-        '[^/]*\\.txt'
-        >>> t.translate_core('a?txt')
-        'a[^/]txt'
-        >>> t.translate_core('**/*').replace('\\\\', '')
-        '.*/[^/][^/]*'
-        """
-        self.restrict_rglob(pattern)
-        return ''.join(map(self.replace, separate(self.star_not_empty(pattern))))
-
-    def replace(self, match):
-        """
-        Perform the replacements for a match from :func:`separate`.
-        """
-        return match.group('set') or (
-            re.escape(match.group(0))
-            .replace('\\*\\*', r'.*')
-            .replace('\\*', rf'[^{re.escape(self.seps)}]*')
-            .replace('\\?', r'[^/]')
-        )
-
-    def restrict_rglob(self, pattern):
-        """
-        Raise ValueError if ** appears in anything but a full path segment.
-
-        >>> Translator().translate('**foo')
-        Traceback (most recent call last):
-        ...
-        ValueError: ** must appear alone in a path segment
-        """
-        seps_pattern = rf'[{re.escape(self.seps)}]+'
-        segments = re.split(seps_pattern, pattern)
-        if any('**' in segment and segment != '**' for segment in segments):
-            raise ValueError("** must appear alone in a path segment")
-
-    def star_not_empty(self, pattern):
-        """
-        Ensure that * will not match an empty segment.
-        """
-
-        def handle_segment(match):
-            segment = match.group(0)
-            return '?*' if segment == '*' else segment
-
-        not_seps_pattern = rf'[^{re.escape(self.seps)}]+'
-        return re.sub(not_seps_pattern, handle_segment, pattern)
-
-
-def separate(pattern):
-    """
-    Separate out character sets to avoid translating their contents.
-
-    >>> [m.group(0) for m in separate('*.txt')]
-    ['*.txt']
-    >>> [m.group(0) for m in separate('a[?]txt')]
-    ['a', '[?]', 'txt']
-    """
-    return re.finditer(r'([^\[]+)|(?P[\[].*?[\]])|([\[][^\]]*$)', pattern)
diff --git a/server/noxfile.py b/server/noxfile.py
deleted file mode 100644
index 96c8b8b..0000000
--- a/server/noxfile.py
+++ /dev/null
@@ -1,164 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-"""All the action we need during build"""
-
-import json
-import os
-import pathlib
-import sys
-import tomllib
-import urllib.request as url_lib
-from typing import List
-
-import nox  # pylint: disable=import-error
-
-
-def _read_dependencies() -> List[str]:
-    """Read project dependencies from pyproject.toml."""
-    pyproject = tomllib.loads(pathlib.Path("pyproject.toml").read_text())
-    return list(pyproject.get("project", {}).get("dependencies", []))
-
-
-def _install_bundle(session: nox.Session) -> None:
-    deps = _read_dependencies()
-    session.run(
-        "uv",
-        "pip",
-        "install",
-        "--target",
-        "./libs",
-        "--no-cache-dir",
-        "py",
-        "--upgrade",
-        *deps,
-        external=True,
-    )
-
-
-def _check_files(names: List[str]) -> None:
-    root_dir = pathlib.Path(__file__).parent
-    for name in names:
-        file_path = root_dir / name
-        lines: List[str] = file_path.read_text().splitlines()
-        if any(line for line in lines if line.startswith("# TODO:")):
-            raise Exception(f"Please update {os.fspath(file_path)}.")
-
-
-def _get_package_data(package):
-    json_uri = f"https://registry.npmjs.org/{package}"
-    with url_lib.urlopen(json_uri) as response:
-        return json.loads(response.read())
-
-
-def _update_npm_packages(session: nox.Session) -> None:
-    pinned = {
-        "vscode-languageclient",
-        "@types/vscode",
-        "@types/node",
-    }
-    package_json_path = pathlib.Path(__file__).parent / "package.json"
-    package_json = json.loads(package_json_path.read_text(encoding="utf-8"))
-
-    for package in package_json["dependencies"]:
-        if package not in pinned:
-            data = _get_package_data(package)
-            latest = "^" + data["dist-tags"]["latest"]
-            package_json["dependencies"][package] = latest
-
-    for package in package_json["devDependencies"]:
-        if package not in pinned:
-            data = _get_package_data(package)
-            latest = "^" + data["dist-tags"]["latest"]
-            package_json["devDependencies"][package] = latest
-
-    # Ensure engine matches the package
-    if package_json["engines"]["vscode"] != package_json["devDependencies"]["@types/vscode"]:
-        print("Please check VS Code engine version and @types/vscode version in package.json.")
-
-    new_package_json = json.dumps(package_json, indent=4)
-    # JSON dumps uses \n for line ending on all platforms by default
-    if not new_package_json.endswith("\n"):
-        new_package_json += "\n"
-    package_json_path.write_text(new_package_json, encoding="utf-8")
-    session.run("npm", "install", external=True)
-
-
-def _setup_template_environment(session: nox.Session) -> None:
-    """Install project dependencies into the bundled libs directory."""
-    _install_bundle(session)
-
-
-@nox.session()
-def setup(session: nox.Session) -> None:
-    """Sets up the template for development."""
-    _setup_template_environment(session)
-
-
-@nox.session()
-def tests(session: nox.Session) -> None:
-    """Runs all the tests for the extension."""
-    deps = _read_dependencies()
-    session.run("uv", "pip", "install", "--python", sys.executable, *deps, external=True)
-    session.run("uv", "pip", "install", "--python", sys.executable, "pytest", external=True)
-    session.run("pytest", "tests/python_tests")
-
-
-@nox.session()
-def lint(session: nox.Session) -> None:
-    """Runs linter and formatter checks on python files."""
-    deps = _read_dependencies()
-    session.run("uv", "pip", "install", "--python", sys.executable, *deps, external=True)
-    session.run(
-        "uv",
-        "pip",
-        "install",
-        "--python",
-        sys.executable,
-        "pytest",
-        "pylint",
-        "black",
-        "isort",
-        external=True,
-    )
-    session.run("pylint", "-d", "W0511", "./bundled/tool")
-    session.run(
-        "pylint",
-        "-d",
-        "W0511",
-        "--ignore=./tests/python_tests/test_data",
-        "./tests/python_tests",
-    )
-    session.run("pylint", "-d", "W0511", "noxfile.py")
-
-    # check formatting using black
-    session.run("black", "--check", "./bundled/tool")
-    session.run("black", "--check", "./tests/python_tests")
-    session.run("black", "--check", "noxfile.py")
-
-    # check import sorting using isort
-    session.run("isort", "--check", "./bundled/tool")
-    session.run("isort", "--check", "./tests/python_tests")
-    session.run("isort", "--check", "noxfile.py")
-
-    # check typescript code
-    session.run("npm", "run", "lint", external=True)
-
-
-@nox.session()
-def build_package(session: nox.Session) -> None:
-    """Builds VSIX package for publishing."""
-    _check_files(["README.md", "LICENSE", "SECURITY.md", "SUPPORT.md"])
-    _setup_template_environment(session)
-    session.run("npm", "install", external=True)
-    session.run("npm", "run", "vsce-package", external=True)
-
-
-def _update_uv_lock(session: nox.Session) -> None:
-    session.run("uv", "lock", "--upgrade", external=True)
-
-
-@nox.session()
-def update_packages(session: nox.Session) -> None:
-    """Update Python and npm packages."""
-    _update_uv_lock(session)
-    _update_npm_packages(session)
diff --git a/server/package.json b/server/package.json
new file mode 100644
index 0000000..7b8ec1f
--- /dev/null
+++ b/server/package.json
@@ -0,0 +1,11 @@
+{
+	"private": true,
+	"name": "server",
+	"displayName": "Native Language Server",
+	"version": "0.1.0",
+	"author": "Microsoft Corporation",
+	"license": "MIT",
+	"scripts": {
+		"build": "cargo build --release --target x86_64-pc-windows-gnu"
+	}
+}
\ No newline at end of file
diff --git a/server/pyproject.toml b/server/pyproject.toml
deleted file mode 100644
index 4b33473..0000000
--- a/server/pyproject.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-[project]
-name = "nx-post-support-server"
-version = "0.1.0"
-description = "Python language server for NX Postprocessor Support"
-requires-python = ">=3.8"
-dependencies = [
-    "pygls",
-    "packaging",
-    "tclint",
-]
-
-[build-system]
-requires = ["setuptools>=61.0"]
-build-backend = "setuptools.build_meta"
\ No newline at end of file
diff --git a/server/src/__init__.py b/server/src/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/server/src/_debug_server.py b/server/src/_debug_server.py
deleted file mode 100644
index 52d3f0c..0000000
--- a/server/src/_debug_server.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-"""Debugging support for LSP."""
-
-import os
-import pathlib
-import runpy
-import sys
-
-
-def update_sys_path(path_to_add: str) -> None:
-    """Add given path to `sys.path`."""
-    if path_to_add not in sys.path and os.path.isdir(path_to_add):
-        sys.path.append(path_to_add)
-
-
-# Ensure debugger is loaded before we load anything else, to debug initialization.
-debugger_path = os.getenv("DEBUGPY_PATH", None)
-if debugger_path:
-    if debugger_path.endswith("debugpy"):
-        debugger_path = os.fspath(pathlib.Path(debugger_path).parent)
-
-    update_sys_path(debugger_path)
-
-    # pylint: disable=wrong-import-position,import-error
-    import debugpy
-
-    # 5678 is the default port, If you need to change it update it here
-    # and in launch.json.
-    debugpy.connect(5678)
-
-    # This will ensure that execution is paused as soon as the debugger
-    # connects to VS Code. If you don't want to pause here comment this
-    # line and set breakpoints as appropriate.
-    # debugpy.breakpoint()
-
-SERVER_PATH = os.fspath(pathlib.Path(__file__).parent / "lsp_server.py")
-# NOTE: Set breakpoint in `lsp_server.py` before continuing.
-runpy.run_path(SERVER_PATH, run_name="__main__")
diff --git a/server/src/common/load_data.py b/server/src/common/load_data.py
deleted file mode 100644
index dc22c99..0000000
--- a/server/src/common/load_data.py
+++ /dev/null
@@ -1,153 +0,0 @@
-import json
-import lsprotocol.types as lsp
-import pathlib
-
-
-KIND_MAP = {
-    "function": lsp.CompletionItemKind.Function,
-    "method": lsp.CompletionItemKind.Method,
-    "class": lsp.CompletionItemKind.Class,
-    "variable": lsp.CompletionItemKind.Variable,
-    "field": lsp.CompletionItemKind.Field,
-    "module": lsp.CompletionItemKind.Module,
-    "namespace": lsp.CompletionItemKind.Class,
-    "keyword": lsp.CompletionItemKind.Keyword,
-}
-
-
-class StandardCompletionItems:
-    def __init__(self):
-        self.__json_data: dict = self.__load_json()
-        self.__tcl_keyword_list = self.__load_tcl_keyword()
-        self.__nx_procs = self.__load_nx_procs()
-        self.__nx_variables = self.__load_nx_variables()
-        self.__custom_functions = list[lsp.CompletionItem]
-
-    @property
-    def json_data(self):
-        return self.__json_data
-
-    @property
-    def tcl_keyword_list(self):
-        return self.__tcl_keyword_list
-
-    @property
-    def nx_procs(self):
-        return self.__nx_procs
-
-    @property
-    def nx_variables(self):
-        return self.__nx_variables
-
-    @property
-    def custom_functions(self) -> list[lsp.CompletionItem]:
-        return self.__custom_functions
-
-    @custom_functions.setter
-    def custom_functions(self, value: lsp.CompletionItem):
-        self.__custom_functions.append(value)
-
-    def __load_json(self) -> dict:
-        with open(
-            pathlib.Path(__file__).parent.joinpath("completion_list.json"), "r"
-        ) as f:
-            data = json.load(f)
-        return data
-
-    def __load_tcl_keyword(self) -> list[lsp.CompletionItem]:
-        data = self.json_data
-
-        items = []
-        for i in data.get("tcl", []):
-            items.append(
-                lsp.CompletionItem(
-                    label=i.get("label", ""),
-                    kind=KIND_MAP.get(i.get("kind", ""), lsp.CompletionItemKind.Text),
-                )
-            )
-        return items
-
-    def __load_nx_variables(self):
-        data = self.json_data
-        items = []
-        for var in data.get("mom_variables", []):
-            label = var.get("label", "")
-            kind_str = var.get("kind", "").lower()
-            kind_enum = KIND_MAP.get(kind_str, lsp.CompletionItemKind.Text)
-            doc_md = f"""\
-**MOM variable**  
-{label}
-
-**Description**  
-{var.get("description", "")}
-
-**Possible Values:**  
-{var.get("possible_values", "any")}
-    
-**Data type**  
-{var.get("data_type", "")}
-"""
-            items.append(
-                lsp.CompletionItem(
-                    label=label,
-                    kind=kind_enum,
-                    detail=f"{label}",
-                    documentation=lsp.MarkupContent(
-                        kind=lsp.MarkupKind.Markdown, value=doc_md
-                    ),
-                )
-            )
-        return items
-
-    def __load_nx_procs(self) -> list[lsp.CompletionItem]:
-        data = self.json_data
-        items = []
-        for proc in data.get("MOM_procs", []):
-            label = proc.get("label", "")
-            kind_str = proc.get("kind", "").lower()
-            kind_enum = KIND_MAP.get(kind_str, lsp.CompletionItemKind.Text)
-
-            parameters = proc.get("parameters", [])
-            param_lines = (
-                "\n".join(f"- `{p['name']}`: {p['desc']}" for p in parameters)
-                or "_None_"
-            )
-
-            example_data = proc.get("example", [])
-            example_md = "\n".join(f"{line}" for line in example_data)
-
-            returns_data = proc.get("returns", ["None"])
-            returns_md = "\n".join(f"- {line}" for line in returns_data)
-
-            doc_md = f"""\
-### 📘 {label}
-
-**Purpose**  
-{proc.get("description", "No description available.")}
-
-**Format**  
-`{proc.get("format", label)}`
-
-**Parameters**  
-{param_lines}
-
-**Return value**  
-{returns_md}
-
-**Example**  
-```tcl
-{example_md}"""
-            items.append(
-                lsp.CompletionItem(
-                    label=label,
-                    kind=kind_enum,
-                    detail=f"{label} – {proc.get('description', '').split('.')[0]}",
-                    documentation=lsp.MarkupContent(
-                        kind=lsp.MarkupKind.Markdown, value=doc_md
-                    ),
-                )
-            )
-        return items
-
-
-standard_items = StandardCompletionItems()
diff --git a/server/src/lsp_jsonrpc.py b/server/src/lsp_jsonrpc.py
deleted file mode 100644
index 011b511..0000000
--- a/server/src/lsp_jsonrpc.py
+++ /dev/null
@@ -1,254 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-"""Light-weight JSON-RPC over standard IO."""
-
-
-import atexit
-import contextlib
-import io
-import json
-import pathlib
-import subprocess
-import threading
-import uuid
-from concurrent.futures import ThreadPoolExecutor
-from typing import BinaryIO, Dict, Optional, Sequence, Union
-
-CONTENT_LENGTH = "Content-Length: "
-RUNNER_SCRIPT = str(pathlib.Path(__file__).parent / "lsp_runner.py")
-
-
-def to_str(text) -> str:
-    """Convert bytes to string as needed."""
-    return text.decode("utf-8") if isinstance(text, bytes) else text
-
-
-class StreamClosedException(Exception):
-    """JSON RPC stream is closed."""
-
-    pass  # pylint: disable=unnecessary-pass
-
-
-class JsonWriter:
-    """Manages writing JSON-RPC messages to the writer stream."""
-
-    def __init__(self, writer: io.TextIOWrapper):
-        self._writer = writer
-        self._lock = threading.Lock()
-
-    def close(self):
-        """Closes the underlying writer stream."""
-        with self._lock:
-            if not self._writer.closed:
-                self._writer.close()
-
-    def write(self, data):
-        """Writes given data to stream in JSON-RPC format."""
-        if self._writer.closed:
-            raise StreamClosedException()
-
-        with self._lock:
-            content = json.dumps(data)
-            length = len(content.encode("utf-8"))
-            self._writer.write(
-                f"{CONTENT_LENGTH}{length}\r\n\r\n{content}".encode("utf-8")
-            )
-            self._writer.flush()
-
-
-class JsonReader:
-    """Manages reading JSON-RPC messages from stream."""
-
-    def __init__(self, reader: io.TextIOWrapper):
-        self._reader = reader
-
-    def close(self):
-        """Closes the underlying reader stream."""
-        if not self._reader.closed:
-            self._reader.close()
-
-    def read(self):
-        """Reads data from the stream in JSON-RPC format."""
-        if self._reader.closed:
-            raise StreamClosedException
-        length = None
-        while not length:
-            line = to_str(self._readline())
-            if line.startswith(CONTENT_LENGTH):
-                length = int(line[len(CONTENT_LENGTH) :])
-
-        line = to_str(self._readline()).strip()
-        while line:
-            line = to_str(self._readline()).strip()
-
-        content = to_str(self._reader.read(length))
-        return json.loads(content)
-
-    def _readline(self):
-        line = self._reader.readline()
-        if not line:
-            raise EOFError
-        return line
-
-
-class JsonRpc:
-    """Manages sending and receiving data over JSON-RPC."""
-
-    def __init__(self, reader: io.TextIOWrapper, writer: io.TextIOWrapper):
-        self._reader = JsonReader(reader)
-        self._writer = JsonWriter(writer)
-
-    def close(self):
-        """Closes the underlying streams."""
-        with contextlib.suppress(Exception):
-            self._reader.close()
-        with contextlib.suppress(Exception):
-            self._writer.close()
-
-    def send_data(self, data):
-        """Send given data in JSON-RPC format."""
-        self._writer.write(data)
-
-    def receive_data(self):
-        """Receive data in JSON-RPC format."""
-        return self._reader.read()
-
-
-def create_json_rpc(readable: BinaryIO, writable: BinaryIO) -> JsonRpc:
-    """Creates JSON-RPC wrapper for the readable and writable streams."""
-    return JsonRpc(readable, writable)
-
-
-class ProcessManager:
-    """Manages sub-processes launched for running tools."""
-
-    def __init__(self):
-        self._args: Dict[str, Sequence[str]] = {}
-        self._processes: Dict[str, subprocess.Popen] = {}
-        self._rpc: Dict[str, JsonRpc] = {}
-        self._lock = threading.Lock()
-        self._thread_pool = ThreadPoolExecutor(10)
-
-    def stop_all_processes(self):
-        """Send exit command to all processes and shutdown transport."""
-        for i in self._rpc.values():
-            with contextlib.suppress(Exception):
-                i.send_data({"id": str(uuid.uuid4()), "method": "exit"})
-        self._thread_pool.shutdown(wait=False)
-
-    def start_process(self, workspace: str, args: Sequence[str], cwd: str) -> None:
-        """Starts a process and establishes JSON-RPC communication over stdio."""
-        # pylint: disable=consider-using-with
-        proc = subprocess.Popen(
-            args,
-            cwd=cwd,
-            stdout=subprocess.PIPE,
-            stdin=subprocess.PIPE,
-        )
-        self._processes[workspace] = proc
-        self._rpc[workspace] = create_json_rpc(proc.stdout, proc.stdin)
-
-        def _monitor_process():
-            proc.wait()
-            with self._lock:
-                try:
-                    del self._processes[workspace]
-                    rpc = self._rpc.pop(workspace)
-                    rpc.close()
-                except:  # pylint: disable=bare-except
-                    pass
-
-        self._thread_pool.submit(_monitor_process)
-
-    def get_json_rpc(self, workspace: str) -> JsonRpc:
-        """Gets the JSON-RPC wrapper for the a given id."""
-        with self._lock:
-            if workspace in self._rpc:
-                return self._rpc[workspace]
-        raise StreamClosedException()
-
-
-_process_manager = ProcessManager()
-atexit.register(_process_manager.stop_all_processes)
-
-
-def _get_json_rpc(workspace: str) -> Union[JsonRpc, None]:
-    try:
-        return _process_manager.get_json_rpc(workspace)
-    except StreamClosedException:
-        return None
-    except KeyError:
-        return None
-
-
-def get_or_start_json_rpc(
-    workspace: str, interpreter: Sequence[str], cwd: str
-) -> Union[JsonRpc, None]:
-    """Gets an existing JSON-RPC connection or starts one and return it."""
-    res = _get_json_rpc(workspace)
-    if not res:
-        args = [*interpreter, RUNNER_SCRIPT]
-        _process_manager.start_process(workspace, args, cwd)
-        res = _get_json_rpc(workspace)
-    return res
-
-
-class RpcRunResult:
-    """Object to hold result from running tool over RPC."""
-
-    def __init__(self, stdout: str, stderr: str, exception: Optional[str] = None):
-        self.stdout: str = stdout
-        self.stderr: str = stderr
-        self.exception: Optional[str] = exception
-
-
-# pylint: disable=too-many-arguments
-def run_over_json_rpc(
-    workspace: str,
-    interpreter: Sequence[str],
-    module: str,
-    argv: Sequence[str],
-    use_stdin: bool,
-    cwd: str,
-    source: str = None,
-) -> RpcRunResult:
-    """Uses JSON-RPC to execute a command."""
-    rpc: Union[JsonRpc, None] = get_or_start_json_rpc(workspace, interpreter, cwd)
-    if not rpc:
-        raise Exception("Failed to run over JSON-RPC.")
-
-    msg_id = str(uuid.uuid4())
-    msg = {
-        "id": msg_id,
-        "method": "run",
-        "module": module,
-        "argv": argv,
-        "useStdin": use_stdin,
-        "cwd": cwd,
-    }
-    if source:
-        msg["source"] = source
-
-    rpc.send_data(msg)
-
-    data = rpc.receive_data()
-
-    if data["id"] != msg_id:
-        return RpcRunResult(
-            "", f"Invalid result for request: {json.dumps(msg, indent=4)}"
-        )
-
-    result = data["result"] if "result" in data else ""
-    if "error" in data:
-        error = data["error"]
-
-        if data.get("exception", False):
-            return RpcRunResult(result, "", error)
-        return RpcRunResult(result, error)
-
-    return RpcRunResult(result, "")
-
-
-def shutdown_json_rpc():
-    """Shutdown all JSON-RPC processes."""
-    _process_manager.stop_all_processes()
diff --git a/server/src/lsp_runner.py b/server/src/lsp_runner.py
deleted file mode 100644
index b294834..0000000
--- a/server/src/lsp_runner.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-"""
-Runner to use when running under a different interpreter.
-"""
-
-import os
-import pathlib
-import sys
-import traceback
-
-
-# **********************************************************
-# Update sys.path before importing any bundled libraries.
-# **********************************************************
-def update_sys_path(path_to_add: str, strategy: str) -> None:
-    """Add given path to `sys.path`."""
-    if path_to_add not in sys.path and os.path.isdir(path_to_add):
-        if strategy == "useBundled":
-            sys.path.insert(0, path_to_add)
-        elif strategy == "fromEnvironment":
-            sys.path.append(path_to_add)
-
-
-# Ensure that we can import LSP libraries, and other bundled libraries.
-update_sys_path(
-    os.fspath(pathlib.Path(__file__).parent.parent / "libs"),
-    os.getenv("LS_IMPORT_STRATEGY", "useBundled"),
-)
-
-
-# pylint: disable=wrong-import-position,import-error
-import lsp_jsonrpc as jsonrpc
-import lsp_utils as utils
-
-RPC = jsonrpc.create_json_rpc(sys.stdin.buffer, sys.stdout.buffer)
-
-EXIT_NOW = False
-while not EXIT_NOW:
-    msg = RPC.receive_data()
-
-    method = msg["method"]
-    if method == "exit":
-        EXIT_NOW = True
-        continue
-
-    if method == "run":
-        is_exception = False
-        # This is needed to preserve sys.path, pylint modifies
-        # sys.path and that might not work for this scenario
-        # next time around.
-        with utils.substitute_attr(sys, "path", sys.path[:]):
-            try:
-                # TODO: `utils.run_module` is equivalent to running `python -m `.
-                # If your tool supports a programmatic API then replace the function below
-                # with code for your tool. You can also use `utils.run_api` helper, which
-                # handles changing working directories, managing io streams, etc.
-                # Also update `_run_tool_on_document` and `_run_tool` functions in `lsp_server.py`.
-                result = utils.run_module(
-                    module=msg["module"],
-                    argv=msg["argv"],
-                    use_stdin=msg["useStdin"],
-                    cwd=msg["cwd"],
-                    source=msg["source"] if "source" in msg else None,
-                )
-            except Exception:  # pylint: disable=broad-except
-                result = utils.RunResult("", traceback.format_exc(chain=True))
-                is_exception = True
-
-        response = {"id": msg["id"]}
-        if result.stderr:
-            response["error"] = result.stderr
-            response["exception"] = is_exception
-        elif result.stdout:
-            response["result"] = result.stdout
-
-        RPC.send_data(response)
diff --git a/server/src/lsp_server.py b/server/src/lsp_server.py
deleted file mode 100644
index 42b939f..0000000
--- a/server/src/lsp_server.py
+++ /dev/null
@@ -1,607 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-"""Implementation of tool support over LSP."""
-
-from __future__ import annotations
-
-import json
-import os
-import pathlib
-import re
-import sys
-import threading
-
-from typing import Any, Optional
-import operator
-from functools import reduce
-
-
-# **********************************************************
-# Update sys.path before importing any bundled libraries.
-# **********************************************************
-def update_sys_path(path_to_add: str, strategy: str) -> None:
-    """Add given path to `sys.path`."""
-    if path_to_add not in sys.path and os.path.isdir(path_to_add):
-        if strategy == "useBundled":
-            sys.path.insert(0, path_to_add)
-        elif strategy == "fromEnvironment":
-            sys.path.append(path_to_add)
-
-
-# Ensure that we can import LSP libraries, and other bundled libraries.
-update_sys_path(
-    os.fspath(pathlib.Path(__file__).parent.parent / "libs"),
-    os.getenv("LS_IMPORT_STRATEGY", "useBundled"),
-)
-
-# **********************************************************
-# Imports needed for the language server goes below this.
-# **********************************************************
-# pylint: disable=wrong-import-position,import-error
-import lsp_jsonrpc as jsonrpc
-import lsprotocol.types as lsp
-from pygls import uris, workspace
-from common.load_data import standard_items
-from tools.semantic_tokens import _Highlighter, TOKEN_TYPES, TokenModifier
-from tools.completion_items import completion, remove_existing_items, remove_shared_keys
-from tools.inlay_hint import InlayHintGenerator
-from tools.file_sourcing import get_all_psc_files, read_psc_file
-from lsp_tclserver import TclLanguageServer
-
-
-WORKSPACE_SETTINGS = {}
-GLOBAL_SETTINGS = {}
-
-
-MAX_WORKERS = 5
-LSP_SERVER = TclLanguageServer(name="NX Postprocessor Support", version="0.0.1", max_workers=MAX_WORKERS)
-
-# **********************************************************
-# Tool specific code goes below this.
-# **********************************************************
-
-
-# Delete "Linting features" section if your tool is NOT a linter.
-# **********************************************************
-# Linting features start here
-# **********************************************************
-
-#  See `pylint` implementation for a full featured linter extension:
-#  Pylint: https://github.com/microsoft/vscode-pylint/blob/main/bundled/tool
-
-
-@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DID_OPEN)
-def did_open(params: lsp.DidOpenTextDocumentParams) -> None:
-    """LSP handler for textDocument/didOpen request."""
-    document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
-    LSP_SERVER.compute_diagnostics(document)
-    # Also update custom completion and proc docs for this file
-    LSP_SERVER.update_poco_completion_for_file(document)
-
-
-@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DID_SAVE)
-def did_save(params: lsp.DidSaveTextDocumentParams) -> None:
-    """LSP handler for textDocument/didSave request."""
-    _ = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
-
-
-@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DID_CLOSE)
-def did_close(_: lsp.DidCloseTextDocumentParams) -> None:
-    """LSP handler for textDocument/didClose request."""
-
-
-@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DID_CHANGE)
-def did_change(params: lsp.DidChangeTextDocumentParams) -> None:
-    """LSP handler for textDocument/didChange request"""
-    document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
-    LSP_SERVER.compute_diagnostics(document)
-    LSP_SERVER.update_poco_completion_for_file(document)
-
-
-@LSP_SERVER.feature(
-    lsp.TEXT_DOCUMENT_DIAGNOSTIC,
-    lsp.DiagnosticOptions(
-        identifier="pull-diagnostics",
-        inter_file_dependencies=False,
-        workspace_diagnostics=False,
-    ),
-)
-def document_diagnostic(params: lsp.DocumentDiagnosticParams):
-    """Return diagnostics for the requested document"""
-    was_cached = True
-    if (uri := params.text_document.uri) not in LSP_SERVER.diagnostics:
-        was_cached = False
-        doc = LSP_SERVER.workspace.get_text_document(uri)
-        LSP_SERVER.compute_diagnostics(doc)
-
-    version, diagnostics = LSP_SERVER.diagnostics[uri]
-    result_id = f"{uri}@{version}"
-
-    if was_cached and result_id == params.previous_result_id:
-        return lsp.UnchangedDocumentDiagnosticReport(result_id)
-
-    return lsp.FullDocumentDiagnosticReport(items=diagnostics, result_id=result_id)
-
-
-@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_COMPLETION)
-def on_completion(params: lsp.CompletionParams) -> lsp.CompletionList:
-    from tools.variable_index import build_variable_index
-    from tools.completion_items import BUILTIN_VAR_LABELS
-
-    doc = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
-
-    # Base items
-    poco = [item for items in LSP_SERVER.poco_completion.values() for item in items]
-    base_items = standard_items.tcl_keyword_list + standard_items.nx_procs + standard_items.nx_variables + poco
-
-    # Build variable index from current document
-    globals_set, procs_locals, proc_ranges = build_variable_index(doc.source)
-
-    # Always include globals (excluding built-ins)
-    dynamic_items = []
-    for name in sorted(globals_set):
-        if name not in BUILTIN_VAR_LABELS:
-            dynamic_items.append(lsp.CompletionItem(label=name, kind=lsp.CompletionItemKind.Variable))
-
-    # Include proc-local variables when cursor is inside that proc
-    pos = params.position
-    if pos is not None:
-        for pr in proc_ranges:
-            if pr.start_line <= pos.line <= (pr.end_line or pr.start_line):
-                for name in sorted(procs_locals.get(pr.name, set())):
-                    # Exclude built-ins and globals to avoid duplication
-                    if name not in BUILTIN_VAR_LABELS and name not in globals_set:
-                        dynamic_items.append(lsp.CompletionItem(label=name, kind=lsp.CompletionItemKind.Variable))
-                break
-
-    # Merge with de-duplication for variables only
-    merged: list[lsp.CompletionItem] = []
-    seen_var_labels: set[str] = set()
-    for it in base_items + dynamic_items:
-        if getattr(it, "kind", None) == lsp.CompletionItemKind.Variable:
-            if it.label in seen_var_labels:
-                continue
-            seen_var_labels.add(it.label)
-        merged.append(it)
-
-    return lsp.CompletionList(is_incomplete=False, items=merged)
-
-
-# @LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DOCUMENT_SYMBOL)
-# def document_symbols(params: lsp.DocumentSymbolParams):
-#     doc = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
-#     ast = LSP_SERVER.parser.parse(doc.source)
-#     symbols = LSP_SERVER.extract_tcl_symbols(ast)
-
-#     return symbols
-
-
-@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DOCUMENT_SYMBOL)
-def document_symbols(params: lsp.DocumentSymbolParams):
-    from tools.document_symbols import build_document_symbols
-
-    doc = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
-    return build_document_symbols(doc.source)
-
-
-@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_INLAY_HINT)
-def inlay_hints(params: lsp.InlayHintParams):
-    if not GLOBAL_SETTINGS.get("inlayHint", False):
-        return []
-    document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
-
-    # Reuse cached AST
-    tree = LSP_SERVER.get_tree(document)
-
-    # Merge proc signatures across files and traverse once
-    merged_signatures = {}
-    for sigs in LSP_SERVER.proc_signatures.values():
-        merged_signatures.update(sigs)
-
-    generator = InlayHintGenerator(merged_signatures)
-    tree.accept(generator, recurse=True)
-    return generator.hints
-
-
-@LSP_SERVER.feature(
-    lsp.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
-    lsp.SemanticTokensLegend(
-        token_types=TOKEN_TYPES,
-        token_modifiers=[m.name for m in TokenModifier],
-    ),
-)
-def semantic_tokens(params: lsp.SemanticTokensParams):
-    document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
-
-    data = []
-    plugins = []
-    hl = _Highlighter(plugins, LSP_SERVER.poco_completion)
-
-    # Reuse cached AST
-    tree = LSP_SERVER.get_tree(document)
-    tree.accept(hl, recurse=True)
-
-    tokens = hl.tokens()
-    for token in tokens:
-        data.extend(
-            [
-                token.line,
-                token.offset,
-                token.length,
-                TOKEN_TYPES.index(token.tok_type),
-                reduce(operator.or_, token.tok_modifiers, 0),
-            ]
-        )
-    return lsp.SemanticTokens(data=data)
-
-
-@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_HOVER)
-def hover(params: lsp.HoverParams) -> lsp.Hover:
-    pos = params.position
-    document_uri = params.text_document.uri
-    document = LSP_SERVER.workspace.get_text_document(document_uri)
-    col = params.position.character
-
-    try:
-        line = document.lines[pos.line]
-    except IndexError:
-        return None
-
-    # Do not show hover for proc name in its declaration
-    from tools.proc_docs import is_proc_declaration_position
-
-    if is_proc_declaration_position(document.source, pos.line, pos.character):
-        return None
-
-    # Identify the token under the cursor
-    for m in re.finditer(r"\b\w+\b", line):
-        if m.start() <= col <= m.end():
-            token = m.group(0)
-            break
-    else:
-        return None
-
-    # 1) If token is a known MOM proc/variable, return built-in hover
-    command = token
-    data = standard_items.json_data
-    all_items = data.get("MOM_procs", []) + data.get("mom_variables", [])
-
-    match = next((item for item in all_items if item["label"] == command), None)
-    if match and match.get("kind") == "function":
-        label = match.get("label", "")
-        parameters = match.get("parameters", [])
-        param_lines = "\n".join(f"- `{p['name']}`: {p['desc']}" for p in parameters) or "_None_"
-        example_data = match.get("example", [])
-        example_md = "\n".join(f"{line}" for line in example_data)
-        returns_data = match.get("returns", ["None"])
-        returns_md = "\n".join(f"- {line}" for line in returns_data)
-        doc_md = f"""\
-### 📘 {label}
-
-**Purpose**
-{match.get("description", "No description available.")}
-
-**Format**
-`{match.get("format", label)}`
-
-**Parameters**
-{param_lines}
-
-**Return value**
-{returns_md}
-
-**Example**
-```tcl
-{example_md}"""
-        return lsp.Hover(lsp.MarkupContent(kind=lsp.MarkupKind.Markdown, value=doc_md))
-
-    # 2) Otherwise, check if the token is a custom proc and show its preceding doc block
-    # Build a merged map of proc -> docs gathered during initialization and updates
-    proc_docs: dict[str, str] = {}
-    for file_docs in LSP_SERVER.proc_docs.values():
-        proc_docs.update(file_docs)
-
-    if token in proc_docs:
-        return lsp.Hover(lsp.MarkupContent(kind=lsp.MarkupKind.Markdown, value=proc_docs[token]))
-
-    return None
-
-
-@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DEFINITION)
-def goto_definition(params: lsp.DefinitionParams):
-    """Provide go-to-definition locations for Tcl procs.
-
-    Strategy:
-    - Find the token under the cursor.
-    - If it matches a custom proc collected in proc_signatures, locate its declaration
-      by searching the current document first, then other indexed files.
-    - Return a Location pointing to the proc name in its declaration line.
-    """
-    doc = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
-    pos = params.position
-    try:
-        line = doc.lines[pos.line]
-    except IndexError:
-        return None
-
-    # Identify token under cursor
-    token = None
-    for m in re.finditer(r"\b\w+\b", line):
-        if m.start() <= pos.character <= m.end():
-            token = m.group(0)
-            break
-    if not token:
-        return None
-
-    # Helper to search a single source text for a proc declaration
-    def find_decl_in_source(source_text: str, uri: str) -> Optional[lsp.Location]:
-        lines = source_text.split("\n")
-        pattern = re.compile(r"^\s*proc\s+" + re.escape(token) + r"\b")
-        for i, ln in enumerate(lines):
-            m = pattern.match(ln)
-            if m:
-                start_char = ln.find(token)
-                if start_char < 0:
-                    start_char = max(m.end() - len(token), 0)
-                start = lsp.Position(i, start_char)
-                end = lsp.Position(i, start_char + len(token))
-                return lsp.Location(uri=uri, range=lsp.Range(start=start, end=end))
-        return None
-
-    # 1) Search in current document
-    loc = find_decl_in_source(doc.source, doc.uri)
-    if loc:
-        return loc
-
-    # 2) Search in indexed files from proc_signatures
-    # Build list of candidate files that declare this token as a proc
-    candidate_files: list[str] = []
-    for file_path, procs in LSP_SERVER.proc_signatures.items():
-        if token in procs:
-            candidate_files.append(file_path)
-
-    for fp in candidate_files:
-        uri = pathlib.Path(fp).as_uri()
-        # Try to get from workspace if available; else read from disk
-        try:
-            other_doc = LSP_SERVER.workspace.get_text_document(uri)
-            source = other_doc.source
-        except Exception:
-            try:
-                source = pathlib.Path(fp).read_text(encoding="utf-8")
-            except Exception:
-                continue
-        loc = find_decl_in_source(source, uri)
-        if loc:
-            return loc
-
-    return None
-
-
-# **********************************************************
-# Linting features end here
-# **********************************************************
-
-
-# **********************************************************
-# Formatting features start here
-# **********************************************************
-#  Sample implementations:
-#  Black: https://github.com/microsoft/vscode-black-formatter/blob/main/bundled/tool
-
-
-# **********************************************************
-# Formatting features ends here
-# **********************************************************
-@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_FORMATTING)
-def formatting(params: lsp.DocumentFormattingParams) -> list[lsp.TextEdit] | None:
-    """LSP handler for textDocument/formatting request."""
-    doc = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
-
-    source = doc.source
-    start = lsp.Position(line=0, character=0)
-    last_line = source.rsplit("\n", 1)[-1]
-    end = lsp.Position(line=source.count("\n"), character=len(last_line))
-    if GLOBAL_SETTINGS.get("formatter", True):
-        source = LSP_SERVER.format(doc, params.options)
-    return [
-        lsp.TextEdit(
-            range=lsp.Range(start=start, end=end),
-            new_text=source,
-        )
-    ]
-
-
-# **********************************************************
-# Required Language Server Initialization and Exit handlers.
-# **********************************************************
-@LSP_SERVER.feature(lsp.WORKSPACE_DID_CHANGE_CONFIGURATION)
-def did_change_configuration(_: lsp.DidChangeConfigurationParams):
-    """LSP Handler for Config Changes"""
-
-
-@LSP_SERVER.feature(lsp.INITIALIZE)
-def initialize(params: lsp.InitializeParams) -> lsp.InitializeResult:
-    """LSP handler for initialize request."""
-    log_to_output(f"CWD Server: {os.getcwd()}")
-
-    paths = "\r\n   ".join(sys.path)
-    log_to_output(f"sys.path used to run Server:\r\n   {paths}")
-
-    GLOBAL_SETTINGS.update(**params.initialization_options.get("globalSettings", {}))
-
-    settings = params.initialization_options["settings"]
-    _update_workspace_settings(settings)
-    log_to_output(f"Settings used to run Server:\r\n{json.dumps(settings, indent=4, ensure_ascii=False)}\r\n")
-    log_to_output(f"Global settings:\r\n{json.dumps(GLOBAL_SETTINGS, indent=4, ensure_ascii=False)}\r\n")
-    semantic_tokens_legend = lsp.SemanticTokensLegend(
-        token_types=TOKEN_TYPES,
-        token_modifiers=[m.name for m in TokenModifier],
-    )
-    return lsp.InitializeResult(
-        capabilities=lsp.ServerCapabilities(
-            document_formatting_provider=GLOBAL_SETTINGS.get("formatter", True),
-            semantic_tokens_provider=lsp.SemanticTokensOptions(legend=semantic_tokens_legend, full=True, range=False),
-            definition_provider=True,
-        )
-    )
-
-
-@LSP_SERVER.feature(lsp.INITIALIZED)
-def initialized(_params: lsp.InitializedParams):
-    """Kick off background indexing to avoid blocking initialization."""
-
-    def index_workspace():
-        try:
-            root = LSP_SERVER.workspace.root_path
-            log_to_output("Background indexing started...")
-            psc_files = get_all_psc_files(pathlib.Path(root))
-            for psc_file in psc_files:
-                poco_files = read_psc_file(psc_file)
-                for sourced_layer in poco_files:
-                    completion.reset()
-                    try:
-                        file_root = pathlib.Path(root).joinpath(sourced_layer.subfolder if sourced_layer.subfolder else "")
-                        for tcl_file in sourced_layer.files:
-                            filepath = pathlib.Path(file_root).joinpath(f"{tcl_file}.tcl")
-                            if not filepath.exists():
-                                continue
-                            completion.reset()
-                            document = LSP_SERVER.workspace.get_text_document(filepath.as_uri())
-                            tree = LSP_SERVER.parser.parse(document.source)
-                            tree.accept(completion, recurse=True)
-                            remove_existing_items(completion.custom_functions, LSP_SERVER.poco_completion)
-                            LSP_SERVER.poco_completion[str(filepath)] = completion.custom_functions
-                            remove_shared_keys(LSP_SERVER.proc_signatures, completion.proc_signatures)
-                            LSP_SERVER.proc_signatures[str(filepath)] = completion.proc_signatures
-                            from tools.proc_docs import build_proc_docs
-
-                            LSP_SERVER.proc_docs[str(filepath)] = build_proc_docs(tree, document.source)
-                    except Exception as e:
-                        log_to_output(f"Fehler beim Parsen von {filepath}: {e}")
-            log_to_output("Background indexing completed.")
-        except Exception as e:
-            log_to_output(f"Background indexing failed: {e}")
-
-    threading.Thread(target=index_workspace, name="nxps-indexer", daemon=True).start()
-
-
-@LSP_SERVER.feature(lsp.EXIT)
-def on_exit(_params: Optional[Any] = None) -> None:
-    """Handle clean up on exit."""
-    jsonrpc.shutdown_json_rpc()
-
-
-@LSP_SERVER.feature(lsp.SHUTDOWN)
-def on_shutdown(_params: Optional[Any] = None) -> None:
-    """Handle clean up on shutdown."""
-    jsonrpc.shutdown_json_rpc()
-
-
-def _get_global_defaults():
-    return {
-        "path": GLOBAL_SETTINGS.get("path", []),
-        "interpreter": GLOBAL_SETTINGS.get("interpreter", [sys.executable]),
-        "args": GLOBAL_SETTINGS.get("args", []),
-        "importStrategy": GLOBAL_SETTINGS.get("importStrategy", "useBundled"),
-        "showNotifications": GLOBAL_SETTINGS.get("showNotifications", "off"),
-        "formatter": GLOBAL_SETTINGS.get("formatter", True),
-        "inlayHint": GLOBAL_SETTINGS.get("inlayHint", True),
-    }
-
-
-def _update_workspace_settings(settings):
-    if not settings:
-        key = os.getcwd()
-        WORKSPACE_SETTINGS[key] = {
-            "cwd": key,
-            "workspaceFS": key,
-            "workspace": uris.from_fs_path(key),
-            **_get_global_defaults(),
-        }
-        return
-
-    for setting in settings:
-        key = uris.to_fs_path(setting["workspace"])
-        WORKSPACE_SETTINGS[key] = {
-            "cwd": key,
-            **setting,
-            "workspaceFS": key,
-        }
-
-
-def _get_settings_by_path(file_path: pathlib.Path):
-    workspaces = {s["workspaceFS"] for s in WORKSPACE_SETTINGS.values()}
-
-    while file_path != file_path.parent:
-        str_file_path = str(file_path)
-        if str_file_path in workspaces:
-            return WORKSPACE_SETTINGS[str_file_path]
-        file_path = file_path.parent
-
-    setting_values = list(WORKSPACE_SETTINGS.values())
-    return setting_values[0]
-
-
-def _get_document_key(document: workspace.Document):
-    if WORKSPACE_SETTINGS:
-        document_workspace = pathlib.Path(document.path)
-        workspaces = {s["workspaceFS"] for s in WORKSPACE_SETTINGS.values()}
-
-        # Find workspace settings for the given file.
-        while document_workspace != document_workspace.parent:
-            if str(document_workspace) in workspaces:
-                return str(document_workspace)
-            document_workspace = document_workspace.parent
-
-    return None
-
-
-def _get_settings_by_document(document: workspace.Document | None):
-    if document is None or document.path is None:
-        return list(WORKSPACE_SETTINGS.values())[0]
-
-    key = _get_document_key(document)
-    if key is None:
-        # This is either a non-workspace file or there is no workspace.
-        key = os.fspath(pathlib.Path(document.path).parent)
-        return {
-            "cwd": key,
-            "workspaceFS": key,
-            "workspace": uris.from_fs_path(key),
-            **_get_global_defaults(),
-        }
-
-    return WORKSPACE_SETTINGS[str(key)]
-
-
-# *****************************************************
-# Logging and notification.
-# *****************************************************
-def log_to_output(message: str, msg_type: lsp.MessageType = lsp.MessageType.Log) -> None:
-    LSP_SERVER.show_message_log(message, msg_type)
-
-
-def log_error(message: str) -> None:
-    LSP_SERVER.show_message_log(message, lsp.MessageType.Error)
-    if os.getenv("LS_SHOW_NOTIFICATION", "off") in ["onError", "onWarning", "always"]:
-        LSP_SERVER.show_message(message, lsp.MessageType.Error)
-
-
-def log_warning(message: str) -> None:
-    LSP_SERVER.show_message_log(message, lsp.MessageType.Warning)
-    if os.getenv("LS_SHOW_NOTIFICATION", "off") in ["onWarning", "always"]:
-        LSP_SERVER.show_message(message, lsp.MessageType.Warning)
-
-
-def log_always(message: str) -> None:
-    LSP_SERVER.show_message_log(message, lsp.MessageType.Info)
-    if os.getenv("LS_SHOW_NOTIFICATION", "off") in ["always"]:
-        LSP_SERVER.show_message(message, lsp.MessageType.Info)
-
-
-# *****************************************************
-# Start the server.
-# *****************************************************
-if __name__ == "__main__":
-    LSP_SERVER.start_io()
diff --git a/server/src/lsp_tclserver.py b/server/src/lsp_tclserver.py
deleted file mode 100644
index 6be449a..0000000
--- a/server/src/lsp_tclserver.py
+++ /dev/null
@@ -1,173 +0,0 @@
-import logging
-import pathlib
-from typing import List, Optional, Tuple
-import lsprotocol.types as lsp
-from pygls.workspace.text_document import TextDocument
-from tclint.lexer import TclSyntaxError
-from tclint.format import FormatterOpts
-from tools.formatter import NxFormatter as Formatter
-from tclint.violations import Violation
-from plugins.poco_plugin import commands
-from tools import checks, parser
-from pygls import server, uris
-from tools.completion_items import completion, remove_existing_items, remove_shared_keys
-from tools.proc_docs import build_proc_docs
-
-
-DIAGNOSTIC_SOURCE = "nx-post-support"
-
-
-class TclLanguageServer(server.LanguageServer):
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self.parser = parser.CustomParser()
-        for command in commands:
-            self.parser._commands.update(command)
-        self.diagnostics = {}
-        self.poco_completion: dict = {}
-        self.proc_signatures: dict = {}
-        self.proc_docs: dict = {}
-        # Cache: (uri, version) -> (tree, violations)
-        self._ast_cache = {}
-
-    def get_tree(self, document: TextDocument):
-        key = (document.uri, document.version)
-        cached = self._ast_cache.get(key)
-        if cached:
-            return cached[0]
-        # Parse and cache
-        self.parser.violations = []
-        tree = self.parser.parse(document.source)
-        violations = list(self.parser.violations)
-        self._ast_cache[key] = (tree, violations)
-        return tree
-
-    def get_tree_and_violations(self, document: TextDocument):
-        key = (document.uri, document.version)
-        cached = self._ast_cache.get(key)
-        if cached:
-            return cached
-        # Parse and cache
-        self.parser.violations = []
-        tree = self.parser.parse(document.source)
-        violations = list(self.parser.violations)
-        self._ast_cache[key] = (tree, violations)
-        return tree, violations
-
-    def clear_cache_for_uri(self, uri: str):
-        to_delete = [k for k in self._ast_cache.keys() if k[0] == uri]
-        for k in to_delete:
-            del self._ast_cache[k]
-
-    def update_poco_completion_for_file(self, document: TextDocument):
-        """Update poco_completion for a specific file when it changes"""
-        filepath = str(pathlib.Path(uris.to_fs_path(document.uri)))
-
-        # Remove existing completion items for this file
-        if filepath in self.poco_completion:
-            del self.poco_completion[filepath]
-        if filepath in self.proc_signatures:
-            del self.proc_signatures[filepath]
-        if filepath in self.proc_docs:
-            del self.proc_docs[filepath]
-
-        # Parse and extract new completion items
-        completion.reset()
-        try:
-            tree = self.get_tree(document)
-            tree.accept(completion, recurse=True)
-            remove_existing_items(completion.custom_functions, self.poco_completion)
-            self.poco_completion[filepath] = completion.custom_functions
-            remove_shared_keys(self.proc_signatures, completion.proc_signatures)
-            self.proc_signatures[filepath] = completion.proc_signatures
-            self.proc_docs[filepath] = build_proc_docs(tree, document.source)
-        except Exception as e:
-            logging.debug(f"Error parsing {filepath}: {e}")
-
-    def format(
-        self,
-        document: TextDocument,
-        options: lsp.FormattingOptions,
-        range: Optional[Tuple[int, int]] = None,
-    ):
-        # parser = Parser(command_plugins=["nx_plugins.poco_plugin.py"])
-        # parser._commands.update(commands)
-
-        indent = "\t" if not options.insert_spaces else " " * options.tab_size
-        formatter = Formatter(
-            FormatterOpts(
-                indent=indent,
-                spaces_in_braces=False,
-                max_blank_lines=500,
-                indent_namespace_eval=True,
-            ),
-        )
-
-        if range is not None:
-            start, end = range
-            return formatter.format_partial(document.source[start:end], self.parser)
-
-        return formatter.format_top(document.source, self.parser)
-
-    def linter(
-        self,
-        document: TextDocument,
-    ) -> List[Violation]:
-        tree, violations = self.get_tree_and_violations(document)
-        for checker in checks.get_checkers():
-            violations += checker.check(document.source, tree)
-        return violations
-
-    def lint(self, document: TextDocument):
-        diagnostics = []
-
-        try:
-            violations = self.linter(document)
-        except TclSyntaxError as e:
-            return [
-                lsp.Diagnostic(
-                    message=str(e),
-                    severity=lsp.DiagnosticSeverity.Error,
-                    range=lsp.Range(
-                        start=lsp.Position(e.start[0] - 1, e.start[1] - 1),
-                        end=lsp.Position(e.end[0] - 1, e.end[1] - 1),
-                    ),
-                    code="syntax error",
-                    source=DIAGNOSTIC_SOURCE,
-                )
-            ]
-
-        for violation in violations:
-            message = violation.message
-            severity = lsp.DiagnosticSeverity.Warning
-            start = lsp.Position(line=violation.start[0] - 1, character=violation.start[1] - 1)
-            end = lsp.Position(line=violation.end[0] - 1, character=violation.end[1] - 1)
-
-            diagnostics.append(
-                lsp.Diagnostic(
-                    message=message,
-                    severity=severity,
-                    range=lsp.Range(
-                        start=start,
-                        end=end,
-                    ),
-                    code=violation.id,
-                    source=DIAGNOSTIC_SOURCE,
-                )
-            )
-
-        return diagnostics
-
-    def _compute_diagnostics(self, document: TextDocument) -> List[lsp.Diagnostic]:
-        return self.lint(document)
-
-    def compute_diagnostics(self, document: TextDocument):
-        # `None` sentinel ensures that `diagnostics` gets updated if the URI is not
-        # present.
-        _, previous = self.diagnostics.get(document, (0, None))
-
-        diagnostics = self._compute_diagnostics(document)
-
-        # Only update if the list has changed
-        if previous != diagnostics:
-            self.diagnostics[document.uri] = (document.version, diagnostics)
diff --git a/server/src/lsp_utils.py b/server/src/lsp_utils.py
deleted file mode 100644
index fb5f032..0000000
--- a/server/src/lsp_utils.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-"""Utility functions and classes for use with running tools over LSP."""
-from __future__ import annotations
-
-import contextlib
-import io
-import os
-import os.path
-import runpy
-import site
-import subprocess
-import sys
-import threading
-from typing import Any, Callable, List, Sequence, Tuple, Union
-
-# Save the working directory used when loading this module
-SERVER_CWD = os.getcwd()
-CWD_LOCK = threading.Lock()
-
-
-def as_list(content: Union[Any, List[Any], Tuple[Any]]) -> Union[List[Any], Tuple[Any]]:
-    """Ensures we always get a list"""
-    if isinstance(content, (list, tuple)):
-        return content
-    return [content]
-
-
-# pylint: disable-next=consider-using-generator
-_site_paths = tuple(
-    [
-        os.path.normcase(os.path.normpath(p))
-        for p in (as_list(site.getsitepackages()) + as_list(site.getusersitepackages()))
-    ]
-)
-
-
-def is_same_path(file_path1, file_path2) -> bool:
-    """Returns true if two paths are the same."""
-    return os.path.normcase(os.path.normpath(file_path1)) == os.path.normcase(
-        os.path.normpath(file_path2)
-    )
-
-
-def is_current_interpreter(executable) -> bool:
-    """Returns true if the executable path is same as the current interpreter."""
-    return is_same_path(executable, sys.executable)
-
-
-def is_stdlib_file(file_path) -> bool:
-    """Return True if the file belongs to standard library."""
-    return os.path.normcase(os.path.normpath(file_path)).startswith(_site_paths)
-
-
-# pylint: disable-next=too-few-public-methods
-class RunResult:
-    """Object to hold result from running tool."""
-
-    def __init__(self, stdout: str, stderr: str):
-        self.stdout: str = stdout
-        self.stderr: str = stderr
-
-
-class CustomIO(io.TextIOWrapper):
-    """Custom stream object to replace stdio."""
-
-    name = None
-
-    def __init__(self, name, encoding="utf-8", newline=None):
-        self._buffer = io.BytesIO()
-        self._buffer.name = name
-        super().__init__(self._buffer, encoding=encoding, newline=newline)
-
-    def close(self):
-        """Provide this close method which is used by some tools."""
-        # This is intentionally empty.
-
-    def get_value(self) -> str:
-        """Returns value from the buffer as string."""
-        self.seek(0)
-        return self.read()
-
-
-@contextlib.contextmanager
-def substitute_attr(obj: Any, attribute: str, new_value: Any):
-    """Manage object attributes context when using runpy.run_module()."""
-    old_value = getattr(obj, attribute)
-    setattr(obj, attribute, new_value)
-    yield
-    setattr(obj, attribute, old_value)
-
-
-@contextlib.contextmanager
-def redirect_io(stream: str, new_stream):
-    """Redirect stdio streams to a custom stream."""
-    old_stream = getattr(sys, stream)
-    setattr(sys, stream, new_stream)
-    yield
-    setattr(sys, stream, old_stream)
-
-
-@contextlib.contextmanager
-def change_cwd(new_cwd):
-    """Change working directory before running code."""
-    os.chdir(new_cwd)
-    yield
-    os.chdir(SERVER_CWD)
-
-
-def _run_module(
-    module: str, argv: Sequence[str], use_stdin: bool, source: str = None
-) -> RunResult:
-    """Runs as a module."""
-    str_output = CustomIO("", encoding="utf-8")
-    str_error = CustomIO("", encoding="utf-8")
-
-    with contextlib.suppress(SystemExit):
-        with substitute_attr(sys, "argv", argv):
-            with redirect_io("stdout", str_output):
-                with redirect_io("stderr", str_error):
-                    if use_stdin and source is not None:
-                        str_input = CustomIO("", encoding="utf-8", newline="\n")
-                        with redirect_io("stdin", str_input):
-                            str_input.write(source)
-                            str_input.seek(0)
-                            runpy.run_module(module, run_name="__main__")
-                    else:
-                        runpy.run_module(module, run_name="__main__")
-
-    return RunResult(str_output.get_value(), str_error.get_value())
-
-
-def run_module(
-    module: str, argv: Sequence[str], use_stdin: bool, cwd: str, source: str = None
-) -> RunResult:
-    """Runs as a module."""
-    with CWD_LOCK:
-        if is_same_path(os.getcwd(), cwd):
-            return _run_module(module, argv, use_stdin, source)
-        with change_cwd(cwd):
-            return _run_module(module, argv, use_stdin, source)
-
-
-def run_path(
-    argv: Sequence[str], use_stdin: bool, cwd: str, source: str = None
-) -> RunResult:
-    """Runs as an executable."""
-    if use_stdin:
-        with subprocess.Popen(
-            argv,
-            encoding="utf-8",
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            stdin=subprocess.PIPE,
-            cwd=cwd,
-        ) as process:
-            return RunResult(*process.communicate(input=source))
-    else:
-        result = subprocess.run(
-            argv,
-            encoding="utf-8",
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            check=False,
-            cwd=cwd,
-        )
-        return RunResult(result.stdout, result.stderr)
-
-
-def run_api(
-    callback: Callable[[Sequence[str], CustomIO, CustomIO, CustomIO | None], None],
-    argv: Sequence[str],
-    use_stdin: bool,
-    cwd: str,
-    source: str = None,
-) -> RunResult:
-    """Run a API."""
-    with CWD_LOCK:
-        if is_same_path(os.getcwd(), cwd):
-            return _run_api(callback, argv, use_stdin, source)
-        with change_cwd(cwd):
-            return _run_api(callback, argv, use_stdin, source)
-
-
-def _run_api(
-    callback: Callable[[Sequence[str], CustomIO, CustomIO, CustomIO | None], None],
-    argv: Sequence[str],
-    use_stdin: bool,
-    source: str = None,
-) -> RunResult:
-    str_output = CustomIO("", encoding="utf-8")
-    str_error = CustomIO("", encoding="utf-8")
-
-    with contextlib.suppress(SystemExit):
-        with substitute_attr(sys, "argv", argv):
-            with redirect_io("stdout", str_output):
-                with redirect_io("stderr", str_error):
-                    if use_stdin and source is not None:
-                        str_input = CustomIO("", encoding="utf-8", newline="\n")
-                        with redirect_io("stdin", str_input):
-                            str_input.write(source)
-                            str_input.seek(0)
-                            callback(argv, str_output, str_error, str_input)
-                    else:
-                        callback(argv, str_output, str_error)
-
-    return RunResult(str_output.get_value(), str_error.get_value())
diff --git a/server/src/plugins/__init__.py b/server/src/plugins/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/server/src/plugins/poco_plugin.py b/server/src/plugins/poco_plugin.py
deleted file mode 100644
index f51125c..0000000
--- a/server/src/plugins/poco_plugin.py
+++ /dev/null
@@ -1,55 +0,0 @@
-from tclint.commands.checks import CommandArgError
-from tclint.syntax_tree import BracedWord
-
-
-def _lib_ge_command_buffer_edit(args, parser, command_name, pos_script, len_args):
-    if len(args) != len_args:
-        raise CommandArgError(
-            f"wrong # of args to {command_name}: got {len(args)}, expected {len_args}"
-        )
-    args[pos_script] = parser.parse_script(args[pos_script])
-    return args
-
-
-def _lib_ge_command_buffer(args, parser):
-    if (
-        len(args) < 1
-        or len(args) > 2
-        or (len(args) == 1 and isinstance(args[0], BracedWord))
-    ):
-        raise CommandArgError(
-            f"wrong # of args to LIB_GE_command_buffer: got {len(args)}, expected 1 or 2"
-        )
-    if len(args) == 1:
-        return args
-    args[0] = parser.parse_script(args[0])
-    return args
-
-
-def lib_ge_command_buffer_edit_append(args, parser):
-    _lib_ge_command_buffer_edit(args, parser, "LIB_GE_command_buffer_edit_append", 2, 4)
-
-
-def lib_ge_command_buffer_edit_prepend(args, parser):
-    _lib_ge_command_buffer_edit(
-        args, parser, "LIB_GE_command_buffer_edit_prepend", 2, 4
-    )
-
-
-def lib_ge_command_buffer_edit_replace(args, parser):
-    _lib_ge_command_buffer_edit(
-        args, parser, "LIB_GE_command_buffer_edit_replace", 3, 5
-    )
-
-
-def lib_ge_command_buffer_edit_insert(args, parser):
-    _lib_ge_command_buffer_edit(args, parser, "LIB_GE_command_buffer_edit_insert", 2, 6)
-
-
-commands = [
-    {"LIB_GE_command_buffer_edit_append": lib_ge_command_buffer_edit_append},
-    {"LIB_GE_command_buffer_edit_prepend": lib_ge_command_buffer_edit_prepend},
-    {"LIB_GE_command_buffer_edit_insert": lib_ge_command_buffer_edit_insert},
-    {"LIB_GE_command_buffer_edit_replace": lib_ge_command_buffer_edit_replace},
-    {"LIB_GE_command_buffer": _lib_ge_command_buffer},
-]
diff --git a/server/src/tools/checks.py b/server/src/tools/checks.py
deleted file mode 100644
index 70d6886..0000000
--- a/server/src/tools/checks.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from enum import Enum
-from tclint.syntax_tree import Visitor, BareWord, Command
-from tclint.violations import Violation, Rule
-
-
-class Rules(Enum):
-    VALIDATION = "validation"
-    OPTIONAL_ARG_POSITION = "optinal_args"
-
-    def __str__(self):
-        return self.value
-
-
-class CommandArgsCheck(Visitor):
-    def __init__(self):
-        self._violations = []
-
-    def check(self, _, tree):
-        self._violations.clear()
-        tree.accept(self, recurse=True)
-        return self._violations
-
-    def visit_command(self, command: Command):
-        if (
-            not hasattr(command.routine, "contents")
-            or command.routine.contents != "proc"
-        ):
-            return
-        if len(command.args) < 2:
-            return
-
-        args_node = command.args[1]
-        if not hasattr(args_node, "children"):
-            return
-
-        found_optional = False
-        for arg in args_node.children:
-            # Required argument
-            if isinstance(arg, BareWord):
-                if found_optional:
-                    self._violations.append(
-                        Violation(
-                            Rules.OPTIONAL_ARG_POSITION,
-                            "Required argument follows optional one",
-                            arg.pos,
-                            arg.end_pos,
-                        )
-                    )
-            # Optional argument
-            elif hasattr(arg, "children") and len(arg.children) >= 2:
-                found_optional = True
-
-
-def get_checkers():
-    checkers = (CommandArgsCheck(),)
-
-    return checkers
diff --git a/server/src/tools/completion_items.py b/server/src/tools/completion_items.py
deleted file mode 100644
index 3cade14..0000000
--- a/server/src/tools/completion_items.py
+++ /dev/null
@@ -1,124 +0,0 @@
-from tclint.syntax_tree import Visitor, Command, BareWord, List
-import lsprotocol.types as lsp
-from common.load_data import standard_items
-
-BUILTIN_VAR_LABELS = {ci.label for ci in standard_items.nx_variables}
-
-
-class CompletionItems:
-    def __init__(self):
-        self._custom_functions: list[lsp.CompletionItem] = []
-
-    @property
-    def custom_functions(self) -> list[lsp.CompletionItem]:
-        return self._custom_functions
-
-    @custom_functions.setter
-    def custom_functions(self, value: lsp.CompletionItem):
-        self._custom_functions.append(value)
-
-
-class _Completion(Visitor):
-    def __init__(self):
-        super().__init__()
-        self._custom_functions: list[lsp.CompletionItem] = []
-        self._proc_signatures = {}
-
-    @property
-    def custom_functions(self) -> list[lsp.CompletionItem]:
-        return self._custom_functions
-
-    @property
-    def proc_signatures(self):
-        return self._proc_signatures
-
-    def reset(self):
-        self._custom_functions = []
-        self._proc_signatures = {}
-
-    def _append_unique(self, item: lsp.CompletionItem):
-        # Avoid duplicate labels within the same file scan
-        if not any(ci.label == item.label for ci in self._custom_functions):
-            self._custom_functions.append(item)
-
-    def visit_command(self, command: Command):
-        routine = command.routine
-
-        # Collect custom proc names and their signatures
-        if routine.contents == "proc" and command.args:
-            first_arg = command.args[0]
-            if not getattr(first_arg, "value", None):
-                return
-
-            if any(item.label == first_arg.value for item in standard_items.nx_procs):
-                return
-
-            # Record proc name as a completion item
-            self._append_unique(lsp.CompletionItem(label=first_arg.value, kind=lsp.CompletionItemKind.Function))
-            if len(command.args) < 2:
-                return
-
-            param_list_node = command.args[1]
-            if not hasattr(param_list_node, "children"):
-                return
-
-            param_names = []
-            for arg in param_list_node.children:
-                if isinstance(arg, BareWord):
-                    param_names.append(arg.value)
-                elif isinstance(arg, List) and len(arg.children) >= 1:
-                    first = arg.children[0]
-                    if isinstance(first, BareWord):
-                        param_names.append(first.value)
-
-            self._proc_signatures[first_arg.value] = param_names
-
-        # Collect global variables declared with: global var1 var2 ...
-        elif routine.contents == "global" and command.args:
-            for arg in command.args:
-                if isinstance(arg, BareWord) and getattr(arg, "value", None):
-                    if arg.value not in BUILTIN_VAR_LABELS:
-                        self._append_unique(lsp.CompletionItem(label=arg.value, kind=lsp.CompletionItemKind.Variable))
-
-        # Collect variables set with explicit global namespace: set ::var_name ...
-        elif routine.contents == "set" and command.args:
-            first = command.args[0]
-            if isinstance(first, BareWord) and getattr(first, "value", None):
-                var_name = first.value
-                if var_name.startswith("::"):
-                    base_name = var_name.split("(", 1)[0]
-                    clean_name = base_name[2:]  # remove leading '::' for completion display
-                    if clean_name not in BUILTIN_VAR_LABELS:
-                        self._append_unique(lsp.CompletionItem(label=clean_name, kind=lsp.CompletionItemKind.Variable))
-
-
-def remove_existing_items(items: list[lsp.CompletionItem], store: dict) -> None:
-    """
-    Entfernt alle CompletionItems aus dem store, deren label in der items-Liste vorkommt.
-    Änderungen erfolgen in-place.
-    """
-    labels_to_remove = {item.label for item in items}
-
-    for key in list(store.keys()):
-        filtered = [ci for ci in store[key] if ci.label not in labels_to_remove]
-        if filtered:
-            store[key] = filtered
-        else:
-            del store[key]
-
-
-def remove_shared_keys(nested_dict: dict[str, dict[str, list]], flat_dict: dict[str, list]) -> None:
-    """
-    Entfernt alle Keys aus nested_dict[file][func], wenn func auch in flat_dict vorhanden ist.
-    Änderungen erfolgen in-place.
-    """
-    for file_path, func_dict in list(nested_dict.items()):
-        for func_name in list(func_dict.keys()):
-            if func_name in flat_dict:
-                del nested_dict[file_path][func_name]
-
-        if not nested_dict[file_path]:
-            del nested_dict[file_path]
-
-
-completion = _Completion()
diff --git a/server/src/tools/document_symbols.py b/server/src/tools/document_symbols.py
deleted file mode 100644
index 7f976ef..0000000
--- a/server/src/tools/document_symbols.py
+++ /dev/null
@@ -1,189 +0,0 @@
-from __future__ import annotations
-
-import re
-import lsprotocol.types as lsp
-
-# Precompiled regex patterns for performance
-NS_RE = re.compile(r"^\s*namespace\s+eval\s+([^\s\{]+)")
-PROC_RE = re.compile(r"^\s*proc\s+([^\s\{]+)\s+\{.*\}\s+\{")
-SET_RE = re.compile(r"^\s*set\s+([^\s\}]+)")
-EVENT_START_RE = re.compile(r"^\s*LIB_GE_command_buffer_edit_(prepend|append|insert|replace)\b")
-EVENT_CLOSE_INLINE_RE = re.compile(r"^\s*\}\s*(\S+)\s*.*$")
-EVENT_NAME_LINE_RE = re.compile(r"^\s*([A-Za-z_][A-Za-z0-9_]*)\b")
-
-
-def build_document_symbols(source: str) -> list[lsp.DocumentSymbol]:
-    """Parse a Tcl document source and return DocumentSymbols.
-
-    This mirrors the previous inline implementation in lsp_server, but is extracted
-    for readability and reuse.
-    """
-    lines = source.split("\n")
-
-    class Scope:
-        def __init__(self, name: str, symbol: lsp.DocumentSymbol, start_line: int):
-            self.name = name
-            self.symbol = symbol
-            self.start_line = start_line
-            self.brace_count = 0
-
-    root_symbol = lsp.DocumentSymbol(
-        name="root",
-        detail="",
-        kind=lsp.SymbolKind.Namespace,
-        range=lsp.Range(start=lsp.Position(0, 0), end=lsp.Position(len(lines), 0)),
-        selection_range=lsp.Range(start=lsp.Position(0, 0), end=lsp.Position(0, 0)),
-        children=[],
-    )
-
-    scope_stack: list[Scope] = [Scope("", root_symbol, 0)]
-    pending_event: dict | None = None
-
-    for i, line in enumerate(lines):
-        # If inside an event, update its brace count for this line
-        if pending_event is not None:
-            pe_open = line.count("{")
-            pe_close = line.count("}")
-            pending_event["brace_count"] = pending_event.get("brace_count", 1) + pe_open - pe_close
-            # If this line closed the outer event block, finalize the event
-            if pending_event["brace_count"] <= 0:
-                # Try inline name on the same line
-                close_inline = EVENT_CLOSE_INLINE_RE.match(line)
-                if close_inline:
-                    event_name = close_inline.group(1)
-                    name_line_index = i
-                else:
-                    # Look ahead to next non-empty line for the name
-                    j = i + 1
-                    while j < len(lines) and lines[j].strip() == "":
-                        j += 1
-                    event_name = None
-                    name_line_index = i
-                    if j < len(lines):
-                        name_line = lines[j]
-                        name_match = EVENT_NAME_LINE_RE.match(name_line)
-                        if name_match:
-                            event_name = name_match.group(1)
-                            name_line_index = j
-                if event_name:
-                    start_line = pending_event["start"]
-                    edit_type = pending_event["edit_type"]
-                    children = pending_event.get("children", [])
-                    detail = f"Event ({edit_type})"
-                    event_symbol = lsp.DocumentSymbol(
-                        name=event_name,
-                        detail=detail,
-                        kind=lsp.SymbolKind.Event,
-                        range=lsp.Range(start=lsp.Position(start_line, 0), end=lsp.Position(name_line_index, len(lines[name_line_index]))),
-                        selection_range=lsp.Range(start=lsp.Position(name_line_index, 0), end=lsp.Position(name_line_index, len(lines[name_line_index]))),
-                        children=children or [],
-                    )
-                    if scope_stack[-1].symbol.children is None:
-                        scope_stack[-1].symbol.children = []
-                    scope_stack[-1].symbol.children.append(event_symbol)
-                # Clear event tracking and continue
-                pending_event = None
-                continue
-
-        ns_match = NS_RE.match(line)
-        proc_match = PROC_RE.match(line)
-        set_match = SET_RE.match(line)
-
-        # Namespace
-        if ns_match:
-            ns_name = ns_match.group(1)
-            start = lsp.Position(i, 0)
-            end = lsp.Position(i, len(line))
-            sel_start_char = line.find(ns_name)
-            sel_end_char = sel_start_char + len(ns_name) if sel_start_char >= 0 else len(line)
-            ns_symbol = lsp.DocumentSymbol(
-                name=ns_name,
-                detail="Namespace",
-                kind=lsp.SymbolKind.Namespace,
-                range=lsp.Range(start=start, end=end),
-                selection_range=lsp.Range(
-                    start=lsp.Position(i, max(sel_start_char, 0)),
-                    end=lsp.Position(i, max(sel_end_char, 0)),
-                ),
-                children=[],
-            )
-            scope = Scope(ns_name, ns_symbol, i)
-            if scope_stack[-1].symbol.children is None:
-                scope_stack[-1].symbol.children = []
-            scope_stack[-1].symbol.children.append(ns_symbol)
-            scope_stack.append(scope)
-
-        # Proc
-        elif proc_match:
-            proc_name = proc_match.group(1)
-            start = lsp.Position(i, 0)
-            end = lsp.Position(i, len(line))
-            sel_start_char = line.find(proc_name)
-            sel_end_char = sel_start_char + len(proc_name) if sel_start_char >= 0 else len(line)
-            proc_symbol = lsp.DocumentSymbol(
-                name=proc_name,
-                detail="Procedure",
-                kind=lsp.SymbolKind.Function,
-                range=lsp.Range(start=start, end=end),
-                selection_range=lsp.Range(
-                    start=lsp.Position(i, max(sel_start_char, 0)),
-                    end=lsp.Position(i, max(sel_end_char, 0)),
-                ),
-                children=[],
-            )
-            scope = Scope(proc_name, proc_symbol, i)
-            if scope_stack[-1].symbol.children is None:
-                scope_stack[-1].symbol.children = []
-            scope_stack[-1].symbol.children.append(proc_symbol)
-            scope_stack.append(scope)
-
-        # set variable
-        elif set_match:
-            var_name = set_match.group(1)
-            start = lsp.Position(i, 0)
-            end = lsp.Position(i, len(line))
-            sel_start_char = line.find(var_name)
-            sel_end_char = sel_start_char + len(var_name) if sel_start_char >= 0 else len(line)
-            var_symbol = lsp.DocumentSymbol(
-                name=var_name,
-                detail="Variable",
-                kind=lsp.SymbolKind.Variable,
-                range=lsp.Range(start=start, end=end),
-                selection_range=lsp.Range(
-                    start=lsp.Position(i, max(sel_start_char, 0)),
-                    end=lsp.Position(i, max(sel_end_char, 0)),
-                ),
-                children=None,
-            )
-            # Attach to current scope or pending event as child
-            if pending_event is not None:
-                pending_event["children"].append(var_symbol)
-            else:
-                if scope_stack[-1].symbol.children is None:
-                    scope_stack[-1].symbol.children = []
-                scope_stack[-1].symbol.children.append(var_symbol)
-
-        # Event start (buffer edit)
-        m = EVENT_START_RE.match(line)
-        if m:
-            edit_type = m.group(1)
-            pending_event = {"start": i, "edit_type": edit_type, "children": []}
-            continue
-
-        # Brace balancing for scopes (namespace/proc)
-        open_count = line.count("{")
-        close_count = line.count("}")
-        scope_stack[-1].brace_count += open_count - close_count
-
-        # Close finished scopes
-        while len(scope_stack) > 1 and scope_stack[-1].brace_count <= 0:
-            finished = scope_stack.pop()
-            # Set the full range from startLine to current line
-            finished.symbol.range = lsp.Range(
-                start=lsp.Position(finished.start_line, 0),
-                end=lsp.Position(i, len(line)),
-            )
-
-    # Return top-level children
-    return root_symbol.children
-
diff --git a/server/src/tools/file_sourcing.py b/server/src/tools/file_sourcing.py
deleted file mode 100644
index 8db75b3..0000000
--- a/server/src/tools/file_sourcing.py
+++ /dev/null
@@ -1,51 +0,0 @@
-import xml.etree.ElementTree as ET
-from dataclasses import dataclass
-from typing import List, Optional
-from pathlib import Path
-
-
-@dataclass
-class SourcedFile:
-    layer_name: str
-    subfolder: Optional[str]
-    files: List[str]
-
-
-def read_psc_file(psc_file: Path) -> List[SourcedFile]:
-    tree = ET.parse(psc_file)
-    root = tree.getroot()
-
-    layers = root.findall(".//Layer")
-
-    layer_info_list: List[SourcedFile] = []
-    for layer in layers:
-        layer_name = layer.attrib.get("Name")
-        subfolder = layer.attrib.get("SubFolder")
-        # Scripts-Filenames
-        scripts = layer.find("Scripts")
-        script_names = []
-        if scripts is not None:
-            for filename in scripts.findall("Filename"):
-                name = filename.attrib.get("Name")
-                if name:
-                    script_names.append(name)
-
-        layer_info_list.append(
-            SourcedFile(layer_name=layer_name, subfolder=subfolder, files=script_names)
-        )
-    return layer_info_list
-
-
-def get_all_psc_files(root_path: Path) -> list[Path]:
-    return [path for path in root_path.rglob("*.psc")]
-
-
-if __name__ == "__main__":
-    test = get_all_psc_files(
-        Path(
-            r"H:\janus-engineering-customers\KSB_Frankenthal\custom\library\machine\installed_machines\ksb_pe_grob_g550_sone\postprocessor"
-        )
-    )
-    print(test)
-    for pp in test:
-        read_psc_file(pp)
diff --git a/server/src/tools/formatter.py b/server/src/tools/formatter.py
deleted file mode 100644
index 58edfac..0000000
--- a/server/src/tools/formatter.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from tclint.format import Formatter as BaseFormatter
-from typing import List
-
-
-class NxFormatter(BaseFormatter):
-    """
-    Custom formatter that inherits from tclint's Formatter but preserves explicit
-    line continuations (\\) inside braced expressions when they span multiple lines.
-
-    This avoids generating syntax errors in environments that require a trailing
-    backslash for multi-line expressions (e.g., certain NX Post interpreters),
-    while leaving all other formatting behavior unchanged.
-    """
-
-    def format_braced_expression(self, expr) -> List[str]:  # type: ignore[override]
-        # This method mirrors BaseFormatter.format_braced_expression but inserts
-        # a line continuation (" \") between continuation lines similar to
-        # BaseFormatter.format_expression.
-        formatted = [""]
-        for child in expr.children:
-            lines = self.format(child)
-            formatted[-1] += lines[0]
-            for line in lines[1:]:
-                # add continuation on the previous line; keep next line at the same level
-                formatted[-1] += " \\"  # keep explicit continuation
-                formatted += [line]
-
-        if expr.pos[0] == expr.end_pos[0]:
-            return self._brace(formatted)
-
-        return ["{"] + self._indent(formatted, self.opts.indent) + ["}"]
diff --git a/server/src/tools/inlay_hint.py b/server/src/tools/inlay_hint.py
deleted file mode 100644
index ea4f3e6..0000000
--- a/server/src/tools/inlay_hint.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import lsprotocol.types as lsp
-from tclint.syntax_tree import Visitor, Command
-
-
-class InlayHintGenerator(Visitor):
-    def __init__(self, proc_signatures):
-        self.proc_signatures = proc_signatures
-        self.hints = []
-
-    def visit_command(self, command: Command):
-        name = getattr(command.routine, "contents", None)
-        if name not in self.proc_signatures:
-            return
-
-        param_names = self.proc_signatures[name]
-        for idx, arg in enumerate(command.args):
-            if idx >= len(param_names):
-                break
-            param_name = param_names[idx]
-
-            if arg.pos:
-                line, col = arg.pos
-                self.hints.append(
-                    lsp.InlayHint(
-                        position=lsp.Position(line=line - 1, character=col - 1),
-                        label=f"{param_name}:",
-                        kind=lsp.InlayHintKind.Parameter,
-                    )
-                )
diff --git a/server/src/tools/parser.py b/server/src/tools/parser.py
deleted file mode 100644
index c1f15e8..0000000
--- a/server/src/tools/parser.py
+++ /dev/null
@@ -1,73 +0,0 @@
-import io
-from typing import Optional, Tuple
-from tclint.parser import Parser
-from tclint.commands import CommandArgError
-from tclint.syntax_tree import (
-    BracedWord,
-    BareWord,
-    BracedExpression,
-    List,
-    QuotedWord,
-    Expression,
-)
-from tclint.lexer import TclSyntaxError, Lexer, TOK_EOF
-
-
-class CustomParser(Parser):
-    def __init__(self, debug=False, command_plugins=None):
-        super().__init__(debug, command_plugins)
-        # Used to normalize newlines consistently with open()'s universal newlines mode.
-        self._decoder = io.IncrementalNewlineDecoder(None, True)
-
-    def parse(self, script: str, pos: Optional[Tuple[int, int]] = None):
-        script = self._decoder.decode(script, True)
-        lexer = Lexer(pos=pos)
-        lexer.input(script)
-        tree = self._parse_script(lexer, in_command_sub=False)
-        assert lexer.type() == TOK_EOF, (
-            "Didn't reach EOF parsing script, please file a bug report."
-        )
-
-        return tree
-
-    def _parse_operator(self, ts):
-        pos = ts.pos()
-
-        # hacky logic to handle parsing legal operators
-
-        if ts.value() in {"*", "&", "|"}:
-            # one or two of these characters are legal operators
-            operator = ts.value()
-            ts.next()
-            if ts.value() == operator:
-                operator += ts.value()
-                ts.next()
-        elif ts.value() in {"<", ">"}:
-            operator = ts.value()
-            ts.next()
-            if ts.value() in {operator, "="}:
-                operator += ts.value()
-                ts.next()
-        elif ts.value() in {"=", "!"}:
-            operator = ts.value()
-            ts.next()
-            if ts.value() != "=":
-                raise TclSyntaxError(
-                    f"invalid operator in expression: {operator}", pos, ts.pos()
-                )
-            operator += ts.value()
-            ts.next()
-        elif ts.value() in {"*", "/", "%", "+", "-", "^", "eq", "ne", "in", "ni"}:
-            operator = ts.value()
-            ts.next()
-        else:
-            message = "invalid operator in expression: "
-            if ts.value() == "\\ ":
-                message += (
-                    "\\ (check for trailing whitespace if it's the end of the line)"
-                )
-            else:
-                message += ts.value()
-            raise TclSyntaxError(message, pos, ts.pos())
-
-        return BareWord(operator, pos=pos, end_pos=ts.pos())
diff --git a/server/src/tools/poco_check.py b/server/src/tools/poco_check.py
deleted file mode 100644
index 933fb4a..0000000
--- a/server/src/tools/poco_check.py
+++ /dev/null
@@ -1,53 +0,0 @@
-from enum import Enum
-from tclint.syntax_tree import Visitor
-from tclint.violations import Violation
-
-
-class PoCoRule(Enum):
-    POCO_VALIDATION = "poco-validation"
-
-    def __str__(self):
-        return self.value
-
-
-class PocoCommandChecker(Visitor):
-    def __init__(self):
-        self._violations = []
-
-    def check(self, _, tree):
-        self._violations.clear()
-        tree.accept(self, recurse=True)
-        return self._violations
-
-    def visit_command(self, command):
-        name = command.routine.contents
-        if name not in {"LIB_GE_command_buffer_edit_prepend"}:
-            return
-
-        if len(command.args) != 4:
-            self._violations.append(
-                Violation(
-                    PoCoRule.POCO_VALIDATION,
-                    f"{name}: expected 4 arguments, got {len(command.args)}",
-                    command.pos,
-                    command.end_pos,
-                )
-            )
-            return
-
-        script_arg = command.args[2]
-        if script_arg.contents is None:
-            self._violations.append(
-                Violation(
-                    PoCoRule.POCO_VALIDATION,
-                    f"{name}: third argument must be a braced script",
-                    script_arg.pos,
-                    script_arg.end_pos,
-                )
-            )
-
-
-def get_checkers():
-    checkers = (PocoCommandChecker(),)
-
-    return checkers
diff --git a/server/src/tools/proc_docs.py b/server/src/tools/proc_docs.py
deleted file mode 100644
index c603ab1..0000000
--- a/server/src/tools/proc_docs.py
+++ /dev/null
@@ -1,177 +0,0 @@
-import re
-from typing import Dict, List
-
-from tclint.syntax_tree import Visitor, Command
-from tools.parser import CustomParser
-
-
-def _strip_comment_prefix(line: str) -> str:
-    """Strip leading '# ' or '#' from a line."""
-    if line.lstrip().startswith("#"):
-        # remove up to one leading '#' and one optional following space
-        return re.sub(r"^\s*#\s?", "", line)
-    return line
-
-
-def extract_doc_block_above(lines: List[str], start_line_index: int) -> str | None:
-    """
-    Extract a contiguous block of line comments immediately above the given line index.
-
-    - lines: document split into lines
-    - start_line_index: 0-based index of the line where the proc command starts
-
-    Returns the cleaned documentation text or None if no comment block found.
-    """
-    i = start_line_index - 1
-    if i < 0:
-        return None
-
-    doc_lines: List[str] = []
-
-    # Skip trailing empty lines directly above
-    while i >= 0 and lines[i].strip() == "":
-        i -= 1
-
-    # Collect contiguous comment lines going upwards
-    while i >= 0 and lines[i].lstrip().startswith("#"):
-        doc_lines.append(lines[i])
-        i -= 1
-
-    if not doc_lines:
-        return None
-
-    # Reverse to original order and strip comment prefixes
-    doc_lines.reverse()
-    cleaned = [_strip_comment_prefix(line_text) for line_text in doc_lines]
-
-    # Simple tag -> markdown conversions for nicer rendering
-    md_lines: List[str] = []
-    tag_map = {
-        "": "### Documentation",
-        "": "### Arguments",
-        "": "### Return value",
-        "": "### Example",
-        "": "### Internal Documentation",
-        "": "### Internal Example",
-    }
-
-    in_example = False
-    code_block_open = False
-
-    def close_code_block_if_open():
-        nonlocal code_block_open
-        if code_block_open:
-            md_lines.append("```")
-            code_block_open = False
-
-    for line in cleaned:
-        stripped = line.strip()
-        # Convert tags to headings and manage example sections
-        if stripped in tag_map:
-            # If we hit any new tag, close a pending code block
-            close_code_block_if_open()
-            heading = tag_map[stripped]
-            md_lines.append(heading)
-            in_example = heading in ("### Example", "### Internal Example")
-            continue
-
-        if in_example:
-            low = stripped.lower()
-            if low.startswith("code:"):
-                # Open code block if needed and append the code content
-                code_text = line.split(":", 1)[1].strip()
-                if not code_block_open:
-                    md_lines.append("```tcl")
-                    code_block_open = True
-                md_lines.append(code_text)
-                continue
-            # Keep name/desc lines as regular text outside code
-            if low.startswith("name:") or low.startswith("desc:"):
-                md_lines.append(line)
-                continue
-
-        md_lines.append(line)
-
-    # Close any dangling code fence at the end of the block
-    close_code_block_if_open()
-
-    return "\n".join(md_lines).rstrip()
-
-
-class ProcDocExtractor(Visitor):
-    """Visitor that collects documentation blocks above proc declarations."""
-
-    def __init__(self, source_text: str):
-        super().__init__()
-        self._lines = source_text.split("\n")
-        self.docs: Dict[str, str] = {}
-
-    def visit_command(self, command: Command):
-        routine = getattr(command.routine, "contents", None)
-        if routine != "proc":
-            return
-
-        if not command.args:
-            return
-        name_node = command.args[0]
-        proc_name = getattr(name_node, "contents", None)
-        if not proc_name:
-            return
-
-        # Prefer line of the 'proc' keyword; fallback to the name node
-        pos = getattr(command.routine, "pos", None) or getattr(name_node, "pos", None)
-        if not pos:
-            return
-        line_idx = pos[0] - 1  # 0-based
-        block = extract_doc_block_above(self._lines, line_idx)
-        if block:
-            self.docs[proc_name] = block
-
-
-def build_proc_docs(tree, source_text: str) -> Dict[str, str]:
-    """Build a mapping of proc name -> markdown doc from a parsed tree and source text."""
-    extractor = ProcDocExtractor(source_text)
-    tree.accept(extractor, recurse=True)
-    return extractor.docs
-
-
-def is_proc_declaration_position(source_text: str, line_zero_based: int, char_zero_based: int) -> bool:
-    """Return True if the position is on a proc name within its declaration."""
-    parser = CustomParser()
-    tree = parser.parse(source_text)
-
-    # Walk commands to find 'proc' declarations and check if position intersects the name arg
-    class _DeclFinder(Visitor):
-        def __init__(self):
-            self.is_decl = False
-
-        def visit_command(self, command: Command):
-            if self.is_decl:
-                return
-            routine = getattr(command.routine, "contents", None)
-            if routine != "proc" or not command.args:
-                return
-            name_node = command.args[0]
-            if not hasattr(name_node, "pos"):
-                return
-            # Calculate range for the name token
-            try:
-                start_line, start_col = name_node.pos
-                end_line, end_col = getattr(name_node, "end_pos", name_node.pos)
-            except Exception:
-                return
-            if start_line - 1 == line_zero_based:
-                length = 0
-                if hasattr(name_node, "value") and name_node.value is not None:
-                    length = len(name_node.value)
-                elif hasattr(name_node, "contents") and name_node.contents is not None:
-                    length = len(name_node.contents)
-                if length:
-                    start_c = start_col - 1
-                    end_c = start_c + length
-                    if start_c <= char_zero_based <= end_c:
-                        self.is_decl = True
-
-    finder = _DeclFinder()
-    tree.accept(finder, recurse=True)
-    return finder.is_decl
diff --git a/server/src/tools/semantic_tokens.py b/server/src/tools/semantic_tokens.py
deleted file mode 100644
index 597634d..0000000
--- a/server/src/tools/semantic_tokens.py
+++ /dev/null
@@ -1,200 +0,0 @@
-import enum
-from typing import List
-from tclint.syntax_tree import Visitor, QuotedWord, Command, BareWord
-from tclint.commands import get_commands
-import attrs
-from common.load_data import standard_items
-import lsprotocol.types as lsp
-
-
-class TokenModifier(enum.IntFlag):
-    deprecated = enum.auto()
-    readonly = enum.auto()
-    defaultLibrary = enum.auto()
-    definition = enum.auto()
-    declaration = enum.auto()
-    builtin = enum.auto()
-
-
-@attrs.define
-class Token:
-    line: int
-    offset: int
-    lenght: int
-
-    tok_type: str = ""
-    tok_modifiers: List[TokenModifier] = attrs.field(factory=list)
-
-    @property
-    def length(self) -> int:
-        """Compatibility alias for misspelled 'lenght' field."""
-        return self.lenght
-
-
-TOKEN_TYPES = [
-    "keyword",
-    "variable",
-    "function",
-    "operator",
-    "parameter",
-    "type",
-    "class",
-    "string",
-    "parameter",
-]
-
-
-class _Highlighter(Visitor):
-    def __init__(self, plugins, custom_functions: dict[str : list[lsp.CompletionItem]]):
-        self._commands = get_commands(plugins)
-        self._tokens = []
-        self.custom_functions = custom_functions
-
-    def _get_token_info(self, node):
-        """Hilfsmethode um Token-Informationen aus verschiedenen Node-Typen zu extrahieren."""
-        if not hasattr(node, "pos"):
-            return None
-
-        # Einfacher Fall: Node hat direkten value
-        if hasattr(node, "value") and node.value is not None:
-            line, col = node.pos
-            return (line - 1, col - 1), len(node.value)
-
-        # CompoundBareWord: versuche erstes Segment
-        if hasattr(node, "children") and node.children:
-            first_segment = node.children[0]
-            if hasattr(first_segment, "value") and first_segment.value is not None and hasattr(first_segment, "pos"):
-                line, col = first_segment.pos
-                return (line - 1, col - 1), len(first_segment.value)
-
-        # Fallback: Gesamtlänge aus Positionen berechnen
-        if hasattr(node, "end_pos"):
-            start_line, start_col = node.pos
-            end_line, end_col = node.end_pos
-            if start_line == end_line:
-                length = end_col - start_col
-                return (start_line - 1, start_col - 1), length
-
-        return None
-
-    def visit_quoted_word(self, word: QuotedWord):
-        if not word.contents:
-            return
-        line, col = word.contents_pos
-        self._tokens.append(((line - 1, col - 1), len(word.contents), "string", []))
-        pass
-
-    def visit_bare_word(self, word: BareWord):
-        # Intentionally do not classify bare words as functions here.
-        # Function highlighting is handled in visit_command for the routine only,
-        # using completion items (custom functions) as the source of truth.
-        return
-
-    def visit_command(self, command: Command):
-        routine = command.routine
-
-        # Highlight functions (custom or standard) when used as the routine
-        name = getattr(routine, "contents", None)
-        if name:
-            in_custom = any(item.label == name for items in self.custom_functions.values() for item in items)
-            in_standard = any(item.label == name for item in standard_items.nx_procs)
-            if in_custom or in_standard:
-                line, col = routine.contents_pos
-                self._tokens.append((((line - 1, col - 1), len(name), "function", [])))
-
-        if routine.contents == "puts":
-            line, col = routine.contents_pos
-            self._tokens.append(
-                (
-                    (
-                        (line - 1, col - 1),
-                        len(routine.contents),
-                        "function",
-                        [TokenModifier.builtin],
-                    )
-                )
-            )
-        if routine.contents == "set" and command.args:
-            first_arg = command.args[0]
-            token_info = self._get_token_info(first_arg)
-            if token_info:
-                (line, col), length = token_info
-                self._tokens.append(
-                    (
-                        (
-                            (line, col),
-                            length,
-                            "variable",
-                            [TokenModifier.declaration],
-                        )
-                    )
-                )
-        if routine.contents == "proc" and command.args:
-            first_arg = command.args[0]
-            if hasattr(first_arg, "pos") and hasattr(first_arg, "value"):
-                line, col = first_arg.pos
-                self._tokens.append(
-                    (
-                        (
-                            (line - 1, col - 1),
-                            len(first_arg.value),
-                            "function",
-                            [TokenModifier.declaration],
-                        )
-                    )
-                )
-
-            if len(command.args) >= 2:
-                param_list = command.args[1]
-
-                # BracedWord oder Liste erwartet
-                if hasattr(param_list, "children"):
-                    for child in param_list.children:
-                        # Parameter kann einfaches Wort sein
-                        if hasattr(child, "value") and child.value is not None:
-                            line, col = child.pos
-                            self._tokens.append(
-                                (
-                                    (line - 1, col - 1),
-                                    len(child.value),
-                                    "parameter",
-                                    [TokenModifier.declaration],
-                                )
-                            )
-
-                        # Parameter mit Default-Wert ist meist eine List (z. B. {arg default})
-                        elif hasattr(child, "children") and len(child.children) >= 1:
-                            name_node = child.children[0]
-                            if hasattr(name_node, "value") and hasattr(name_node, "pos"):
-                                line, col = name_node.pos
-                                self._tokens.append(
-                                    (
-                                        (line - 1, col - 1),
-                                        len(name_node.value),
-                                        "parameter",
-                                        [TokenModifier.declaration],
-                                    )
-                                )
-        if routine.contents == "namespace" and command.args:
-            first_arg = command.args[1]
-            if hasattr(first_arg, "pos") and first_arg.value is not None:
-                line, col = first_arg.pos
-                self._tokens.append((((line - 1, col - 1), len(first_arg.value), "class", [])))
-
-    def tokens(self) -> list[Token]:
-        """Encode tokens as described in
-        https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens.
-        """
-        tokens = []
-        last_line = 0
-        last_col = 0
-        for (line, col), length, tok_type, tok_modifier in sorted(self._tokens, key=lambda x: x[0]):
-            line_delta = line - last_line
-            col_delta = col
-            if line == last_line:
-                col_delta -= last_col
-
-            tokens.append(Token(line_delta, col_delta, length, tok_type, tok_modifier))
-            last_line, last_col = line, col
-
-        return tokens
diff --git a/server/src/tools/symbols.py b/server/src/tools/symbols.py
deleted file mode 100644
index b34f914..0000000
--- a/server/src/tools/symbols.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import logging
-from collections import defaultdict
-from typing import List, DefaultDict, Union
-
-from tclint.syntax_tree import Visitor, Command, CommandSub, Node, Script
-
-
-class SymbolTable:
-    """Holds a symbol table (links symbols to nodes)."""
-
-    def __init__(self):
-        self.proc_def: DefaultDict[str, list[Node]] = defaultdict(list)
-
-    def add_proc_definition(self, command: Command) -> None:
-        """Add definition of procedure"""
-        # command holds the "proc" keyword, so the proc name is 1st argument
-        proc_name_node = command.args[0]
-        proc_name = proc_name_node.contents
-        if not proc_name:
-            return
-        logging.debug(
-            f"Definition of proc '{proc_name}' at {proc_name_node._pos_str()}"
-        )
-        self.proc_def[proc_name].append(proc_name_node)
-
-    def lookup_proc_definitions(self, symbol_text: str) -> List[Node]:
-        """Lookup definitions of the procedure pointed at by node"""
-        if symbol_text is None or symbol_text not in self.proc_def:
-            return []
-        return self.proc_def[symbol_text]
-
-
-class SymbolTableBuilder(Visitor):
-    """Builds a symbol table."""
-
-    def __init__(self):
-        self.table = SymbolTable()
-
-    def build(self, tree: Union[CommandSub, Script]) -> SymbolTable:
-        """Run the builder visitor through the syntax tree, building a table."""
-        tree.accept(self, recurse=True)
-        return self.table
-
-    def visit_command(self, command: Command) -> None:
-        if command.routine.contents == "proc":
-            self.table.add_proc_definition(command)
diff --git a/server/src/tools/variable_index.py b/server/src/tools/variable_index.py
deleted file mode 100644
index b04514c..0000000
--- a/server/src/tools/variable_index.py
+++ /dev/null
@@ -1,100 +0,0 @@
-import re
-from dataclasses import dataclass
-from typing import Dict, Set, List, Tuple
-
-# Reuse patterns similar to document_symbols
-NS_RE = re.compile(r"^\s*namespace\s+eval\s+([^\s\{]+)")
-PROC_RE = re.compile(r"^\s*proc\s+([^\s\{]+)\s+\{.*\}\s+\{")
-SET_RE = re.compile(r"^\s*set\s+([^\s\}]+)")
-
-
-@dataclass
-class ProcRange:
-    name: str
-    start_line: int
-    end_line: int | None = None
-
-
-def build_variable_index(source: str) -> tuple[Set[str], Dict[str, Set[str]], List[ProcRange]]:
-    """
-    Parse Tcl source text and build:
-    - globals: set of variable names considered global suggestions
-    - procs: mapping proc_name -> set of local variable names (set without :: inside that proc)
-    - proc_ranges: list of ProcRange (name, start_line, end_line)
-
-    Rules:
-    - set ::var -> global var suggestion (strip leading :: and any array index "(")
-    - set var without :: at top level (not in namespace/proc) -> global suggestion
-    - set var without :: inside proc -> local to that proc
-    - set var inside namespace (no ::) is ignored for global suggestions
-    """
-    lines = source.split("\n")
-
-    class Scope:
-        def __init__(self, name: str, kind: str, start_line: int):
-            self.name = name
-            self.kind = kind  # "namespace" or "proc" or "root"
-            self.start_line = start_line
-            self.brace_count = 0
-
-    globals_set: Set[str] = set()
-    procs: Dict[str, Set[str]] = {}
-    proc_ranges: List[ProcRange] = []
-
-    scope_stack: List[Scope] = [Scope("", "root", 0)]
-
-    for i, line in enumerate(lines):
-        ns_match = NS_RE.match(line)
-        proc_match = PROC_RE.match(line)
-        set_match = SET_RE.match(line)
-
-        # Namespace scope
-        if ns_match:
-            scope_stack.append(Scope(ns_match.group(1), "namespace", i))
-
-        # Proc scope
-        elif proc_match:
-            pname = proc_match.group(1)
-            scope_stack.append(Scope(pname, "proc", i))
-            proc_ranges.append(ProcRange(name=pname, start_line=i, end_line=None))
-
-        # Track set statements
-        if set_match:
-            raw_name = set_match.group(1)
-            # Normalize array names and leading ::
-            base = raw_name.split("(", 1)[0]
-            if base.startswith("::"):
-                clean = base[2:]
-                globals_set.add(clean)
-            else:
-                top = scope_stack[-1]
-                if top.kind == "root":
-                    globals_set.add(base)
-                elif top.kind == "proc":
-                    procs.setdefault(top.name, set()).add(base)
-                else:
-                    # inside namespace without :: -> ignore for globals
-                    pass
-
-        # Brace balancing for current top scope
-        open_count = line.count("{")
-        close_count = line.count("}")
-        scope_stack[-1].brace_count += open_count - close_count
-
-        # Close finished scopes
-        while len(scope_stack) > 1 and scope_stack[-1].brace_count <= 0:
-            finished = scope_stack.pop()
-            if finished.kind == "proc":
-                # Update the last matching proc range end_line
-                for pr in reversed(proc_ranges):
-                    if pr.name == finished.name and pr.end_line is None:
-                        pr.end_line = i
-                        break
-
-    # Finalize any unterminated proc ranges
-    for pr in proc_ranges:
-        if pr.end_line is None:
-            pr.end_line = len(lines) - 1
-
-    return globals_set, procs, proc_ranges
-
diff --git a/server/libs/attr/py.typed b/server/tests/completion_list.rs
similarity index 100%
rename from server/libs/attr/py.typed
rename to server/tests/completion_list.rs
diff --git a/server/tests/python_tests/test_document_symbols.py b/server/tests/python_tests/test_document_symbols.py
deleted file mode 100644
index c2eb66f..0000000
--- a/server/tests/python_tests/test_document_symbols.py
+++ /dev/null
@@ -1,115 +0,0 @@
-import sys
-from pathlib import Path
-
-THIS_DIR = Path(__file__).parent
-SRC_DIR = THIS_DIR.parent.parent / "src"
-if str(SRC_DIR) not in sys.path:
-    sys.path.insert(0, str(SRC_DIR))
-
-import lsprotocol.types as lsp  # type: ignore
-from lsp_server import LSP_SERVER, document_symbols  # type: ignore
-
-
-def test_document_symbols_namespace_proc_set_hierarchy(tmp_path: Path):
-    source_lines = [
-        "set top_var 1",
-        "namespace eval myns {",
-        "    set ns_var 2",
-        "    proc add {a b} {",
-        "        set sum [expr {$a + $b}]",
-        "        return $sum",
-        "    }",
-        "}",
-        "proc top_proc {} {",
-        "    set x 3",
-        "}",
-    ]
-    source = "\n".join(source_lines)
-
-    uri = Path(tmp_path / "sym.tcl").as_uri()
-    # Put a text document into the workspace
-    LSP_SERVER.workspace.put_text_document(lsp.TextDocumentItem(uri=uri, language_id="tcl", version=1, text=source))
-
-    # Request document symbols
-    params = lsp.DocumentSymbolParams(text_document=lsp.TextDocumentIdentifier(uri=uri))
-    symbols = document_symbols(params)
-
-    # Expect at least 2 top-level children: root contains 'set top_var' (variable) and 'namespace myns' and 'proc top_proc'
-    names_kinds = {(s.name, s.kind) for s in symbols}
-    assert ("root", lsp.SymbolKind.Namespace) not in names_kinds  # root should not be included itself
-
-    # Find namespace symbol
-    ns = next(s for s in symbols if s.name == "myns")
-    assert ns.kind == lsp.SymbolKind.Namespace
-    assert ns.children is not None
-
-    # Inside namespace: has variable and proc
-    child_names = {c.name for c in ns.children}
-    assert "ns_var" in child_names
-    assert "add" in child_names
-
-    # top-level variable and proc also present
-    top_names = {s.name for s in symbols}
-    assert "top_var" in top_names
-    assert "top_proc" in top_names
-
-    # Check that proc add has no children (we're not extracting params as children here)
-    add = next(c for c in ns.children if c.name == "add")
-    assert add.kind == lsp.SymbolKind.Function
-    assert add.children == []
-
-
-def test_buffer_edit_events_are_symbols_with_type_and_name(tmp_path: Path):
-    source_lines = [
-        "LIB_GE_command_buffer_edit_insert LIB_ROTARY_positioning_first_move_pos ROTARY_POSITIONING_FIRST_MOVE_POS {",
-        "    MOM_enable_address Z M_coolant_off D M_coolant_1 M_coolant_2 H_pressure",
-        "}",
-        " Coolant after @DECOMPOSEZUL",
-        "",
-        "LIB_GE_command_buffer_edit_append MOM_start_of_path_LIB MOM_start_of_path_LIB_ENTRY_end {",
-        "    MOM_force once M_coolant_1 M_coolant_2 H_pressure",
-        "}",
-        " force_coolant",
-    ]
-    source = "\n".join(source_lines)
-
-    uri = Path(tmp_path / "events.tcl").as_uri()
-    LSP_SERVER.workspace.put_text_document(lsp.TextDocumentItem(uri=uri, language_id="tcl", version=1, text=source))
-    params = lsp.DocumentSymbolParams(text_document=lsp.TextDocumentIdentifier(uri=uri))
-    symbols = document_symbols(params)
-
-    # Find event symbols
-    events = [s for s in symbols if s.kind == lsp.SymbolKind.Event]
-    assert events, "Expected at least one event symbol"
-
-    # Verify names and details
-    names = [e.name for e in events]
-    assert "Coolant" in names or "force_coolant" in names
-    for e in events:
-        assert e.detail.startswith("Event (")
-
-
-def test_event_children_include_set_variable(tmp_path: Path):
-    source_lines = [
-        "LIB_GE_command_buffer_edit_append MOM_rapid_move_LIB MOM_rapid_move_LIB_ENTRY_start {",
-        "    if {[info exists ::mom_lift_off_output] && $::kapp_vars(retract_start) == 0} {",
-        "        kapp_retract_subpgm",
-        "    }",
-        "    set ::kapp_vars(retract_start) 0",
-        "}",
-        " KappRetractSubPgm",
-    ]
-    source = "\n".join(source_lines)
-
-    uri = Path(tmp_path / "event_children.tcl").as_uri()
-    LSP_SERVER.workspace.put_text_document(lsp.TextDocumentItem(uri=uri, language_id="tcl", version=1, text=source))
-    params = lsp.DocumentSymbolParams(text_document=lsp.TextDocumentIdentifier(uri=uri))
-    symbols = document_symbols(params)
-
-    events = [s for s in symbols if s.kind == lsp.SymbolKind.Event and s.name == "KappRetractSubPgm"]
-    assert events, "Expected event symbol for KappRetractSubPgm"
-    ev = events[0]
-    assert ev.children is not None
-    # Ensure the set variable is a child of the event
-    child_names = {c.name for c in ev.children}
-    assert "::kapp_vars(retract_start)" in child_names
diff --git a/server/tests/python_tests/test_goto_definition.py b/server/tests/python_tests/test_goto_definition.py
deleted file mode 100644
index 09cd93e..0000000
--- a/server/tests/python_tests/test_goto_definition.py
+++ /dev/null
@@ -1,116 +0,0 @@
-import sys
-from pathlib import Path
-
-# Ensure server/src is on the path for imports
-THIS_DIR = Path(__file__).parent
-SRC_DIR = THIS_DIR.parent.parent / "src"
-if str(SRC_DIR) not in sys.path:
-    sys.path.insert(0, str(SRC_DIR))
-
-import lsprotocol.types as lsp  # type: ignore
-from lsp_server import LSP_SERVER, goto_definition  # type: ignore
-
-
-def _loc_to_tuple(loc: lsp.Location) -> tuple[str, int, int, int, int]:
-    """Helper to normalize Location into a tuple for easy asserts."""
-    return (
-        loc.uri,
-        loc.range.start.line,
-        loc.range.start.character,
-        loc.range.end.line,
-        loc.range.end.character,
-    )
-
-
-def _extract_first_location(result) -> lsp.Location | None:
-    if result is None:
-        return None
-    if isinstance(result, list):
-        return result[0] if result else None
-    return result
-
-
-def test_goto_definition_same_file(tmp_path: Path):
-    source_lines = [
-        "proc add {a b} {",
-        "    return [expr {$a + $b}]",
-        "}",
-        "",
-        "set x [add 1 2]",
-    ]
-    source = "\n".join(source_lines)
-
-    uri = Path(tmp_path / "same.tcl").as_uri()
-    # Put a text document into the workspace
-    LSP_SERVER.workspace.put_text_document(
-        lsp.TextDocumentItem(uri=uri, language_id="tcl", version=1, text=source)
-    )
-
-    # Position on the word 'add' in the last line
-    line_idx = 4
-    char_idx = source_lines[line_idx].index("add") + 1  # somewhere inside token
-
-    params = lsp.DefinitionParams(
-        text_document=lsp.TextDocumentIdentifier(uri=uri),
-        position=lsp.Position(line=line_idx, character=char_idx),
-    )
-
-    result = goto_definition(params)
-    loc = _extract_first_location(result)
-
-    assert loc is not None
-    assert loc.uri == uri
-    # Definition should be on line 0 at the token 'add'
-    start = loc.range.start
-    end = loc.range.end
-    assert start.line == 0
-    assert end.line == 0
-    assert source_lines[0][start.character : end.character] == "add"
-
-
-def test_goto_definition_cross_file(tmp_path: Path):
-    # File A declares the proc
-    a_lines = [
-        "proc myproc {arg} {",
-        "    return $arg",
-        "}",
-    ]
-    a_src = "\n".join(a_lines)
-    a_path = tmp_path / "a.tcl"
-    a_uri = a_path.as_uri()
-    LSP_SERVER.workspace.put_text_document(
-        lsp.TextDocumentItem(uri=a_uri, language_id="tcl", version=1, text=a_src)
-    )
-
-    # Update indices for file A so proc_signatures gets populated
-    doc_a = LSP_SERVER.workspace.get_text_document(a_uri)
-    LSP_SERVER.update_poco_completion_for_file(doc_a)
-
-    # File B calls the proc
-    b_lines = [
-        "set y [myproc 42]",
-    ]
-    b_src = "\n".join(b_lines)
-    b_uri = (tmp_path / "b.tcl").as_uri()
-    LSP_SERVER.workspace.put_text_document(
-        lsp.TextDocumentItem(uri=b_uri, language_id="tcl", version=1, text=b_src)
-    )
-
-    call_line = 0
-    call_char = b_lines[0].index("myproc") + 2
-
-    params = lsp.DefinitionParams(
-        text_document=lsp.TextDocumentIdentifier(uri=b_uri),
-        position=lsp.Position(line=call_line, character=call_char),
-    )
-
-    result = goto_definition(params)
-    loc = _extract_first_location(result)
-
-    assert loc is not None
-    assert loc.uri == a_uri
-    start = loc.range.start
-    end = loc.range.end
-    assert start.line == 0
-    assert a_lines[start.line][start.character : end.character] == "myproc"
-
diff --git a/server/tests/python_tests/test_hover_proc_docs.py b/server/tests/python_tests/test_hover_proc_docs.py
deleted file mode 100644
index ca9ce6d..0000000
--- a/server/tests/python_tests/test_hover_proc_docs.py
+++ /dev/null
@@ -1,103 +0,0 @@
-import os
-import sys
-from pathlib import Path
-
-# Ensure server/src is on the path for imports
-THIS_DIR = Path(__file__).parent
-SRC_DIR = THIS_DIR.parent.parent / "src"
-if str(SRC_DIR) not in sys.path:
-    sys.path.insert(0, str(SRC_DIR))
-
-import lsprotocol.types as lsp  # type: ignore
-from tools.proc_docs import build_proc_docs, is_proc_declaration_position
-from lsp_server import LSP_SERVER, hover  # type: ignore
-
-
-def test_build_proc_docs_extracts_block_and_tags():
-    source = (
-        "#____________________________________________________________________________________________\n"
-        "# \n"
-        "# This procedure creates a new directory if it does not exist.\n"
-        "# \n"
-        "# directory\n"
-        "#\tThe full pathname of the directory to be created.\n"
-        "# \n"
-        "# 0 - directory created or already exists\n"
-        "# 1 - error\n"
-        "#______________________________________________________________________________________________\n"
-        "proc LIB_FH_create_directory {directory} {\n"
-        "    return 0\n"
-        "}\n"
-    )
-
-    from tools.parser import CustomParser
-
-    tree = CustomParser().parse(source)
-    docs = build_proc_docs(tree, source)
-
-    assert "LIB_FH_create_directory" in docs
-    md = docs["LIB_FH_create_directory"]
-    # Tags become markdown headings
-    assert "### Documentation" in md
-    assert "### Arguments" in md
-    assert "### Return value" in md
-    # Content preserved
-    assert "creates a new directory" in md
-
-
-def test_hover_shows_doc_on_usage_but_not_on_declaration(tmp_path: Path):
-    # Build a TCL file with a documented proc and a usage
-    source_lines = [
-        "#_________________________________________________________________________________________________",
-        "# ",
-        "# Function to delete the file",
-        "#_________________________________________________________________________________________________",
-        "proc SERVICE_remove_file {file} {",
-        "    if {![SERVICE_check_file_exists $file]} {return}",
-        "    MOM_remove_file $file",
-        "}",
-        "",
-        "proc SERVICE_check_file_exists {file} {",
-        "    if {[file exists $file]} {return 1}",
-        "    return 0",
-        "}",
-        "",
-        "# usage below",
-        "SERVICE_remove_file \"C:/tmp/x\"",
-    ]
-    source = "\n".join(source_lines)
-
-    # Register document with server
-    uri = Path(tmp_path / "test.tcl").as_uri()
-    LSP_SERVER.workspace.put_text_document(
-        lsp.TextDocumentItem(uri=uri, language_id="tcl", version=1, text=source)
-    )
-
-    # Force server to parse and build proc docs
-    doc = LSP_SERVER.workspace.get_text_document(uri)
-    LSP_SERVER.update_poco_completion_for_file(doc)
-
-    # 1) Hover on usage -> should return docs
-    usage_line = source_lines.index("SERVICE_remove_file \"C:/tmp/x\"")
-    char_index = source_lines[usage_line].find("SERVICE_remove_file") + 5  # inside the token
-
-    params = lsp.HoverParams(
-        text_document=lsp.TextDocumentIdentifier(uri=uri),
-        position=lsp.Position(line=usage_line, character=char_index),
-    )
-    result = hover(params)
-    assert result is not None
-    assert "Function to delete the file" in result.contents.value  # type: ignore[attr-defined]
-
-    # 2) Hover on declaration name -> should be None
-    decl_line = source_lines.index("proc SERVICE_remove_file {file} {")
-    decl_char = source_lines[decl_line].find("SERVICE_remove_file") + 2
-    assert is_proc_declaration_position(source, decl_line, decl_char)
-
-    params_decl = lsp.HoverParams(
-        text_document=lsp.TextDocumentIdentifier(uri=uri),
-        position=lsp.Position(line=decl_line, character=decl_char),
-    )
-    none_result = hover(params_decl)
-    assert none_result is None
-
diff --git a/server/tests/python_tests/test_proc_docs.py b/server/tests/python_tests/test_proc_docs.py
deleted file mode 100644
index e94397a..0000000
--- a/server/tests/python_tests/test_proc_docs.py
+++ /dev/null
@@ -1,75 +0,0 @@
-import sys
-from pathlib import Path
-
-# Ensure server/src is on sys.path for imports
-THIS_DIR = Path(__file__).parent
-SRC_DIR = THIS_DIR.parent.parent / "src"
-if str(SRC_DIR) not in sys.path:
-    sys.path.insert(0, str(SRC_DIR))
-
-import lsprotocol.types as lsp  # type: ignore
-from tools.parser import CustomParser
-from tools.proc_docs import build_proc_docs
-
-
-def test_example_is_marked_as_tcl_code_block():
-    source_lines = [
-        "#____________________________________________________________________________________________",
-        "# ",
-        "# This procedure creates a new directory if it does not exist.",
-        "# ",
-        "# directory",
-        "#\tThe full pathname of the directory to be created.",
-        "# ",
-        "# 0 - directory created or already exists",
-        "# 1 - error",
-        "# ",
-        "# name: Example 1",
-        "# code: LIB_FH_create_directory \"C:/Temp/Test\"",
-        "# desc: If error = 0, the directory is created.",
-        "proc LIB_FH_create_directory {directory} {",
-        "    return 0",
-        "}",
-    ]
-    source = "\n".join(source_lines)
-
-    tree = CustomParser().parse(source)
-    docs = build_proc_docs(tree, source)
-
-    assert "LIB_FH_create_directory" in docs
-    md = docs["LIB_FH_create_directory"]
-
-    # Headings preserved
-    assert "### Documentation" in md
-    assert "### Arguments" in md
-    assert "### Return value" in md
-    assert "### Example" in md
-
-    # Code fence with tcl language hint and the code line present
-    assert "```tcl" in md
-    assert "LIB_FH_create_directory \"C:/Temp/Test\"" in md
-    assert md.strip().endswith("```")
-
-
-def test_internal_example_is_marked_as_tcl_code_block():
-    source_lines = [
-        "# ",
-        "# Helper utility",
-        "# ",
-        "# code: puts \"hello\"",
-        "proc helper {} {",
-        "    return",
-        "}",
-    ]
-    source = "\n".join(source_lines)
-
-    tree = CustomParser().parse(source)
-    docs = build_proc_docs(tree, source)
-
-    assert "helper" in docs
-    md = docs["helper"]
-
-    assert "### Internal Documentation" in md
-    assert "### Internal Example" in md
-    assert "```tcl" in md and "puts \"hello\"" in md and md.strip().endswith("```")
-
diff --git a/test/test.tcl b/test/test.tcl
index d7793b4..d6f1d5c 100644
--- a/test/test.tcl
+++ b/test/test.tcl
@@ -1,5 +1,7 @@
-set ::custom_flag(from_move,$::mom_path_name) 1
-# set ::custom_flag(from_move,$::mom_path_name) 1
+namespace eval test {
+    
+}
+
 
 set te875st 11111
 
@@ -9,7 +11,14 @@ if {$main == 1 && 1 == 1} {
     puts "main"
 }
 
-proc test {} {
+
+
+testZZZZZZ
+
+bnbjbjbjbjbjbj
+mmmm
+
+proc testZZZZZZ {} {
     puts "main"
     proc llll {} {}
     set rrrrrrr
@@ -35,6 +44,7 @@ proc SERVICE_spacer_output {type {length 20} {line_num 0} {output 1}} {
 }
 
 
+
 SERVICE_spacer_output "*" 2 0 0
 
 #_________________________________________________________________________________________________