-c 'import sys; print(sys.executable)'`. ALWAYS call configure_python_environment before using this tool. IMPORTANT: This tool is only for Python environments (venv, virtualenv, conda, pipenv, poetry, pyenv, pixi, or any other Python environment manager). Do not use this tool for npm packages, system packages, Ruby gems, or any other non-Python dependencies.",
+ "toolReferenceName": "getPythonExecutableCommand",
+ "tags": [
+ "python",
+ "python environment",
+ "extension_installed_by_tool",
+ "enable_other_tool_configure_python_environment"
+ ],
+ "icon": "$(terminal)",
+ "canBeReferencedInPrompt": true,
+ "inputSchema": {
+ "type": "object",
+ "properties": {
+ "resourcePath": {
+ "type": "string",
+ "description": "The path to the Python file or workspace to get the executable information for. If not provided, the current workspace will be used. Where possible pass the path to the file or workspace."
+ }
+ },
+ "required": []
+ }
},
{
- "fileMatch": "meta.yaml",
- "url": "./schemas/conda-meta.json"
- }
- ],
- "views": {
- "test": [
- {
- "id": "python_tests",
- "name": "Python",
- "when": "testsDiscovered"
+ "name": "install_python_packages",
+ "displayName": "Install Python Package",
+ "userDescription": "%python.languageModelTools.install_python_packages.userDescription%",
+ "modelDescription": "Installs Python packages in the given workspace. Use this tool to install Python packages in the user's chosen Python environment. ALWAYS call configure_python_environment before using this tool. IMPORTANT: This tool should only be used to install Python packages using package managers like pip or conda (works with any Python environment: venv, virtualenv, pipenv, poetry, pyenv, pixi, conda, etc.). Do not use this tool to install npm packages, system packages (apt/brew/yum), Ruby gems, or any other non-Python dependencies.",
+ "toolReferenceName": "installPythonPackage",
+ "tags": [
+ "python",
+ "python environment",
+ "install python package",
+ "extension_installed_by_tool",
+ "enable_other_tool_configure_python_environment"
+ ],
+ "icon": "$(package)",
+ "canBeReferencedInPrompt": true,
+ "inputSchema": {
+ "type": "object",
+ "properties": {
+ "packageList": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "The list of Python packages to install."
+ },
+ "resourcePath": {
+ "type": "string",
+ "description": "The path to the Python file or workspace into which the packages are installed. If not provided, the current workspace will be used. Where possible pass the path to the file or workspace."
+ }
+ },
+ "required": [
+ "packageList"
+ ]
}
- ]
+ },
+ {
+ "name": "configure_python_environment",
+ "displayName": "Configure Python Environment",
+ "modelDescription": "This tool configures a Python environment in the given workspace. ALWAYS Use this tool to set up the user's chosen environment and ALWAYS call this tool before using any other Python related tools or running any Python command in the terminal. If you already know which Python interpreter to use (e.g. from a previous tool call or user message), pass it as 'pythonPath' to skip interactive prompts and configure the environment automatically. IMPORTANT: This tool is only for Python environments (venv, virtualenv, conda, pipenv, poetry, pyenv, pixi, or any other Python environment manager). Do not use this tool for npm packages, system packages, Ruby gems, or any other non-Python dependencies.",
+ "userDescription": "%python.languageModelTools.configure_python_environment.userDescription%",
+ "toolReferenceName": "configurePythonEnvironment",
+ "tags": [
+ "python",
+ "python environment",
+ "extension_installed_by_tool"
+ ],
+ "icon": "$(gear)",
+ "canBeReferencedInPrompt": true,
+ "inputSchema": {
+ "type": "object",
+ "properties": {
+ "resourcePath": {
+ "type": "string",
+ "description": "The path to the Python file or workspace for which a Python Environment needs to be configured."
+ },
+ "pythonPath": {
+ "type": "string",
+ "description": "Optional absolute path to a Python interpreter to use. When provided, the environment is configured automatically without any interactive prompts. Use this to avoid blocking the session on user input."
+ }
+ },
+ "required": []
+ }
+ },
+ {
+ "name": "create_virtual_environment",
+ "displayName": "Create a Virtual Environment",
+ "modelDescription": "This tool will create a Virual Environment",
+ "tags": [],
+ "canBeReferencedInPrompt": false,
+ "inputSchema": {
+ "type": "object",
+ "properties": {
+ "packageList": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "The list of packages to install."
+ },
+ "resourcePath": {
+ "type": "string",
+ "description": "The path to the Python file or workspace for which a Python Environment needs to be configured."
+ }
+ },
+ "required": []
+ },
+ "when": "false"
+ },
+ {
+ "name": "selectEnvironment",
+ "displayName": "Select a Python Environment",
+ "modelDescription": "This tool will prompt the user to select an existing Python Environment",
+ "tags": [],
+ "canBeReferencedInPrompt": false,
+ "inputSchema": {
+ "type": "object",
+ "properties": {
+ "resourcePath": {
+ "type": "string",
+ "description": "The path to the Python file or workspace for which a Python Environment needs to be configured."
+ }
+ },
+ "required": []
+ },
+ "when": "false"
+ }
+ ]
+ },
+ "copilot": {
+ "tests": {
+ "getSetupConfirmation": "python.copilotSetupTests"
}
},
"scripts": {
"package": "gulp clean && gulp prePublishBundle && vsce package -o ms-python-insiders.vsix",
"prePublish": "gulp clean && gulp prePublishNonBundle",
"compile": "tsc -watch -p ./",
+ "compileApi": "node ./node_modules/typescript/lib/tsc.js -b ./pythonExtensionApi/tsconfig.json",
"compiled": "deemon npm run compile",
"kill-compiled": "deemon --kill npm run compile",
- "compile-webviews-watch": "cross-env NODE_OPTIONS=--max_old_space_size=9096 webpack --config ./build/webpack/webpack.startPage-ui-viewers.config.js --watch",
- "compile-webviews-watchd": "deemon npm run compile-webviews-watch",
- "kill-compile-webviews-watchd": "deemon --kill npm run compile-webviews-watch",
"checkDependencies": "gulp checkDependencies",
"test": "node ./out/test/standardTest.js && node ./out/test/multiRootTest.js",
"test:unittests": "mocha --config ./build/.mocha.unittests.json",
@@ -2044,245 +1695,123 @@
"testSmoke": "cross-env INSTALL_JUPYTER_EXTENSION=true \"node ./out/test/smokeTest.js\"",
"testInsiders": "cross-env VSC_PYTHON_CI_TEST_VSC_CHANNEL=insiders INSTALL_PYLANCE_EXTENSION=true TEST_FILES_SUFFIX=insiders.test CODE_TESTS_WORKSPACE=src/testMultiRootWkspc/smokeTests \"node ./out/test/standardTest.js\"",
"lint-staged": "node gulpfile.js",
- "lint": "eslint --ext .ts,.tsx,.js src build",
- "lint-fix": "eslint --fix --ext .ts,.tsx,.js src build gulpfile.js",
- "format-check": "prettier --check 'src/**/*.ts' 'src/**/*.tsx' 'build/**/*.js' '.github/**/*.yml' gulpfile.js",
- "format-fix": "prettier --write 'src/**/*.ts' 'src/**/*.tsx' 'build/**/*.js' '.github/**/*.yml' gulpfile.js",
+ "lint": "eslint src build pythonExtensionApi",
+ "lint-fix": "eslint --fix src build pythonExtensionApi gulpfile.js",
+ "format-check": "prettier --check 'src/**/*.ts' 'build/**/*.js' '.github/**/*.yml' gulpfile.js",
+ "format-fix": "prettier --write 'src/**/*.ts' 'build/**/*.js' '.github/**/*.yml' gulpfile.js",
+ "check-python": "npm run check-python:ruff && npm run check-python:pyright",
+ "check-python:ruff": "cd python_files && python -m pip install -U ruff && python -m ruff check . && python -m ruff format --check",
+ "check-python:pyright": "cd python_files && npx --yes pyright@1.1.308 .",
"clean": "gulp clean",
- "addExtensionDependencies": "gulp addExtensionDependencies",
+ "addExtensionPackDependencies": "gulp addExtensionPackDependencies",
"updateBuildNumber": "gulp updateBuildNumber",
"verifyBundle": "gulp verifyBundle",
"webpack": "webpack"
},
"dependencies": {
+ "@iarna/toml": "^3.0.0",
+ "@vscode/extension-telemetry": "^1.5.2",
"arch": "^2.1.0",
- "azure-storage": "^2.10.3",
- "chokidar": "^3.4.3",
- "diff-match-patch": "^1.0.0",
- "fs-extra": "^9.1.0",
- "fuzzy": "^0.1.3",
- "get-port": "^3.2.0",
- "glob": "^7.1.2",
- "hash.js": "^1.1.7",
- "iconv-lite": "^0.4.21",
- "inversify": "^5.0.4",
- "jsonc-parser": "^2.0.3",
- "line-by-line": "^0.1.6",
- "lodash": "^4.17.19",
- "log4js": "^6.1.2",
- "md5": "^2.2.1",
- "minimatch": "^3.0.4",
+ "fs-extra": "^11.2.0",
+ "glob": "^7.2.0",
+ "iconv-lite": "^0.6.3",
+ "inversify": "^6.0.2",
+ "jsonc-parser": "^3.0.0",
+ "lodash": "^4.18.1",
+ "minimatch": "^5.1.8",
"named-js-regexp": "^1.3.3",
- "node-fetch": "^2.6.1",
"node-stream-zip": "^1.6.0",
- "portfinder": "^1.0.25",
- "reflect-metadata": "^0.1.12",
- "request": "^2.87.0",
- "request-progress": "^3.0.0",
+ "reflect-metadata": "^0.2.2",
"rxjs": "^6.5.4",
"rxjs-compat": "^6.5.4",
- "semver": "^5.5.0",
+ "semver": "^7.5.2",
"stack-trace": "0.0.10",
- "string-argv": "^0.3.1",
- "strip-ansi": "^5.2.0",
- "sudo-prompt": "^8.2.0",
- "tmp": "^0.0.29",
- "tree-kill": "^1.2.2",
- "typescript-char": "^0.0.0",
- "uint64be": "^1.0.1",
- "unicode": "^10.0.0",
- "untildify": "^3.0.2",
- "vscode-debugadapter": "^1.28.0",
+ "sudo-prompt": "^9.2.1",
+ "tmp": "^0.2.7",
+ "uint64be": "^3.0.0",
+ "unicode": "^14.0.0",
"vscode-debugprotocol": "^1.28.0",
- "vscode-extension-telemetry": "0.1.4",
- "vscode-jsonrpc": "6.0.0",
- "vscode-languageclient": "7.0.0",
- "vscode-languageserver": "7.0.0",
- "vscode-languageserver-protocol": "3.16.0",
- "vscode-tas-client": "^0.1.22",
+ "vscode-jsonrpc": "^9.0.0-next.5",
+ "vscode-languageclient": "^10.0.0-next.12",
+ "vscode-languageserver-protocol": "^3.17.6-next.10",
+ "vscode-tas-client": "^0.1.84",
+ "which": "^2.0.2",
"winreg": "^1.2.4",
- "winston": "^3.2.1",
- "xml2js": "^0.4.19"
+ "xml2js": "^0.5.0"
},
"devDependencies": {
- "@enonic/fnv-plus": "^1.3.0",
- "@istanbuljs/nyc-config-typescript": "^0.1.3",
- "@sinonjs/fake-timers": "^6.0.1",
- "@types/ansi-regex": "^4.0.0",
+ "@istanbuljs/nyc-config-typescript": "^1.0.2",
+ "@types/bent": "^7.3.0",
"@types/chai": "^4.1.2",
- "@types/chai-arrays": "^1.0.2",
+ "@types/chai-arrays": "^2.0.0",
"@types/chai-as-promised": "^7.1.0",
- "@types/copy-webpack-plugin": "^4.4.2",
- "@types/cors": "^2.8.6",
- "@types/debug": "^4.1.5",
- "@types/dedent": "^0.7.0",
- "@types/del": "^3.0.0",
- "@types/diff-match-patch": "^1.0.32",
- "@types/download": "^6.2.2",
- "@types/enzyme": "^3.1.14",
- "@types/enzyme-adapter-react-16": "^1.0.3",
- "@types/event-stream": "^3.3.33",
- "@types/fs-extra": "^5.0.1",
- "@types/get-port": "^3.2.0",
- "@types/glob": "^5.0.35",
- "@types/html-webpack-plugin": "^3.2.0",
- "@types/iconv-lite": "^0.0.1",
- "@types/jsdom": "^11.12.0",
+ "@types/download": "^8.0.1",
+ "@types/fs-extra": "^11.0.4",
+ "@types/glob": "^7.2.0",
"@types/lodash": "^4.14.104",
- "@types/md5": "^2.1.32",
- "@types/memoize-one": "^4.1.1",
- "@types/mocha": "^5.2.7",
- "@types/nock": "^10.0.3",
- "@types/node": "^12.19.12",
- "@types/promisify-node": "^0.4.0",
- "@types/react": "^16.4.14",
- "@types/react-dom": "^16.0.8",
- "@types/react-json-tree": "^0.6.8",
- "@types/request": "^2.47.0",
+ "@types/mocha": "^9.1.0",
+ "@types/node": "^22.19.1",
"@types/semver": "^5.5.0",
"@types/shortid": "^0.0.29",
- "@types/sinon": "^7.5.1",
- "@types/sinonjs__fake-timers": "^6.0.1",
- "@types/socket.io": "^2.1.4",
+ "@types/sinon": "^17.0.3",
"@types/stack-trace": "0.0.29",
- "@types/temp": "^0.8.32",
- "@types/tmp": "0.0.33",
- "@types/untildify": "^3.0.0",
- "@types/uuid": "^3.4.3",
- "@types/vscode": "~1.53.0",
- "@types/webpack-bundle-analyzer": "^2.13.0",
+ "@types/tmp": "^0.0.33",
+ "@types/vscode": "^1.95.0",
+ "@types/which": "^2.0.1",
"@types/winreg": "^1.2.30",
"@types/xml2js": "^0.4.2",
- "@typescript-eslint/eslint-plugin": "^3.7.0",
- "@typescript-eslint/parser": "^3.7.0",
- "acorn": "^6.4.1",
- "ansi-to-html": "^0.6.7",
- "babel-loader": "^8.0.3",
- "babel-plugin-inline-json-import": "^0.3.1",
- "babel-plugin-transform-runtime": "^6.23.0",
- "babel-polyfill": "^6.26.0",
- "cache-loader": "^4.1.0",
- "canvas": "^2.6.0",
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
+ "@typescript-eslint/parser": "^6.21.0",
+ "@vscode/test-electron": "^3.1.0",
+ "@vscode/vsce": "^3.9.2",
+ "bent": "^7.3.12",
"chai": "^4.1.2",
"chai-arrays": "^2.0.0",
"chai-as-promised": "^7.1.1",
- "chai-http": "^4.3.0",
- "copy-webpack-plugin": "^5.1.2",
- "cors": "^2.8.5",
- "cross-env": "^6.0.3",
+ "copy-webpack-plugin": "^9.1.0",
+ "cross-env": "^7.0.3",
"cross-spawn": "^6.0.5",
- "css-loader": "^1.0.1",
- "dedent": "^0.7.0",
- "deemon": "^1.4.0",
- "del": "^3.0.0",
- "download": "^7.0.0",
- "enzyme": "^3.7.0",
- "enzyme-adapter-react-16": "^1.6.0",
- "eslint": "^7.2.0",
- "eslint-config-airbnb": "^18.2.0",
- "eslint-config-prettier": "^6.15.0",
- "eslint-plugin-import": "^2.22.0",
+ "del": "^6.0.0",
+ "download": "^8.0.0",
+ "eslint": "^8.57.1",
+ "eslint-config-prettier": "^8.3.0",
+ "eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
+ "eslint-plugin-no-only-tests": "^3.3.0",
"eslint-plugin-react": "^7.20.3",
"eslint-plugin-react-hooks": "^4.0.0",
- "expose-loader": "^0.7.5",
- "express": "^4.17.1",
- "extract-zip": "^1.6.7",
- "fast-xml-parser": "^3.16.0",
- "file-loader": "^5.1.0",
- "filemanager-webpack-plugin-fixed": "^2.0.9",
- "flat": "^4.0.0",
- "fork-ts-checker-webpack-plugin": "^4.1.6",
- "gulp": "^4.0.0",
- "gulp-azure-storage": "^0.11.1",
- "gulp-chmod": "^2.0.0",
- "gulp-gunzip": "^1.1.0",
- "gulp-rename": "^1.4.0",
- "gulp-sourcemaps": "^2.6.4",
- "gulp-typescript": "^4.0.1",
- "gulp-untar": "0.0.8",
- "gulp-vinyl-zip": "^2.1.2",
- "html-webpack-plugin": "^3.2.0",
- "husky": "^1.1.2",
- "immutable": "^4.0.0-rc.12",
- "jsdom": "^15.0.0",
- "json-loader": "^0.5.7",
- "less": "^3.9.0",
- "less-loader": "^5.0.0",
- "less-plugin-inline-urls": "^1.2.0",
- "loader-utils": "^1.1.0",
- "lolex": "^5.1.2",
- "memoize-one": "^5.1.1",
- "mocha": "^8.1.1",
- "mocha-junit-reporter": "^1.17.0",
+ "expose-loader": "^3.1.0",
+ "flat": "^5.0.2",
+ "get-port": "^5.1.1",
+ "gulp": "^5.0.0",
+ "gulp-typescript": "^5.0.0",
+ "mocha": "^11.1.0",
+ "mocha-junit-reporter": "^2.0.2",
"mocha-multi-reporters": "^1.1.7",
- "monaco-editor": "0.18.1",
- "monaco-editor-textmate": "^2.2.1",
- "monaco-editor-webpack-plugin": "^1.7.0",
- "monaco-textmate": "^3.0.1",
- "nocache": "^2.1.0",
- "nock": "^10.0.6",
"node-has-native-dependencies": "^1.0.2",
- "node-html-parser": "^1.1.13",
"node-loader": "^1.0.2",
- "nyc": "^15.0.0",
- "postcss": "^7.0.27",
- "postcss-cssnext": "^3.1.0",
- "postcss-import": "^12.0.1",
- "postcss-loader": "^3.0.0",
+ "node-polyfill-webpack-plugin": "^1.1.4",
+ "nyc": "^18.0.0",
"prettier": "^2.0.2",
- "range-inclusive": "^1.0.2",
- "raw-loader": "^0.5.1",
- "react": "^16.5.2",
- "react-dev-utils": "^11.0.4",
- "react-dom": "^16.5.2",
- "react-svgmt": "^1.1.8",
- "remove-files-webpack-plugin": "^1.4.0",
- "requirejs": "^2.3.6",
"rewiremock": "^3.13.0",
- "rimraf": "^3.0.2",
- "serialize-javascript": "^3.1.0",
"shortid": "^2.2.8",
- "sinon": "^8.0.1",
- "socket.io": "^2.4.0",
+ "sinon": "^18.0.0",
"source-map-support": "^0.5.12",
- "style-loader": "^0.23.1",
- "styled-jsx": "^3.1.0",
- "svg-inline-loader": "^0.8.0",
- "svg-inline-react": "^3.1.0",
- "terser-webpack-plugin": "^3.1.0",
- "thread-loader": "^2.1.3",
- "transform-loader": "^0.2.4",
- "ts-loader": "^5.3.0",
- "ts-mock-imports": "^1.3.0",
+ "ts-loader": "^9.2.8",
"ts-mockito": "^2.5.0",
- "ts-node": "^8.3.0",
+ "ts-node": "^10.7.0",
"tsconfig-paths-webpack-plugin": "^3.2.0",
- "typed-react-markdown": "^0.1.0",
"typemoq": "^2.1.0",
- "typescript": "^4.0.2",
- "typescript-formatter": "^7.1.0",
- "unicode-properties": "^1.3.1",
- "url-loader": "^1.1.2",
- "uuid": "^3.3.2",
- "vinyl-fs": "^3.0.3",
- "vsce": "^1.59.0",
- "vscode-debugadapter-testsupport": "^1.27.0",
- "vscode-test": "^1.2.3",
- "webpack": "^4.33.0",
- "webpack-bundle-analyzer": "^3.6.0",
- "webpack-cli": "^3.1.2",
+ "typescript": "~5.9",
+ "uuid": "^14.0.0",
+ "webpack": "^5.105.0",
+ "webpack-bundle-analyzer": "^4.5.0",
+ "webpack-cli": "^4.9.2",
"webpack-fix-default-import-plugin": "^1.0.3",
- "webpack-merge": "^4.1.4",
- "webpack-node-externals": "^1.7.2",
- "webpack-require-from": "^1.8.0",
- "why-is-node-running": "^2.0.3",
- "wtfnode": "^0.8.0",
+ "webpack-merge": "^5.8.0",
+ "webpack-node-externals": "^3.0.0",
+ "webpack-require-from": "^1.8.6",
+ "worker-loader": "^3.0.8",
"yargs": "^15.3.1"
- },
- "__metadata": {
- "id": "f1f59ae4-9318-4f3c-a9b5-81b2eaa5f8a5",
- "publisherDisplayName": "Microsoft",
- "publisherId": "998b010b-e2af-44a5-a6cd-0b5fd3b9b6f8"
}
}
diff --git a/package.nls.de.json b/package.nls.de.json
deleted file mode 100644
index 77ec14b3ee9c..000000000000
--- a/package.nls.de.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "python.command.python.sortImports.title": "Sortieren der Importe",
- "python.command.python.startREPL.title": "Starten des REPL",
- "python.command.python.createTerminal.title": "Terminal erstellen",
- "python.command.python.buildWorkspaceSymbols.title": "Arbeitsplatz-Symbole erstellen",
- "python.command.python.runtests.title": "Alle Unittests ausführen",
- "python.command.python.debugtests.title": "Alle Unittests debuggen",
- "python.command.python.execInTerminal.title": "Python-Datei im Terminal ausführen",
- "python.command.python.setInterpreter.title": "Interpreter auswählen",
- "python.command.python.refactorExtractVariable.title": "Variable extrahieren",
- "python.command.python.refactorExtractMethod.title": "Methode extrahieren",
- "python.command.python.viewTestOutput.title": "Unittest-Ausgabe anzeigen",
- "python.command.python.selectAndRunTestMethod.title": "Unittest-Methode ausführen ...",
- "python.command.python.selectAndDebugTestMethod.title": "Unittest-Debug-Methode ausführen ...",
- "python.command.python.selectAndRunTestFile.title": "Unittest-Datei ausführen ...",
- "python.command.python.runCurrentTestFile.title": "Ausgewählte Unittest-Datei ausführen",
- "python.command.python.runFailedTests.title": "Fehlerhafte Unittests ausführen",
- "python.command.python.discoverTests.title": "Unittests durchsuchen",
- "python.command.python.execSelectionInTerminal.title": "Selektion/Reihe in Python-Terminal ausführen",
- "python.command.python.execSelectionInDjangoShell.title": "Selektion/Reihe in Django-Shell ausführen",
- "python.command.python.goToPythonObject.title": "Gehe zu Python-Objekt",
- "python.command.python.setLinter.title": "Linter auswählen",
- "python.command.python.enableLinting.title": "Linting aktivieren",
- "python.command.python.runLinting.title": "Linting ausführen",
- "python.snippet.launch.standard.label": "Python: Aktuelle Datei",
- "python.snippet.launch.module.label": "Python: Modul",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Pyramid-Anwendung",
- "python.snippet.launch.attach.label": "Python: Anfügen"
-}
diff --git a/package.nls.es.json b/package.nls.es.json
deleted file mode 100644
index 227e268dbc8d..000000000000
--- a/package.nls.es.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "python.command.python.sortImports.title": "Ordenar importaciones",
- "python.command.python.startREPL.title": "Nuevo REPL",
- "python.command.python.createTerminal.title": "Nueva terminal",
- "python.command.python.buildWorkspaceSymbols.title": "Compilar símbolos del área de trabajo",
- "python.command.python.runtests.title": "Ejecutar todas las pruebas unitarias",
- "python.command.python.debugtests.title": "Depurar todas las pruebas unitarias",
- "python.command.python.execInTerminal.title": "Ejecutar archivo Python en la terminal",
- "python.command.python.setInterpreter.title": "Seleccionar intérprete",
- "python.command.python.refactorExtractVariable.title": "Extraer variable",
- "python.command.python.refactorExtractMethod.title": "Extraer método",
- "python.command.python.viewTestOutput.title": "Mostrar resultados de la prueba unitaria",
- "python.command.python.selectAndRunTestMethod.title": "Método de ejecución de pruebas unitarias ...",
- "python.command.python.selectAndDebugTestMethod.title": "Método de depuración de pruebas unitarias ...",
- "python.command.python.selectAndRunTestFile.title": "Ejecutar archivo de prueba unitaria ...",
- "python.command.python.runCurrentTestFile.title": "Ejecutar archivo de prueba unitaria actual",
- "python.command.python.runFailedTests.title": "Ejecutar pruebas unitarias fallidas",
- "python.command.python.discoverTests.title": "Encontrar pruebas unitarias",
- "python.command.python.execSelectionInTerminal.title": "Ejecutar línea/selección en la terminal",
- "python.command.python.execSelectionInDjangoShell.title": "Ejecutar línea/selección en el intérprete de Django",
- "python.command.python.goToPythonObject.title": "Ir al objeto de Python",
- "python.command.python.setLinter.title": "Seleccionar Linter",
- "python.command.python.enableLinting.title": "Habilitar Linting",
- "python.command.python.runLinting.title": "Ejecutar Linting",
- "python.snippet.launch.standard.label": "Python: Archivo actual",
- "python.snippet.launch.module.label": "Python: Módulo",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Pyramid",
- "python.snippet.launch.attach.label": "Python: Adjuntar"
-}
diff --git a/package.nls.fr.json b/package.nls.fr.json
deleted file mode 100644
index ad28a94d6e09..000000000000
--- a/package.nls.fr.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "python.command.python.sortImports.title": "Trier les imports",
- "python.command.python.startREPL.title": "Démarrer la console interactive",
- "python.command.python.createTerminal.title": "Créer un terminal",
- "python.command.python.buildWorkspaceSymbols.title": "Construire les symboles de l'espace de travail",
- "python.command.python.runtests.title": "Exécuter tous les tests unitaires",
- "python.command.python.debugtests.title": "Déboguer tous les tests unitaires",
- "python.command.python.execInTerminal.title": "Exécuter le script Python dans un terminal",
- "python.command.python.setInterpreter.title": "Sélectionner l'interpreteur",
- "python.command.python.refactorExtractVariable.title": "Extraire la variable",
- "python.command.python.refactorExtractMethod.title": "Extraire la méthode",
- "python.command.python.viewTestOutput.title": "Afficher la sortie des tests unitaires",
- "python.command.python.selectAndRunTestMethod.title": "Exécuter la méthode de test unitaire ...",
- "python.command.python.selectAndDebugTestMethod.title": "Déboguer la méthode de test unitaire ...",
- "python.command.python.selectAndRunTestFile.title": "Exécuter le fichier de test unitaire ...",
- "python.command.python.runCurrentTestFile.title": "Exécuter le fichier de test unitaire courant",
- "python.command.python.runFailedTests.title": "Exécuter les derniers test unitaires échoués",
- "python.command.python.execSelectionInTerminal.title": "Exécuter la ligne/sélection dans un terminal Python",
- "python.command.python.execSelectionInDjangoShell.title": "Exécuter la ligne/sélection dans un shell Django",
- "python.command.python.goToPythonObject.title": "Se rendre à l'objet Python",
- "python.command.python.setLinter.title": "Sélectionner le linter",
- "python.command.python.enableLinting.title": "Activer le linting",
- "python.command.python.runLinting.title": "Exécuter le linting",
- "python.snippet.launch.standard.label": "Python : Fichier actuel",
- "python.snippet.launch.module.label": "Python: Module",
- "python.snippet.launch.django.label": "Python : Django",
- "python.snippet.launch.flask.label": "Python : Flask",
- "python.snippet.launch.pyramid.label": "Python : application Pyramid",
- "python.snippet.launch.attach.label": "Python: Attacher"
-}
diff --git a/package.nls.it.json b/package.nls.it.json
deleted file mode 100644
index c16d6ce74241..000000000000
--- a/package.nls.it.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "python.command.python.sortImports.title": "Ordina gli import",
- "python.command.python.startREPL.title": "Apri nuova REPL",
- "python.command.python.createTerminal.title": "Apri nuovo terminale",
- "python.command.python.buildWorkspaceSymbols.title": "Compila simboli dello spazio di lavoro",
- "python.command.python.runtests.title": "Esegui tutti i test",
- "python.command.python.debugtests.title": "Esegui debug di tutti i test",
- "python.command.python.execInTerminal.title": "Esegui file Python nel terminale",
- "python.command.python.setInterpreter.title": "Seleziona interprete",
- "python.command.python.refactorExtractVariable.title": "Estrai variable",
- "python.command.python.refactorExtractMethod.title": "Estrai metodo",
- "python.command.python.viewTestOutput.title": "Mostra output dei test",
- "python.command.python.selectAndRunTestMethod.title": "Esegui metodo di test ...",
- "python.command.python.selectAndDebugTestMethod.title": "Esegui debug del metodo di test ...",
- "python.command.python.selectAndRunTestFile.title": "Esegui file di test ...",
- "python.command.python.runCurrentTestFile.title": "Esegui file di test attuale",
- "python.command.python.runFailedTests.title": "Esegui test falliti",
- "python.command.python.execSelectionInTerminal.title": "Esegui selezione/linea nel terminale di Python",
- "python.command.python.execSelectionInDjangoShell.title": "Esegui selezione/linea nella shell Django",
- "python.command.python.goToPythonObject.title": "Vai a oggetto Python",
- "python.command.python.setLinter.title": "Selezione Linter",
- "python.command.python.enableLinting.title": "Attiva Linting",
- "python.command.python.runLinting.title": "Esegui Linting",
- "python.snippet.launch.standard.label": "Python: File corrente",
- "python.snippet.launch.module.label": "Python: Modulo",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Applicazione Pyramid",
- "python.snippet.launch.attach.label": "Python: Allega",
- "ExtensionSurveyBanner.bannerLabelYes": "Sì, prenderò il sondaggio ora"
-}
diff --git a/package.nls.ja.json b/package.nls.ja.json
deleted file mode 100644
index a2db0a823636..000000000000
--- a/package.nls.ja.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "python.command.python.sortImports.title": "import 文を並び替える",
- "python.command.python.startREPL.title": "REPL を開始",
- "python.command.python.buildWorkspaceSymbols.title": "ワークスペースのシンボルをビルド",
- "python.command.python.runtests.title": "すべての単体テストを実行",
- "python.command.python.debugtests.title": "すべての単体テストをデバッグ",
- "python.command.python.execInTerminal.title": "ターミナルで Python ファイルを実行",
- "python.command.python.setInterpreter.title": "インタープリターを選択",
- "python.command.python.refactorExtractVariable.title": "変数を抽出",
- "python.command.python.refactorExtractMethod.title": "メソッドを抽出",
- "python.command.python.viewTestOutput.title": "単体テストの出力を表示",
- "python.command.python.selectAndRunTestMethod.title": "単体テストメソッドを実行...",
- "python.command.python.selectAndDebugTestMethod.title": "単体テストメソッドをデバッグ...",
- "python.command.python.selectAndRunTestFile.title": "単体テストファイルを実行...",
- "python.command.python.runCurrentTestFile.title": "現在の単体テストファイルを実行",
- "python.command.python.runFailedTests.title": "失敗した単体テストを実行",
- "python.command.python.execSelectionInTerminal.title": "Python ターミナルで選択範囲/行を実行",
- "python.command.python.execSelectionInDjangoShell.title": "Django シェルで選択範囲/行を実行",
- "python.command.python.goToPythonObject.title": "Python オブジェクトに移動",
- "python.snippet.launch.standard.label": "Python: Current File",
- "python.snippet.launch.module.label": "Python: モジュール",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Pyramid アプリケーション",
- "python.snippet.launch.attach.label": "Python: アタッチ"
-}
diff --git a/package.nls.json b/package.nls.json
index a88ba79a1fda..57f2ed95b2c0 100644
--- a/package.nls.json
+++ b/package.nls.json
@@ -1,254 +1,177 @@
{
- "python.command.python.sortImports.title": "Sort Imports",
- "python.command.python.startREPL.title": "Start REPL",
+ "python.command.python.startTerminalREPL.title": "Start Terminal REPL",
+ "python.languageModelTools.get_python_environment_details.userDescription": "Get information for a Python Environment, such as Type, Version, Packages, and more.",
+ "python.languageModelTools.install_python_packages.userDescription": "Installs Python packages in a Python Environment.",
+ "python.languageModelTools.get_python_executable_details.userDescription": "Get executable info for a Python Environment",
+ "python.languageModelTools.configure_python_environment.userDescription": "Configure a Python Environment for a workspace",
+ "python.command.python.startNativeREPL.title": "Start Native Python REPL",
+ "python.command.python.createEnvironment.title": "Create Environment...",
+ "python.command.python.createNewFile.title": "New Python File",
"python.command.python.createTerminal.title": "Create Terminal",
- "python.command.python.buildWorkspaceSymbols.title": "Build Workspace Symbols",
- "python.command.python.runtests.title": "Run All Tests",
- "python.command.python.debugtests.title": "Debug All Tests",
"python.command.python.execInTerminal.title": "Run Python File in Terminal",
+ "python.command.python.execInTerminalIcon.title": "Run Python File",
+ "python.command.python.execInDedicatedTerminal.title": "Run Python File in Dedicated Terminal",
"python.command.python.setInterpreter.title": "Select Interpreter",
- "python.command.python.switchOffInsidersChannel.title": "Switch to Default Channel",
- "python.command.python.switchToDailyChannel.title": "Switch to Insiders Daily Channel",
- "python.command.python.switchToWeeklyChannel.title": "Switch to Insiders Weekly Channel",
"python.command.python.clearWorkspaceInterpreter.title": "Clear Workspace Interpreter Setting",
- "python.command.python.resetInterpreterSecurityStorage.title": "Reset Stored Info for Untrusted Interpreters",
- "python.command.python.refactorExtractVariable.title": "Extract Variable",
- "python.command.python.refactorExtractMethod.title": "Extract Method",
"python.command.python.viewOutput.title": "Show Output",
- "python.command.python.viewTestOutput.title": "Show Test Output",
+ "python.command.python.installJupyter.title": "Install the Jupyter extension",
"python.command.python.viewLanguageServerOutput.title": "Show Language Server Output",
- "python.command.python.selectAndRunTestMethod.title": "Run Test Method ...",
- "python.command.python.selectAndDebugTestMethod.title": "Debug Test Method ...",
- "python.command.python.selectAndRunTestFile.title": "Run Test File ...",
- "python.command.python.runCurrentTestFile.title": "Run Current Test File",
- "python.command.python.runFailedTests.title": "Run Failed Tests",
- "python.command.python.discoverTests.title": "Discover Tests",
- "python.command.python.discoveringTests.title": "Discovering...",
- "python.command.python.stopTests.title": "Stop",
"python.command.python.configureTests.title": "Configure Tests",
+ "python.command.testing.rerunFailedTests.title": "Rerun Failed Tests",
"python.command.python.execSelectionInTerminal.title": "Run Selection/Line in Python Terminal",
+ "python.command.python.execSelectionInTerminal.shortTitle": "Run Selection/Line",
+ "python.command.python.execInREPL.title": "Run Selection/Line in Native Python REPL",
"python.command.python.execSelectionInDjangoShell.title": "Run Selection/Line in Django Shell",
- "python.command.python.goToPythonObject.title": "Go to Python Object",
- "python.command.python.reportIssue.title": "Report Issue",
- "python.command.python.setLinter.title": "Select Linter",
- "python.command.python.enableLinting.title": "Enable/Disable Linting",
- "python.command.python.runLinting.title": "Run Linting",
- "python.command.python.enableSourceMapSupport.title": "Enable Source Map Support For Extension Debugging",
- "python.command.python.clearPersistentStorage.title": "Clear Internal Extension Cache",
- "python.command.python.startPage.open.title": "Open Start Page",
- "python.command.python.analysis.clearCache.title": "Clear Module Analysis Cache",
+ "python.command.python.reportIssue.title": "Report Issue...",
+ "python.command.python.clearCacheAndReload.title": "Clear Cache and Reload Window",
"python.command.python.analysis.restartLanguageServer.title": "Restart Language Server",
"python.command.python.launchTensorBoard.title": "Launch TensorBoard",
- "python.snippet.launch.standard.label": "Python: Current File",
- "python.snippet.launch.module.label": "Python: Module",
- "python.snippet.launch.module.default": "enter-your-module-name",
- "python.snippet.launch.attach.label": "Python: Remote Attach",
- "python.snippet.launch.attachpid.label": "Python: Attach using Process Id",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.fastapi.label": "Python: FastAPI",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Pyramid Application",
- "Pylance.proposePylanceMessage": "Try out a new faster, feature-rich language server for Python by Microsoft, Pylance! Install the extension now.",
- "Pylance.tryItNow": "Try it now",
- "Pylance.remindMeLater": "Remind me later",
- "Pylance.pylanceNotInstalledMessage": "Pylance extension is not installed.",
- "Pylance.pylanceInstalledReloadPromptMessage": "Pylance extension is now installed. Reload window to activate?",
- "Pylance.pylanceRevertToJediPrompt": "The Pylance extension is not installed but the python.languageServer value is set to \"Pylance\". Would you like to install the Pylance extension to use Pylance, or revert back to Jedi?",
- "Pylance.pylanceInstallPylance": "Install Pylance",
- "Pylance.pylanceRevertToJedi": "Revert to Jedi",
- "Experiments.inGroup": "User belongs to experiment group '{0}'",
- "Experiments.optedOutOf": "User opted out of experiment group '{0}'",
- "Interpreters.RefreshingInterpreters": "Refreshing Python Interpreters",
- "Interpreters.entireWorkspace": "Entire workspace",
- "Interpreters.pythonInterpreterPath": "Python interpreter path: {0}",
- "Interpreters.LoadingInterpreters": "Loading Python Interpreters",
- "Interpreters.unsafeInterpreterMessage": "We found a Python environment in this workspace. Do you want to select it to start up the features in the Python extension? Only accept if you trust this environment.",
- "Interpreters.condaInheritEnvMessage": "We noticed you're using a conda environment. If you are experiencing issues with this environment in the integrated terminal, we recommend that you let the Python extension change \"terminal.integrated.inheritEnv\" to false in your user settings.",
- "Logging.CurrentWorkingDirectory": "cwd:",
- "InterpreterQuickPickList.quickPickListPlaceholder": "Current: {0}",
- "InterpreterQuickPickList.enterPath.detail": "Enter path or find an existing interpreter",
- "InterpreterQuickPickList.enterPath.label": "Enter interpreter path...",
- "InterpreterQuickPickList.enterPath.placeholder": "Enter path to a Python interpreter.",
- "InterpreterQuickPickList.findPath.detail": "Browse the file system to find a Python interpreter.",
- "InterpreterQuickPickList.findPath.label": "I can't find the interpreter I want to select...",
- "InterpreterQuickPickList.refreshInterpreterList": "Refresh Interpreter list",
- "InterpreterQuickPickList.browsePath.label": "Find...",
- "InterpreterQuickPickList.browsePath.detail": "Browse your file system to find a Python interpreter.",
- "InterpreterQuickPickList.browsePath.title": "Select Python interpreter",
- "diagnostics.upgradeCodeRunner": "Please update the Code Runner extension for it to be compatible with the Python extension.",
- "Common.bannerLabelYes": "Yes",
- "Common.bannerLabelNo": "No",
- "Common.doNotShowAgain": "Do not show again",
- "Common.reload": "Reload",
- "Common.moreInfo": "More Info",
- "Common.and": "and",
- "Common.ok": "Ok",
- "Common.install": "Install",
- "Common.learnMore": "Learn more",
- "Common.reportThisIssue": "Report this issue",
- "CommonSurvey.remindMeLaterLabel": "Remind me later",
- "CommonSurvey.yesLabel": "Yes, take survey now",
- "CommonSurvey.noLabel": "No, thanks",
- "OutputChannelNames.languageServer": "Python Language Server",
- "OutputChannelNames.python": "Python",
- "OutputChannelNames.pythonTest": "Python Test Log",
- "ExtensionSurveyBanner.bannerMessage": "Can you please take 2 minutes to tell us how the Python extension is working for you?",
- "ExtensionSurveyBanner.bannerLabelYes": "Yes, take survey now",
- "ExtensionSurveyBanner.bannerLabelNo": "No, thanks",
- "ExtensionSurveyBanner.maybeLater": "Maybe later",
- "ExtensionChannels.installingInsidersMessage": "Installing Insiders... ",
- "ExtensionChannels.installingStableMessage": "Installing Stable... ",
- "ExtensionChannels.installationCompleteMessage": "complete.",
- "ExtensionChannels.downloadingInsidersMessage": "Downloading Insiders Extension... ",
- "ExtensionChannels.yesWeekly": "Yes, weekly",
- "ExtensionChannels.yesDaily": "Yes, daily",
- "ExtensionChannels.promptMessage": "We noticed you are using Visual Studio Code Insiders. Would you like to use the Insiders build of the Python extension?",
- "ExtensionChannels.reloadToUseInsidersMessage": "Please reload Visual Studio Code to use the insiders build of the Python extension.",
- "ExtensionChannels.downloadCompletedOutputMessage": "Insiders build download complete.",
- "ExtensionChannels.startingDownloadOutputMessage": "Starting download for Insiders build.",
- "Interpreters.environmentPromptMessage": "We noticed a new virtual environment has been created. Do you want to select it for the workspace folder?",
- "Linter.enableLinter": "Enable {0}",
- "Linter.enablePylint": "You have a pylintrc file in your workspace. Do you want to enable pylint?",
- "Linter.replaceWithSelectedLinter": "Multiple linters are enabled in settings. Replace with '{0}'?",
- "Linter.install": "Install a linter to get error reporting.",
- "Linter.installPylint": "Install pylint",
- "Linter.installFlake8": "Install flake8",
- "Linter.selectLinter": "Select Linter",
- "Installer.noCondaOrPipInstaller": "There is no Conda or Pip installer available in the selected environment.",
- "Installer.noPipInstaller": "There is no Pip installer available in the selected environment.",
- "Installer.searchForHelp": "Search for help",
- "Installer.couldNotInstallLibrary": "Could not install {0}. If pip is not available, please use the package manager of your choice to manually install this library into your Python environment.",
- "Installer.dataScienceInstallPrompt": "Data Science library {0} is not installed. Install?",
- "diagnostics.removedPythonPathFromSettings": "We removed the \"python.pythonPath\" setting from your settings.json file as the setting is no longer used by the Python extension. You can get the path of your selected interpreter in the Python output channel. [Learn more](https://aka.ms/AA7jfor).",
- "diagnostics.warnSourceMaps": "Source map support is enabled in the Python Extension, this will adversely impact performance of the extension.",
- "diagnostics.disableSourceMaps": "Disable Source Map Support",
- "diagnostics.warnBeforeEnablingSourceMaps": "Enabling source map support in the Python Extension will adversely impact performance of the extension.",
- "diagnostics.enableSourceMapsAndReloadVSC": "Enable and reload Window",
- "diagnostics.lsNotSupported": "Your operating system does not meet the minimum requirements of the Python Language Server. Reverting to the alternative autocompletion provider, Jedi.",
- "diagnostics.invalidPythonPathInDebuggerSettings": "You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Python Interpreter\" in the status bar.",
- "diagnostics.invalidPythonPathInDebuggerLaunch": "The Python path in your debug configuration is invalid.",
- "diagnostics.invalidDebuggerTypeDiagnostic": "Your launch.json file needs to be updated to change the \"pythonExperimental\" debug configurations to use the \"python\" debugger type, otherwise Python debugging may not work. Would you like to automatically update your launch.json file now?",
- "diagnostics.consoleTypeDiagnostic": "Your launch.json file needs to be updated to change the console type string from \"none\" to \"internalConsole\", otherwise Python debugging may not work. Would you like to automatically update your launch.json file now?",
- "diagnostics.justMyCodeDiagnostic": "Configuration \"debugStdLib\" in launch.json is no longer supported. It's recommended to replace it with \"justMyCode\", which is the exact opposite of using \"debugStdLib\". Would you like to automatically update your launch.json file to do that?",
- "diagnostics.checkIsort5UpgradeGuide": "We found outdated configuration for sorting imports in this workspace. Check the [isort upgrade guide](https://aka.ms/AA9j5x4) to update your settings.",
- "diagnostics.yesUpdateLaunch": "Yes, update launch.json",
- "diagnostics.invalidTestSettings": "Your settings needs to be updated to change the setting \"python.unitTest.\" to \"python.testing.\", otherwise testing Python code using the extension may not work. Would you like to automatically update your settings now?",
- "Common.canceled": "Canceled",
- "Common.cancel": "Cancel",
- "Common.yesPlease": "Yes, please",
- "Common.loadingPythonExtension": "Python extension loading...",
- "debug.selectConfigurationTitle": "Select a debug configuration",
- "debug.selectConfigurationPlaceholder": "Debug Configuration",
- "debug.launchJsonConfigurationsCompletionLabel": "Python",
- "debug.launchJsonConfigurationsCompletionDescription": "Select a Python debug configuration",
- "debug.debugFileConfigurationLabel": "Python File",
- "debug.debugFileConfigurationDescription": "Debug the currently active Python file",
- "debug.debugModuleConfigurationLabel": "Module",
- "debug.debugModuleConfigurationDescription": "Debug a Python module by invoking it with '-m'",
- "debug.moduleEnterModuleTitle": "Debug Module",
- "debug.moduleEnterModulePrompt": "Enter a Python module/package name",
- "debug.moduleEnterModuleDefault": "enter-your-module-name",
- "debug.moduleEnterModuleInvalidNameError": "Enter a valid module name",
- "debug.remoteAttachConfigurationLabel": "Remote Attach",
- "debug.remoteAttachConfigurationDescription": "Attach to a remote debug server",
- "debug.attachRemoteHostTitle": "Remote Debugging",
- "debug.attachRemoteHostPrompt": "Enter the host name",
- "debug.attachRemoteHostValidationError": "Enter a valid host name or IP address",
- "debug.attachRemotePortTitle": "Remote Debugging",
- "debug.attachRemotePortPrompt": "Enter the port number that the debug server is listening on",
- "debug.attachRemotePortValidationError": "Enter a valid port number",
- "debug.attachPidConfigurationLabel": "Attach using Process ID",
- "debug.attachPidConfigurationDescription": "Attach to a local process",
- "debug.debugDjangoConfigurationLabel": "Django",
- "debug.debugDjangoConfigurationDescription": "Launch and debug a Django web application",
- "debug.djangoEnterManagePyPathTitle": "Debug Django",
- "debug.djangoEnterManagePyPathPrompt": "Enter the path to manage.py ('${workspaceFolderToken}' points to the root of the current workspace folder)",
- "debug.djangoEnterManagePyPathInvalidFilePathError": "Enter a valid Python file path",
- "debug.debugFastAPIConfigurationLabel": "FastAPI",
- "debug.debugFastAPIConfigurationDescription": "Launch and debug a FastAPI web application",
- "debug.fastapiEnterAppPathOrNamePathTitle": "Debug FastAPI",
- "debug.fastapiEnterAppPathOrNamePathPrompt": "Enter the path to the application, e.g. 'main.py' or 'main'",
- "debug.fastapiEnterAppPathOrNamePathInvalidNameError": "Enter a valid name",
- "debug.debugFlaskConfigurationLabel": "Flask",
- "debug.debugFlaskConfigurationDescription": "Launch and debug a Flask web application",
- "debug.flaskEnterAppPathOrNamePathTitle": "Debug Flask",
- "debug.flaskEnterAppPathOrNamePathPrompt": "Enter the path to the application, e.g. 'app.py' or 'app'",
- "debug.flaskEnterAppPathOrNamePathInvalidNameError": "Enter a valid name",
- "debug.debugPyramidConfigurationLabel": "Pyramid",
- "debug.debugPyramidConfigurationDescription": "Launch and debug a Pyramid web application",
- "debug.pyramidEnterDevelopmentIniPathTitle": "Debug Pyramid",
- "debug.pyramidEnterDevelopmentIniPathPrompt": "`Enter the path to development.ini ('${workspaceFolderToken}' points to the root of the current workspace folder)`",
- "debug.pyramidEnterDevelopmentIniPathInvalidFilePathError": "Enter a valid file path",
- "Testing.testErrorDiagnosticMessage": "Error",
- "Testing.testFailDiagnosticMessage": "Fail",
- "Testing.testSkippedDiagnosticMessage": "Skipped",
- "Testing.configureTests": "Configure Test Framework",
- "Testing.disableTests": "Disable Tests",
- "Common.openOutputPanel": "Show output",
- "LanguageService.lsFailedToStart": "We encountered an issue starting the language server. Reverting to Jedi language engine. Check the Python output panel for details.",
- "LanguageService.lsFailedToDownload": "We encountered an issue downloading the language server. Reverting to Jedi language engine. Check the Python output panel for details.",
- "LanguageService.lsFailedToExtract": "We encountered an issue extracting the language server. Reverting to Jedi language engine. Check the Python output panel for details.",
- "LanguageService.downloadFailedOutputMessage": "Language server download failed",
- "LanguageService.extractionFailedOutputMessage": "Language server extraction failed",
- "LanguageService.extractionCompletedOutputMessage": "Language server download complete",
- "LanguageService.extractionDoneOutputMessage": "done",
- "LanguageService.reloadVSCodeIfSeachPathHasChanged": "Search paths have changed for this Python interpreter. Please reload the extension to ensure that the IntelliSense works correctly",
- "LanguageService.startingJedi": "Starting Jedi Python language engine.",
- "LanguageService.startingMicrosoft": "Starting Microsoft Python language server.",
- "LanguageService.startingPylance": "Starting Pylance language server.",
- "LanguageService.startingJediLSP": "Starting Jedi language server.",
- "LanguageService.startingNone": "Editor support is inactive since language server is set to None.",
- "LanguageService.reloadAfterLanguageServerChange": "Please reload the window switching between language servers.",
- "AttachProcess.unsupportedOS": "Operating system '{0}' not supported.",
- "AttachProcess.attachTitle": "Attach to process",
- "AttachProcess.selectProcessPlaceholder": "Select the process to attach to",
- "AttachProcess.noProcessSelected": "No process selected",
- "AttachProcess.refreshList": "Refresh process list",
- "diagnostics.updateSettings": "Yes, update settings",
- "Common.noIWillDoItLater": "No, I will do it later",
- "Common.notNow": "Not now",
- "Common.gotIt": "Got it!",
- "Interpreters.selectInterpreterTip": "Tip: you can change the Python interpreter used by the Python extension by clicking on the Python version in the status bar",
- "downloading.file": "Downloading {0}...",
- "downloading.file.progress": "{0}{1} of {2} KB ({3}%)",
- "products.installingModule": "Installing {0}",
- "OutdatedDebugger.updateDebuggerMessage": "We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).",
- "StartPage.getStarted": "Python - Get Started",
- "StartPage.pythonExtensionTitle": "Python Extension",
- "StartPage.createJupyterNotebook": "Create a Jupyter Notebook",
- "StartPage.notebookDescription": "- Run \"Create New Blank Notebook
\" in the Command Palette (Shift + Command + P
) - Explore our sample notebook
to learn about notebook features",
- "StartPage.createAPythonFile": "Create a Python File",
- "StartPage.pythonFileDescription": "- Create a new file
with a .py extension",
- "StartPage.openInteractiveWindow": "Use the Interactive Window to develop Python Scripts",
- "StartPage.interactiveWindowDesc": "- You can create cells on a Python file by typing \"#%%\" - Use \"Shift + Enter
\" to run a cell, the output will be shown in the interactive window",
- "StartPage.releaseNotes": "Take a look at our Release Notes to learn more about the latest features.",
- "StartPage.mailingList": "Sign up for tips and tutorials through our mailing list.",
- "StartPage.tutorialAndDoc": "Explore more features in our Tutorials or check Documentation for tips and troubleshooting.",
- "StartPage.dontShowAgain": "Don't show this page again",
- "StartPage.helloWorld": "Hello world",
- "StartPage.sampleNotebook": "Notebooks intro",
- "StartPage.openFolder": "Open a Folder or Workspace",
- "StartPage.folderDesc": "- Open a Folder
- Open a Workspace
",
- "StartPage.badWebPanelFormatString": "{0} is not a valid file name ",
- "Jupyter.extensionRequired": "The Jupyter extension is required to perform that task. Click Yes to open the Jupyter extension installation page.",
- "TensorBoard.missingSourceFile": "We could not locate the requested source file on disk. Please manually specify the file.",
- "TensorBoard.selectMissingSourceFile": "Choose File",
- "TensorBoard.selectMissingSourceFileDescription": "The source file's contents may not match the original contents in the trace.",
- "TensorBoard.useCurrentWorkingDirectory": "Use current working directory",
- "TensorBoard.currentDirectory": "Current: {0}",
- "TensorBoard.logDirectoryPrompt": "Select a log directory to start TensorBoard with",
- "TensorBoard.progressMessage": "Starting TensorBoard session...",
- "TensorBoard.failedToStartSessionError": "We failed to start a TensorBoard session due to the following error: {0}",
- "TensorBoard.nativeTensorBoardPrompt": "VS Code now has integrated TensorBoard support. Would you like to launch TensorBoard? (Tip: Launch TensorBoard anytime by opening the command palette and searching for \"Launch TensorBoard\".)",
- "TensorBoard.selectAFolder": "Select a folder",
- "TensorBoard.selectAnotherFolder": "Select another folder",
- "TensorBoard.selectAFolderDetail": "Select a log directory containing tfevent files",
- "TensorBoard.selectAnotherFolderDetail": "Use the file explorer to select another folder",
- "TensorBoard.useCurrentWorkingDirectoryDetail": "TensorBoard will search for tfevent files in all subdirectories of the current working directory",
- "TensorBoard.installPrompt": "The package TensorBoard is required to launch a TensorBoard session. Would you like to install it?",
- "TensorBoard.installTensorBoardAndProfilerPluginPrompt": "TensorBoard >= 2.4.1 and the PyTorch Profiler TensorBoard Plugin are required. Would you like to install these packages?",
- "TensorBoard.installProfilerPluginPrompt": "We recommend installing the PyTorch Profiler TensorBoard plugin. Would you like to install the package?",
- "TensorBoard.upgradePrompt": "Integrated TensorBoard support is only available for TensorBoard >= 2.4.1. Would you like to upgrade your copy of TensorBoard?",
- "TensorBoard.launchNativeTensorBoardSessionCodeAction": "Launch TensorBoard session",
- "TensorBoard.launchNativeTensorBoardSessionCodeLens": "▶ Launch TensorBoard Session"
+ "python.command.python.refreshTensorBoard.title": "Refresh TensorBoard",
+ "python.command.python.testing.copyTestId.title": "Copy Test Id",
+ "python.createEnvironment.contentButton.description": "Show or hide Create Environment button in the editor for `requirements.txt` or other dependency files.",
+ "python.createEnvironment.trigger.description": "Detect if environment creation is required for the current project",
+ "python.menu.createNewFile.title": "Python File",
+ "python.editor.context.submenu.runPython": "Run Python",
+ "python.editor.context.submenu.runPythonInteractive": "Run in Interactive window",
+ "python.activeStateToolPath.description": "Path to the State Tool executable for ActiveState runtimes (version 0.36+).",
+ "python.autoComplete.extraPaths.description": "List of paths to libraries and the like that need to be imported by auto complete engine. E.g. when using Google App SDK, the paths are not in system path, hence need to be added into this list.",
+ "python.condaPath.description": "Path to the conda executable to use for activation (version 4.4+).",
+ "python.debugger.deprecatedMessage": "This configuration will be deprecated soon. Please replace `python` with `debugpy` to use the new Python Debugger extension.",
+ "python.defaultInterpreterPath.description": "Path to default Python to use when extension loads up for the first time, no longer used once an interpreter is selected for the workspace. See [here](https://aka.ms/AAfekmf) to understand when this is used",
+ "python.envFile.description": "Absolute path to a file containing environment variable definitions.",
+ "python.useEnvironmentsExtension.description": "Enables the Python Environments extension. Requires window reload on change.",
+ "python.experiments.enabled.description": "Enables A/B tests experiments in the Python extension. If enabled, you may get included in proposed enhancements and/or features.",
+ "python.experiments.optInto.description": "List of experiments to opt into. If empty, user is assigned the default experiment groups. See [here](https://github.com/microsoft/vscode-python/wiki/AB-Experiments) for more details.",
+ "python.experiments.optOutFrom.description": "List of experiments to opt out of. If empty, user is assigned the default experiment groups. See [here](https://github.com/microsoft/vscode-python/wiki/AB-Experiments) for more details.",
+ "python.experiments.All.description": "Combined list of all experiments.",
+ "python.experiments.pythonSurveyNotification.description": "Denotes the Python Survey Notification experiment.",
+ "python.experiments.pythonPromptNewToolsExt.description": "Denotes the Python Prompt New Tools Extension experiment.",
+ "python.experiments.pythonTerminalEnvVarActivation.description": "Enables use of environment variables to activate terminals instead of sending activation commands.",
+ "python.experiments.pythonDiscoveryUsingWorkers.description": "Enables use of worker threads to do heavy computation when discovering interpreters.",
+ "python.experiments.pythonTestAdapter.description": "Denotes the Python Test Adapter experiment.",
+ "python.experiments.pythonRecommendTensorboardExt.description": "Denotes the Tensorboard Extension recommendation experiment.",
+ "python.globalModuleInstallation.description": "Whether to install Python modules globally when not using an environment.",
+ "python.languageServer.description": "Defines type of the language server.",
+ "python.languageServer.defaultDescription": "Automatically select a language server: Pylance if installed and available, otherwise fallback to Jedi.",
+ "python.languageServer.jediDescription": "Use Jedi behind the Language Server Protocol (LSP) as a language server.",
+ "python.languageServer.pylanceDescription": "Use Pylance as a language server.",
+ "python.languageServer.noneDescription": "Disable language server capabilities.",
+ "python.interpreter.infoVisibility.description": "Controls when to display information of selected interpreter in the status bar.",
+ "python.interpreter.infoVisibility.never.description": "Never display information.",
+ "python.interpreter.infoVisibility.onPythonRelated.description": "Only display information if Python-related files are opened.",
+ "python.interpreter.infoVisibility.always.description": "Always display information.",
+ "python.logging.level.description": "The logging level the extension logs at, defaults to 'error'",
+ "python.logging.level.deprecation": "This setting is deprecated. Please use command `Developer: Set Log Level...` to set logging level.",
+ "python.missingPackage.severity.description": "Set severity of missing packages in requirements.txt or pyproject.toml",
+ "python.locator.description": "[Experimental] Select implementation of environment locators. This is an experimental setting while we test native environment location.",
+ "python.pipenvPath.description": "Path to the pipenv executable to use for activation.",
+ "python.poetryPath.description": "Path to the poetry executable.",
+ "python.pixiToolPath.description": "Path to the pixi executable.",
+ "python.EnableREPLSmartSend.description": "Toggle Smart Send for the Python REPL. Smart Send enables sending the smallest runnable block of code to the REPL on Shift+Enter and moves the cursor accordingly.",
+ "python.REPL.sendToNativeREPL.description": "Toggle to send code to Python REPL instead of the terminal on execution. Turning this on will change the behavior for both Smart Send and Run Selection/Line in the Context Menu.",
+ "python.REPL.provideVariables.description": "Toggle to provide variables for the REPL variable view for the native REPL.",
+ "python.tensorBoard.logDirectory.description": "Set this setting to your preferred TensorBoard log directory to skip log directory prompt when starting TensorBoard.",
+ "python.tensorBoard.logDirectory.markdownDeprecationMessage": "Tensorboard support has been moved to the extension [Tensorboard extension](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.tensorboard). Instead use the setting `tensorBoard.logDirectory`.",
+ "python.tensorBoard.logDirectory.deprecationMessage": "Tensorboard support has been moved to the extension Tensorboard extension. Instead use the setting `tensorBoard.logDirectory`.",
+ "python.terminal.shellIntegration.enabled.description": "Enable [shell integration](https://code.visualstudio.com/docs/terminal/shell-integration) for the terminals running python. Shell integration enhances the terminal experience by enabling command decorations, run recent command, improving accessibility among other things. Note: PyREPL (available in Python 3.13+) is automatically disabled when shell integration is enabled to avoid cursor indentation issues.",
+ "python.terminal.activateEnvInCurrentTerminal.description": "Activate Python Environment in the current Terminal on load of the Extension.",
+ "python.terminal.activateEnvironment.description": "Activate Python Environment in all Terminals created.",
+ "python.terminal.executeInFileDir.description": "When executing a file in the terminal, whether to use execute in the file's directory, instead of the current open folder.",
+ "python.terminal.focusAfterLaunch.description": "When launching a python terminal, whether to focus the cursor on the terminal.",
+ "python.terminal.launchArgs.description": "Python launch arguments to use when executing a file in the terminal.",
+ "python.testing.autoTestDiscoverOnSaveEnabled.description": "Enable auto run test discovery when saving a test file.",
+ "python.testing.autoTestDiscoverOnSavePattern.description": "Glob pattern used to determine which files are used by autoTestDiscoverOnSaveEnabled.",
+ "python.testing.cwd.description": "Optional working directory for tests.",
+ "python.testing.debugPort.description": "Port number used for debugging of tests.",
+ "python.testing.promptToConfigure.description": "Prompt to configure a test framework if potential tests directories are discovered.",
+ "python.testing.pytestArgs.description": "Arguments passed in. Each argument is a separate item in the array.",
+ "python.testing.pytestEnabled.description": "Enable testing using pytest.",
+ "python.testing.pytestPath.description": "Path to pytest. You can use a custom version of pytest by modifying this setting to include the full path.",
+ "python.testing.unittestArgs.description": "Arguments passed in. Each argument is a separate item in the array.",
+ "python.testing.unittestEnabled.description": "Enable testing using unittest.",
+ "python.venvFolders.description": "Folders in your home directory to look into for virtual environments (supports pyenv, direnv and virtualenvwrapper by default).",
+ "python.venvPath.description": "Path to folder with a list of Virtual Environments (e.g. ~/.pyenv, ~/Envs, ~/.virtualenvs).",
+ "walkthrough.pythonWelcome.title": "Get Started with Python Development",
+ "walkthrough.pythonWelcome.description": "Your first steps to set up a Python project with all the powerful tools and features that the Python extension has to offer!",
+ "walkthrough.step.python.createPythonFile.title": "Create a Python file",
+ "walkthrough.step.python.createPythonFolder.title": "Open a Python project folder",
+ "walkthrough.step.python.createPythonFile.description": {
+ "message": "[Open](command:toSide:workbench.action.files.openFile) or [create](command:toSide:workbench.action.files.newUntitledFile?%7B%22languageId%22%3A%22python%22%7D) a Python file - make sure to save it as \".py\".\n[Create Python File](command:toSide:workbench.action.files.newUntitledFile?%7B%22languageId%22%3A%22python%22%7D)",
+ "comment": [
+ "{Locked='](command:toSide:workbench.action.files.newUntitledFile?%7B%22languageId%22%3A%22python%22%7D'}",
+ "Do not translate the 'command:*' part inside of the '(..)'. It is an internal command syntax for VS Code",
+ "Please make sure there is no space between the right bracket and left parenthesis: ]( this is an internal syntax for links"
+ ]
+ },
+ "walkthrough.step.python.createPythonFolder.description": {
+ "message": "[Open](command:workbench.action.files.openFolder) or create a project folder.\n[Open Project Folder](command:workbench.action.files.openFolder)",
+ "comment": [
+ "{Locked='](command:workbench.action.files.openFolder'}",
+ "Do not translate the 'command:*' part inside of the '(..)'. It is an internal command syntax for VS Code",
+ "Please make sure there is no space between the right bracket and left parenthesis: ]( this is an internal syntax for links"
+ ]
+ },
+ "walkthrough.step.python.installPythonWin8.title": "Install Python",
+ "walkthrough.step.python.installPythonWin8.description": "The Python Extension requires Python to be installed. Install Python [from python.org](https://www.python.org/downloads).\n\n[Install Python](https://www.python.org/downloads)\n",
+ "walkthrough.step.python.installPythonMac.title": "Install Python",
+ "walkthrough.step.python.installPythonMac.description": {
+ "message": "The Python Extension requires Python to be installed. Install Python 3 through the terminal.\n[Install Python via Brew](command:python.installPythonOnMac)\n",
+ "comment": [
+ "{Locked='](command:python.installPythonOnMac'}",
+ "Do not translate the 'command:*' part inside of the '(..)'. It is an internal command syntax for VS Code",
+ "Please make sure there is no space between the right bracket and left parenthesis: ]( this is an internal syntax for links"
+ ]
+ },
+ "walkthrough.step.python.installPythonLinux.title": "Install Python",
+ "walkthrough.step.python.installPythonLinux.description": {
+ "message": "The Python Extension requires Python to be installed. Install Python 3 through the terminal.\n[Install Python via terminal](command:python.installPythonOnLinux)\n",
+ "comment": [
+ "{Locked='](command:python.installPythonOnLinux'}",
+ "Do not translate the 'command:*' part inside of the '(..)'. It is an internal command syntax for VS Code",
+ "Please make sure there is no space between the right bracket and left parenthesis: ]( this is an internal syntax for links"
+ ]
+ },
+ "walkthrough.step.python.selectInterpreter.title": "Select a Python Interpreter",
+ "walkthrough.step.python.createEnvironment.title": "Select or create a Python environment",
+ "walkthrough.step.python.createEnvironment.description": {
+ "message": "Create an environment for your Python project or use [Select Python Interpreter](command:python.setInterpreter) to select an existing one.\n[Create Environment](command:python.createEnvironment)\n**Tip**: Run the ``Python: Create Environment`` command in the [Command Palette](command:workbench.action.showCommands).",
+ "comment": [
+ "{Locked='](command:python.createEnvironment'}",
+ "{Locked='](command:workbench.action.showCommands'}",
+ "{Locked='](command:python.setInterpreter'}",
+ "Do not translate the 'command:*' part inside of the '(..)'. It is an internal command syntax for VS Code",
+ "Please make sure there is no space between the right bracket and left parenthesis: ]( this is an internal syntax for links"
+ ]
+ },
+ "walkthrough.step.python.runAndDebug.title": "Run and debug your Python file",
+ "walkthrough.step.python.runAndDebug.description": "Open your Python file and click on the play button on the top right of the editor, or press F5 when on the file and select \"Python File\" to run with the debugger. \n \n[Learn more](https://code.visualstudio.com/docs/python/python-tutorial#_run-hello-world)",
+ "walkthrough.step.python.learnMoreWithDS.title": "Keep exploring!",
+ "walkthrough.step.python.learnMoreWithDS.description": {
+ "message": "🎨 Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands). \n 📈 Learn more about getting started with [data science](command:workbench.action.openWalkthrough?%7B%22category%22%3A%22ms-python.python%23pythonDataScienceWelcome%22%2C%22step%22%3A%22ms-python.python%23python.createNewNotebook%22%7D) in Python. \n ✨ Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features. \n \n[Follow along with the Python Tutorial](https://aka.ms/AA8dqti)",
+ "comment": [
+ "{Locked='](command:workbench.action.showCommands'}",
+ "{Locked='](command:workbench.action.openWalkthrough?%7B%22category%22%3A%22ms-python.python%23pythonDataScienceWelcome%22%2C%22step%22%3A%22ms-python.python%23python.createNewNotebook%22%7D'}",
+ "Do not translate the 'command:*' part inside of the '(..)'. It is an internal command syntax for VS Code",
+ "Please make sure there is no space between the right bracket and left parenthesis: ]( this is an internal syntax for links"
+ ]
+ },
+ "walkthrough.pythonDataScienceWelcome.title": "Get Started with Python for Data Science",
+ "walkthrough.pythonDataScienceWelcome.description": "Your first steps to getting started with a Data Science project with Python!",
+ "walkthrough.step.python.installJupyterExt.title": "Install Jupyter extension",
+ "walkthrough.step.python.installJupyterExt.description": "If you haven't already, install the [Jupyter extension](command:workbench.extensions.search?\"ms-toolsai.jupyter\") to take full advantage of notebooks experiences in VS Code!\n \n[Search Jupyter extension](command:workbench.extensions.search?\"ms-toolsai.jupyter\")",
+ "walkthrough.step.python.createNewNotebook.title": "Create or open a Jupyter Notebook",
+ "walkthrough.step.python.createNewNotebook.description": "Right click in the file explorer and create a new file with an .ipynb extension. Or, open the [Command Palette](command:workbench.action.showCommands) and run the command \n``Jupyter: Create New Blank Notebook``.\n[Create new Jupyter Notebook](command:toSide:jupyter.createnewnotebook)\n If you have an existing project, you can also [open a folder](command:workbench.action.files.openFolder) and/or clone a project from GitHub: [clone a Git repository](command:git.clone).",
+ "walkthrough.step.python.openInteractiveWindow.title": "Open the Python Interactive Window",
+ "walkthrough.step.python.openInteractiveWindow.description": "The Python Interactive Window is a Python shell where you can execute and view the results of your Python code. You can create cells on a Python file by typing ``#%%``.\n \nTo open the interactive window anytime, open the [Command Palette](command:workbench.action.showCommands) and run the command \n``Jupyter: Create Interactive Window``.\n[Open Interactive Window](command:jupyter.createnewinteractive)",
+ "walkthrough.step.python.dataScienceLearnMore.title": "Find out more!",
+ "walkthrough.step.python.dataScienceLearnMore.description": "📒 Take a look into the [Jupyter extension](command:workbench.extensions.search?\"ms-toolsai.jupyter\") features, by looking for \"Jupyter\" in the [Command Palette](command:workbench.action.showCommands). \n 🏃🏻 Find out more features in our [Tutorials](https://aka.ms/AAdjzpd). \n[Learn more](https://aka.ms/AAdar6q)",
+ "walkthrough.step.python.createPythonFile.altText": "Open a Python file or a folder with a Python project.",
+ "walkthrough.step.python.selectInterpreter.altText": "Selecting a Python interpreter from the status bar",
+ "walkthrough.step.python.createEnvironment.altText": "Creating a Python environment from the Command Palette",
+ "walkthrough.step.python.runAndDebug.altText": "How to run and debug in VS Code with F5 or the play button on the top right.",
+ "walkthrough.step.python.learnMoreWithDS.altText": "Image representing our documentation page and mailing list resources.",
+ "walkthrough.step.python.installJupyterExt.altText": "Creating a new Jupyter notebook",
+ "walkthrough.step.python.createNewNotebook.altText": "Creating a new Jupyter notebook",
+ "walkthrough.step.python.openInteractiveWindow.altText": "Opening Python interactive window",
+ "walkthrough.step.python.dataScienceLearnMore.altText": "Image representing our documentation page and mailing list resources."
}
diff --git a/package.nls.ko-kr.json b/package.nls.ko-kr.json
deleted file mode 100644
index 5309a9b07b81..000000000000
--- a/package.nls.ko-kr.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "python.command.python.sortImports.title": "Import문 정렬",
- "python.command.python.startREPL.title": "REPL 시작",
- "python.command.python.buildWorkspaceSymbols.title": "작업 영역 기호 빌드",
- "python.command.python.runtests.title": "모든 단위 테스트 실행",
- "python.command.python.debugtests.title": "모든 단위 테스트 디버그",
- "python.command.python.execInTerminal.title": "터미널에서 Python 파일 실행",
- "python.command.python.setInterpreter.title": "인터프리터 선택",
- "python.command.python.refactorExtractVariable.title": "변수 추출",
- "python.command.python.refactorExtractMethod.title": "메서드 추출",
- "python.command.python.viewTestOutput.title": "단위 테스트 결과 보기",
- "python.command.python.selectAndRunTestMethod.title": "단위 테스트 메서드 실행 ...",
- "python.command.python.selectAndDebugTestMethod.title": "단위 테스트 메서드 디버그 ...",
- "python.command.python.selectAndRunTestFile.title": "단위 테스트 파일 실행 ...",
- "python.command.python.runCurrentTestFile.title": "현재 단위 테스트 파일 실행",
- "python.command.python.runFailedTests.title": "실패한 단위 테스트 실행",
- "python.command.python.execSelectionInTerminal.title": "Python 터미널에서 선택 영역/줄 실행",
- "python.command.python.execSelectionInDjangoShell.title": "Django 셸에서 선택 영역/줄 실행",
- "python.command.python.goToPythonObject.title": " Python 객체로 이동",
- "python.snippet.launch.standard.label": "Python: Current File",
- "python.snippet.launch.module.label": "Python: 모듈",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Pyramid 응용 프로그램",
- "python.snippet.launch.attach.label": "Python: 연결"
-}
diff --git a/package.nls.nl.json b/package.nls.nl.json
deleted file mode 100644
index 08c9534dc962..000000000000
--- a/package.nls.nl.json
+++ /dev/null
@@ -1,83 +0,0 @@
-{
- "python.command.python.sortImports.title": "Import sorteren",
- "python.command.python.startREPL.title": "REPL starten",
- "python.command.python.createTerminal.title": "Terminal aanmaken",
- "python.command.python.buildWorkspaceSymbols.title": "Werkruimte-symbolen aanmaken",
- "python.command.python.runtests.title": "Alle unittests uitvoeren",
- "python.command.python.debugtests.title": "Alle unittests debuggen",
- "python.command.python.execInTerminal.title": "Python-bestand in terminal uitvoeren",
- "python.command.python.setInterpreter.title": "Interpreter selecteren",
- "python.command.python.refactorExtractVariable.title": "Variabelen selecteren",
- "python.command.python.refactorExtractMethod.title": "Methode selecteren",
- "python.command.python.viewTestOutput.title": "Unittest-resultaat laten zien",
- "python.command.python.selectAndRunTestMethod.title": "Unittest-methode uitvoeren ...",
- "python.command.python.selectAndDebugTestMethod.title": "Unittest-methode debuggen ...",
- "python.command.python.selectAndRunTestFile.title": "Unittest-bestand uitvoeren ...",
- "python.command.python.runCurrentTestFile.title": "Huidige unittest-bestand uitvoeren",
- "python.command.python.runFailedTests.title": "Gefaalde unittests uitvoeren",
- "python.command.python.discoverTests.title": "Unittests doorzoeken",
- "python.command.python.execSelectionInTerminal.title": "Selectie/rij in Python-terminal uitvoeren",
- "python.command.python.execSelectionInDjangoShell.title": "Selectie/rij in Django-shell uitvoeren",
- "python.command.python.goToPythonObject.title": "Naar Python-object gaan",
- "python.command.python.setLinter.title": "Linter selecteren",
- "python.command.python.enableLinting.title": "Linting activeren",
- "python.command.python.runLinting.title": "Linting uitvoeren",
- "python.command.python.enableSourceMapSupport.title": "Bronkaartondersteuning voor extensie-debugging inschakelen",
- "python.snippet.launch.standard.label": "Python: Huidige bestand",
- "python.snippet.launch.module.label": "Python: Module",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Pyramid-applicatie",
- "python.snippet.launch.attach.label": "Python: aankoppelen",
- "ExtensionSurveyBanner.bannerLabelYes": "Ja, neem nu deel aan het onderzoek",
- "ExtensionSurveyBanner.bannerLabelNo": "Nee, bedankt",
- "LanguageService.lsFailedToStart": "We zijn een probleem tegengekomen bij het starten van de language server. Aan het terugschakelen naar het alternatief, Jedi. Bekijk het weergavepaneel voor details.",
- "LanguageService.lsFailedToDownload": "We zijn een probleem tegengekomen bij het downloaden van de language server. Aan het terugschakelen naar het alternatief, Jedi. Bekijk het weergavepaneel voor details.",
- "LanguageService.lsFailedToExtract": "We zijn een probleem tegengekomen bij het uitpakken van de language server. Aan het terugschakelen naar het alternatief, Jedi. Bekijk het weergavepaneel voor details.",
- "Interpreters.RefreshingInterpreters": "Python-Interpreters verversen",
- "Interpreters.LoadingInterpreters": "Python-Interpreters laden",
- "Linter.InstalledButNotEnabled": "Linter {0} is geinstalleerd maar niet ingeschakeld.",
- "Linter.replaceWithSelectedLinter": "Meerdere linters zijn ingeschakeld in de instellingen. Vervangen met '{0}'?",
- "diagnostics.warnSourceMaps": "Bronkaartondersteuning is ingeschakeld in de Python-extensie, dit zal een ongunstige impact hebben op de uitvoering van de extensie.",
- "diagnostics.disableSourceMaps": "Bronkaartondersteuning uitschakelen",
- "diagnostics.warnBeforeEnablingSourceMaps": "Bronkaartondersteuning inschakelen in de Python-extensie zal een ongunstige impact hebben op de uitvoering van de extensie.",
- "diagnostics.enableSourceMapsAndReloadVSC": "Venster inschakelen en herladen",
- "diagnostics.lsNotSupported": "Uw besturingssysteem voldoet niet aan de minimumeisen van de language server. Aan het terugschakelen naar het alternatief, Jedi.",
- "Common.canceled": "Geannuleerd",
- "Common.loadingPythonExtension": "Python-extensie aan het laden...",
- "debug.selectConfigurationTitle": "Een debug-configuratie selecteren",
- "debug.selectConfigurationPlaceholder": "Debug-configuratie",
- "debug.debugFileConfigurationLabel": "Python-bestand",
- "debug.debugFileConfigurationDescription": "Python-bestand debuggen",
- "debug.debugModuleConfigurationLabel": "Module",
- "debug.debugModuleConfigurationDescription": "Python module/package debuggen",
- "debug.remoteAttachConfigurationLabel": "Extern aankoppelen",
- "debug.remoteAttachConfigurationDescription": "Een externe Python-applicatie debuggen",
- "debug.debugDjangoConfigurationLabel": "Django",
- "debug.debugDjangoConfigurationDescription": "Web-applicatie",
- "debug.debugFlaskConfigurationLabel": "Flask",
- "debug.debugFlaskConfigurationDescription": "Web-applicatie",
- "debug.debugPyramidConfigurationLabel": "Pyramid",
- "debug.debugPyramidConfigurationDescription": "Web-applicatie",
- "debug.djangoEnterManagePyPathTitle": "Django debuggen",
- "debug.djangoEnterManagePyPathPrompt": "Voer een pad in naar manage.py ('${workspaceFolderToken}' verwijzen naar de root van de huidige werkruimtemap)",
- "debug.djangoEnterManagePyPathInvalidFilePathError": "Voer een geldig Python-bestandspad in",
- "debug.flaskEnterAppPathOrNamePathTitle": "Flask debuggen",
- "debug.flaskEnterAppPathOrNamePathPrompt": "Voer een pad in naar een applicatie, bijvoorbeeld 'app.py' of 'app'",
- "debug.flaskEnterAppPathOrNamePathInvalidNameError": "Voer een geldige naam in",
- "debug.moduleEnterModuleTitle": "Module debuggen",
- "debug.moduleEnterModulePrompt": "Voer Python module/package naam in",
- "debug.moduleEnterModuleInvalidNameError": "Voer een geldige naam in",
- "debug.pyramidEnterDevelopmentIniPathTitle": "Pyramid debuggen",
- "debug.pyramidEnterDevelopmentIniPathPrompt": "`Voer een pad in naar development.ini ('${workspaceFolderToken}' verwijzen naar de root van de huidige werkruimtemap)`",
- "debug.pyramidEnterDevelopmentIniPathInvalidFilePathError": "Voer een geldig bestandspad in",
- "debug.attachRemotePortTitle": "Extern debuggen",
- "debug.attachRemotePortPrompt": "Voer een port-nummer in",
- "debug.attachRemotePortValidationError": "Voer een geldig port-nummer in",
- "debug.attachRemoteHostTitle": "Extern debuggen",
- "debug.attachRemoteHostPrompt": "Voer een hostname of IP-adres in",
- "debug.attachRemoteHostValidationError": "Voer een geldige hostname of IP-adres in",
- "Testing.testErrorDiagnosticMessage": "Error",
- "Testing.testFailDiagnosticMessage": "Mislukt",
- "Testing.testSkippedDiagnosticMessage": "Overgeslagen"
-}
diff --git a/package.nls.pl.json b/package.nls.pl.json
deleted file mode 100644
index 00f186f2ebab..000000000000
--- a/package.nls.pl.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "python.command.python.sortImports.title": "Sortuj importy",
- "python.command.python.startREPL.title": "Uruchom REPL",
- "python.command.python.createTerminal.title": "Otwórz Terminal",
- "python.command.python.buildWorkspaceSymbols.title": "Zbuduj symbole dla przestrzeni roboczej",
- "python.command.python.runtests.title": "Uruchom wszystkie testy jednostkowe",
- "python.command.python.debugtests.title": "Debuguj wszystkie testy jednostkowe",
- "python.command.python.execInTerminal.title": "Uruchom plik pythonowy w terminalu",
- "python.command.python.setInterpreter.title": "Wybierz wersję interpretera",
- "python.command.python.refactorExtractVariable.title": "Wyodrębnij zmienną",
- "python.command.python.refactorExtractMethod.title": "Wyodrębnij metodę",
- "python.command.python.viewOutput.title": "Pokaż wyniki",
- "python.command.python.viewTestOutput.title": "Pokaż wyniki testów jednostkowych",
- "python.command.python.selectAndRunTestMethod.title": "Uruchom metodę testów jednostkowych ...",
- "python.command.python.selectAndDebugTestMethod.title": "Debuguj metodę testów jednostkowych ...",
- "python.command.python.selectAndRunTestFile.title": "Uruchom plik z testami jednostkowymi ...",
- "python.command.python.runCurrentTestFile.title": "Uruchom bieżący plik z testami jednostkowymi",
- "python.command.python.runFailedTests.title": "Uruchom testy jednostkowe, które się nie powiodły",
- "python.command.python.discoverTests.title": "Wyszukaj testy jednostkowe",
- "python.command.python.configureTests.title": "Konfiguruj testy jednostkowe",
- "python.command.python.execSelectionInTerminal.title": "Uruchom zaznaczony obszar w interpreterze Pythona",
- "python.command.python.execSelectionInDjangoShell.title": "Uruchom zaznaczony obszar w powłoce Django",
- "python.command.python.goToPythonObject.title": "Idź do obiektu pythonowego",
- "python.command.python.setLinter.title": "Wybierz linter",
- "python.command.python.enableLinting.title": "Włącz linting",
- "python.command.python.runLinting.title": "Uruchom linting",
- "python.command.python.enableSourceMapSupport.title": "Włącz obsługę map źródłowych do debugowania rozszerzeń"
-}
diff --git a/package.nls.pt-br.json b/package.nls.pt-br.json
deleted file mode 100644
index 1acc94053ca0..000000000000
--- a/package.nls.pt-br.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "python.command.python.sortImports.title": "Ordenar Importações",
- "python.command.python.startREPL.title": "Iniciar REPL",
- "python.command.python.createTerminal.title": "Criar Terminal",
- "python.command.python.buildWorkspaceSymbols.title": "Construir Símbolos da Área de Trabalho",
- "python.command.python.runtests.title": "Executar Todos os Testes Unitários",
- "python.command.python.debugtests.title": "Depurar Todos os Testes Unitários",
- "python.command.python.execInTerminal.title": "Executar Arquivo no Terminal",
- "python.command.python.setInterpreter.title": "Selecionar Interpretador",
- "python.command.python.refactorExtractVariable.title": "Extrair Variável",
- "python.command.python.refactorExtractMethod.title": "Extrair Método",
- "python.command.python.viewTestOutput.title": "Exibir Resultados dos Testes Unitários",
- "python.command.python.selectAndRunTestMethod.title": "Executar Testes Unitários do Método ...",
- "python.command.python.selectAndDebugTestMethod.title": "Depurar Testes Unitários do Método ...",
- "python.command.python.selectAndRunTestFile.title": "Executar Arquivo de Testes Unitários ...",
- "python.command.python.runCurrentTestFile.title": "Executar o Arquivo de Testes Unitários Atual",
- "python.command.python.runFailedTests.title": "Executar Testes Unitários com Falhas",
- "python.command.python.discoverTests.title": "Descobrir Testes Unitários",
- "python.command.python.execSelectionInTerminal.title": "Executar Seleção/Linha no Terminal",
- "python.command.python.execSelectionInDjangoShell.title": "Executar Seleção/Linha no Django Shell",
- "python.command.python.goToPythonObject.title": "Ir para Objeto Python",
- "python.command.python.setLinter.title": "Selecionar Linter",
- "python.command.python.enableLinting.title": "Habilitar Linting",
- "python.command.python.runLinting.title": "Executar Linting",
- "python.snippet.launch.standard.label": "Python: Arquivo Atual",
- "python.snippet.launch.module.label": "Python: Módulo",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Aplicação Pyramid",
- "python.snippet.launch.attach.label": "Python: Anexar"
-}
diff --git a/package.nls.ru.json b/package.nls.ru.json
deleted file mode 100644
index 0a80260e6644..000000000000
--- a/package.nls.ru.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "python.command.python.sortImports.title": "Отсортировать Imports",
- "python.command.python.startREPL.title": "Открыть REPL",
- "python.command.python.buildWorkspaceSymbols.title": "Собрать символы рабочего пространства",
- "python.command.python.runtests.title": "Запустить все тесты",
- "python.command.python.debugtests.title": "Запустить все тесты под отладчиком",
- "python.command.python.execInTerminal.title": "Выполнить файл в консоли",
- "python.command.python.setInterpreter.title": "Выбрать интерпретатор",
- "python.command.python.refactorExtractVariable.title": "Извлечь в переменную",
- "python.command.python.refactorExtractMethod.title": "Извлечь в метод",
- "python.command.python.viewTestOutput.title": "Показать вывод теста",
- "python.command.python.selectAndRunTestMethod.title": "Запусть тестовый метод...",
- "python.command.python.selectAndDebugTestMethod.title": "Отладить тестовый метод...",
- "python.command.python.selectAndRunTestFile.title": "Запустить тестовый файл...",
- "python.command.python.runCurrentTestFile.title": "Запустить текущий тестовый файл",
- "python.command.python.runFailedTests.title": "Запустить непрошедшие тесты",
- "python.command.python.discoverTests.title": "Обнаружить тесты",
- "python.command.python.execSelectionInTerminal.title": "Выполнить выбранный текст или текущую строку в консоли",
- "python.command.python.execSelectionInDjangoShell.title": "Выполнить выбранный текст или текущую строку в оболочке Django",
- "python.command.python.goToPythonObject.title": "Перейти к объекту Python",
- "python.command.python.setLinter.title": "Выбрать анализатор кода",
- "python.command.python.enableLinting.title": "Включить анализатор кода",
- "python.command.python.runLinting.title": "Выполнить анализ кода",
- "python.snippet.launch.standard.label": "Python: Текущий файл",
- "python.snippet.launch.module.label": "Python: Модуль",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Приложение Pyramid",
- "python.snippet.launch.attach.label": "Python: Подключить отладчик",
- "ExtensionSurveyBanner.bannerLabelYes": "Да, открыть опрос сейчас",
- "ExtensionSurveyBanner.bannerLabelNo": "Нет, спасибо",
- "ExtensionSurveyBanner.maybeLater": "Может быть, позже",
- "ExtensionSurveyBanner.bannerMessage": "Не могли бы вы потратить пару минут на опрос о языковом сервере Pylance?",
- "Pylance.proposePylanceMessage": "Попробуйте новый языковый сервер для Python от Microsoft: Pylance! Установите расширение Pylance.",
- "Pylance.tryItNow": "Да, хочу",
- "Pylance.remindMeLater": "Напомните позже",
- "Pylance.pylanceNotInstalledMessage": "Расширение Pylance не установлено.",
- "Pylance.pylanceInstalledReloadPromptMessage": "Расширение Pylance установлено. Перезагрузить окно для его активации?",
- "LanguageService.reloadAfterLanguageServerChange": "Пожалуйста, перезагрузите окно после смены типа языкового сервера."
-}
diff --git a/package.nls.tr.json b/package.nls.tr.json
deleted file mode 100644
index 0e648bb38fdf..000000000000
--- a/package.nls.tr.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "python.command.python.sortImports.title": "Import İfadelerini Sırala",
- "python.command.python.startREPL.title": "REPL Başlat",
- "python.command.python.createTerminal.title": "Terminal Oluştur",
- "python.command.python.buildWorkspaceSymbols.title": "Çalışma Alanındaki Sembolleri Derle",
- "python.command.python.runtests.title": "Testleri Çalıştır",
- "python.command.python.debugtests.title": "Testleri Debug Et",
- "python.command.python.execInTerminal.title": "Terminalde Çalıştır",
- "python.command.python.setInterpreter.title": "Bir Interpreter Seçin",
- "python.command.python.refactorExtractVariable.title": "Değişken Çıkar",
- "python.command.python.refactorExtractMethod.title": "Metot Çıkar",
- "python.command.python.viewTestOutput.title": "Test Çıktısını Görüntüle",
- "python.command.python.selectAndRunTestMethod.title": "Test Metodu Çalıştır",
- "python.command.python.selectAndDebugTestMethod.title": "Test Metodu Debug Et",
- "python.command.python.selectAndRunTestFile.title": "Bir Test Dosyası Seç ve Çalıştır",
- "python.command.python.runCurrentTestFile.title": "Aktif Test Dosyasını Çalıştır",
- "python.command.python.runFailedTests.title": "Başarısız Testleri Çalıştır",
- "python.command.python.discoverTests.title": "Testleri Keşfet",
- "python.command.python.discoveringTests.title": "Testler Keşfediliyor...",
- "python.command.python.execSelectionInTerminal.title": "Seçimi/Satırı Terminalde Çalıştır",
- "python.command.python.execSelectionInDjangoShell.title": "Seçimi/Satırı Django Shell'inde Çalıştır",
- "python.command.python.goToPythonObject.title": "Python Nesnesine Git",
- "python.command.python.setLinter.title": "Bir Linter Seç",
- "python.command.python.enableLinting.title": "Linting'i Aktifleştir",
- "python.command.python.runLinting.title": "Linter Çalıştır",
- "python.snippet.launch.standard.label": "Python: Geçerli Dosya",
- "python.snippet.launch.module.label": "Python: Modül",
- "python.snippet.launch.module.default": "modül-adını-yazın",
- "python.snippet.launch.attach.label": "Python: Remote Attach",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Pyramid Uygulaması"
-}
diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json
deleted file mode 100644
index a645a0ae600c..000000000000
--- a/package.nls.zh-cn.json
+++ /dev/null
@@ -1,237 +0,0 @@
-{
- "python.command.python.sortImports.title": "排序 import 语句",
- "python.command.python.startREPL.title": "启动 REPL",
- "python.command.python.createTerminal.title": "创建终端",
- "python.command.python.buildWorkspaceSymbols.title": "构建工作区符号",
- "python.command.python.runtests.title": "运行所有单元测试",
- "python.command.python.debugtests.title": "调试所有单元测试",
- "python.command.python.execInTerminal.title": "在终端中运行 Python 文件",
- "python.command.python.setInterpreter.title": "选择解释器",
- "python.command.python.switchOffInsidersChannel.title": "切换到默认版本",
- "python.command.python.switchToDailyChannel.title": "切换到每日预览版本",
- "python.command.python.switchToWeeklyChannel.title": "切换到每周预览版本",
- "python.command.python.clearWorkspaceInterpreter.title": "清除工作区解释器设置",
- "python.command.python.resetInterpreterSecurityStorage.title": "重置已存储的未受信任解释器的信息",
- "python.command.python.refactorExtractVariable.title": "提取变量",
- "python.command.python.refactorExtractMethod.title": "提取方法",
- "python.command.python.viewOutput.title": "显示输出",
- "python.command.python.viewTestOutput.title": "显示单元测试输出",
- "python.command.python.viewLanguageServerOutput.title": "显示语言服务器输出",
- "python.command.python.selectAndRunTestMethod.title": "运行单元测试方法...",
- "python.command.python.selectAndDebugTestMethod.title": "调试单元测试方法...",
- "python.command.python.selectAndRunTestFile.title": "运行单元测试文件...",
- "python.command.python.runCurrentTestFile.title": "运行当前单元测试文件",
- "python.command.python.runFailedTests.title": "运行失败的单元测试",
- "python.command.python.discoverTests.title": "检测单元测试",
- "python.command.python.discoveringTests.title": "检测中...",
- "python.command.python.stopTests.title": "停止",
- "python.command.python.configureTests.title": "配置单元测试",
- "python.command.python.execSelectionInTerminal.title": "在 Python 终端中运行选定内容/行",
- "python.command.python.execSelectionInDjangoShell.title": "在 Django Shell 中运行选定内容/行",
- "python.command.python.goToPythonObject.title": "转到 Python 对象",
- "python.command.python.setLinter.title": "选择代码检查器",
- "python.command.python.enableLinting.title": "启用代码检查",
- "python.command.python.runLinting.title": "执行代码检查",
- "python.command.python.enableSourceMapSupport.title": "为扩展调试启用 Source Map 支持",
- "python.command.python.startPage.open.title": "打开起始页",
- "python.command.python.analysis.clearCache.title": "清除模块分析缓存",
- "python.command.python.analysis.restartLanguageServer.title": "重启语言服务器",
- "python.command.python.launchTensorBoard.title": "启动 TensorBoard",
- "python.snippet.launch.standard.label": "Python: 当前文件",
- "python.snippet.launch.module.label": "Python: 模块",
- "python.snippet.launch.module.default": "请输入模块名称",
- "python.snippet.launch.attach.label": "Python: 远程连接",
- "python.snippet.launch.attachpid.label": "Python: 使用 PID 连接",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.fastapi.label": "Python: FastAPI",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Pyramid 应用",
- "Pylance.proposePylanceMessage": "试试微软新的更快的、功能丰富的语言服务器 Pylance! ",
- "Pylance.tryItNow": "立即安装",
- "Pylance.remindMeLater": "稍后提醒",
- "Pylance.pylanceNotInstalledMessage": "Pylance 扩展未安装。",
- "Pylance.pylanceInstalledReloadPromptMessage": "Pylance 扩展未安装。重新加载窗口以激活?",
- "Experiments.inGroup": "用户属于 '{0}' 实验组",
- "Interpreters.RefreshingInterpreters": "正在刷新 Python 解释器",
- "Interpreters.entireWorkspace": "完整工作区",
- "Interpreters.pythonInterpreterPath": "Python 解释器路径: {0}",
- "Interpreters.LoadingInterpreters": "正在加载 Python 解释器",
- "Interpreters.unsafeInterpreterMessage": "此工作区中有一个 Python 环境,是否启用它来激活扩展中的功能?请在信任此环境时启用。",
- "Interpreters.condaInheritEnvMessage": "您正在使用 conda 环境,如果您在集成终端中遇到相关问题,建议您允许 Python 扩展将用户设置中的 \"terminal.integrated.inheritEnv\" 改为 false。",
- "Logging.CurrentWorkingDirectory": "cwd:",
- "InterpreterQuickPickList.quickPickListPlaceholder": "当前: {0}",
- "InterpreterQuickPickList.enterPath.detail": "输入路径或选择一个现有的解释器",
- "InterpreterQuickPickList.enterPath.label": "输入解释器路径...",
- "InterpreterQuickPickList.enterPath.placeholder": "请输入 Python 解释器的路径。",
- "InterpreterQuickPickList.browsePath.label": "浏览...",
- "InterpreterQuickPickList.browsePath.detail": "浏览文件系统来选择一个 Python 解释器。",
- "InterpreterQuickPickList.browsePath.title": "选择 Python 解释器",
- "diagnostics.upgradeCodeRunner": "请更新 Code Runner 扩展,使其与 Python 扩展兼容。",
- "Common.bannerLabelYes": "是",
- "Common.bannerLabelNo": "否",
- "Common.doNotShowAgain": "不再提示",
- "Common.reload": "重新加载",
- "Common.moreInfo": "更多信息",
- "Common.and": "和",
- "Common.ok": "好的",
- "Common.install": "安装",
- "Common.learnMore": "了解更多",
- "Common.reportThisIssue": "反馈此问题",
- "CommonSurvey.remindMeLaterLabel": "稍后提醒",
- "CommonSurvey.yesLabel": "是的,现在接受调查",
- "CommonSurvey.noLabel": "不,谢谢",
- "OutputChannelNames.languageServer": "Python 语言服务器",
- "OutputChannelNames.python": "Python",
- "OutputChannelNames.pythonTest": "Python 测试日志",
- "ExtensionSurveyBanner.bannerMessage": "请您花两分钟的时间告诉我们 Python 扩展是否正常工作?",
- "ExtensionSurveyBanner.bannerLabelYes": "是的,现在接受调查",
- "ExtensionSurveyBanner.bannerLabelNo": "不,谢谢",
- "ExtensionSurveyBanner.maybeLater": "稍后提醒",
- "ExtensionChannels.installingInsidersMessage": "正在安装预览版... ",
- "ExtensionChannels.installingStableMessage": "正在安装稳定版... ",
- "ExtensionChannels.installationCompleteMessage": "完成。",
- "ExtensionChannels.downloadingInsidersMessage": "正在下载预览版... ",
- "ExtensionChannels.yesWeekly": "是,每周版",
- "ExtensionChannels.yesDaily": "是,每日版",
- "ExtensionChannels.promptMessage": "您正在使用 Visual Studio Code 预览版,是否安装 Python 扩展的预览版?",
- "ExtensionChannels.reloadToUseInsidersMessage": "请重新加载 Visual Studio Code 以使用 Python 扩展的预览版。",
- "ExtensionChannels.downloadCompletedOutputMessage": "预览版下载完成。",
- "ExtensionChannels.startingDownloadOutputMessage": "开始下载预览版。",
- "Interpreters.environmentPromptMessage": "检测到新的虚拟环境,是否在此工作区中使用它?",
- "Linter.enableLinter": "启用 {0}",
- "Linter.enablePylint": "该工作区有一个 pylintrc 文件,是否启用 pylint?",
- "Linter.replaceWithSelectedLinter": "设置中启用了多个代码检查器,是否用 '{0}' 替换?",
- "Linter.install": "请安装一个代码检查器以获得错误报告。",
- "Linter.installPylint": "安装 pylint",
- "Linter.installFlake8": "安装 flake8",
- "Linter.selectLinter": "选择代码检查器",
- "Installer.noCondaOrPipInstaller": "所选环境中没有可用的 Conda 或 pip 安装器。",
- "Installer.noPipInstaller": "所选环境中没有可用的 pip 安装器。",
- "Installer.searchForHelp": "搜索帮助",
- "Installer.couldNotInstallLibrary": "无法安装 {0} 。如果 pip 不可用,请使用选择的包管理器手动将此库安装到您的 Python 环境中。",
- "Installer.dataScienceInstallPrompt": "数据科学库 {0} 未安装,是否安装?",
- "diagnostics.removedPythonPathFromSettings": "已在 settings.json 文件中删除了 \"python.pythonPath\" ,因为 Python 扩展不再使用该设置。您可以在 Python 输出中获取所选解释器的路径。[了解更多](https://aka.ms/AA7jfor).",
- "diagnostics.warnSourceMaps": "已启用 Source Map 支持,这会影响 Python 扩展的性能。",
- "diagnostics.disableSourceMaps": "禁用 Source Map 支持",
- "diagnostics.warnBeforeEnablingSourceMaps": "启用 Source Map 支持将影响 Python 扩展的性能。",
- "diagnostics.enableSourceMapsAndReloadVSC": "启用并重新加载窗口",
- "diagnostics.lsNotSupported": "该操作系统不符合 Python 语言服务器的最低要求,正在恢复替代的自动补全器 Jedi。",
- "diagnostics.invalidPythonPathInDebuggerSettings": "您需要在开始调试前选择一个 Python 解释器。\n\n提示: 点击状态栏中的 \"选择解释器\"。",
- "diagnostics.invalidPythonPathInDebuggerLaunch": "调试设置中的 Python 路径无效。",
- "diagnostics.invalidDebuggerTypeDiagnostic": "您的 launch.json 文件需要更新,以将 \"pythonExperimental\" 调试设置设为使用 \"python\" 调试器,否则 Python 调试器可能无法工作。立即自动更新 launch.json?",
- "diagnostics.consoleTypeDiagnostic": "您的 launch.json 文件需要更新,以将控制台类型字符串从 \"none\" 改为 \"internalConsole\",否则 Python 调试器可能无法工作。立即自动更新 launch.json?",
- "diagnostics.justMyCodeDiagnostic": "不再支持 launch.json 中的配置 \"debugStdLib\",建议用 \"justMyCode\" 代替,这与使用 \"debugStdLib\" 完全相反。是否自动更新 launch.json?",
- "diagnostics.checkIsort5UpgradeGuide": "此工作区的排序 import 语句配置已过时。查看 [isort 升级指南](https://aka.ms/AA9j5x4) 来更新设置。",
- "diagnostics.yesUpdateLaunch": "是,更新 launch.json",
- "diagnostics.invalidTestSettings": "您的设置需要更新,以将设置 \"python.unitTest.\" 改为 \"python.testing.\",否则使用该扩展测试 Python 代码可能无法工作。是否自动更新设置?",
- "Common.canceled": "已取消",
- "Common.cancel": "取消",
- "Common.yesPlease": "好的",
- "Common.loadingPythonExtension": "Python 扩展正在加载...",
- "debug.selectConfigurationTitle": "选择调试配置",
- "debug.selectConfigurationPlaceholder": "调试配置",
- "debug.launchJsonConfigurationsCompletionLabel": "Python",
- "debug.launchJsonConfigurationsCompletionDescription": "选择 Python 调试配置",
- "debug.debugFileConfigurationLabel": "Python 文件",
- "debug.debugFileConfigurationDescription": "调试打开的 Python 文件",
- "debug.debugModuleConfigurationLabel": "模块",
- "debug.debugModuleConfigurationDescription": "用'-m'调用 Python 模块进行调试",
- "debug.moduleEnterModuleTitle": "调试模块",
- "debug.moduleEnterModulePrompt": "请输入 Python 模块/包名",
- "debug.moduleEnterModuleDefault": "请输入模块名称",
- "debug.moduleEnterModuleInvalidNameError": "请输入有效的模块名称",
- "debug.remoteAttachConfigurationLabel": "远程连接",
- "debug.remoteAttachConfigurationDescription": "连接到远程调试服务器",
- "debug.attachRemoteHostTitle": "远程连接",
- "debug.attachRemoteHostPrompt": "请输入主机名",
- "debug.attachRemoteHostValidationError": "请输入有效的主机名或 IP 地址",
- "debug.attachRemotePortTitle": "远程调试",
- "debug.attachRemotePortPrompt": "请输入调试服务器的监听端口号",
- "debug.attachRemotePortValidationError": "请输入有效的端口号",
- "debug.attachPidConfigurationLabel": "使用 PID 连接",
- "debug.attachPidConfigurationDescription": "连接到本地进程",
- "debug.debugDjangoConfigurationLabel": "Django",
- "debug.debugDjangoConfigurationDescription": "启动并调试 Django Web 应用",
- "debug.djangoEnterManagePyPathTitle": "调试 Django",
- "debug.djangoEnterManagePyPathPrompt": "请输入 manage.py 的路径('${workspaceFolderToken}'指向当前工作区文件夹的根目录)",
- "debug.djangoEnterManagePyPathInvalidFilePathError": "请输入有效的 Python 文件路径",
- "debug.debugFastAPIConfigurationLabel": "FastAPI",
- "debug.debugFastAPIConfigurationDescription": "启动并调试 FastAPI Web 应用",
- "debug.fastapiEnterAppPathOrNamePathTitle": "调试 FastAPI",
- "debug.fastapiEnterAppPathOrNamePathPrompt": "请输入应用路径,例如 'main.py' 或 'main'",
- "debug.fastapiEnterAppPathOrNamePathInvalidNameError": "请输入有效的名称",
- "debug.debugFlaskConfigurationLabel": "Flask",
- "debug.debugFlaskConfigurationDescription": "启动并调试 Flask Web 应用",
- "debug.flaskEnterAppPathOrNamePathTitle": "调试 Flask",
- "debug.flaskEnterAppPathOrNamePathPrompt": "请输入应用路径,例如 'app.py' 或 'app'",
- "debug.flaskEnterAppPathOrNamePathInvalidNameError": "请输入有效的名称",
- "debug.debugPyramidConfigurationLabel": "Pyramid",
- "debug.debugPyramidConfigurationDescription": "Web 应用",
- "debug.pyramidEnterDevelopmentIniPathTitle": "调试 Pyramid",
- "debug.pyramidEnterDevelopmentIniPathPrompt": "`请输入development.ini的路径('${workspaceFolderToken}'指向当前工作区文件夹的根目录)`",
- "debug.pyramidEnterDevelopmentIniPathInvalidFilePathError": "请输入有效的文件路径",
- "Testing.testErrorDiagnosticMessage": "Error",
- "Testing.testFailDiagnosticMessage": "Fail",
- "Testing.testSkippedDiagnosticMessage": "Skipped",
- "Testing.configureTests": "配置单元测试框架",
- "Testing.disableTests": "禁用单元测试",
- "Common.openOutputPanel": "显示输出",
- "LanguageService.lsFailedToStart": "启动语言服务器时出错,正在恢复到 Jedi 语言引擎。查看 Python 输出面板了解详情。",
- "LanguageService.lsFailedToDownload": "下载语言服务器时出错,正在恢复到 Jedi 语言引擎。查看 Python 输出面板了解详情。",
- "LanguageService.lsFailedToExtract": "提取语言服务器时出错,正在恢复到 Jedi 语言引擎。查看 Python 输出面板了解详情。",
- "LanguageService.downloadFailedOutputMessage": "语言服务器下载失败",
- "LanguageService.extractionFailedOutputMessage": "语言服务器提取失败",
- "LanguageService.extractionCompletedOutputMessage": "语言服务器下载完成",
- "LanguageService.extractionDoneOutputMessage": "完成",
- "LanguageService.reloadVSCodeIfSeachPathHasChanged": "该 Python 解释器的搜索路径已改变,请重新加载扩展以确保 IntelliSense 正常工作。",
- "LanguageService.startingJedi": "正在启动 Jedi Python 语言引擎。",
- "LanguageService.startingMicrosoft": "正在启动 Microsoft Python 语言服务器。",
- "LanguageService.startingPylance": "正在启动 Pylance 语言服务器。",
- "LanguageService.startingNone": "由于语言服务器设置为空,编辑器支持处于非活动状态。",
- "LanguageService.reloadAfterLanguageServerChange": "切换语言服务器后请重新加载窗口。",
- "AttachProcess.unsupportedOS": "不支持 '{0}' 操作系统。",
- "AttachProcess.attachTitle": "连接到进程",
- "AttachProcess.selectProcessPlaceholder": "选择要连接的流程",
- "AttachProcess.noProcessSelected": "未选择进程",
- "AttachProcess.refreshList": "刷新进程列表",
- "diagnostics.updateSettings": "是,更新设置",
- "Common.noIWillDoItLater": "稍后再做",
- "Common.notNow": "稍后提醒",
- "Common.gotIt": "好的!",
- "Interpreters.selectInterpreterTip": "提示:您可以通过点击状态栏中的 Python 版本来更改 Python 扩展所使用的 Python 解释器",
- "downloading.file": "正在下载 {0}...",
- "downloading.file.progress": "{2} 中的 {0}{1} KB ({3}%)",
- "products.installingModule": "正在安装 {0}",
- "OutdatedDebugger.updateDebuggerMessage": "您正在连接至 ptvsd (Python 调试器),而 ptvsd 已于2020年5月1日停止更新。请切换至 [debugpy](https://aka.ms/migrateToDebugpy)。",
- "StartPage.getStarted": "Python - 开始",
- "StartPage.pythonExtensionTitle": "Python 扩展",
- "StartPage.createJupyterNotebook": "创建 Jupyter 笔记本",
- "StartPage.notebookDescription": "- 在命令面板 (Shift + Command + P
) 中运行 \"创建新的 笔记本
\" - 探索 示例笔记本
来了解笔记本的功能",
- "StartPage.createAPythonFile": "创建 Python 文件",
- "StartPage.pythonFileDescription": "- 创建以 .py 为扩展名的新文件
",
- "StartPage.openInteractiveWindow": "使用交互式窗口开发 Python 脚本",
- "StartPage.interactiveWindowDesc": "- 您可以在 Python 文件中输入 \"#%%\" 来创建一个单元 - 使用 \"Shift + Enter
\" 来运行一个单元,输出将显示在交互式窗口中",
- "StartPage.releaseNotes": "请查看 发行说明 ,了解更多最新功能。",
- "StartPage.tutorialAndDoc": "在 教程 中探索更多的功能,或查看 文档 以获得提示和排除故障。",
- "StartPage.dontShowAgain": "不再显示此页面",
- "StartPage.helloWorld": "Hello world",
- "StartPage.sampleNotebook": "笔记本介绍",
- "StartPage.openFolder": "打开文件夹或工作区",
- "StartPage.folderDesc": "- 打开 文件夹
- 打开 工作区
",
- "StartPage.badWebPanelFormatString": "{0} 文件名无效 ",
- "Jupyter.extensionRequired": "执行该任务需要 Jupyter 扩展。点击\"是 \"打开 Jupyter 扩展的安装页面。",
- "TensorBoard.useCurrentWorkingDirectory": "使用当前工作目录",
- "TensorBoard.currentDirectory": "当前:{0}",
- "TensorBoard.logDirectoryPrompt": "选择一个日志目录来启动 TensorBoard",
- "TensorBoard.progressMessage": "正在启动 TensorBoard 会话...",
- "TensorBoard.failedToStartSessionError": "启动 TensorBoard 会话失败,错误:{0}",
- "TensorBoard.nativeTensorBoardPrompt": "VS Code 现已集成了 TensorBoard 支持。是否启动 TensorBoard?(提示:打开命令面板并搜索 \"启动 TensorBoard\",即可随时启动 TensorBoard。)",
- "TensorBoard.selectAFolder": "选择一个文件夹",
- "TensorBoard.selectAnotherFolder": "选择另一个文件夹",
- "TensorBoard.selectAFolderDetail": "选择一个包含 tfevent 文件的日志目录",
- "TensorBoard.selectAnotherFolderDetail": "使用文件资源管理器选择另一个文件夹",
- "TensorBoard.useCurrentWorkingDirectoryDetail": "TensorBoard 将在当前工作目录的所有子目录中搜索 tfevent 文件",
- "TensorBoard.installPrompt": "启动 TensorBoard 会话需要安装 TensorBoard 包。是否安装?",
- "TensorBoard.launchNativeTensorBoardSessionCodeAction": "启动 TensorBoard 会话",
- "TensorBoard.launchNativeTensorBoardSessionCodeLens": "▶ 启动 TensorBoard 会话"
-}
diff --git a/package.nls.zh-tw.json b/package.nls.zh-tw.json
deleted file mode 100644
index 373a44299d87..000000000000
--- a/package.nls.zh-tw.json
+++ /dev/null
@@ -1,154 +0,0 @@
-{
- "python.command.python.sortImports.title": "排序 Import 語句",
- "python.command.python.startREPL.title": "啟動 REPL",
- "python.command.python.createTerminal.title": "建立終端機",
- "python.command.python.buildWorkspaceSymbols.title": "建構工作區符號",
- "python.command.python.runtests.title": "執行所有單元測試",
- "python.command.python.debugtests.title": "偵錯所有單元測試",
- "python.command.python.execInTerminal.title": "在終端機中執行 Python 檔案",
- "python.command.python.setInterpreter.title": "選擇直譯器",
- "python.command.python.refactorExtractVariable.title": "提取變數",
- "python.command.python.refactorExtractMethod.title": "提取方法",
- "python.command.python.viewTestOutput.title": "顯示單元測試輸出",
- "python.command.python.selectAndRunTestMethod.title": "執行單元測試方法…",
- "python.command.python.selectAndDebugTestMethod.title": "偵錯單元測試方法…",
- "python.command.python.selectAndRunTestFile.title": "執行單元測試檔案…",
- "python.command.python.runCurrentTestFile.title": "執行目前單元測試檔案",
- "python.command.python.runFailedTests.title": "執行失敗的單元測試",
- "python.command.python.execSelectionInTerminal.title": "在 Python 終端機中執行選定內容/行",
- "python.command.python.execSelectionInDjangoShell.title": "在 Django Shell 中執行選定內容/行",
- "python.command.python.goToPythonObject.title": "跳至 Python 物件",
- "python.command.python.setLinter.title": "選擇 Linter",
- "python.command.python.enableLinting.title": "啟用 Linting",
- "python.command.python.runLinting.title": "執行 Linting",
- "python.snippet.launch.standard.label": "Python: 目前檔案",
- "python.snippet.launch.module.label": "Python: 模組",
- "python.snippet.launch.django.label": "Python: Django",
- "python.snippet.launch.flask.label": "Python: Flask",
- "python.snippet.launch.pyramid.label": "Python: Pyramid 程式",
- "python.snippet.launch.attach.label": "Python: 附加",
- "python.command.python.discoverTests.title": "探索 Unit 測試項目",
- "python.command.python.switchOffInsidersChannel.title": "切換至預設頻道",
- "python.command.python.switchToDailyChannel.title": "切換至 Insiders 每日頻道",
- "python.command.python.switchToWeeklyChannel.title": "切換至 Insiders 每週頻道",
- "python.command.python.viewOutput.title": "顯示輸出",
- "python.command.python.viewLanguageServerOutput.title": "顯示語言伺服器輸出",
- "python.command.python.discoveringTests.title": "正在探索...",
- "python.command.python.stopTests.title": "停止",
- "python.command.python.configureTests.title": "設定測試",
- "python.command.python.enableSourceMapSupport.title": "啟用供偵錯延伸模組的原始碼映射 (Source Map) 支援",
- "python.command.python.analysis.clearCache.title": "清除模組分析快取",
- "python.snippet.launch.module.default": "請輸入-模組-名稱",
- "python.snippet.launch.attachpid.label": "Python: 使用處理程序 ID 連結",
- "LanguageService.lsFailedToStart": "啟動語言伺服器時遇到問題。改回使用替代方案 \"Jedi\"。請檢查 Python 輸出面板以取得更多資訊。",
- "LanguageService.lsFailedToDownload": "下載語言伺服器時遇到問題。改回使用替代方案 \"Jedi\"。請檢查 Python 輸出面板以取得更多資訊。",
- "LanguageService.lsFailedToExtract": "擷取語言伺服器時遇到問題。改回使用替代方案 \"Jedi\"。請檢查 Python 輸出面板以取得更多資訊。",
- "Experiments.inGroup": "使用者屬於 \"{0}\" 實驗性群組",
- "Interpreters.RefreshingInterpreters": "正在重新整理 Python 解譯器",
- "Interpreters.LoadingInterpreters": "正在載入 Python 解譯器",
- "Interpreters.condaInheritEnvMessage": "我們發覺到您在使用 conda 環境。如果你在整合式終端器中使用這個環境時遇到問題,建議您讓 Python 延伸模組變更使用者設定中的 \"terminal.integrated.inheritEnv\" 為 false。",
- "Logging.CurrentWorkingDirectory": "cwd:",
- "Common.doNotShowAgain": "不再顯示",
- "Common.reload": "重新載入",
- "Common.moreInfo": "更多資訊",
- "OutputChannelNames.languageServer": "Python 語言伺服器",
- "OutputChannelNames.python": "Python",
- "OutputChannelNames.pythonTest": "Python 測試記錄",
- "ExtensionSurveyBanner.bannerMessage": "請問您是否可以用兩分鐘的時間,告訴我們 Python 延伸模組在您環境中的運作情況?",
- "ExtensionSurveyBanner.bannerLabelYes": "是,現在填寫調查",
- "ExtensionSurveyBanner.bannerLabelNo": "不了,謝謝",
- "ExtensionSurveyBanner.maybeLater": "等一下",
- "ExtensionChannels.installingInsidersMessage": "正在安裝 Insiders... ",
- "ExtensionChannels.installingStableMessage": "正在安裝穩定版... ",
- "ExtensionChannels.installationCompleteMessage": "完成。",
- "ExtensionChannels.downloadingInsidersMessage": "正在下載 Insiders 延伸模組... ",
- "ExtensionChannels.yesWeekly": "是,每週",
- "ExtensionChannels.yesDaily": "是,每天",
- "ExtensionChannels.promptMessage": "我們發覺到您在使用 Visual Studio Code Insiders。請問您是否想使用 Python 延伸模組的 Insiders 組建?",
- "ExtensionChannels.reloadToUseInsidersMessage": "請重新載入 Visual Studio Code 以使用 Python 延伸模組的 Insiders 組建。",
- "ExtensionChannels.downloadCompletedOutputMessage": "Insiders 組建下載完成。",
- "ExtensionChannels.startingDownloadOutputMessage": "開始下載 Insiders 組建。",
- "Interpreters.environmentPromptMessage": "We noticed a new virtual environment has been created. Do you want to select it for the workspace folder?",
- "Linter.enableLinter": "啟用 {0}",
- "Linter.enablePylint": "您的工作區有 pylintrc 檔案。是否啟用 pylint?",
- "Linter.replaceWithSelectedLinter": "設定中啟用了多個 Linter。是否用 '{0}' 取代?",
- "Installer.noCondaOrPipInstaller": "選取環境中沒有可用的 Conda 或 Pip 安裝工具。",
- "Installer.noPipInstaller": "選取環境中沒有可用的 Pip 安裝工具。",
- "Installer.searchForHelp": "搜尋說明",
- "diagnostics.warnSourceMaps": "已在 Python 延伸模組中啟用原始碼映射 (Source Map) 支援,這會降低延伸模組效能。",
- "diagnostics.disableSourceMaps": "停用原始碼映射 (Source Map) 支援",
- "diagnostics.warnBeforeEnablingSourceMaps": "在 Python 延伸模組中啟用原始碼映射 (Source Map) 支援會降低延伸模組效能。",
- "diagnostics.enableSourceMapsAndReloadVSC": "啟用並重新載入視窗",
- "diagnostics.lsNotSupported": "您的作業系統不符合 Python 語言伺服器的最低需求。改回使用替代自動完成提供者 \"Jedi\"。",
- "diagnostics.invalidPythonPathInDebuggerSettings": "開始偵錯前,您需要選取 Python 解譯器。\n\n小提示:按一下狀態列的 \"選擇 Python 解譯器\"。",
- "diagnostics.invalidPythonPathInDebuggerLaunch": "偵錯設定檔的 Python 路徑無效。",
- "diagnostics.invalidDebuggerTypeDiagnostic": "Your launch.json file needs to be updated to change the \"pythonExperimental\" debug configurations to use the \"python\" debugger type, otherwise Python debugging may not work. Would you like to automatically update your launch.json file now?",
- "diagnostics.consoleTypeDiagnostic": "Your launch.json file needs to be updated to change the console type string from \"none\" to \"internalConsole\", otherwise Python debugging may not work. Would you like to automatically update your launch.json file now?",
- "diagnostics.justMyCodeDiagnostic": "Configuration \"debugStdLib\" in launch.json is no longer supported. It's recommended to replace it with \"justMyCode\", which is the exact opposite of using \"debugStdLib\". Would you like to automatically update your launch.json file to do that?",
- "diagnostics.yesUpdateLaunch": "是,更新 launch.json",
- "diagnostics.invalidTestSettings": "Your settings needs to be updated to change the setting \"python.unitTest.\" to \"python.testing.\", otherwise testing Python code using the extension may not work. Would you like to automatically update your settings now?",
- "Common.canceled": "已取消",
- "Common.cancel": "取消",
- "Common.loadingPythonExtension": "正在載入 Python 延伸模組...",
- "debug.selectConfigurationTitle": "選擇偵錯設定檔",
- "debug.selectConfigurationPlaceholder": "偵錯設定檔",
- "debug.launchJsonConfigurationsCompletionLabel": "Python",
- "debug.launchJsonConfigurationsCompletionDescription": "選取 Python 偵錯設定檔",
- "debug.debugFileConfigurationLabel": "Python 檔案",
- "debug.debugFileConfigurationDescription": "偵錯目前使用中的 Python 檔案",
- "debug.debugModuleConfigurationLabel": "模組",
- "debug.debugModuleConfigurationDescription": "使用 '-m' 叫用以偵錯 Python 模組",
- "debug.moduleEnterModuleTitle": "偵錯模組",
- "debug.moduleEnterModulePrompt": "輸入 Python 模組 / 套件名稱",
- "debug.moduleEnterModuleDefault": "輸入-模組-名稱",
- "debug.moduleEnterModuleInvalidNameError": "請輸入有效的模組名稱",
- "debug.remoteAttachConfigurationLabel": "遠端連結",
- "debug.remoteAttachConfigurationDescription": "連結到遠端偵錯伺服器",
- "debug.attachRemoteHostTitle": "遠端偵錯",
- "debug.attachRemoteHostPrompt": "輸入主機名稱",
- "debug.attachRemoteHostValidationError": "請輸入有效的主機名稱或 IP 位址",
- "debug.attachRemotePortTitle": "遠端偵錯",
- "debug.attachRemotePortPrompt": "輸入偵錯伺服器正在監聽的連線埠號。",
- "debug.attachRemotePortValidationError": "請輸入有效的連線埠號。",
- "debug.attachPidConfigurationLabel": "使用處理程序 ID 連結",
- "debug.attachPidConfigurationDescription": "連結至本機處理程序",
- "debug.debugDjangoConfigurationLabel": "Django",
- "debug.debugDjangoConfigurationDescription": "執行並偵錯 Django 網路應用程式",
- "debug.djangoEnterManagePyPathTitle": "偵錯 Django",
- "debug.djangoEnterManagePyPathPrompt": "請輸入 manage.py 的路徑 ('${workspaceFolderToken}' 指向目前工作區資料夾的根目錄)",
- "debug.djangoEnterManagePyPathInvalidFilePathError": "請輸入有效的 Python 檔案路徑",
- "debug.debugFlaskConfigurationLabel": "Flask",
- "debug.debugFlaskConfigurationDescription": "執行並偵錯 Flask 網路應用程式",
- "debug.flaskEnterAppPathOrNamePathTitle": "偵錯 Flask",
- "debug.flaskEnterAppPathOrNamePathPrompt": "請輸入應用程式路徑。例如:'app.py' 或 'app'",
- "debug.flaskEnterAppPathOrNamePathInvalidNameError": "請輸入有效名稱",
- "debug.debugPyramidConfigurationLabel": "Pyramid",
- "debug.debugPyramidConfigurationDescription": "網路應用程式",
- "debug.pyramidEnterDevelopmentIniPathTitle": "偵錯 Pyramid",
- "debug.pyramidEnterDevelopmentIniPathPrompt": "`請輸入 development.ini 的路徑 ('${workspaceFolderToken}' 指向目前工作區資料夾的根目錄)`",
- "debug.pyramidEnterDevelopmentIniPathInvalidFilePathError": "請輸入有效的檔案路徑",
- "Testing.testErrorDiagnosticMessage": "錯誤",
- "Testing.testFailDiagnosticMessage": "失敗",
- "Testing.testSkippedDiagnosticMessage": "略過",
- "Testing.configureTests": "設定測試框架",
- "Testing.disableTests": "停用測試",
- "Common.openOutputPanel": "顯示輸出",
- "LanguageService.downloadFailedOutputMessage": "下載語言伺服器失敗",
- "LanguageService.extractionFailedOutputMessage": "擷取語言伺服器失敗",
- "LanguageService.extractionCompletedOutputMessage": "下載語言伺服器完成",
- "LanguageService.extractionDoneOutputMessage": "完成",
- "LanguageService.reloadVSCodeIfSeachPathHasChanged": "已為此 Python 解譯器變更搜尋路徑。請重新載入延伸模組以確保 IntelliSense 能夠正常運作",
- "AttachProcess.unsupportedOS": "不支援 '{0}' 作業系統。",
- "AttachProcess.attachTitle": "連結至處理程序",
- "AttachProcess.selectProcessPlaceholder": "選擇要連結的處理程序",
- "AttachProcess.noProcessSelected": "沒有選取的處理程序",
- "AttachProcess.refreshList": "重新整理處理程序列表",
- "diagnostics.updateSettings": "是,更新設定",
- "Common.noIWillDoItLater": "否,我稍候再做",
- "Common.notNow": "先不要",
- "Common.gotIt": "懂了!",
- "Interpreters.selectInterpreterTip": "小提示:您能透過按下狀態列中的 Python 版本,變更 Python 延伸模組使用的 Python 解譯器。",
- "downloading.file": "正在下載 {0}...",
- "downloading.file.progress": "目前 {0}{1},總共 {2} KB ({3}%)",
- "products.installingModule": "正在安裝 {0}"
-}
diff --git a/pythonExtensionApi/.eslintrc b/pythonExtensionApi/.eslintrc
new file mode 100644
index 000000000000..8828c49002ed
--- /dev/null
+++ b/pythonExtensionApi/.eslintrc
@@ -0,0 +1,11 @@
+{
+ "overrides": [
+ {
+ "files": ["**/main.d.ts"],
+ "rules": {
+ "@typescript-eslint/no-explicit-any": "off",
+ "padding-line-between-statements": ["error", { "blankLine": "always", "prev": "export", "next": "*" }]
+ }
+ }
+ ]
+}
diff --git a/pythonExtensionApi/.npmignore b/pythonExtensionApi/.npmignore
new file mode 100644
index 000000000000..283d589ea5fe
--- /dev/null
+++ b/pythonExtensionApi/.npmignore
@@ -0,0 +1,8 @@
+example/**
+dist/
+out/**/*.map
+out/**/*.tsbuildInfo
+src/
+.eslintrc*
+.eslintignore
+tsconfig*.json
diff --git a/pythonExtensionApi/LICENSE.md b/pythonExtensionApi/LICENSE.md
new file mode 100644
index 000000000000..767f4076ba05
--- /dev/null
+++ b/pythonExtensionApi/LICENSE.md
@@ -0,0 +1,21 @@
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+MIT License
+
+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/pythonExtensionApi/README.md b/pythonExtensionApi/README.md
new file mode 100644
index 000000000000..5208d90cdfa5
--- /dev/null
+++ b/pythonExtensionApi/README.md
@@ -0,0 +1,55 @@
+# Python extension's API
+
+This npm module implements an API facade for the Python extension in VS Code.
+
+## Example
+
+First we need to define a `package.json` for the extension that wants to use the API:
+
+```jsonc
+{
+ "name": "...",
+ ...
+ // depend on the Python extension
+ "extensionDependencies": [
+ "ms-python.python"
+ ],
+ // Depend on the Python extension facade npm module to get easier API access to the
+ // core extension.
+ "dependencies": {
+ "@vscode/python-extension": "...",
+ "@types/vscode": "..."
+ },
+}
+```
+
+Update `"@types/vscode"` to [a recent version](https://code.visualstudio.com/updates/) of VS Code, say `"^1.81.0"` for VS Code version `"1.81"`, in case there are any conflicts.
+
+The actual source code to get the active environment to run some script could look like this:
+
+```typescript
+// Import the API
+import { PythonExtension } from '@vscode/python-extension';
+
+...
+
+// Load the Python extension API
+const pythonApi: PythonExtension = await PythonExtension.api();
+
+// This will return something like /usr/bin/python
+const environmentPath = pythonApi.environments.getActiveEnvironmentPath();
+
+// `environmentPath.path` carries the value of the setting. Note that this path may point to a folder and not the
+// python binary. Depends entirely on how the env was created.
+// E.g., `conda create -n myenv python` ensures the env has a python binary
+// `conda create -n myenv` does not include a python binary.
+// Also, the path specified may not be valid, use the following to get complete details for this environment if
+// need be.
+
+const environment = await pythonApi.environments.resolveEnvironment(environmentPath);
+if (environment) {
+ // run your script here.
+}
+```
+
+Check out [the wiki](https://aka.ms/pythonEnvironmentApi) for many more examples and usage.
diff --git a/pythonExtensionApi/SECURITY.md b/pythonExtensionApi/SECURITY.md
new file mode 100644
index 000000000000..a050f362c152
--- /dev/null
+++ b/pythonExtensionApi/SECURITY.md
@@ -0,0 +1,41 @@
+
+
+## Security
+
+Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
+
+If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.
+
+## Reporting Security Issues
+
+**Please do not report security vulnerabilities through public GitHub issues.**
+
+Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
+
+If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
+
+You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
+
+Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
+
+ * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
+ * Full paths of source file(s) related to the manifestation of the issue
+ * The location of the affected source code (tag/branch/commit or direct URL)
+ * Any special configuration required to reproduce the issue
+ * Step-by-step instructions to reproduce the issue
+ * Proof-of-concept or exploit code (if possible)
+ * Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
+
+If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
+
+## Preferred Languages
+
+We prefer all communications to be in English.
+
+## Policy
+
+Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
+
+
diff --git a/pythonExtensionApi/package-lock.json b/pythonExtensionApi/package-lock.json
new file mode 100644
index 000000000000..e462fc1c888a
--- /dev/null
+++ b/pythonExtensionApi/package-lock.json
@@ -0,0 +1,157 @@
+{
+ "name": "@vscode/python-extension",
+ "version": "1.0.6",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@vscode/python-extension",
+ "version": "1.0.6",
+ "license": "MIT",
+ "devDependencies": {
+ "@types/vscode": "^1.93.0",
+ "source-map": "^0.8.0-beta.0",
+ "typescript": "~5.2"
+ },
+ "engines": {
+ "node": ">=22.17.0",
+ "vscode": "^1.93.0"
+ }
+ },
+ "node_modules/@types/vscode": {
+ "version": "1.94.0",
+ "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.94.0.tgz",
+ "integrity": "sha512-UyQOIUT0pb14XSqJskYnRwD2aG0QrPVefIfrW1djR+/J4KeFQ0i1+hjZoaAmeNf3Z2jleK+R2hv+EboG/m8ruw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
+ "dev": true
+ },
+ "node_modules/punycode": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
+ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.8.0-beta.0",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
+ "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==",
+ "dev": true,
+ "dependencies": {
+ "whatwg-url": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
+ "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
+ "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
+ "dev": true
+ },
+ "node_modules/whatwg-url": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
+ "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
+ "dev": true,
+ "dependencies": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ }
+ },
+ "dependencies": {
+ "@types/vscode": {
+ "version": "1.94.0",
+ "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.94.0.tgz",
+ "integrity": "sha512-UyQOIUT0pb14XSqJskYnRwD2aG0QrPVefIfrW1djR+/J4KeFQ0i1+hjZoaAmeNf3Z2jleK+R2hv+EboG/m8ruw==",
+ "dev": true
+ },
+ "lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
+ "dev": true
+ },
+ "punycode": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
+ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.8.0-beta.0",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
+ "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==",
+ "dev": true,
+ "requires": {
+ "whatwg-url": "^7.0.0"
+ }
+ },
+ "tr46": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
+ "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
+ "dev": true,
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "typescript": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
+ "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
+ "dev": true
+ },
+ "webidl-conversions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
+ "dev": true
+ },
+ "whatwg-url": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
+ "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
+ "dev": true,
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ }
+ }
+}
diff --git a/pythonExtensionApi/package.json b/pythonExtensionApi/package.json
new file mode 100644
index 000000000000..11e0445aa8da
--- /dev/null
+++ b/pythonExtensionApi/package.json
@@ -0,0 +1,43 @@
+{
+ "name": "@vscode/python-extension",
+ "description": "An API facade for the Python extension in VS Code",
+ "version": "1.0.6",
+ "author": {
+ "name": "Microsoft Corporation"
+ },
+ "keywords": [
+ "Python",
+ "VSCode",
+ "API"
+ ],
+ "main": "./out/main.js",
+ "types": "./out/main.d.ts",
+ "engines": {
+ "node": ">=22.21.1",
+ "vscode": "^1.93.0"
+ },
+ "license": "MIT",
+ "homepage": "https://github.com/microsoft/vscode-python/tree/main/pythonExtensionApi",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/Microsoft/vscode-python"
+ },
+ "bugs": {
+ "url": "https://github.com/Microsoft/vscode-python/issues"
+ },
+ "devDependencies": {
+ "typescript": "~5.2",
+ "@types/vscode": "^1.102.0",
+ "source-map": "^0.8.0-beta.0"
+ },
+ "scripts": {
+ "prepublishOnly": "echo \"⛔ Can only publish from a secure pipeline ⛔\" && node ../build/fail",
+ "prepack": "npm run all:publish",
+ "compile": "node ./node_modules/typescript/lib/tsc.js -b ./tsconfig.json",
+ "clean": "node ../node_modules/rimraf/bin.js out",
+ "lint": "node ../node_modules/eslint/bin/eslint.js --ext ts src",
+ "all": "npm run clean && npm run compile",
+ "formatTypings": "node ../node_modules/eslint/bin/eslint.js --fix ./out/main.d.ts",
+ "all:publish": "git clean -xfd . && npm install && npm run compile && npm run formatTypings"
+ }
+}
diff --git a/pythonExtensionApi/src/main.ts b/pythonExtensionApi/src/main.ts
new file mode 100644
index 000000000000..2173245cbb28
--- /dev/null
+++ b/pythonExtensionApi/src/main.ts
@@ -0,0 +1,348 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+import { CancellationToken, Event, Uri, WorkspaceFolder, extensions } from 'vscode';
+
+/*
+ * Do not introduce any breaking changes to this API.
+ * This is the public API for other extensions to interact with this extension.
+ */
+export interface PythonExtension {
+ /**
+ * Promise indicating whether all parts of the extension have completed loading or not.
+ */
+ ready: Promise;
+ debug: {
+ /**
+ * Generate an array of strings for commands to pass to the Python executable to launch the debugger for remote debugging.
+ * Users can append another array of strings of what they want to execute along with relevant arguments to Python.
+ * E.g `['/Users/..../pythonVSCode/python_files/lib/python/debugpy', '--listen', 'localhost:57039', '--wait-for-client']`
+ * @param host
+ * @param port
+ * @param waitUntilDebuggerAttaches Defaults to `true`.
+ */
+ getRemoteLauncherCommand(host: string, port: number, waitUntilDebuggerAttaches: boolean): Promise;
+
+ /**
+ * Gets the path to the debugger package used by the extension.
+ */
+ getDebuggerPackagePath(): Promise;
+ };
+
+ /**
+ * These APIs provide a way for extensions to work with by python environments available in the user's machine
+ * as found by the Python extension. See
+ * https://github.com/microsoft/vscode-python/wiki/Python-Environment-APIs for usage examples and more.
+ */
+ readonly environments: {
+ /**
+ * Returns the environment configured by user in settings. Note that this can be an invalid environment, use
+ * {@link resolveEnvironment} to get full details.
+ * @param resource : Uri of a file or workspace folder. This is used to determine the env in a multi-root
+ * scenario. If `undefined`, then the API returns what ever is set for the workspace.
+ */
+ getActiveEnvironmentPath(resource?: Resource): EnvironmentPath;
+ /**
+ * Sets the active environment path for the python extension for the resource. Configuration target will always
+ * be the workspace folder.
+ * @param environment : If string, it represents the full path to environment folder or python executable
+ * for the environment. Otherwise it can be {@link Environment} or {@link EnvironmentPath} itself.
+ * @param resource : [optional] File or workspace to scope to a particular workspace folder.
+ */
+ updateActiveEnvironmentPath(
+ environment: string | EnvironmentPath | Environment,
+ resource?: Resource,
+ ): Promise;
+ /**
+ * This event is triggered when the active environment setting changes.
+ */
+ readonly onDidChangeActiveEnvironmentPath: Event;
+ /**
+ * Carries environments known to the extension at the time of fetching the property. Note this may not
+ * contain all environments in the system as a refresh might be going on.
+ *
+ * Only reports environments in the current workspace.
+ */
+ readonly known: readonly Environment[];
+ /**
+ * This event is triggered when the known environment list changes, like when a environment
+ * is found, existing environment is removed, or some details changed on an environment.
+ */
+ readonly onDidChangeEnvironments: Event;
+ /**
+ * This API will trigger environment discovery, but only if it has not already happened in this VSCode session.
+ * Useful for making sure env list is up-to-date when the caller needs it for the first time.
+ *
+ * To force trigger a refresh regardless of whether a refresh was already triggered, see option
+ * {@link RefreshOptions.forceRefresh}.
+ *
+ * Note that if there is a refresh already going on then this returns the promise for that refresh.
+ * @param options Additional options for refresh.
+ * @param token A cancellation token that indicates a refresh is no longer needed.
+ */
+ refreshEnvironments(options?: RefreshOptions, token?: CancellationToken): Promise;
+ /**
+ * Returns details for the given environment, or `undefined` if the env is invalid.
+ * @param environment : If string, it represents the full path to environment folder or python executable
+ * for the environment. Otherwise it can be {@link Environment} or {@link EnvironmentPath} itself.
+ */
+ resolveEnvironment(
+ environment: Environment | EnvironmentPath | string,
+ ): Promise;
+ /**
+ * Returns the environment variables used by the extension for a resource, which includes the custom
+ * variables configured by user in `.env` files.
+ * @param resource : Uri of a file or workspace folder. This is used to determine the env in a multi-root
+ * scenario. If `undefined`, then the API returns what ever is set for the workspace.
+ */
+ getEnvironmentVariables(resource?: Resource): EnvironmentVariables;
+ /**
+ * This event is fired when the environment variables for a resource change. Note it's currently not
+ * possible to detect if environment variables in the system change, so this only fires if custom
+ * environment variables are updated in `.env` files.
+ */
+ readonly onDidEnvironmentVariablesChange: Event;
+ };
+}
+
+export type RefreshOptions = {
+ /**
+ * When `true`, force trigger a refresh regardless of whether a refresh was already triggered. Note this can be expensive so
+ * it's best to only use it if user manually triggers a refresh.
+ */
+ forceRefresh?: boolean;
+};
+
+/**
+ * Details about the environment. Note the environment folder, type and name never changes over time.
+ */
+export type Environment = EnvironmentPath & {
+ /**
+ * Carries details about python executable.
+ */
+ readonly executable: {
+ /**
+ * Uri of the python interpreter/executable. Carries `undefined` in case an executable does not belong to
+ * the environment.
+ */
+ readonly uri: Uri | undefined;
+ /**
+ * Bitness if known at this moment.
+ */
+ readonly bitness: Bitness | undefined;
+ /**
+ * Value of `sys.prefix` in sys module if known at this moment.
+ */
+ readonly sysPrefix: string | undefined;
+ };
+ /**
+ * Carries details if it is an environment, otherwise `undefined` in case of global interpreters and others.
+ */
+ readonly environment:
+ | {
+ /**
+ * Type of the environment.
+ */
+ readonly type: EnvironmentType;
+ /**
+ * Name to the environment if any.
+ */
+ readonly name: string | undefined;
+ /**
+ * Uri of the environment folder.
+ */
+ readonly folderUri: Uri;
+ /**
+ * Any specific workspace folder this environment is created for.
+ */
+ readonly workspaceFolder: WorkspaceFolder | undefined;
+ }
+ | undefined;
+ /**
+ * Carries Python version information known at this moment, carries `undefined` for envs without python.
+ */
+ readonly version:
+ | (VersionInfo & {
+ /**
+ * Value of `sys.version` in sys module if known at this moment.
+ */
+ readonly sysVersion: string | undefined;
+ })
+ | undefined;
+ /**
+ * Tools/plugins which created the environment or where it came from. First value in array corresponds
+ * to the primary tool which manages the environment, which never changes over time.
+ *
+ * Array is empty if no tool is responsible for creating/managing the environment. Usually the case for
+ * global interpreters.
+ */
+ readonly tools: readonly EnvironmentTools[];
+};
+
+/**
+ * Derived form of {@link Environment} where certain properties can no longer be `undefined`. Meant to represent an
+ * {@link Environment} with complete information.
+ */
+export type ResolvedEnvironment = Environment & {
+ /**
+ * Carries complete details about python executable.
+ */
+ readonly executable: {
+ /**
+ * Uri of the python interpreter/executable. Carries `undefined` in case an executable does not belong to
+ * the environment.
+ */
+ readonly uri: Uri | undefined;
+ /**
+ * Bitness of the environment.
+ */
+ readonly bitness: Bitness;
+ /**
+ * Value of `sys.prefix` in sys module.
+ */
+ readonly sysPrefix: string;
+ };
+ /**
+ * Carries complete Python version information, carries `undefined` for envs without python.
+ */
+ readonly version:
+ | (ResolvedVersionInfo & {
+ /**
+ * Value of `sys.version` in sys module if known at this moment.
+ */
+ readonly sysVersion: string;
+ })
+ | undefined;
+};
+
+export type EnvironmentsChangeEvent = {
+ readonly env: Environment;
+ /**
+ * * "add": New environment is added.
+ * * "remove": Existing environment in the list is removed.
+ * * "update": New information found about existing environment.
+ */
+ readonly type: 'add' | 'remove' | 'update';
+};
+
+export type ActiveEnvironmentPathChangeEvent = EnvironmentPath & {
+ /**
+ * Resource the environment changed for.
+ */
+ readonly resource: Resource | undefined;
+};
+
+/**
+ * Uri of a file inside a workspace or workspace folder itself.
+ */
+export type Resource = Uri | WorkspaceFolder;
+
+export type EnvironmentPath = {
+ /**
+ * The ID of the environment.
+ */
+ readonly id: string;
+ /**
+ * Path to environment folder or path to python executable that uniquely identifies an environment. Environments
+ * lacking a python executable are identified by environment folder paths, whereas other envs can be identified
+ * using python executable path.
+ */
+ readonly path: string;
+};
+
+/**
+ * Tool/plugin where the environment came from. It can be {@link KnownEnvironmentTools} or custom string which
+ * was contributed.
+ */
+export type EnvironmentTools = KnownEnvironmentTools | string;
+/**
+ * Tools or plugins the Python extension currently has built-in support for. Note this list is expected to shrink
+ * once tools have their own separate extensions.
+ */
+export type KnownEnvironmentTools =
+ | 'Conda'
+ | 'Pipenv'
+ | 'Poetry'
+ | 'VirtualEnv'
+ | 'Venv'
+ | 'VirtualEnvWrapper'
+ | 'Pyenv'
+ | 'Unknown';
+
+/**
+ * Type of the environment. It can be {@link KnownEnvironmentTypes} or custom string which was contributed.
+ */
+export type EnvironmentType = KnownEnvironmentTypes | string;
+/**
+ * Environment types the Python extension is aware of. Note this list is expected to shrink once tools have their
+ * own separate extensions, in which case they're expected to provide the type themselves.
+ */
+export type KnownEnvironmentTypes = 'VirtualEnvironment' | 'Conda' | 'Unknown';
+
+/**
+ * Carries bitness for an environment.
+ */
+export type Bitness = '64-bit' | '32-bit' | 'Unknown';
+
+/**
+ * The possible Python release levels.
+ */
+export type PythonReleaseLevel = 'alpha' | 'beta' | 'candidate' | 'final';
+
+/**
+ * Release information for a Python version.
+ */
+export type PythonVersionRelease = {
+ readonly level: PythonReleaseLevel;
+ readonly serial: number;
+};
+
+export type VersionInfo = {
+ readonly major: number | undefined;
+ readonly minor: number | undefined;
+ readonly micro: number | undefined;
+ readonly release: PythonVersionRelease | undefined;
+};
+
+export type ResolvedVersionInfo = {
+ readonly major: number;
+ readonly minor: number;
+ readonly micro: number;
+ readonly release: PythonVersionRelease;
+};
+
+/**
+ * A record containing readonly keys.
+ */
+export type EnvironmentVariables = { readonly [key: string]: string | undefined };
+
+export type EnvironmentVariablesChangeEvent = {
+ /**
+ * Workspace folder the environment variables changed for.
+ */
+ readonly resource: WorkspaceFolder | undefined;
+ /**
+ * Updated value of environment variables.
+ */
+ readonly env: EnvironmentVariables;
+};
+
+export const PVSC_EXTENSION_ID = 'ms-python.python';
+
+// eslint-disable-next-line @typescript-eslint/no-namespace
+export namespace PythonExtension {
+ /**
+ * Returns the API exposed by the Python extension in VS Code.
+ */
+ export async function api(): Promise {
+ const extension = extensions.getExtension(PVSC_EXTENSION_ID);
+ if (extension === undefined) {
+ throw new Error(`Python extension is not installed or is disabled`);
+ }
+ if (!extension.isActive) {
+ await extension.activate();
+ }
+ const pythonApi: PythonExtension = extension.exports;
+ return pythonApi;
+ }
+}
diff --git a/pythonExtensionApi/tsconfig.json b/pythonExtensionApi/tsconfig.json
new file mode 100644
index 000000000000..9ab7617023df
--- /dev/null
+++ b/pythonExtensionApi/tsconfig.json
@@ -0,0 +1,34 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "*": ["types/*"]
+ },
+ "module": "commonjs",
+ "target": "es2018",
+ "outDir": "./out",
+ "lib": [
+ "es6",
+ "es2018",
+ "dom",
+ "ES2019",
+ "ES2020"
+ ],
+ "sourceMap": true,
+ "rootDir": "src",
+ "experimentalDecorators": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "noImplicitAny": true,
+ "noImplicitThis": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "resolveJsonModule": true,
+ "declaration": true
+ },
+ "exclude": [
+ "node_modules",
+ "out"
+ ]
+}
diff --git a/pythonExtensionApi/tsconfig.tsbuildinfo b/pythonExtensionApi/tsconfig.tsbuildinfo
new file mode 100644
index 000000000000..678718bec396
--- /dev/null
+++ b/pythonExtensionApi/tsconfig.tsbuildinfo
@@ -0,0 +1 @@
+{"root":["./src/main.ts"],"version":"5.9.3"}
\ No newline at end of file
diff --git a/pythonFiles/completion.py b/pythonFiles/completion.py
deleted file mode 100644
index 5a82d8177ecf..000000000000
--- a/pythonFiles/completion.py
+++ /dev/null
@@ -1,692 +0,0 @@
-import os
-import os.path
-import io
-import re
-import sys
-import json
-import traceback
-import platform
-
-jediPreview = False
-
-
-class RedirectStdout(object):
- def __init__(self, new_stdout=None):
- """If stdout is None, redirect to /dev/null"""
- self._new_stdout = new_stdout or open(os.devnull, "w")
-
- def __enter__(self):
- sys.stdout.flush()
- self.oldstdout_fno = os.dup(sys.stdout.fileno())
- os.dup2(self._new_stdout.fileno(), 1)
-
- def __exit__(self, exc_type, exc_value, traceback):
- self._new_stdout.flush()
- os.dup2(self.oldstdout_fno, 1)
- os.close(self.oldstdout_fno)
-
-
-class JediCompletion(object):
- basic_types = {
- "module": "import",
- "instance": "variable",
- "statement": "value",
- "param": "variable",
- }
-
- def __init__(self):
- self.default_sys_path = sys.path
- self._input = io.open(sys.stdin.fileno(), encoding="utf-8")
- if (os.path.sep == "/") and (platform.uname()[2].find("Microsoft") > -1):
- # WSL; does not support UNC paths
- self.drive_mount = "/mnt/"
- elif sys.platform == "cygwin":
- # cygwin
- self.drive_mount = "/cygdrive/"
- else:
- # Do no normalization, e.g. Windows build of Python.
- # Could add additional test: ((os.path.sep == '/') and os.path.isdir('/mnt/c'))
- # However, this may have more false positives trying to identify Windows/*nix hybrids
- self.drive_mount = ""
-
- def _get_definition_type(self, definition):
- # if definition.type not in ['import', 'keyword'] and is_built_in():
- # return 'builtin'
- try:
- if definition.type in ["statement"] and definition.name.isupper():
- return "constant"
- return self.basic_types.get(definition.type, definition.type)
- except Exception:
- return "builtin"
-
- def _additional_info(self, completion):
- """Provide additional information about the completion object."""
- if not hasattr(completion, "_definition") or completion._definition is None:
- return ""
- if completion.type == "statement":
- nodes_to_display = ["InstanceElement", "String", "Node", "Lambda", "Number"]
- return "".join(
- c.get_code()
- for c in completion._definition.children
- if type(c).__name__ in nodes_to_display
- ).replace("\n", "")
- return ""
-
- @classmethod
- def _get_top_level_module(cls, path):
- """Recursively walk through directories looking for top level module.
-
- Jedi will use current filepath to look for another modules at same
- path, but it will not be able to see modules **above**, so our goal
- is to find the higher python module available from filepath.
- """
- _path, _ = os.path.split(path)
- if os.path.isfile(os.path.join(_path, "__init__.py")):
- return cls._get_top_level_module(_path)
- return path
-
- def _generate_signature(self, completion):
- """Generate signature with function arguments."""
- if completion.type in ["module"] or not hasattr(completion, "params"):
- return ""
- return "%s(%s)" % (
- completion.name,
- ", ".join(p.description[6:] for p in completion.params if p),
- )
-
- def _get_call_signatures(self, script):
- """Extract call signatures from jedi.api.Script object in failsafe way.
-
- Returns:
- Tuple with original signature object, name and value.
- """
- _signatures = []
- try:
- call_signatures = script.call_signatures()
- except KeyError:
- call_signatures = []
- except:
- call_signatures = []
- for signature in call_signatures:
- for pos, param in enumerate(signature.params):
- if not param.name:
- continue
-
- name = self._get_param_name(param)
- if param.name == "self" and pos == 0:
- continue
- if name.startswith("*"):
- continue
-
- value = self._get_param_value(param)
- _signatures.append((signature, name, value))
- return _signatures
-
- def _get_param_name(self, p):
- if p.name.startswith("param "):
- return p.name[6:] # drop leading 'param '
- return p.name
-
- def _get_param_value(self, p):
- pair = p.description.split("=")
- if len(pair) > 1:
- return pair[1]
- return None
-
- def _get_call_signatures_with_args(self, script):
- """Extract call signatures from jedi.api.Script object in failsafe way.
-
- Returns:
- Array with dictionary
- """
- _signatures = []
- try:
- call_signatures = script.call_signatures()
- except KeyError:
- call_signatures = []
- for signature in call_signatures:
- sig = {
- "name": "",
- "description": "",
- "docstring": "",
- "paramindex": 0,
- "params": [],
- "bracketstart": [],
- }
- sig["description"] = signature.description
- try:
- sig["docstring"] = signature.docstring()
- sig["raw_docstring"] = signature.docstring(raw=True)
- except Exception:
- sig["docstring"] = ""
- sig["raw_docstring"] = ""
-
- sig["name"] = signature.name
- sig["paramindex"] = signature.index
- sig["bracketstart"].append(signature.index)
-
- _signatures.append(sig)
- for pos, param in enumerate(signature.params):
- if not param.name:
- continue
-
- name = self._get_param_name(param)
- if param.name == "self" and pos == 0:
- continue
-
- value = self._get_param_value(param)
- paramDocstring = ""
- try:
- paramDocstring = param.docstring()
- except Exception:
- paramDocstring = ""
-
- sig["params"].append(
- {
- "name": name,
- "value": value,
- "docstring": paramDocstring,
- "description": param.description,
- }
- )
- return _signatures
-
- def _serialize_completions(self, script, identifier=None, prefix=""):
- """Serialize response to be read from VSCode.
-
- Args:
- script: Instance of jedi.api.Script object.
- identifier: Unique completion identifier to pass back to VSCode.
- prefix: String with prefix to filter function arguments.
- Used only when fuzzy matcher turned off.
-
- Returns:
- Serialized string to send to VSCode.
- """
- _completions = []
-
- for signature, name, value in self._get_call_signatures(script):
- if not self.fuzzy_matcher and not name.lower().startswith(prefix.lower()):
- continue
- _completion = {
- "type": "property",
- "raw_type": "",
- "rightLabel": self._additional_info(signature),
- }
- _completion["description"] = ""
- _completion["raw_docstring"] = ""
-
- # we pass 'text' here only for fuzzy matcher
- if value:
- _completion["snippet"] = "%s=${1:%s}$0" % (name, value)
- _completion["text"] = "%s=" % (name)
- else:
- _completion["snippet"] = "%s=$1$0" % name
- _completion["text"] = name
- _completion["displayText"] = name
- _completions.append(_completion)
-
- try:
- completions = script.completions()
- except KeyError:
- completions = []
- except:
- completions = []
- for completion in completions:
- try:
- _completion = {
- "text": completion.name,
- "type": self._get_definition_type(completion),
- "raw_type": completion.type,
- "rightLabel": self._additional_info(completion),
- }
- except Exception:
- continue
-
- for c in _completions:
- if c["text"] == _completion["text"]:
- c["type"] = _completion["type"]
- c["raw_type"] = _completion["raw_type"]
-
- if any(
- [c["text"].split("=")[0] == _completion["text"] for c in _completions]
- ):
- # ignore function arguments we already have
- continue
- _completions.append(_completion)
- return json.dumps({"id": identifier, "results": _completions})
-
- def _serialize_methods(self, script, identifier=None, prefix=""):
- _methods = []
- try:
- completions = script.completions()
- except KeyError:
- return []
-
- for completion in completions:
- if completion.name == "__autocomplete_python":
- instance = completion.parent().name
- break
- else:
- instance = "self.__class__"
-
- for completion in completions:
- params = []
- if hasattr(completion, "params"):
- params = [p.description for p in completion.params if p]
- if completion.parent().type == "class":
- _methods.append(
- {
- "parent": completion.parent().name,
- "instance": instance,
- "name": completion.name,
- "params": params,
- "moduleName": completion.module_name,
- "fileName": completion.module_path,
- "line": completion.line,
- "column": completion.column,
- }
- )
- return json.dumps({"id": identifier, "results": _methods})
-
- def _serialize_arguments(self, script, identifier=None):
- """Serialize response to be read from VSCode.
-
- Args:
- script: Instance of jedi.api.Script object.
- identifier: Unique completion identifier to pass back to VSCode.
-
- Returns:
- Serialized string to send to VSCode.
- """
- return json.dumps(
- {"id": identifier, "results": self._get_call_signatures_with_args(script)}
- )
-
- def _top_definition(self, definition):
- for d in definition.goto_assignments():
- if d == definition:
- continue
- if d.type == "import":
- return self._top_definition(d)
- else:
- return d
- return definition
-
- def _extract_range_jedi_0_11_1(self, definition):
- from parso.utils import split_lines
-
- # get the scope range
- try:
- if definition.type in ["class", "function"]:
- tree_name = definition._name.tree_name
- scope = tree_name.get_definition()
- start_line = scope.start_pos[0] - 1
- start_column = scope.start_pos[1]
- # get the lines
- code = scope.get_code(include_prefix=False)
- lines = split_lines(code)
- # trim the lines
- lines = "\n".join(lines).rstrip().split("\n")
- end_line = start_line + len(lines) - 1
- end_column = len(lines[-1]) - 1
- else:
- symbol = definition._name.tree_name
- start_line = symbol.start_pos[0] - 1
- start_column = symbol.start_pos[1]
- end_line = symbol.end_pos[0] - 1
- end_column = symbol.end_pos[1]
- return {
- "start_line": start_line,
- "start_column": start_column,
- "end_line": end_line,
- "end_column": end_column,
- }
- except Exception as e:
- return {
- "start_line": definition.line - 1,
- "start_column": definition.column,
- "end_line": definition.line - 1,
- "end_column": definition.column,
- }
-
- def _extract_range(self, definition):
- """Provides the definition range of a given definition
-
- For regular symbols it returns the start and end location of the
- characters making up the symbol.
-
- For scoped containers it will return the entire definition of the
- scope.
-
- The scope that jedi provides ends with the first character of the next
- scope so it's not ideal. For vscode we need the scope to end with the
- last character of actual code. That's why we extract the lines that
- make up our scope and trim the trailing whitespace.
- """
- return self._extract_range_jedi_0_11_1(definition)
-
- def _get_definitionsx(self, definitions, identifier=None, ignoreNoModulePath=False):
- """Serialize response to be read from VSCode.
-
- Args:
- definitions: List of jedi.api.classes.Definition objects.
- identifier: Unique completion identifier to pass back to VSCode.
-
- Returns:
- Serialized string to send to VSCode.
- """
- _definitions = []
- for definition in definitions:
- try:
- if definition.type == "import":
- definition = self._top_definition(definition)
- definitionRange = {
- "start_line": 0,
- "start_column": 0,
- "end_line": 0,
- "end_column": 0,
- }
- module_path = ""
- if hasattr(definition, "module_path") and definition.module_path:
- module_path = definition.module_path
- definitionRange = self._extract_range(definition)
- else:
- if not ignoreNoModulePath:
- continue
- try:
- parent = definition.parent()
- container = parent.name if parent.type != "module" else ""
- except Exception:
- container = ""
-
- try:
- docstring = definition.docstring()
- rawdocstring = definition.docstring(raw=True)
- except Exception:
- docstring = ""
- rawdocstring = ""
- _definition = {
- "text": definition.name,
- "type": self._get_definition_type(definition),
- "raw_type": definition.type,
- "fileName": module_path,
- "container": container,
- "range": definitionRange,
- "description": definition.description,
- "docstring": docstring,
- "raw_docstring": rawdocstring,
- "signature": self._generate_signature(definition),
- }
- _definitions.append(_definition)
- except Exception as e:
- pass
- return _definitions
-
- def _serialize_definitions(self, definitions, identifier=None):
- """Serialize response to be read from VSCode.
-
- Args:
- definitions: List of jedi.api.classes.Definition objects.
- identifier: Unique completion identifier to pass back to VSCode.
-
- Returns:
- Serialized string to send to VSCode.
- """
- _definitions = []
- for definition in definitions:
- try:
- if definition.module_path:
- if definition.type == "import":
- definition = self._top_definition(definition)
- if not definition.module_path:
- continue
- try:
- parent = definition.parent()
- container = parent.name if parent.type != "module" else ""
- except Exception:
- container = ""
-
- try:
- docstring = definition.docstring()
- rawdocstring = definition.docstring(raw=True)
- except Exception:
- docstring = ""
- rawdocstring = ""
- _definition = {
- "text": definition.name,
- "type": self._get_definition_type(definition),
- "raw_type": definition.type,
- "fileName": definition.module_path,
- "container": container,
- "range": self._extract_range(definition),
- "description": definition.description,
- "docstring": docstring,
- "raw_docstring": rawdocstring,
- }
- _definitions.append(_definition)
- except Exception as e:
- pass
- return json.dumps({"id": identifier, "results": _definitions})
-
- def _serialize_tooltip(self, definitions, identifier=None):
- _definitions = []
- for definition in definitions:
- signature = definition.name
- description = None
- if definition.type in ["class", "function"]:
- signature = self._generate_signature(definition)
- try:
- description = definition.docstring(raw=True).strip()
- except Exception:
- description = ""
- if not description and not hasattr(definition, "get_line_code"):
- # jedi returns an empty string for compiled objects
- description = definition.docstring().strip()
- if definition.type == "module":
- signature = definition.full_name
- try:
- description = definition.docstring(raw=True).strip()
- except Exception:
- description = ""
- if not description and hasattr(definition, "get_line_code"):
- # jedi returns an empty string for compiled objects
- description = definition.docstring().strip()
- _definition = {
- "type": self._get_definition_type(definition),
- "text": definition.name,
- "description": description,
- "docstring": description,
- "signature": signature,
- }
- _definitions.append(_definition)
- return json.dumps({"id": identifier, "results": _definitions})
-
- def _serialize_usages(self, usages, identifier=None):
- _usages = []
- for usage in usages:
- _usages.append(
- {
- "name": usage.name,
- "moduleName": usage.module_name,
- "fileName": usage.module_path,
- "line": usage.line,
- "column": usage.column,
- }
- )
- return json.dumps({"id": identifier, "results": _usages})
-
- def _deserialize(self, request):
- """Deserialize request from VSCode.
-
- Args:
- request: String with raw request from VSCode.
-
- Returns:
- Python dictionary with request data.
- """
- return json.loads(request)
-
- def _set_request_config(self, config):
- """Sets config values for current request.
-
- This includes sys.path modifications which is getting restored to
- default value on each request so each project should be isolated
- from each other.
-
- Args:
- config: Dictionary with config values.
- """
- sys.path = self.default_sys_path
- self.use_snippets = config.get("useSnippets")
- self.show_doc_strings = config.get("showDescriptions", True)
- self.fuzzy_matcher = config.get("fuzzyMatcher", False)
- jedi.settings.case_insensitive_completion = config.get(
- "caseInsensitiveCompletion", True
- )
- for path in config.get("extraPaths", []):
- if path and path not in sys.path:
- sys.path.insert(0, path)
-
- def _normalize_request_path(self, request):
- """Normalize any Windows paths received by a *nix build of
- Python. Does not alter the reverse os.path.sep=='\\',
- i.e. *nix paths received by a Windows build of Python.
- """
- if "path" in request:
- if not self.drive_mount:
- return
- newPath = request["path"].replace("\\", "/")
- if newPath[0:1] == "/":
- # is absolute path with no drive letter
- request["path"] = newPath
- elif newPath[1:2] == ":":
- # is path with drive letter, only absolute can be mapped
- request["path"] = self.drive_mount + newPath[0:1].lower() + newPath[2:]
- else:
- # is relative path
- request["path"] = newPath
-
- def _process_request(self, request):
- """Accept serialized request from VSCode and write response."""
- request = self._deserialize(request)
-
- self._set_request_config(request.get("config", {}))
-
- self._normalize_request_path(request)
- path = self._get_top_level_module(request.get("path", ""))
- if len(path) > 0 and path not in sys.path:
- sys.path.insert(0, path)
- lookup = request.get("lookup", "completions")
-
- if lookup == "names":
- return self._serialize_definitions(
- jedi.Script(
- source=request.get("source", None), path=request.get("path", "")
- ).get_names(all_scopes=True),
- request["id"],
- )
-
- script = jedi.Script(
- source=request.get("source", None),
- line=request["line"] + 1,
- column=request["column"],
- path=request.get("path", ""),
- project=jedi.get_default_project(os.path.dirname(path)),
- sys_path=sys.path,
- )
-
- if lookup == "definitions":
- defs = self._get_definitionsx(
- script.goto_assignments(follow_imports=True), request["id"]
- )
- return json.dumps({"id": request["id"], "results": defs})
- if lookup == "tooltip":
- if jediPreview:
- defs = []
- try:
- defs = self._get_definitionsx(
- script.goto_definitions(), request["id"], True
- )
- except:
- pass
- try:
- if len(defs) == 0:
- defs = self._get_definitionsx(
- script.goto_assignments(), request["id"], True
- )
- except:
- pass
- return json.dumps({"id": request["id"], "results": defs})
- else:
- try:
- return self._serialize_tooltip(
- script.goto_definitions(), request["id"]
- )
- except:
- return json.dumps({"id": request["id"], "results": []})
- elif lookup == "arguments":
- return self._serialize_arguments(script, request["id"])
- elif lookup == "usages":
- return self._serialize_usages(script.usages(), request["id"])
- elif lookup == "methods":
- return self._serialize_methods(
- script, request["id"], request.get("prefix", "")
- )
- else:
- return self._serialize_completions(
- script, request["id"], request.get("prefix", "")
- )
-
- def _write_response(self, response):
- sys.stdout.write(response + "\n")
- sys.stdout.flush()
-
- def watch(self):
- while True:
- try:
- rq = self._input.readline()
- if len(rq) == 0:
- # Reached EOF - indication our parent process is gone.
- sys.stderr.write(
- "Received EOF from the standard input,exiting" + "\n"
- )
- sys.stderr.flush()
- return
- with RedirectStdout():
- response = self._process_request(rq)
- self._write_response(response)
-
- except Exception:
- sys.stderr.write(traceback.format_exc() + "\n")
- sys.stderr.flush()
-
-
-if __name__ == "__main__":
- cachePrefix = "v"
- modulesToLoad = ""
- if len(sys.argv) > 2 and sys.argv[1] == "custom":
- jediPath = sys.argv[2]
- jediPreview = True
- cachePrefix = "custom_v"
- if len(sys.argv) > 3:
- modulesToLoad = sys.argv[3]
- else:
- # release
- jediPath = os.path.join(os.path.dirname(__file__), "lib", "python")
- if len(sys.argv) > 1:
- modulesToLoad = sys.argv[1]
-
- sys.path.insert(0, jediPath)
- import jedi
-
- if jediPreview:
- jedi.settings.cache_directory = os.path.join(
- jedi.settings.cache_directory,
- cachePrefix + jedi.__version__.replace(".", ""),
- )
- # remove jedi from path after we import it so it will not be completed
- sys.path.pop(0)
- if len(modulesToLoad) > 0:
- jedi.preload_module(*modulesToLoad.split(","))
- JediCompletion().watch()
diff --git a/pythonFiles/install_debugpy.py b/pythonFiles/install_debugpy.py
deleted file mode 100644
index e9361a6aeb3e..000000000000
--- a/pythonFiles/install_debugpy.py
+++ /dev/null
@@ -1,63 +0,0 @@
-import io
-import json
-import os
-import urllib.request as url_lib
-import zipfile
-from packaging.version import parse as version_parser
-
-
-EXTENSION_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-DEBUGGER_DEST = os.path.join(EXTENSION_ROOT, "pythonFiles", "lib", "python")
-DEBUGGER_PACKAGE = "debugpy"
-DEBUGGER_PYTHON_VERSIONS = ("cp38",)
-
-
-def _contains(s, parts=()):
- return any(p for p in parts if p in s)
-
-
-def _get_package_data():
- json_uri = "https://pypi.org/pypi/{0}/json".format(DEBUGGER_PACKAGE)
- # Response format: https://warehouse.readthedocs.io/api-reference/json/#project
- # Release metadata format: https://github.com/pypa/interoperability-peps/blob/master/pep-0426-core-metadata.rst
- with url_lib.urlopen(json_uri) as response:
- return json.loads(response.read())
-
-
-def _get_debugger_wheel_urls(data, version):
- return list(
- r["url"]
- for r in data["releases"][version]
- if _contains(r["url"], DEBUGGER_PYTHON_VERSIONS)
- )
-
-
-def _download_and_extract(root, url, version):
- root = os.getcwd() if root is None or root == "." else root
- prefix = os.path.join("debugpy-{0}.data".format(version), "purelib")
- with url_lib.urlopen(url) as response:
- # Extract only the contents of the purelib subfolder (parent folder of debugpy),
- # since debugpy files rely on the presence of a 'debugpy' folder.
- with zipfile.ZipFile(io.BytesIO(response.read()), "r") as wheel:
- for zip_info in wheel.infolist():
- # Ignore dist info since we are merging multiple wheels
- if ".dist-info" in zip_info.filename:
- continue
- # Normalize path for Windows, the wheel folder structure
- # uses forward slashes.
- normalized = os.path.normpath(zip_info.filename)
- # Flatten the folder structure.
- zip_info.filename = normalized.split(prefix)[-1]
- wheel.extract(zip_info, root)
-
-
-def main(root):
- data = _get_package_data()
- latest_version = max(data["releases"].keys(), key=version_parser)
-
- for url in _get_debugger_wheel_urls(data, latest_version):
- _download_and_extract(root, url, latest_version)
-
-
-if __name__ == "__main__":
- main(DEBUGGER_DEST)
diff --git a/pythonFiles/normalizeSelection.py b/pythonFiles/normalizeSelection.py
deleted file mode 100644
index 621c59b806af..000000000000
--- a/pythonFiles/normalizeSelection.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-import ast
-import json
-import re
-import sys
-import textwrap
-
-
-def split_lines(source):
- """
- Split selection lines in a version-agnostic way.
-
- Python grammar only treats \r, \n, and \r\n as newlines.
- But splitlines() in Python 3 has a much larger list: for example, it also includes \v, \f.
- As such, this function will split lines across all Python versions.
- """
- return re.split(r"[\n\r]+", source)
-
-
-def _get_statements(selection):
- """
- Process a multiline selection into a list of its top-level statements.
- This will remove empty newlines around and within the selection, dedent it,
- and split it using the result of `ast.parse()`.
- """
-
- # Remove blank lines within the selection to prevent the REPL from thinking the block is finished.
- lines = (line for line in split_lines(selection) if line.strip() != "")
-
- # Dedent the selection and parse it using the ast module.
- # Note that leading comments in the selection will be discarded during parsing.
- source = textwrap.dedent("\n".join(lines))
- tree = ast.parse(source)
-
- # We'll need the dedented lines to rebuild the selection.
- lines = split_lines(source)
-
- # Get the line ranges for top-level blocks returned from parsing the dedented text
- # and split the selection accordingly.
- # tree.body is a list of AST objects, which we rely on to extract top-level statements.
- # If we supported Python 3.8+ only we could use the lineno and end_lineno attributes of each object
- # to get the boundaries of each block.
- # However, earlier Python versions only have the lineno attribute, which is the range start position (1-indexed).
- # Therefore, to retrieve the end line of each block in a version-agnostic way we need to do
- # `end = next_block.lineno - 1`
- # for all blocks except the last one, which will will just run until the last line.
- ends = [node.lineno - 1 for node in tree.body[1:]] + [len(lines)]
- for node, end in zip(tree.body, ends):
- # Given this selection:
- # 1: if (m > 0 and
- # 2: n < 3):
- # 3: print('foo')
- # 4: value = 'bar'
- #
- # The first block would have lineno = 1,and the second block lineno = 4
- start = node.lineno - 1
- block = "\n".join(lines[start:end])
-
- # If the block is multiline, add an extra newline character at its end.
- # This way, when joining blocks back together, there will be a blank line between each multiline statement
- # and no blank lines between single-line statements, or it would look like this:
- # >>> x = 22
- # >>>
- # >>> total = x + 30
- # >>>
- # Note that for the multiline parentheses case this newline is redundant,
- # since the closing parenthesis terminates the statement already.
- # This means that for this pattern we'll end up with:
- # >>> x = [
- # ... 1
- # ... ]
- # >>>
- # >>> y = [
- # ... 2
- # ...]
- if end - start > 1:
- block += "\n"
-
- yield block
-
-
-def normalize_lines(selection):
- """
- Normalize the text selection received from the extension.
-
- If it is a single line selection, dedent it and append a newline and
- send it back to the extension.
- Otherwise, sanitize the multiline selection before returning it:
- split it in a list of top-level statements
- and add newlines between each of them so the REPL knows where each block ends.
- """
- try:
- # Parse the selection into a list of top-level blocks.
- # We don't differentiate between single and multiline statements
- # because it's not a perf bottleneck,
- # and the overhead from splitting and rejoining strings in the multiline case is one-off.
- statements = _get_statements(selection)
-
- # Insert a newline between each top-level statement, and append a newline to the selection.
- source = "\n".join(statements) + "\n"
- except:
- # If there's a problem when parsing statements,
- # append a blank line to end the block and send it as-is.
- source = selection + "\n\n"
-
- return source
-
-
-if __name__ == "__main__":
- # Content is being sent from the extension as a JSON object.
- # Decode the data from the raw bytes.
- stdin = sys.stdin if sys.version_info < (3,) else sys.stdin.buffer
- raw = stdin.read()
- contents = json.loads(raw.decode("utf-8"))
-
- normalized = normalize_lines(contents["code"])
-
- # Send the normalized code back to the extension in a JSON object.
- data = json.dumps({"normalized": normalized})
-
- stdout = sys.stdout if sys.version_info < (3,) else sys.stdout.buffer
- stdout.write(data.encode("utf-8"))
- stdout.close()
diff --git a/pythonFiles/printEnvVariablesToFile.py b/pythonFiles/printEnvVariablesToFile.py
deleted file mode 100644
index be966bcac28c..000000000000
--- a/pythonFiles/printEnvVariablesToFile.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-import os
-import json
-import sys
-
-
-# Last argument is the target file into which we'll write the env variables as json.
-json_file = sys.argv[-1]
-
-with open(json_file, "w") as outfile:
- json.dump(dict(os.environ), outfile)
diff --git a/pythonFiles/pyproject.toml b/pythonFiles/pyproject.toml
deleted file mode 100644
index 52c7c96d11e7..000000000000
--- a/pythonFiles/pyproject.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-[tool.black]
-exclude = '''
-
-(
- /(
- .data
- | .vscode
- | lib
- )/
-)
-'''
diff --git a/pythonFiles/pyvsc-run-isolated.py b/pythonFiles/pyvsc-run-isolated.py
deleted file mode 100644
index 18c2a61872f0..000000000000
--- a/pythonFiles/pyvsc-run-isolated.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-if __name__ != "__main__":
- raise Exception("{} cannot be imported".format(__name__))
-
-import os
-import os.path
-import runpy
-import sys
-
-
-def normalize(path):
- return os.path.normcase(os.path.normpath(path))
-
-
-# We "isolate" the script/module (sys.argv[1]) by removing current working
-# directory or '' in sys.path and then sending the target on to runpy.
-cwd = normalize(os.getcwd())
-sys.path[:] = [p for p in sys.path if p != "" and normalize(p) != cwd]
-del sys.argv[0]
-module = sys.argv[0]
-if module == "-c":
- ns = {}
- for code in sys.argv[1:]:
- exec(code, ns, ns)
-elif module.startswith("-"):
- raise NotImplementedError(sys.argv)
-elif module.endswith(".py"):
- runpy.run_path(module, run_name="__main__")
-else:
- runpy.run_module(module, run_name="__main__", alter_sys=True)
diff --git a/pythonFiles/refactor.py b/pythonFiles/refactor.py
deleted file mode 100644
index f9d3b29e3b19..000000000000
--- a/pythonFiles/refactor.py
+++ /dev/null
@@ -1,395 +0,0 @@
-# Arguments are:
-# 1. Working directory.
-# 2. Rope folder
-
-import difflib
-import io
-import json
-import os
-import sys
-import traceback
-
-try:
- import rope
- from rope.base import libutils
- from rope.refactor.rename import Rename
- from rope.refactor.extract import ExtractMethod, ExtractVariable
- import rope.base.project
- import rope.base.taskhandle
-except:
- jsonMessage = {
- "error": True,
- "message": "Rope not installed",
- "traceback": "",
- "type": "ModuleNotFoundError",
- }
- sys.stderr.write(json.dumps(jsonMessage))
- sys.stderr.flush()
-
-WORKSPACE_ROOT = sys.argv[1]
-ROPE_PROJECT_FOLDER = ".vscode/.ropeproject"
-
-
-class RefactorProgress:
- """
- Refactor progress information
- """
-
- def __init__(self, name="Task Name", message=None, percent=0):
- self.name = name
- self.message = message
- self.percent = percent
-
-
-class ChangeType:
- """
- Change Type Enum
- """
-
- EDIT = 0
- NEW = 1
- DELETE = 2
-
-
-class Change:
- """ """
-
- EDIT = 0
- NEW = 1
- DELETE = 2
-
- def __init__(self, filePath, fileMode=ChangeType.EDIT, diff=""):
- self.filePath = filePath
- self.diff = diff
- self.fileMode = fileMode
-
-
-def get_diff(changeset):
- """This is a copy of the code form the ChangeSet.get_description method found in Rope."""
- new = changeset.new_contents
- old = changeset.old_contents
- if old is None:
- if changeset.resource.exists():
- old = changeset.resource.read()
- else:
- old = ""
-
- # Ensure code has a trailing empty lines, before generating a diff.
- # https://github.com/Microsoft/vscode-python/issues/695.
- old_lines = old.splitlines(True)
- if not old_lines[-1].endswith("\n"):
- old_lines[-1] = old_lines[-1] + os.linesep
- new = new + os.linesep
-
- result = difflib.unified_diff(
- old_lines,
- new.splitlines(True),
- "a/" + changeset.resource.path,
- "b/" + changeset.resource.path,
- )
- return "".join(list(result))
-
-
-class BaseRefactoring(object):
- """
- Base class for refactorings
- """
-
- def __init__(self, project, resource, name="Refactor", progressCallback=None):
- self._progressCallback = progressCallback
- self._handle = rope.base.taskhandle.TaskHandle(name)
- self._handle.add_observer(self._update_progress)
- self.project = project
- self.resource = resource
- self.changes = []
-
- def _update_progress(self):
- jobset = self._handle.current_jobset()
- if jobset and not self._progressCallback is None:
- progress = RefactorProgress()
- # getting current job set name
- if jobset.get_name() is not None:
- progress.name = jobset.get_name()
- # getting active job name
- if jobset.get_active_job_name() is not None:
- progress.message = jobset.get_active_job_name()
- # adding done percent
- percent = jobset.get_percent_done()
- if percent is not None:
- progress.percent = percent
- if not self._progressCallback is None:
- self._progressCallback(progress)
-
- def stop(self):
- self._handle.stop()
-
- def refactor(self):
- try:
- self.onRefactor()
- except rope.base.exceptions.InterruptedTaskError:
- # we can ignore this exception, as user has cancelled refactoring
- pass
-
- def onRefactor(self):
- """
- To be implemented by each base class
- """
- pass
-
-
-class RenameRefactor(BaseRefactoring):
- def __init__(
- self,
- project,
- resource,
- name="Rename",
- progressCallback=None,
- startOffset=None,
- newName="new_Name",
- ):
- BaseRefactoring.__init__(self, project, resource, name, progressCallback)
- self._newName = newName
- self.startOffset = startOffset
-
- def onRefactor(self):
- renamed = Rename(self.project, self.resource, self.startOffset)
- changes = renamed.get_changes(self._newName, task_handle=self._handle)
- for item in changes.changes:
- if isinstance(item, rope.base.change.ChangeContents):
- self.changes.append(
- Change(item.resource.real_path, ChangeType.EDIT, get_diff(item))
- )
- else:
- raise Exception("Unknown Change")
-
-
-class ExtractVariableRefactor(BaseRefactoring):
- def __init__(
- self,
- project,
- resource,
- name="Extract Variable",
- progressCallback=None,
- startOffset=None,
- endOffset=None,
- newName="new_Name",
- similar=False,
- global_=False,
- ):
- BaseRefactoring.__init__(self, project, resource, name, progressCallback)
- self._newName = newName
- self._startOffset = startOffset
- self._endOffset = endOffset
- self._similar = similar
- self._global = global_
-
- def onRefactor(self):
- renamed = ExtractVariable(
- self.project, self.resource, self._startOffset, self._endOffset
- )
- changes = renamed.get_changes(self._newName, self._similar, self._global)
- for item in changes.changes:
- if isinstance(item, rope.base.change.ChangeContents):
- self.changes.append(
- Change(item.resource.real_path, ChangeType.EDIT, get_diff(item))
- )
- else:
- raise Exception("Unknown Change")
-
-
-class ExtractMethodRefactor(ExtractVariableRefactor):
- def __init__(
- self,
- project,
- resource,
- name="Extract Method",
- progressCallback=None,
- startOffset=None,
- endOffset=None,
- newName="new_Name",
- similar=False,
- global_=False,
- ):
- ExtractVariableRefactor.__init__(
- self,
- project,
- resource,
- name,
- progressCallback,
- startOffset=startOffset,
- endOffset=endOffset,
- newName=newName,
- similar=similar,
- global_=global_,
- )
-
- def onRefactor(self):
- renamed = ExtractMethod(
- self.project, self.resource, self._startOffset, self._endOffset
- )
- changes = renamed.get_changes(self._newName, self._similar, self._global)
- for item in changes.changes:
- if isinstance(item, rope.base.change.ChangeContents):
- self.changes.append(
- Change(item.resource.real_path, ChangeType.EDIT, get_diff(item))
- )
- else:
- raise Exception("Unknown Change")
-
-
-class RopeRefactoring(object):
- def __init__(self):
- self.default_sys_path = sys.path
- self._input = io.open(sys.stdin.fileno(), encoding="utf-8")
-
- def _rename(self, filePath, start, newName, indent_size):
- """
- Renames a variable
- """
- project = rope.base.project.Project(
- WORKSPACE_ROOT,
- ropefolder=ROPE_PROJECT_FOLDER,
- save_history=False,
- indent_size=indent_size,
- )
- resourceToRefactor = libutils.path_to_resource(project, filePath)
- refactor = RenameRefactor(
- project, resourceToRefactor, startOffset=start, newName=newName
- )
- refactor.refactor()
- changes = refactor.changes
- project.close()
- valueToReturn = []
- for change in changes:
- valueToReturn.append({"diff": change.diff})
- return valueToReturn
-
- def _extractVariable(self, filePath, start, end, newName, indent_size):
- """
- Extracts a variable
- """
- project = rope.base.project.Project(
- WORKSPACE_ROOT,
- ropefolder=ROPE_PROJECT_FOLDER,
- save_history=False,
- indent_size=indent_size,
- )
- resourceToRefactor = libutils.path_to_resource(project, filePath)
- refactor = ExtractVariableRefactor(
- project,
- resourceToRefactor,
- startOffset=start,
- endOffset=end,
- newName=newName,
- similar=True,
- )
- refactor.refactor()
- changes = refactor.changes
- project.close()
- valueToReturn = []
- for change in changes:
- valueToReturn.append({"diff": change.diff})
- return valueToReturn
-
- def _extractMethod(self, filePath, start, end, newName, indent_size):
- """
- Extracts a method
- """
- project = rope.base.project.Project(
- WORKSPACE_ROOT,
- ropefolder=ROPE_PROJECT_FOLDER,
- save_history=False,
- indent_size=indent_size,
- )
- resourceToRefactor = libutils.path_to_resource(project, filePath)
- refactor = ExtractMethodRefactor(
- project,
- resourceToRefactor,
- startOffset=start,
- endOffset=end,
- newName=newName,
- similar=True,
- )
- refactor.refactor()
- changes = refactor.changes
- project.close()
- valueToReturn = []
- for change in changes:
- valueToReturn.append({"diff": change.diff})
- return valueToReturn
-
- def _serialize(self, identifier, results):
- """
- Serializes the refactor results
- """
- return json.dumps({"id": identifier, "results": results})
-
- def _deserialize(self, request):
- """Deserialize request from VSCode.
-
- Args:
- request: String with raw request from VSCode.
-
- Returns:
- Python dictionary with request data.
- """
- return json.loads(request)
-
- def _process_request(self, request):
- """Accept serialized request from VSCode and write response."""
- request = self._deserialize(request)
- lookup = request.get("lookup", "")
-
- if lookup == "":
- pass
- elif lookup == "rename":
- changes = self._rename(
- request["file"],
- int(request["start"]),
- request["name"],
- int(request["indent_size"]),
- )
- return self._write_response(self._serialize(request["id"], changes))
- elif lookup == "extract_variable":
- changes = self._extractVariable(
- request["file"],
- int(request["start"]),
- int(request["end"]),
- request["name"],
- int(request["indent_size"]),
- )
- return self._write_response(self._serialize(request["id"], changes))
- elif lookup == "extract_method":
- changes = self._extractMethod(
- request["file"],
- int(request["start"]),
- int(request["end"]),
- request["name"],
- int(request["indent_size"]),
- )
- return self._write_response(self._serialize(request["id"], changes))
-
- def _write_response(self, response):
- sys.stdout.write(response + "\n")
- sys.stdout.flush()
-
- def watch(self):
- self._write_response("STARTED")
- while True:
- try:
- self._process_request(self._input.readline())
- except:
- exc_type, exc_value, exc_tb = sys.exc_info()
- tb_info = traceback.extract_tb(exc_tb)
- jsonMessage = {
- "error": True,
- "message": str(exc_value),
- "traceback": str(tb_info),
- "type": str(exc_type),
- }
- sys.stderr.write(json.dumps(jsonMessage))
- sys.stderr.flush()
-
-
-if __name__ == "__main__":
- RopeRefactoring().watch()
diff --git a/pythonFiles/run-jedi-language-server.py b/pythonFiles/run-jedi-language-server.py
deleted file mode 100644
index 31095121409f..000000000000
--- a/pythonFiles/run-jedi-language-server.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import sys
-import os
-
-# Add the lib path to our sys path so jedi_language_server can find its references
-EXTENSION_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-sys.path.insert(0, os.path.join(EXTENSION_ROOT, "pythonFiles", "lib", "jedilsp"))
-
-
-from jedi_language_server.cli import cli
-
-sys.exit(cli())
diff --git a/pythonFiles/sortImports.py b/pythonFiles/sortImports.py
deleted file mode 100644
index 070f7883fd66..000000000000
--- a/pythonFiles/sortImports.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-import io
-import os
-import os.path
-import sys
-
-isort_path = os.path.join(os.path.dirname(__file__), "lib", "python")
-sys.path.insert(0, isort_path)
-
-import isort.main
-
-isort.main.main()
diff --git a/pythonFiles/symbolProvider.py b/pythonFiles/symbolProvider.py
deleted file mode 100644
index 033ce4b99900..000000000000
--- a/pythonFiles/symbolProvider.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-import ast
-import json
-import sys
-
-
-class Visitor(ast.NodeVisitor):
- def __init__(self):
- self.symbols = {"classes": [], "methods": [], "functions": []}
-
- def visit_Module(self, node):
- self.visitChildren(node)
-
- def visitChildren(self, node, namespace=""):
- for child in node.body:
- if isinstance(child, ast.FunctionDef):
- self.visitDef(child, namespace)
- if isinstance(child, ast.ClassDef):
- self.visitClassDef(child, namespace)
- try:
- if isinstance(child, ast.AsyncFunctionDef):
- self.visitDef(child, namespace)
- except Exception:
- pass
-
- def visitDef(self, node, namespace=""):
- end_position = self.getEndPosition(node)
- symbol = "functions" if namespace == "" else "methods"
- self.symbols[symbol].append(self.getDataObject(node, namespace))
-
- def visitClassDef(self, node, namespace=""):
- end_position = self.getEndPosition(node)
- self.symbols["classes"].append(self.getDataObject(node, namespace))
-
- if len(namespace) > 0:
- namespace = "{0}::{1}".format(namespace, node.name)
- else:
- namespace = node.name
- self.visitChildren(node, namespace)
-
- def getDataObject(self, node, namespace=""):
- end_position = self.getEndPosition(node)
- return {
- "namespace": namespace,
- "name": node.name,
- "range": {
- "start": {"line": node.lineno - 1, "character": node.col_offset},
- "end": {"line": end_position[0], "character": end_position[1]},
- },
- }
-
- def getEndPosition(self, node):
- if not hasattr(node, "body") or len(node.body) == 0:
- return (node.lineno - 1, node.col_offset)
- return self.getEndPosition(node.body[-1])
-
-
-def provide_symbols(source):
- """Provides a list of all symbols in provided code.
-
- The list comprises of 3-item tuples that contain the starting line number,
- ending line number and whether the statement is a single line.
-
- """
- tree = ast.parse(source)
- visitor = Visitor()
- visitor.visit(tree)
- sys.stdout.write(json.dumps(visitor.symbols))
- sys.stdout.flush()
-
-
-if __name__ == "__main__":
- if len(sys.argv) == 3:
- contents = sys.argv[2]
- else:
- with open(sys.argv[1], "r") as source:
- contents = source.read()
-
- try:
- default_encoding = sys.getdefaultencoding()
- encoded_contents = contents.encode(default_encoding, "surrogateescape")
- contents = encoded_contents.decode(default_encoding, "replace")
- except (UnicodeError, LookupError):
- pass
- if isinstance(contents, bytes):
- contents = contents.decode("utf8")
- provide_symbols(contents)
diff --git a/pythonFiles/tensorboard_launcher.py b/pythonFiles/tensorboard_launcher.py
deleted file mode 100644
index f92eb44786d4..000000000000
--- a/pythonFiles/tensorboard_launcher.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import time
-import sys
-import os
-from tensorboard import default
-from tensorboard import program
-
-
-def main(logdir):
- os.environ["VSCODE_TENSORBOARD_LAUNCH"] = "1"
- tb = program.TensorBoard()
- tb.configure(bind_all=False, logdir=logdir)
- url = tb.launch()
- sys.stdout.write("TensorBoard started at %s\n" % (url))
- sys.stdout.flush()
- while True:
- try:
- time.sleep(60)
- except KeyboardInterrupt:
- break
- sys.stdout.write("TensorBoard is shutting down")
- sys.stdout.flush()
-
-
-if __name__ == "__main__":
- if len(sys.argv) == 2:
- logdir = str(sys.argv[1])
- sys.stdout.write("Starting TensorBoard with logdir %s" % (logdir))
- main(logdir)
diff --git a/pythonFiles/testing_tools/adapter/__main__.py b/pythonFiles/testing_tools/adapter/__main__.py
deleted file mode 100644
index 5857c63db049..000000000000
--- a/pythonFiles/testing_tools/adapter/__main__.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-from __future__ import absolute_import
-
-import argparse
-import sys
-
-from . import pytest, report
-from .errors import UnsupportedToolError, UnsupportedCommandError
-
-
-TOOLS = {
- "pytest": {
- "_add_subparser": pytest.add_cli_subparser,
- "discover": pytest.discover,
- },
-}
-REPORTERS = {
- "discover": report.report_discovered,
-}
-
-
-def parse_args(
- # the args to parse
- argv=sys.argv[1:],
- # the program name
- prog=sys.argv[0],
-):
- """
- Return the subcommand & tool to run, along with its args.
-
- This defines the standard CLI for the different testing frameworks.
- """
- parser = argparse.ArgumentParser(
- description="Run Python testing operations.",
- prog=prog,
- # ...
- )
- cmdsubs = parser.add_subparsers(dest="cmd")
-
- # Add "run" and "debug" subcommands when ready.
- for cmdname in ["discover"]:
- sub = cmdsubs.add_parser(cmdname)
- subsubs = sub.add_subparsers(dest="tool")
- for toolname in sorted(TOOLS):
- try:
- add_subparser = TOOLS[toolname]["_add_subparser"]
- except KeyError:
- continue
- subsub = add_subparser(cmdname, toolname, subsubs)
- if cmdname == "discover":
- subsub.add_argument("--simple", action="store_true")
- subsub.add_argument(
- "--no-hide-stdio", dest="hidestdio", action="store_false"
- )
- subsub.add_argument("--pretty", action="store_true")
-
- # Parse the args!
- if "--" in argv:
- sep_index = argv.index("--")
- toolargs = argv[sep_index + 1 :]
- argv = argv[:sep_index]
- else:
- toolargs = []
- args = parser.parse_args(argv)
- ns = vars(args)
-
- cmd = ns.pop("cmd")
- if not cmd:
- parser.error("missing command")
-
- tool = ns.pop("tool")
- if not tool:
- parser.error("missing tool")
-
- return tool, cmd, ns, toolargs
-
-
-def main(
- toolname,
- cmdname,
- subargs,
- toolargs,
- # internal args (for testing):
- _tools=TOOLS,
- _reporters=REPORTERS,
-):
- try:
- tool = _tools[toolname]
- except KeyError:
- raise UnsupportedToolError(toolname)
-
- try:
- run = tool[cmdname]
- report_result = _reporters[cmdname]
- except KeyError:
- raise UnsupportedCommandError(cmdname)
-
- parents, result = run(toolargs, **subargs)
- report_result(result, parents, **subargs)
-
-
-if __name__ == "__main__":
- tool, cmd, subargs, toolargs = parse_args()
- main(tool, cmd, subargs, toolargs)
diff --git a/pythonFiles/testing_tools/adapter/discovery.py b/pythonFiles/testing_tools/adapter/discovery.py
deleted file mode 100644
index 798aea1e93f1..000000000000
--- a/pythonFiles/testing_tools/adapter/discovery.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-from __future__ import absolute_import, print_function
-
-import re
-
-from .util import fix_fileid, DIRNAME, NORMCASE
-from .info import ParentInfo
-
-
-FILE_ID_RE = re.compile(
- r"""
- ^
- (?:
- ( .* [.] (?: py | txt ) \b ) # .txt for doctest files
- ( [^.] .* )?
- )
- $
- """,
- re.VERBOSE,
-)
-
-
-def fix_nodeid(
- nodeid,
- kind,
- rootdir=None,
- # *,
- _fix_fileid=fix_fileid,
-):
- if not nodeid:
- raise ValueError("missing nodeid")
- if nodeid == ".":
- return nodeid
-
- fileid = nodeid
- remainder = ""
- if kind not in ("folder", "file"):
- m = FILE_ID_RE.match(nodeid)
- if m:
- fileid, remainder = m.groups()
- elif len(nodeid) > 1:
- fileid = nodeid[:2]
- remainder = nodeid[2:]
- fileid = _fix_fileid(fileid, rootdir)
- return fileid + (remainder or "")
-
-
-class DiscoveredTests(object):
- """A container for the discovered tests and their parents."""
-
- def __init__(self):
- self.reset()
-
- def __len__(self):
- return len(self._tests)
-
- def __getitem__(self, index):
- return self._tests[index]
-
- @property
- def parents(self):
- return sorted(
- self._parents.values(),
- # Sort by (name, id).
- key=lambda p: (NORMCASE(p.root or p.name), p.id),
- )
-
- def reset(self):
- """Clear out any previously discovered tests."""
- self._parents = {}
- self._tests = []
-
- def add_test(self, test, parents):
- """Add the given test and its parents."""
- parentid = self._ensure_parent(test.path, parents)
- # Updating the parent ID and the test ID aren't necessary if the
- # provided test and parents (from the test collector) are
- # properly generated. However, we play it safe here.
- test = test._replace(
- # Clean up the ID.
- id=fix_nodeid(test.id, "test", test.path.root),
- parentid=parentid,
- )
- self._tests.append(test)
-
- def _ensure_parent(
- self,
- path,
- parents,
- # *,
- _dirname=DIRNAME,
- ):
- rootdir = path.root
- relpath = path.relfile
-
- _parents = iter(parents)
- nodeid, name, kind = next(_parents)
- # As in add_test(), the node ID *should* already be correct.
- nodeid = fix_nodeid(nodeid, kind, rootdir)
- _parentid = nodeid
- for parentid, parentname, parentkind in _parents:
- # As in add_test(), the parent ID *should* already be correct.
- parentid = fix_nodeid(parentid, kind, rootdir)
- if kind in ("folder", "file"):
- info = ParentInfo(nodeid, kind, name, rootdir, relpath, parentid)
- relpath = _dirname(relpath)
- else:
- info = ParentInfo(nodeid, kind, name, rootdir, None, parentid)
- self._parents[(rootdir, nodeid)] = info
- nodeid, name, kind = parentid, parentname, parentkind
- assert nodeid == "."
- info = ParentInfo(nodeid, kind, name=rootdir)
- self._parents[(rootdir, nodeid)] = info
-
- return _parentid
diff --git a/pythonFiles/testing_tools/adapter/errors.py b/pythonFiles/testing_tools/adapter/errors.py
deleted file mode 100644
index 3e6ae5189cb8..000000000000
--- a/pythonFiles/testing_tools/adapter/errors.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-
-class UnsupportedToolError(ValueError):
- def __init__(self, tool):
- msg = "unsupported tool {!r}".format(tool)
- super(UnsupportedToolError, self).__init__(msg)
- self.tool = tool
-
-
-class UnsupportedCommandError(ValueError):
- def __init__(self, cmd):
- msg = "unsupported cmd {!r}".format(cmd)
- super(UnsupportedCommandError, self).__init__(msg)
- self.cmd = cmd
diff --git a/pythonFiles/testing_tools/adapter/info.py b/pythonFiles/testing_tools/adapter/info.py
deleted file mode 100644
index f99ce0b6f9a2..000000000000
--- a/pythonFiles/testing_tools/adapter/info.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-from collections import namedtuple
-
-
-class SingleTestPath(namedtuple("TestPath", "root relfile func sub")):
- """Where to find a single test."""
-
- def __new__(cls, root, relfile, func, sub=None):
- self = super(SingleTestPath, cls).__new__(
- cls,
- str(root) if root else None,
- str(relfile) if relfile else None,
- str(func) if func else None,
- [str(s) for s in sub] if sub else None,
- )
- return self
-
- def __init__(self, *args, **kwargs):
- if self.root is None:
- raise TypeError("missing id")
- if self.relfile is None:
- raise TypeError("missing kind")
- # self.func may be None (e.g. for doctests).
- # self.sub may be None.
-
-
-class ParentInfo(namedtuple("ParentInfo", "id kind name root relpath parentid")):
-
- KINDS = ("folder", "file", "suite", "function", "subtest")
-
- def __new__(cls, id, kind, name, root=None, relpath=None, parentid=None):
- self = super(ParentInfo, cls).__new__(
- cls,
- id=str(id) if id else None,
- kind=str(kind) if kind else None,
- name=str(name) if name else None,
- root=str(root) if root else None,
- relpath=str(relpath) if relpath else None,
- parentid=str(parentid) if parentid else None,
- )
- return self
-
- def __init__(self, *args, **kwargs):
- if self.id is None:
- raise TypeError("missing id")
- if self.kind is None:
- raise TypeError("missing kind")
- if self.kind not in self.KINDS:
- raise ValueError("unsupported kind {!r}".format(self.kind))
- if self.name is None:
- raise TypeError("missing name")
- if self.root is None:
- if self.parentid is not None or self.kind != "folder":
- raise TypeError("missing root")
- if self.relpath is not None:
- raise TypeError("unexpected relpath {}".format(self.relpath))
- elif self.parentid is None:
- raise TypeError("missing parentid")
- elif self.relpath is None and self.kind in ("folder", "file"):
- raise TypeError("missing relpath")
-
-
-class SingleTestInfo(
- namedtuple("TestInfo", "id name path source markers parentid kind")
-):
- """Info for a single test."""
-
- MARKERS = ("skip", "skip-if", "expected-failure")
- KINDS = ("function", "doctest")
-
- def __new__(cls, id, name, path, source, markers, parentid, kind="function"):
- self = super(SingleTestInfo, cls).__new__(
- cls,
- str(id) if id else None,
- str(name) if name else None,
- path or None,
- str(source) if source else None,
- [str(marker) for marker in markers or ()],
- str(parentid) if parentid else None,
- str(kind) if kind else None,
- )
- return self
-
- def __init__(self, *args, **kwargs):
- if self.id is None:
- raise TypeError("missing id")
- if self.name is None:
- raise TypeError("missing name")
- if self.path is None:
- raise TypeError("missing path")
- if self.source is None:
- raise TypeError("missing source")
- else:
- srcfile, _, lineno = self.source.rpartition(":")
- if not srcfile or not lineno or int(lineno) < 0:
- raise ValueError("bad source {!r}".format(self.source))
- if self.markers:
- badmarkers = [m for m in self.markers if m not in self.MARKERS]
- if badmarkers:
- raise ValueError("unsupported markers {!r}".format(badmarkers))
- if self.parentid is None:
- raise TypeError("missing parentid")
- if self.kind is None:
- raise TypeError("missing kind")
- elif self.kind not in self.KINDS:
- raise ValueError("unsupported kind {!r}".format(self.kind))
-
- @property
- def root(self):
- return self.path.root
-
- @property
- def srcfile(self):
- return self.source.rpartition(":")[0]
-
- @property
- def lineno(self):
- return int(self.source.rpartition(":")[-1])
diff --git a/pythonFiles/testing_tools/adapter/pytest/__init__.py b/pythonFiles/testing_tools/adapter/pytest/__init__.py
deleted file mode 100644
index e894f7bcdb8e..000000000000
--- a/pythonFiles/testing_tools/adapter/pytest/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-from __future__ import absolute_import
-
-from ._cli import add_subparser as add_cli_subparser
-from ._discovery import discover
diff --git a/pythonFiles/testing_tools/adapter/pytest/_cli.py b/pythonFiles/testing_tools/adapter/pytest/_cli.py
deleted file mode 100644
index 3d3eec09a199..000000000000
--- a/pythonFiles/testing_tools/adapter/pytest/_cli.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-from __future__ import absolute_import
-
-from ..errors import UnsupportedCommandError
-
-
-def add_subparser(cmd, name, parent):
- """Add a new subparser to the given parent and add args to it."""
- parser = parent.add_parser(name)
- if cmd == "discover":
- # For now we don't have any tool-specific CLI options to add.
- pass
- else:
- raise UnsupportedCommandError(cmd)
- return parser
diff --git a/pythonFiles/testing_tools/adapter/pytest/_discovery.py b/pythonFiles/testing_tools/adapter/pytest/_discovery.py
deleted file mode 100644
index 51c94527302d..000000000000
--- a/pythonFiles/testing_tools/adapter/pytest/_discovery.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-from __future__ import absolute_import, print_function
-
-import sys
-
-import pytest
-
-from .. import util, discovery
-from ._pytest_item import parse_item
-
-
-def discover(
- pytestargs=None,
- hidestdio=False,
- # *,
- _pytest_main=pytest.main,
- _plugin=None,
- **_ignored
-):
- """Return the results of test discovery."""
- if _plugin is None:
- _plugin = TestCollector()
-
- pytestargs = _adjust_pytest_args(pytestargs)
- # We use this helper rather than "-pno:terminal" due to possible
- # platform-dependent issues.
- with (util.hide_stdio() if hidestdio else util.noop_cm()) as stdio:
- ec = _pytest_main(pytestargs, [_plugin])
- # See: https://docs.pytest.org/en/latest/usage.html#possible-exit-codes
- if ec == 5:
- # No tests were discovered.
- pass
- elif ec != 0:
- print(
- "equivalent command: {} -m pytest {}".format(
- sys.executable, util.shlex_unsplit(pytestargs)
- )
- )
- if hidestdio:
- print(stdio.getvalue(), file=sys.stderr)
- sys.stdout.flush()
- raise Exception("pytest discovery failed (exit code {})".format(ec))
- if not _plugin._started:
- print(
- "equivalent command: {} -m pytest {}".format(
- sys.executable, util.shlex_unsplit(pytestargs)
- )
- )
- if hidestdio:
- print(stdio.getvalue(), file=sys.stderr)
- sys.stdout.flush()
- raise Exception("pytest discovery did not start")
- return (
- _plugin._tests.parents,
- list(_plugin._tests),
- )
-
-
-def _adjust_pytest_args(pytestargs):
- """Return a corrected copy of the given pytest CLI args."""
- pytestargs = list(pytestargs) if pytestargs else []
- # Duplicate entries should be okay.
- pytestargs.insert(0, "--collect-only")
- # TODO: pull in code from:
- # src/client/testing/pytest/services/discoveryService.ts
- # src/client/testing/pytest/services/argsService.ts
- return pytestargs
-
-
-class TestCollector(object):
- """This is a pytest plugin that collects the discovered tests."""
-
- @classmethod
- def parse_item(cls, item):
- return parse_item(item)
-
- def __init__(self, tests=None):
- if tests is None:
- tests = discovery.DiscoveredTests()
- self._tests = tests
- self._started = False
-
- # Relevant plugin hooks:
- # https://docs.pytest.org/en/latest/reference.html#collection-hooks
-
- def pytest_collection_modifyitems(self, session, config, items):
- self._started = True
- self._tests.reset()
- for item in items:
- test, parents = self.parse_item(item)
- if test is not None:
- self._tests.add_test(test, parents)
-
- # This hook is not specified in the docs, so we also provide
- # the "modifyitems" hook just in case.
- def pytest_collection_finish(self, session):
- self._started = True
- try:
- items = session.items
- except AttributeError:
- # TODO: Is there an alternative?
- return
- self._tests.reset()
- for item in items:
- test, parents = self.parse_item(item)
- if test is not None:
- self._tests.add_test(test, parents)
diff --git a/pythonFiles/testing_tools/adapter/pytest/_pytest_item.py b/pythonFiles/testing_tools/adapter/pytest/_pytest_item.py
deleted file mode 100644
index f9ed1fe0f289..000000000000
--- a/pythonFiles/testing_tools/adapter/pytest/_pytest_item.py
+++ /dev/null
@@ -1,604 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-"""
-During "collection", pytest finds all the tests it supports. These are
-called "items". The process is top-down, mostly tracing down through
-the file system. Aside from its own machinery, pytest supports hooks
-that find tests. Effectively, pytest starts with a set of "collectors";
-objects that can provide a list of tests and sub-collectors. All
-collectors in the resulting tree are visited and the tests aggregated.
-For the most part, each test's (and collector's) parent is identified
-as the collector that collected it.
-
-Collectors and items are collectively identified as "nodes". The pytest
-API relies on collector and item objects providing specific methods and
-attributes. In addition to corresponding base classes, pytest provides
-a number of concrete implementations.
-
-The following are the known pytest node types:
-
- Node
- Collector
- FSCollector
- Session (the top-level collector)
- File
- Module
- Package
- DoctestTextfile
- DoctestModule
- PyCollector
- (Module)
- (...)
- Class
- UnitTestCase
- Instance
- Item
- Function
- TestCaseFunction
- DoctestItem
-
-Here are the unique attrs for those classes:
-
- Node
- name
- nodeid (readonly)
- config
- session
- (parent) - the parent node
- (fspath) - the file from which the node was collected
- ----
- own_marksers - explicit markers (e.g. with @pytest.mark())
- keywords
- extra_keyword_matches
-
- Item
- location - where the actual test source code is: (relfspath, lno, fullname)
- user_properties
-
- PyCollector
- module
- class
- instance
- obj
-
- Function
- module
- class
- instance
- obj
- function
- (callspec)
- (fixturenames)
- funcargs
- originalname - w/o decorations, e.g. [...] for parameterized
-
- DoctestItem
- dtest
- obj
-
-When parsing an item, we make use of the following attributes:
-
-* name
-* nodeid
-* __class__
- + __name__
-* fspath
-* location
-* function
- + __name__
- + __code__
- + __closure__
-* own_markers
-"""
-
-from __future__ import absolute_import, print_function
-
-import sys
-
-import pytest
-import _pytest.doctest
-import _pytest.unittest
-
-from ..info import SingleTestInfo, SingleTestPath
-from ..util import fix_fileid, PATH_SEP, NORMCASE
-
-
-def should_never_reach_here(item, **extra):
- """Indicates a code path we should never reach."""
- print("The Python extension has run into an unexpected situation")
- print("while processing a pytest node during test discovery. Please")
- print("Please open an issue at:")
- print(" https://github.com/microsoft/vscode-python/issues")
- print("and paste the following output there.")
- print()
- for field, info in _summarize_item(item):
- print("{}: {}".format(field, info))
- if extra:
- print()
- print("extra info:")
- for name, info in extra.items():
- print("{:10}".format(name + ":"), end="")
- if isinstance(info, str):
- print(info)
- else:
- try:
- print(*info)
- except TypeError:
- print(info)
- print()
- print("traceback:")
- import traceback
-
- traceback.print_stack()
-
- msg = "Unexpected pytest node (see printed output)."
- exc = NotImplementedError(msg)
- exc.item = item
- return exc
-
-
-def parse_item(
- item,
- # *,
- _get_item_kind=(lambda *a: _get_item_kind(*a)),
- _parse_node_id=(lambda *a: _parse_node_id(*a)),
- _split_fspath=(lambda *a: _split_fspath(*a)),
- _get_location=(lambda *a: _get_location(*a)),
-):
- """Return (TestInfo, [suite ID]) for the given item.
-
- The suite IDs, if any, are in parent order with the item's direct
- parent at the beginning. The parent of the last suite ID (or of
- the test if there are no suites) is the file ID, which corresponds
- to TestInfo.path.
-
- """
- # _debug_item(item, showsummary=True)
- kind, _ = _get_item_kind(item)
- # Skip plugin generated tests
- if kind is None:
- return None, None
- (nodeid, parents, fileid, testfunc, parameterized) = _parse_node_id(
- item.nodeid, kind
- )
- # Note: testfunc does not necessarily match item.function.__name__.
- # This can result from importing a test function from another module.
-
- # Figure out the file.
- testroot, relfile = _split_fspath(str(item.fspath), fileid, item)
- location, fullname = _get_location(item, testroot, relfile)
- if kind == "function":
- if testfunc and fullname != testfunc + parameterized:
- raise should_never_reach_here(
- item,
- fullname=fullname,
- testfunc=testfunc,
- parameterized=parameterized,
- # ...
- )
- elif kind == "doctest":
- if testfunc and fullname != testfunc and fullname != "[doctest] " + testfunc:
- raise should_never_reach_here(
- item,
- fullname=fullname,
- testfunc=testfunc,
- # ...
- )
- testfunc = None
-
- # Sort out the parent.
- if parents:
- parentid, _, _ = parents[0]
- else:
- parentid = None
-
- # Sort out markers.
- # See: https://docs.pytest.org/en/latest/reference.html#marks
- markers = set()
- for marker in getattr(item, "own_markers", []):
- if marker.name == "parameterize":
- # We've already covered these.
- continue
- elif marker.name == "skip":
- markers.add("skip")
- elif marker.name == "skipif":
- markers.add("skip-if")
- elif marker.name == "xfail":
- markers.add("expected-failure")
- # We can add support for other markers as we need them?
-
- test = SingleTestInfo(
- id=nodeid,
- name=item.name,
- path=SingleTestPath(
- root=testroot,
- relfile=relfile,
- func=testfunc,
- sub=[parameterized] if parameterized else None,
- ),
- source=location,
- markers=sorted(markers) if markers else None,
- parentid=parentid,
- )
- if parents and parents[-1] == (".", None, "folder"): # This should always be true?
- parents[-1] = (".", testroot, "folder")
- return test, parents
-
-
-def _split_fspath(
- fspath,
- fileid,
- item,
- # *,
- _normcase=NORMCASE,
-):
- """Return (testroot, relfile) for the given fspath.
-
- "relfile" will match "fileid".
- """
- # "fileid" comes from nodeid and is always relative to the testroot
- # (with a "./" prefix). There are no guarantees about casing, so we
- # normcase just be to sure.
- relsuffix = fileid[1:] # Drop (only) the "." prefix.
- if not _normcase(fspath).endswith(_normcase(relsuffix)):
- raise should_never_reach_here(
- item,
- fspath=fspath,
- fileid=fileid,
- # ...
- )
- testroot = fspath[: -len(fileid) + 1] # Ignore the "./" prefix.
- relfile = "." + fspath[-len(fileid) + 1 :] # Keep the pathsep.
- return testroot, relfile
-
-
-def _get_location(
- item,
- testroot,
- relfile,
- # *,
- _matches_relfile=(lambda *a: _matches_relfile(*a)),
- _is_legacy_wrapper=(lambda *a: _is_legacy_wrapper(*a)),
- _unwrap_decorator=(lambda *a: _unwrap_decorator(*a)),
- _pathsep=PATH_SEP,
-):
- """Return (loc str, fullname) for the given item."""
- # When it comes to normcase, we favor relfile (from item.fspath)
- # over item.location in this function.
-
- srcfile, lineno, fullname = item.location
- if _matches_relfile(srcfile, testroot, relfile):
- srcfile = relfile
- else:
- # pytest supports discovery of tests imported from other
- # modules. This is reflected by a different filename
- # in item.location.
-
- if _is_legacy_wrapper(srcfile):
- srcfile = relfile
- unwrapped = _unwrap_decorator(item.function)
- if unwrapped is None:
- # It was an invalid legacy wrapper so we just say
- # "somewhere in relfile".
- lineno = None
- else:
- _srcfile, lineno = unwrapped
- if not _matches_relfile(_srcfile, testroot, relfile):
- # For legacy wrappers we really expect the wrapped
- # function to be in relfile. So here we ignore any
- # other file and just say "somewhere in relfile".
- lineno = None
- elif _matches_relfile(srcfile, testroot, relfile):
- srcfile = relfile
- # Otherwise we just return the info from item.location as-is.
-
- if not srcfile.startswith("." + _pathsep):
- srcfile = "." + _pathsep + srcfile
-
- if lineno is None:
- lineno = -1 # i.e. "unknown"
-
- # from pytest, line numbers are 0-based
- location = "{}:{}".format(srcfile, int(lineno) + 1)
- return location, fullname
-
-
-def _matches_relfile(
- srcfile,
- testroot,
- relfile,
- # *,
- _normcase=NORMCASE,
- _pathsep=PATH_SEP,
-):
- """Return True if "srcfile" matches the given relfile."""
- testroot = _normcase(testroot)
- srcfile = _normcase(srcfile)
- relfile = _normcase(relfile)
- if srcfile == relfile:
- return True
- elif srcfile == relfile[len(_pathsep) + 1 :]:
- return True
- elif srcfile == testroot + relfile[1:]:
- return True
- else:
- return False
-
-
-def _is_legacy_wrapper(
- srcfile,
- # *,
- _pathsep=PATH_SEP,
- _pyversion=sys.version_info,
-):
- """Return True if the test might be wrapped.
-
- In Python 2 unittest's decorators (e.g. unittest.skip) do not wrap
- properly, so we must manually unwrap them.
- """
- if _pyversion > (3,):
- return False
- if (_pathsep + "unittest" + _pathsep + "case.py") not in srcfile:
- return False
- return True
-
-
-def _unwrap_decorator(func):
- """Return (filename, lineno) for the func the given func wraps.
-
- If the wrapped func cannot be identified then return None. Likewise
- for the wrapped filename. "lineno" is None if it cannot be found
- but the filename could.
- """
- try:
- func = func.__closure__[0].cell_contents
- except (IndexError, AttributeError):
- return None
- else:
- if not callable(func):
- return None
- try:
- filename = func.__code__.co_filename
- except AttributeError:
- return None
- else:
- try:
- lineno = func.__code__.co_firstlineno - 1
- except AttributeError:
- return (filename, None)
- else:
- return filename, lineno
-
-
-def _parse_node_id(
- testid,
- kind,
- # *,
- _iter_nodes=(lambda *a: _iter_nodes(*a)),
-):
- """Return the components of the given node ID, in heirarchical order."""
- nodes = iter(_iter_nodes(testid, kind))
-
- testid, name, kind = next(nodes)
- parents = []
- parameterized = None
- if kind == "doctest":
- parents = list(nodes)
- fileid, _, _ = parents[0]
- return testid, parents, fileid, name, parameterized
- elif kind is None:
- fullname = None
- else:
- if kind == "subtest":
- node = next(nodes)
- parents.append(node)
- funcid, funcname, _ = node
- parameterized = testid[len(funcid) :]
- elif kind == "function":
- funcname = name
- else:
- raise should_never_reach_here(
- testid,
- kind=kind,
- # ...
- )
- fullname = funcname
-
- for node in nodes:
- parents.append(node)
- parentid, name, kind = node
- if kind == "file":
- fileid = parentid
- break
- elif fullname is None:
- # We don't guess how to interpret the node ID for these tests.
- continue
- elif kind == "suite":
- fullname = name + "." + fullname
- else:
- raise should_never_reach_here(
- testid,
- node=node,
- # ...
- )
- else:
- fileid = None
- parents.extend(nodes) # Add the rest in as-is.
-
- return (
- testid,
- parents,
- fileid,
- fullname,
- parameterized or "",
- )
-
-
-def _iter_nodes(
- testid,
- kind,
- # *,
- _normalize_test_id=(lambda *a: _normalize_test_id(*a)),
- _normcase=NORMCASE,
- _pathsep=PATH_SEP,
-):
- """Yield (nodeid, name, kind) for the given node ID and its parents."""
- nodeid, testid = _normalize_test_id(testid, kind)
- if len(nodeid) > len(testid):
- testid = "." + _pathsep + testid
-
- if kind == "function" and nodeid.endswith("]"):
- funcid, sep, parameterized = nodeid.partition("[")
- if not sep:
- raise should_never_reach_here(
- nodeid,
- # ...
- )
- yield (nodeid, sep + parameterized, "subtest")
- nodeid = funcid
-
- parentid, _, name = nodeid.rpartition("::")
- if not parentid:
- if kind is None:
- # This assumes that plugins can generate nodes that do not
- # have a parent. All the builtin nodes have one.
- yield (nodeid, name, kind)
- return
- # We expect at least a filename and a name.
- raise should_never_reach_here(
- nodeid,
- # ...
- )
- yield (nodeid, name, kind)
-
- # Extract the suites.
- while "::" in parentid:
- suiteid = parentid
- parentid, _, name = parentid.rpartition("::")
- yield (suiteid, name, "suite")
-
- # Extract the file and folders.
- fileid = parentid
- raw = testid[: len(fileid)]
- _parentid, _, filename = _normcase(fileid).rpartition(_pathsep)
- parentid = fileid[: len(_parentid)]
- raw, name = raw[: len(_parentid)], raw[-len(filename) :]
- yield (fileid, name, "file")
- # We're guaranteed at least one (the test root).
- while _pathsep in _normcase(parentid):
- folderid = parentid
- _parentid, _, foldername = _normcase(folderid).rpartition(_pathsep)
- parentid = folderid[: len(_parentid)]
- raw, name = raw[: len(parentid)], raw[-len(foldername) :]
- yield (folderid, name, "folder")
- # We set the actual test root later at the bottom of parse_item().
- testroot = None
- yield (parentid, testroot, "folder")
-
-
-def _normalize_test_id(
- testid,
- kind,
- # *,
- _fix_fileid=fix_fileid,
- _pathsep=PATH_SEP,
-):
- """Return the canonical form for the given node ID."""
- while "::()::" in testid:
- testid = testid.replace("::()::", "::")
- if kind is None:
- return testid, testid
- orig = testid
-
- # We need to keep the testid as-is, or else pytest won't recognize
- # it when we try to use it later (e.g. to run a test). The only
- # exception is that we add a "./" prefix for relative paths.
- # Note that pytest always uses "/" as the path separator in IDs.
- fileid, sep, remainder = testid.partition("::")
- fileid = _fix_fileid(fileid)
- if not fileid.startswith("./"): # Absolute "paths" not expected.
- raise should_never_reach_here(
- testid,
- fileid=fileid,
- # ...
- )
- testid = fileid + sep + remainder
-
- return testid, orig
-
-
-def _get_item_kind(item):
- """Return (kind, isunittest) for the given item."""
- if isinstance(item, _pytest.doctest.DoctestItem):
- return "doctest", False
- elif isinstance(item, _pytest.unittest.TestCaseFunction):
- return "function", True
- elif isinstance(item, pytest.Function):
- # We *could* be more specific, e.g. "method", "subtest".
- return "function", False
- else:
- return None, False
-
-
-#############################
-# useful for debugging
-
-_FIELDS = [
- "nodeid",
- "kind",
- "class",
- "name",
- "fspath",
- "location",
- "function",
- "markers",
- "user_properties",
- "attrnames",
-]
-
-
-def _summarize_item(item):
- if not hasattr(item, "nodeid"):
- yield "nodeid", item
- return
-
- for field in _FIELDS:
- try:
- if field == "kind":
- yield field, _get_item_kind(item)
- elif field == "class":
- yield field, item.__class__.__name__
- elif field == "markers":
- yield field, item.own_markers
- # yield field, list(item.iter_markers())
- elif field == "attrnames":
- yield field, dir(item)
- else:
- yield field, getattr(item, field, "??>")
- except Exception as exc:
- yield field, "".format(exc)
-
-
-def _debug_item(item, showsummary=False):
- item._debugging = True
- try:
- summary = dict(_summarize_item(item))
- finally:
- item._debugging = False
-
- if showsummary:
- print(item.nodeid)
- for key in (
- "kind",
- "class",
- "name",
- "fspath",
- "location",
- "func",
- "markers",
- "props",
- ):
- print(" {:12} {}".format(key, summary[key]))
- print()
-
- return summary
diff --git a/pythonFiles/testing_tools/adapter/report.py b/pythonFiles/testing_tools/adapter/report.py
deleted file mode 100644
index bacdef7b9a00..000000000000
--- a/pythonFiles/testing_tools/adapter/report.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-from __future__ import print_function
-
-import json
-
-
-def report_discovered(
- tests,
- parents,
- # *,
- pretty=False,
- simple=False,
- _send=print,
- **_ignored
-):
- """Serialize the discovered tests and write to stdout."""
- if simple:
- data = [
- {
- "id": test.id,
- "name": test.name,
- "testroot": test.path.root,
- "relfile": test.path.relfile,
- "lineno": test.lineno,
- "testfunc": test.path.func,
- "subtest": test.path.sub or None,
- "markers": test.markers or [],
- }
- for test in tests
- ]
- else:
- byroot = {}
- for parent in parents:
- rootdir = parent.name if parent.root is None else parent.root
- try:
- root = byroot[rootdir]
- except KeyError:
- root = byroot[rootdir] = {
- "id": rootdir,
- "parents": [],
- "tests": [],
- }
- if not parent.root:
- root["id"] = parent.id
- continue
- root["parents"].append(
- {
- # "id" must match what the testing framework recognizes.
- "id": parent.id,
- "kind": parent.kind,
- "name": parent.name,
- "parentid": parent.parentid,
- }
- )
- if parent.relpath is not None:
- root["parents"][-1]["relpath"] = parent.relpath
- for test in tests:
- # We are guaranteed that the parent was added.
- root = byroot[test.path.root]
- testdata = {
- # "id" must match what the testing framework recognizes.
- "id": test.id,
- "name": test.name,
- # TODO: Add a "kind" field
- # (e.g. "unittest", "function", "doctest")
- "source": test.source,
- "markers": test.markers or [],
- "parentid": test.parentid,
- }
- root["tests"].append(testdata)
- data = [
- {
- "rootid": byroot[root]["id"],
- "root": root,
- "parents": byroot[root]["parents"],
- "tests": byroot[root]["tests"],
- }
- for root in sorted(byroot)
- ]
-
- kwargs = {}
- if pretty:
- # human-formatted
- kwargs = dict(
- sort_keys=True,
- indent=4,
- separators=(",", ": "),
- # ...
- )
- serialized = json.dumps(data, **kwargs)
-
- _send(serialized)
diff --git a/pythonFiles/testing_tools/adapter/util.py b/pythonFiles/testing_tools/adapter/util.py
deleted file mode 100644
index 77778c5b6126..000000000000
--- a/pythonFiles/testing_tools/adapter/util.py
+++ /dev/null
@@ -1,287 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-import contextlib
-import io
-
-try:
- from io import StringIO
-except ImportError:
- from StringIO import StringIO # 2.7
-import os
-import os.path
-import sys
-import tempfile
-
-
-@contextlib.contextmanager
-def noop_cm():
- yield
-
-
-def group_attr_names(attrnames):
- grouped = {
- "dunder": [],
- "private": [],
- "constants": [],
- "classes": [],
- "vars": [],
- "other": [],
- }
- for name in attrnames:
- if name.startswith("__") and name.endswith("__"):
- group = "dunder"
- elif name.startswith("_"):
- group = "private"
- elif name.isupper():
- group = "constants"
- elif name.islower():
- group = "vars"
- elif name == name.capitalize():
- group = "classes"
- else:
- group = "other"
- grouped[group].append(name)
- return grouped
-
-
-if sys.version_info < (3,):
- _str_to_lower = lambda val: val.decode().lower()
-else:
- _str_to_lower = str.lower
-
-
-#############################
-# file paths
-
-_os_path = os.path
-# Uncomment to test Windows behavior on non-windows OS:
-# import ntpath as _os_path
-PATH_SEP = _os_path.sep
-NORMCASE = _os_path.normcase
-DIRNAME = _os_path.dirname
-BASENAME = _os_path.basename
-IS_ABS_PATH = _os_path.isabs
-PATH_JOIN = _os_path.join
-
-
-def fix_path(
- path,
- # *,
- _pathsep=PATH_SEP,
-):
- """Return a platform-appropriate path for the given path."""
- if not path:
- return "."
- return path.replace("/", _pathsep)
-
-
-def fix_relpath(
- path,
- # *,
- _fix_path=fix_path,
- _path_isabs=IS_ABS_PATH,
- _pathsep=PATH_SEP,
-):
- """Return a ./-prefixed, platform-appropriate path for the given path."""
- path = _fix_path(path)
- if path in (".", ".."):
- return path
- if not _path_isabs(path):
- if not path.startswith("." + _pathsep):
- path = "." + _pathsep + path
- return path
-
-
-def _resolve_relpath(
- path,
- rootdir=None,
- # *,
- _path_isabs=IS_ABS_PATH,
- _normcase=NORMCASE,
- _pathsep=PATH_SEP,
-):
- # "path" is expected to use "/" for its path separator, regardless
- # of the provided "_pathsep".
-
- if path.startswith("./"):
- return path[2:]
- if not _path_isabs(path):
- return path
-
- # Deal with root-dir-as-fileid.
- _, sep, relpath = path.partition("/")
- if sep and not relpath.replace("/", ""):
- return ""
-
- if rootdir is None:
- return None
- rootdir = _normcase(rootdir)
- if not rootdir.endswith(_pathsep):
- rootdir += _pathsep
-
- if not _normcase(path).startswith(rootdir):
- return None
- return path[len(rootdir) :]
-
-
-def fix_fileid(
- fileid,
- rootdir=None,
- # *,
- normalize=False,
- strictpathsep=None,
- _pathsep=PATH_SEP,
- **kwargs
-):
- """Return a pathsep-separated file ID ("./"-prefixed) for the given value.
-
- The file ID may be absolute. If so and "rootdir" is
- provided then make the file ID relative. If absolute but "rootdir"
- is not provided then leave it absolute.
- """
- if not fileid or fileid == ".":
- return fileid
-
- # We default to "/" (forward slash) as the final path sep, since
- # that gives us a consistent, cross-platform result. (Windows does
- # actually support "/" as a path separator.) Most notably, node IDs
- # from pytest use "/" as the path separator by default.
- _fileid = fileid.replace(_pathsep, "/")
-
- relpath = _resolve_relpath(
- _fileid,
- rootdir,
- _pathsep=_pathsep,
- # ...
- **kwargs
- )
- if relpath: # Note that we treat "" here as an absolute path.
- _fileid = "./" + relpath
-
- if normalize:
- if strictpathsep:
- raise ValueError("cannot normalize *and* keep strict path separator")
- _fileid = _str_to_lower(_fileid)
- elif strictpathsep:
- # We do not use _normcase since we want to preserve capitalization.
- _fileid = _fileid.replace("/", _pathsep)
- return _fileid
-
-
-#############################
-# stdio
-
-
-@contextlib.contextmanager
-def _replace_fd(file, target):
- """
- Temporarily replace the file descriptor for `file`,
- for which sys.stdout or sys.stderr is passed.
- """
- try:
- fd = file.fileno()
- except (AttributeError, io.UnsupportedOperation):
- # `file` does not have fileno() so it's been replaced from the
- # default sys.stdout, etc. Return with noop.
- yield
- return
- target_fd = target.fileno()
-
- # Keep the original FD to be restored in the finally clause.
- dup_fd = os.dup(fd)
- try:
- # Point the FD at the target.
- os.dup2(target_fd, fd)
- try:
- yield
- finally:
- # Point the FD back at the original.
- os.dup2(dup_fd, fd)
- finally:
- os.close(dup_fd)
-
-
-@contextlib.contextmanager
-def _replace_stdout(target):
- orig = sys.stdout
- sys.stdout = target
- try:
- yield orig
- finally:
- sys.stdout = orig
-
-
-@contextlib.contextmanager
-def _replace_stderr(target):
- orig = sys.stderr
- sys.stderr = target
- try:
- yield orig
- finally:
- sys.stderr = orig
-
-
-if sys.version_info < (3,):
- _coerce_unicode = lambda s: unicode(s)
-else:
- _coerce_unicode = lambda s: s
-
-
-@contextlib.contextmanager
-def _temp_io():
- sio = StringIO()
- with tempfile.TemporaryFile("r+") as tmp:
- try:
- yield sio, tmp
- finally:
- tmp.seek(0)
- buff = tmp.read()
- sio.write(_coerce_unicode(buff))
-
-
-@contextlib.contextmanager
-def hide_stdio():
- """Swallow stdout and stderr."""
- with _temp_io() as (sio, fileobj):
- with _replace_fd(sys.stdout, fileobj):
- with _replace_stdout(fileobj):
- with _replace_fd(sys.stderr, fileobj):
- with _replace_stderr(fileobj):
- yield sio
-
-
-#############################
-# shell
-
-
-def shlex_unsplit(argv):
- """Return the shell-safe string for the given arguments.
-
- This effectively the equivalent of reversing shlex.split().
- """
- argv = [_quote_arg(a) for a in argv]
- return " ".join(argv)
-
-
-try:
- from shlex import quote as _quote_arg
-except ImportError:
-
- def _quote_arg(arg):
- parts = None
- for i, c in enumerate(arg):
- if c.isspace():
- pass
- elif c == '"':
- pass
- elif c == "'":
- c = "'\"'\"'"
- else:
- continue
- if parts is None:
- parts = list(arg)
- parts[i] = c
- if parts is not None:
- arg = "'" + "".join(parts) + "'"
- return arg
diff --git a/pythonFiles/testing_tools/run_adapter.py b/pythonFiles/testing_tools/run_adapter.py
deleted file mode 100644
index 1eeef194f8f5..000000000000
--- a/pythonFiles/testing_tools/run_adapter.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-# Replace the "." entry.
-import os.path
-import sys
-
-sys.path.insert(
- 1,
- os.path.dirname( # pythonFiles
- os.path.dirname( # pythonFiles/testing_tools
- os.path.abspath(__file__) # this file
- )
- ),
-)
-
-from testing_tools.adapter.__main__ import parse_args, main
-
-
-if __name__ == "__main__":
- tool, cmd, subargs, toolargs = parse_args()
- main(tool, cmd, subargs, toolargs)
diff --git a/pythonFiles/testlauncher.py b/pythonFiles/testlauncher.py
deleted file mode 100644
index 25b56b7c0604..000000000000
--- a/pythonFiles/testlauncher.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-import os
-import sys
-
-
-def parse_argv():
- """Parses arguments for use with the test launcher.
- Arguments are:
- 1. Working directory.
- 2. Test runner, `pytest` or `nose`
- 3. Rest of the arguments are passed into the test runner.
- """
- cwd = sys.argv[1]
- testRunner = sys.argv[2]
- args = sys.argv[3:]
- if testRunner == "nose":
- # Nose expects the program name to be first argument in vargs
- args.insert(0, sys.argv[0])
-
- return (cwd, testRunner, args)
-
-
-def run(cwd, testRunner, args):
- """Runs the test
- cwd -- the current directory to be set
- testRunner -- test runner to be used `pytest` or `nose`
- args -- arguments passed into the test runner
- """
-
- sys.path[0] = os.getcwd()
- os.chdir(cwd)
-
- try:
- if testRunner == "pytest":
- import pytest
-
- pytest.main(args)
- else:
- import nose
-
- nose.run(argv=args)
- sys.exit(0)
- finally:
- pass
-
-
-if __name__ == "__main__":
- cwd, testRunner, args = parse_argv()
- run(cwd, testRunner, args)
diff --git a/pythonFiles/tests/__init__.py b/pythonFiles/tests/__init__.py
deleted file mode 100644
index 4f762cd1f81a..000000000000
--- a/pythonFiles/tests/__init__.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-import os.path
-
-TEST_ROOT = os.path.dirname(__file__)
-SRC_ROOT = os.path.dirname(TEST_ROOT)
-PROJECT_ROOT = os.path.dirname(SRC_ROOT)
-TESTING_TOOLS_ROOT = os.path.join(SRC_ROOT, "testing_tools")
-DEBUG_ADAPTER_ROOT = os.path.join(SRC_ROOT, "debug_adapter")
-
-PYTHONFILES = os.path.join(SRC_ROOT, "lib", "python")
diff --git a/pythonFiles/tests/__main__.py b/pythonFiles/tests/__main__.py
deleted file mode 100644
index 901385d41d87..000000000000
--- a/pythonFiles/tests/__main__.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-import argparse
-import sys
-
-import pytest
-
-from . import DEBUG_ADAPTER_ROOT, SRC_ROOT, TEST_ROOT, TESTING_TOOLS_ROOT
-
-
-def parse_args():
- parser = argparse.ArgumentParser()
- # To mark a test as functional: (decorator) @pytest.mark.functional
- parser.add_argument(
- "--functional", dest="markers", action="append_const", const="functional"
- )
- parser.add_argument(
- "--no-functional", dest="markers", action="append_const", const="not functional"
- )
- args, remainder = parser.parse_known_args()
-
- ns = vars(args)
-
- if remainder:
- for arg in remainder:
- if arg.startswith("-") and arg not in ("-v", "--verbose", "-h", "--help"):
- specific = False
- break
- else:
- specific = True
- else:
- specific = False
- args.specific = specific
-
- return ns, remainder
-
-
-def main(pytestargs, markers=None, specific=False):
- sys.path.insert(1, TESTING_TOOLS_ROOT)
- sys.path.insert(1, DEBUG_ADAPTER_ROOT)
-
- if not specific:
- pytestargs.insert(0, TEST_ROOT)
- pytestargs.insert(0, "--rootdir")
- pytestargs.insert(1, SRC_ROOT)
- for marker in reversed(markers or ()):
- pytestargs.insert(0, marker)
- pytestargs.insert(0, "-m")
-
- ec = pytest.main(pytestargs)
- return ec
-
-
-if __name__ == "__main__":
- mainkwargs, pytestargs = parse_args()
- ec = main(pytestargs, **mainkwargs)
- sys.exit(ec)
diff --git a/pythonFiles/tests/debug_adapter/test_install_debugpy.py b/pythonFiles/tests/debug_adapter/test_install_debugpy.py
deleted file mode 100644
index 19565c19675c..000000000000
--- a/pythonFiles/tests/debug_adapter/test_install_debugpy.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import os
-import pytest
-import subprocess
-import sys
-
-
-def _check_binaries(dir_path):
- expected_endswith = (
- "win_amd64.pyd",
- "win32.pyd",
- "darwin.so",
- "i386-linux-gnu.so",
- "x86_64-linux-gnu.so",
- )
-
- binaries = list(p for p in os.listdir(dir_path) if p.endswith(expected_endswith))
-
- assert len(binaries) == len(expected_endswith)
-
-
-@pytest.mark.skipif(
- sys.version_info[:2] != (3, 7),
- reason="DEBUGPY wheels shipped for Python 3.7 only",
-)
-def test_install_debugpy(tmpdir):
- import install_debugpy
-
- install_debugpy.main(str(tmpdir))
- dir_path = os.path.join(
- str(tmpdir), "debugpy", "_vendored", "pydevd", "_pydevd_bundle"
- )
- _check_binaries(dir_path)
-
- dir_path = os.path.join(
- str(tmpdir), "debugpy", "_vendored", "pydevd", "_pydevd_frame_eval"
- )
- _check_binaries(dir_path)
diff --git a/pythonFiles/tests/run_all.py b/pythonFiles/tests/run_all.py
deleted file mode 100644
index ce5a62649962..000000000000
--- a/pythonFiles/tests/run_all.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-# Replace the "." entry.
-import os.path
-import sys
-
-sys.path[0] = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-from tests.__main__ import main, parse_args
-
-
-if __name__ == "__main__":
- mainkwargs, pytestargs = parse_args()
- ec = main(pytestargs, **mainkwargs)
- sys.exit(ec)
diff --git a/pythonFiles/tests/test_normalize_selection.py b/pythonFiles/tests/test_normalize_selection.py
deleted file mode 100644
index 6d852e9ae43b..000000000000
--- a/pythonFiles/tests/test_normalize_selection.py
+++ /dev/null
@@ -1,181 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-import textwrap
-
-import normalizeSelection
-
-
-class TestNormalizationScript(object):
- """Unit tests for the normalization script."""
-
- def test_basicNormalization(self):
- src = 'print("this is a test")'
- expected = src + "\n"
- result = normalizeSelection.normalize_lines(src)
- assert result == expected
-
- def test_moreThanOneLine(self):
- src = textwrap.dedent(
- """\
- # Some rando comment
-
- def show_something():
- print("Something")
- """
- )
- expected = textwrap.dedent(
- """\
- def show_something():
- print("Something")
-
- """
- )
- result = normalizeSelection.normalize_lines(src)
- assert result == expected
-
- def test_withHangingIndent(self):
- src = textwrap.dedent(
- """\
- x = 22
- y = 30
- z = -10
- result = x + y + z
-
- if result == 42:
- print("The answer to life, the universe, and everything")
- """
- )
- expected = textwrap.dedent(
- """\
- x = 22
- y = 30
- z = -10
- result = x + y + z
- if result == 42:
- print("The answer to life, the universe, and everything")
-
- """
- )
- result = normalizeSelection.normalize_lines(src)
- assert result == expected
-
- def test_clearOutExtraneousNewlines(self):
- src = textwrap.dedent(
- """\
- value_x = 22
-
- value_y = 30
-
- value_z = -10
-
- print(value_x + value_y + value_z)
-
- """
- )
- expected = textwrap.dedent(
- """\
- value_x = 22
- value_y = 30
- value_z = -10
- print(value_x + value_y + value_z)
- """
- )
- result = normalizeSelection.normalize_lines(src)
- assert result == expected
-
- def test_clearOutExtraLinesAndWhitespace(self):
- src = textwrap.dedent(
- """\
- if True:
- x = 22
-
- y = 30
-
- z = -10
-
- print(x + y + z)
-
- """
- )
- expected = textwrap.dedent(
- """\
- if True:
- x = 22
- y = 30
- z = -10
-
- print(x + y + z)
- """
- )
- result = normalizeSelection.normalize_lines(src)
- assert result == expected
-
- def test_partialSingleLine(self):
- src = " print('foo')"
- expected = textwrap.dedent(src) + "\n"
- result = normalizeSelection.normalize_lines(src)
- assert result == expected
-
- def test_multiLineWithIndent(self):
- src = """\
-
- if (x > 0
- and condition == True):
- print('foo')
- else:
-
- print('bar')
- """
-
- expected = textwrap.dedent(
- """\
- if (x > 0
- and condition == True):
- print('foo')
- else:
- print('bar')
-
- """
- )
-
- result = normalizeSelection.normalize_lines(src)
- assert result == expected
-
- def test_multiLineWithComment(self):
- src = textwrap.dedent(
- """\
-
- def show_something():
- # A comment
- print("Something")
- """
- )
- expected = textwrap.dedent(
- """\
- def show_something():
- # A comment
- print("Something")
-
- """
- )
- result = normalizeSelection.normalize_lines(src)
- assert result == expected
-
- def test_exception(self):
- src = " if True:"
- expected = src + "\n\n"
- result = normalizeSelection.normalize_lines(src)
- assert result == expected
-
- def test_multilineException(self):
- src = textwrap.dedent(
- """\
-
- def show_something():
- if True:
- """
- )
- expected = src + "\n\n"
- result = normalizeSelection.normalize_lines(src)
- assert result == expected
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/NormCase/tests/A/b/C/test_Spam.py b/pythonFiles/tests/testing_tools/adapter/.data/NormCase/tests/A/b/C/test_Spam.py
deleted file mode 100644
index 3501b9e118e5..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/NormCase/tests/A/b/C/test_Spam.py
+++ /dev/null
@@ -1,3 +0,0 @@
-
-def test_okay():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/README.md b/pythonFiles/tests/testing_tools/adapter/.data/complex/README.md
deleted file mode 100644
index e30e96142d02..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/README.md
+++ /dev/null
@@ -1,156 +0,0 @@
-## Directory Structure
-
-```
-pythonFiles/tests/testing_tools/adapter/.data/
- tests/ # test root
- test_doctest.txt
- test_pytest.py
- test_unittest.py
- test_mixed.py
- spam.py # note: no "test_" prefix, but contains tests
- test_foo.py
- test_42.py
- test_42-43.py # note the hyphen
- testspam.py
- v/
- __init__.py
- spam.py
- test_eggs.py
- test_ham.py
- test_spam.py
- w/
- # no __init__.py
- test_spam.py
- test_spam_ex.py
- x/y/z/ # each with a __init__.py
- test_ham.py
- a/
- __init__.py
- test_spam.py
- b/
- __init__.py
- test_spam.py
-```
-
-## Tests (and Suites)
-
-basic:
-
-- `./test_foo.py::test_simple`
-- `./test_pytest.py::test_simple`
-- `./test_pytest.py::TestSpam::test_simple`
-- `./test_pytest.py::TestSpam::TestHam::TestEggs::test_simple`
-- `./test_pytest.py::TestEggs::test_simple`
-- `./test_pytest.py::TestParam::test_simple`
-- `./test_mixed.py::test_top_level`
-- `./test_mixed.py::MyTests::test_simple`
-- `./test_mixed.py::TestMySuite::test_simple`
-- `./test_unittest.py::MyTests::test_simple`
-- `./test_unittest.py::OtherTests::test_simple`
-- `./x/y/z/test_ham.py::test_simple`
-- `./x/y/z/a/test_spam.py::test_simple`
-- `./x/y/z/b/test_spam.py::test_simple`
-
-failures:
-
-- `./test_pytest.py::test_failure`
-- `./test_pytest.py::test_runtime_failed`
-- `./test_pytest.py::test_raises`
-
-skipped:
-
-- `./test_mixed.py::test_skipped`
-- `./test_mixed.py::MyTests::test_skipped`
-- `./test_pytest.py::test_runtime_skipped`
-- `./test_pytest.py::test_skipped`
-- `./test_pytest.py::test_maybe_skipped`
-- `./test_pytest.py::SpamTests::test_skipped`
-- `./test_pytest.py::test_param_13_markers[???]`
-- `./test_pytest.py::test_param_13_skipped[*]`
-- `./test_unittest.py::MyTests::test_skipped`
-- (`./test_unittest.py::MyTests::test_maybe_skipped`)
-- (`./test_unittest.py::MyTests::test_maybe_not_skipped`)
-
-in namespace package:
-
-- `./w/test_spam.py::test_simple`
-- `./w/test_spam_ex.py::test_simple`
-
-filename oddities:
-
-- `./test_42.py::test_simple`
-- `./test_42-43.py::test_simple`
-- (`./testspam.py::test_simple` not discovered by default)
-- (`./spam.py::test_simple` not discovered)
-
-imports discovered:
-
-- `./v/test_eggs.py::test_simple`
-- `./v/test_eggs.py::TestSimple::test_simple`
-- `./v/test_ham.py::test_simple`
-- `./v/test_ham.py::test_not_hard`
-- `./v/test_spam.py::test_simple`
-- `./v/test_spam.py::test_simpler`
-
-subtests:
-
-- `./test_pytest.py::test_dynamic_*`
-- `./test_pytest.py::test_param_01[]`
-- `./test_pytest.py::test_param_11[1]`
-- `./test_pytest.py::test_param_13[*]`
-- `./test_pytest.py::test_param_13_markers[*]`
-- `./test_pytest.py::test_param_13_repeat[*]`
-- `./test_pytest.py::test_param_13_skipped[*]`
-- `./test_pytest.py::test_param_23_13[*]`
-- `./test_pytest.py::test_param_23_raises[*]`
-- `./test_pytest.py::test_param_33[*]`
-- `./test_pytest.py::test_param_33_ids[*]`
-- `./test_pytest.py::TestParam::test_param_13[*]`
-- `./test_pytest.py::TestParamAll::test_param_13[*]`
-- `./test_pytest.py::TestParamAll::test_spam_13[*]`
-- `./test_pytest.py::test_fixture_param[*]`
-- `./test_pytest.py::test_param_fixture[*]`
-- `./test_pytest_param.py::test_param_13[*]`
-- `./test_pytest_param.py::TestParamAll::test_param_13[*]`
-- `./test_pytest_param.py::TestParamAll::test_spam_13[*]`
-- (`./test_unittest.py::MyTests::test_with_subtests`)
-- (`./test_unittest.py::MyTests::test_with_nested_subtests`)
-- (`./test_unittest.py::MyTests::test_dynamic_*`)
-
-For more options for pytests's parametrize(), see
-https://docs.pytest.org/en/latest/example/parametrize.html#paramexamples.
-
-using fixtures:
-
-- `./test_pytest.py::test_fixture`
-- `./test_pytest.py::test_fixture_param[*]`
-- `./test_pytest.py::test_param_fixture[*]`
-- `./test_pytest.py::test_param_mark_fixture[*]`
-
-other markers:
-
-- `./test_pytest.py::test_known_failure`
-- `./test_pytest.py::test_param_markers[2]`
-- `./test_pytest.py::test_warned`
-- `./test_pytest.py::test_custom_marker`
-- `./test_pytest.py::test_multiple_markers`
-- (`./test_unittest.py::MyTests::test_known_failure`)
-
-others not discovered:
-
-- (`./test_pytest.py::TestSpam::TestHam::TestEggs::TestNoop1`)
-- (`./test_pytest.py::TestSpam::TestNoop2`)
-- (`./test_pytest.py::TestNoop3`)
-- (`./test_pytest.py::MyTests::test_simple`)
-- (`./test_unittest.py::MyTests::TestSub1`)
-- (`./test_unittest.py::MyTests::TestSub2`)
-- (`./test_unittest.py::NoTests`)
-
-doctests:
-
-- `./test_doctest.txt::test_doctest.txt`
-- (`./test_doctest.py::test_doctest.py`)
-- (`../mod.py::mod`)
-- (`../mod.py::mod.square`)
-- (`../mod.py::mod.Spam`)
-- (`../mod.py::mod.spam.eggs`)
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/mod.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/mod.py
deleted file mode 100644
index b8c495503895..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/mod.py
+++ /dev/null
@@ -1,51 +0,0 @@
-"""
-
-Examples:
-
->>> square(1)
-1
->>> square(2)
-4
->>> square(3)
-9
->>> spam = Spam()
->>> spam.eggs()
-42
-"""
-
-
-def square(x):
- """
-
- Examples:
-
- >>> square(1)
- 1
- >>> square(2)
- 4
- >>> square(3)
- 9
- """
- return x * x
-
-
-class Spam(object):
- """
-
- Examples:
-
- >>> spam = Spam()
- >>> spam.eggs()
- 42
- """
-
- def eggs(self):
- """
-
- Examples:
-
- >>> spam = Spam()
- >>> spam.eggs()
- 42
- """
- return 42
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/spam.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/spam.py
deleted file mode 100644
index 4c4134d75584..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/spam.py
+++ /dev/null
@@ -1,3 +0,0 @@
-
-def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_42-43.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_42-43.py
deleted file mode 100644
index 4c4134d75584..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_42-43.py
+++ /dev/null
@@ -1,3 +0,0 @@
-
-def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_42.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_42.py
deleted file mode 100644
index 4c4134d75584..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_42.py
+++ /dev/null
@@ -1,3 +0,0 @@
-
-def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_doctest.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_doctest.py
deleted file mode 100644
index 27cccbdb77cc..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_doctest.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""
-Doctests:
-
->>> 1 == 1
-True
-"""
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_doctest.txt b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_doctest.txt
deleted file mode 100644
index 4b51fde5667e..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_doctest.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-
-assignment & lookup:
-
->>> x = 3
->>> x
-3
-
-deletion:
-
->>> del x
->>> x
-Traceback (most recent call last):
- ...
-NameError: name 'x' is not defined
-
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_foo.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_foo.py
deleted file mode 100644
index e752106f503a..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_foo.py
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_mixed.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_mixed.py
deleted file mode 100644
index e9c675647f13..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_mixed.py
+++ /dev/null
@@ -1,27 +0,0 @@
-import pytest
-import unittest
-
-
-def test_top_level():
- assert True
-
-
-@pytest.mark.skip
-def test_skipped():
- assert False
-
-
-class TestMySuite(object):
-
- def test_simple(self):
- assert True
-
-
-class MyTests(unittest.TestCase):
-
- def test_simple(self):
- assert True
-
- @pytest.mark.skip
- def test_skipped(self):
- assert False
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_pytest.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_pytest.py
deleted file mode 100644
index 39d3ece9c0ba..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_pytest.py
+++ /dev/null
@@ -1,227 +0,0 @@
-# ...
-
-import pytest
-
-
-def test_simple():
- assert True
-
-
-def test_failure():
- assert False
-
-
-def test_runtime_skipped():
- pytest.skip('???')
-
-
-def test_runtime_failed():
- pytest.fail('???')
-
-
-def test_raises():
- raise Exception
-
-
-@pytest.mark.skip
-def test_skipped():
- assert False
-
-
-@pytest.mark.skipif(True)
-def test_maybe_skipped():
- assert False
-
-
-@pytest.mark.xfail
-def test_known_failure():
- assert False
-
-
-@pytest.mark.filterwarnings
-def test_warned():
- assert False
-
-
-@pytest.mark.spam
-def test_custom_marker():
- assert False
-
-
-@pytest.mark.filterwarnings
-@pytest.mark.skip
-@pytest.mark.xfail
-@pytest.mark.skipif(True)
-@pytest.mark.skip
-@pytest.mark.spam
-def test_multiple_markers():
- assert False
-
-
-for i in range(3):
- def func():
- assert True
- globals()['test_dynamic_{}'.format(i + 1)] = func
-del func
-
-
-class TestSpam(object):
-
- def test_simple():
- assert True
-
- @pytest.mark.skip
- def test_skipped(self):
- assert False
-
- class TestHam(object):
-
- class TestEggs(object):
-
- def test_simple():
- assert True
-
- class TestNoop1(object):
- pass
-
- class TestNoop2(object):
- pass
-
-
-class TestEggs(object):
-
- def test_simple():
- assert True
-
-
-# legend for parameterized test names:
-# "test_param_XY[_XY]*"
-# X - # params
-# Y - # cases
-# [_XY]* - extra decorators
-
-@pytest.mark.parametrize('', [()])
-def test_param_01():
- assert True
-
-
-@pytest.mark.parametrize('x', [(1,)])
-def test_param_11(x):
- assert x == 1
-
-
-@pytest.mark.parametrize('x', [(1,), (1.0,), (1+0j,)])
-def test_param_13(x):
- assert x == 1
-
-
-@pytest.mark.parametrize('x', [(1,), (1,), (1,)])
-def test_param_13_repeat(x):
- assert x == 1
-
-
-@pytest.mark.parametrize('x,y,z', [(1, 1, 1), (3, 4, 5), (0, 0, 0)])
-def test_param_33(x, y, z):
- assert x*x + y*y == z*z
-
-
-@pytest.mark.parametrize('x,y,z', [(1, 1, 1), (3, 4, 5), (0, 0, 0)],
- ids=['v1', 'v2', 'v3'])
-def test_param_33_ids(x, y, z):
- assert x*x + y*y == z*z
-
-
-@pytest.mark.parametrize('z', [(1,), (5,), (0,)])
-@pytest.mark.parametrize('x,y', [(1, 1), (3, 4), (0, 0)])
-def test_param_23_13(x, y, z):
- assert x*x + y*y == z*z
-
-
-@pytest.mark.parametrize('x', [
- (1,),
- pytest.param(1.0, marks=[pytest.mark.skip, pytest.mark.spam], id='???'),
- pytest.param(2, marks=[pytest.mark.xfail]),
- ])
-def test_param_13_markers(x):
- assert x == 1
-
-
-@pytest.mark.skip
-@pytest.mark.parametrize('x', [(1,), (1.0,), (1+0j,)])
-def test_param_13_skipped(x):
- assert x == 1
-
-
-@pytest.mark.parametrize('x,catch', [(1, None), (1.0, None), (2, pytest.raises(Exception))])
-def test_param_23_raises(x, catch):
- if x != 1:
- with catch:
- raise Exception
-
-
-class TestParam(object):
-
- def test_simple():
- assert True
-
- @pytest.mark.parametrize('x', [(1,), (1.0,), (1+0j,)])
- def test_param_13(self, x):
- assert x == 1
-
-
-@pytest.mark.parametrize('x', [(1,), (1.0,), (1+0j,)])
-class TestParamAll(object):
-
- def test_param_13(self, x):
- assert x == 1
-
- def test_spam_13(self, x):
- assert x == 1
-
-
-@pytest.fixture
-def spamfix(request):
- yield 'spam'
-
-
-@pytest.fixture(params=['spam', 'eggs'])
-def paramfix(request):
- return request.param
-
-
-def test_fixture(spamfix):
- assert spamfix == 'spam'
-
-
-@pytest.mark.usefixtures('spamfix')
-def test_mark_fixture():
- assert True
-
-
-@pytest.mark.parametrize('x', [(1,), (1.0,), (1+0j,)])
-def test_param_fixture(spamfix, x):
- assert spamfix == 'spam'
- assert x == 1
-
-
-@pytest.mark.parametrize('x', [
- (1,),
- (1.0,),
- pytest.param(1+0j, marks=[pytest.mark.usefixtures('spamfix')]),
- ])
-def test_param_mark_fixture(x):
- assert x == 1
-
-
-def test_fixture_param(paramfix):
- assert paramfix == 'spam'
-
-
-class TestNoop3(object):
- pass
-
-
-class MyTests(object): # does not match default name pattern
-
- def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_pytest_param.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_pytest_param.py
deleted file mode 100644
index bd22d89f42bd..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_pytest_param.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import pytest
-
-
-# module-level parameterization
-pytestmark = pytest.mark.parametrize('x', [(1,), (1.0,), (1+0j,)])
-
-
-def test_param_13(x):
- assert x == 1
-
-
-class TestParamAll(object):
-
- def test_param_13(self, x):
- assert x == 1
-
- def test_spam_13(self, x):
- assert x == 1
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_unittest.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_unittest.py
deleted file mode 100644
index dd3e82535739..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/test_unittest.py
+++ /dev/null
@@ -1,66 +0,0 @@
-import unittest
-
-
-class MyTests(unittest.TestCase):
-
- def test_simple(self):
- self.assertTrue(True)
-
- @unittest.skip('???')
- def test_skipped(self):
- self.assertTrue(False)
-
- @unittest.skipIf(True, '???')
- def test_maybe_skipped(self):
- self.assertTrue(False)
-
- @unittest.skipUnless(False, '???')
- def test_maybe_not_skipped(self):
- self.assertTrue(False)
-
- def test_skipped_inside(self):
- raise unittest.SkipTest('???')
-
- class TestSub1(object):
-
- def test_simple(self):
- self.assertTrue(True)
-
- class TestSub2(unittest.TestCase):
-
- def test_simple(self):
- self.assertTrue(True)
-
- def test_failure(self):
- raise Exception
-
- @unittest.expectedFailure
- def test_known_failure(self):
- raise Exception
-
- def test_with_subtests(self):
- for i in range(3):
- with self.subtest(i): # This is invalid under Py2.
- self.assertTrue(True)
-
- def test_with_nested_subtests(self):
- for i in range(3):
- with self.subtest(i): # This is invalid under Py2.
- for j in range(3):
- with self.subtest(i): # This is invalid under Py2.
- self.assertTrue(True)
-
- for i in range(3):
- def test_dynamic_(self, i=i):
- self.assertEqual(True)
- test_dynamic_.__name__ += str(i)
-
-
-class OtherTests(unittest.TestCase):
-
- def test_simple(self):
- self.assertTrue(True)
-
-
-class NoTests(unittest.TestCase):
- pass
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/testspam.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/testspam.py
deleted file mode 100644
index 7ec91c783e2c..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/testspam.py
+++ /dev/null
@@ -1,9 +0,0 @@
-'''
-...
-...
-...
-'''
-
-
-def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/spam.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/spam.py
deleted file mode 100644
index 18c92c09306e..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/spam.py
+++ /dev/null
@@ -1,9 +0,0 @@
-
-def test_simple(self):
- assert True
-
-
-class TestSimple(object):
-
- def test_simple(self):
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/test_eggs.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/test_eggs.py
deleted file mode 100644
index f3e7d9517631..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/test_eggs.py
+++ /dev/null
@@ -1 +0,0 @@
-from .spam import *
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/test_ham.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/test_ham.py
deleted file mode 100644
index 6b6a01f87ec5..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/test_ham.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from .spam import test_simple
-from .spam import test_simple as test_not_hard
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/test_spam.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/test_spam.py
deleted file mode 100644
index 18cf56f90533..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/test_spam.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from .spam import test_simple
-
-
-def test_simpler(self):
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/w/test_spam.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/w/test_spam.py
deleted file mode 100644
index 6a0b60d1d5bd..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/w/test_spam.py
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/w/test_spam_ex.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/w/test_spam_ex.py
deleted file mode 100644
index 6a0b60d1d5bd..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/w/test_spam_ex.py
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/a/test_spam.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/a/test_spam.py
deleted file mode 100644
index bdb7e4fec3a5..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/a/test_spam.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-...
-"""
-
-
-# ...
-
-ANSWER = 42
-
-
-def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/b/test_spam.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/b/test_spam.py
deleted file mode 100644
index 4923c556c29a..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/b/test_spam.py
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-# ?!?
-CHORUS = 'spamspamspamspamspam...'
-
-
-def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/test_ham.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/test_ham.py
deleted file mode 100644
index 4c4134d75584..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/test_ham.py
+++ /dev/null
@@ -1,3 +0,0 @@
-
-def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/simple/tests/test_spam.py b/pythonFiles/tests/testing_tools/adapter/.data/simple/tests/test_spam.py
deleted file mode 100644
index 4c4134d75584..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/simple/tests/test_spam.py
+++ /dev/null
@@ -1,3 +0,0 @@
-
-def test_simple():
- assert True
diff --git a/pythonFiles/tests/testing_tools/adapter/.data/syntax-error/tests/test_spam.py b/pythonFiles/tests/testing_tools/adapter/.data/syntax-error/tests/test_spam.py
deleted file mode 100644
index 54d6400a3465..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/.data/syntax-error/tests/test_spam.py
+++ /dev/null
@@ -1,7 +0,0 @@
-
-def test_simple():
- assert True
-
-
-# A syntax error:
-:
diff --git a/pythonFiles/tests/testing_tools/adapter/pytest/test_cli.py b/pythonFiles/tests/testing_tools/adapter/pytest/test_cli.py
deleted file mode 100644
index 6f590a31fa56..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/pytest/test_cli.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-import unittest
-
-from ....util import Stub, StubProxy
-from testing_tools.adapter.errors import UnsupportedCommandError
-from testing_tools.adapter.pytest._cli import add_subparser
-
-
-class StubSubparsers(StubProxy):
- def __init__(self, stub=None, name="subparsers"):
- super(StubSubparsers, self).__init__(stub, name)
-
- def add_parser(self, name):
- self.add_call("add_parser", None, {"name": name})
- return self.return_add_parser
-
-
-class StubArgParser(StubProxy):
- def __init__(self, stub=None):
- super(StubArgParser, self).__init__(stub, "argparser")
-
- def add_argument(self, *args, **kwargs):
- self.add_call("add_argument", args, kwargs)
-
-
-class AddCLISubparserTests(unittest.TestCase):
- def test_discover(self):
- stub = Stub()
- subparsers = StubSubparsers(stub)
- parser = StubArgParser(stub)
- subparsers.return_add_parser = parser
-
- add_subparser("discover", "pytest", subparsers)
-
- self.assertEqual(
- stub.calls,
- [
- ("subparsers.add_parser", None, {"name": "pytest"}),
- ],
- )
-
- def test_unsupported_command(self):
- subparsers = StubSubparsers(name=None)
- subparsers.return_add_parser = None
-
- with self.assertRaises(UnsupportedCommandError):
- add_subparser("run", "pytest", subparsers)
- with self.assertRaises(UnsupportedCommandError):
- add_subparser("debug", "pytest", subparsers)
- with self.assertRaises(UnsupportedCommandError):
- add_subparser("???", "pytest", subparsers)
- self.assertEqual(
- subparsers.calls,
- [
- ("add_parser", None, {"name": "pytest"}),
- ("add_parser", None, {"name": "pytest"}),
- ("add_parser", None, {"name": "pytest"}),
- ],
- )
diff --git a/pythonFiles/tests/testing_tools/adapter/pytest/test_discovery.py b/pythonFiles/tests/testing_tools/adapter/pytest/test_discovery.py
deleted file mode 100644
index 8ef4305f40b9..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/pytest/test_discovery.py
+++ /dev/null
@@ -1,1553 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-from __future__ import print_function, unicode_literals
-
-try:
- from io import StringIO
-except ImportError:
- from StringIO import StringIO # type: ignore (for Pylance)
-import os
-import sys
-import tempfile
-import unittest
-
-import pytest
-import _pytest.doctest
-
-from .... import util
-from testing_tools.adapter import util as adapter_util
-from testing_tools.adapter.pytest import _pytest_item as pytest_item
-from testing_tools.adapter import info
-from testing_tools.adapter.pytest import _discovery
-
-# In Python 3.8 __len__ is called twice, which impacts some of the test assertions we do below.
-PYTHON_38_OR_LATER = sys.version_info[0] >= 3 and sys.version_info[1] >= 8
-
-
-class StubPyTest(util.StubProxy):
- def __init__(self, stub=None):
- super(StubPyTest, self).__init__(stub, "pytest")
- self.return_main = 0
-
- def main(self, args, plugins):
- self.add_call("main", None, {"args": args, "plugins": plugins})
- return self.return_main
-
-
-class StubPlugin(util.StubProxy):
-
- _started = True
-
- def __init__(self, stub=None, tests=None):
- super(StubPlugin, self).__init__(stub, "plugin")
- if tests is None:
- tests = StubDiscoveredTests(self.stub)
- self._tests = tests
-
- def __getattr__(self, name):
- if not name.startswith("pytest_"):
- raise AttributeError(name)
-
- def func(*args, **kwargs):
- self.add_call(name, args or None, kwargs or None)
-
- return func
-
-
-class StubDiscoveredTests(util.StubProxy):
-
- NOT_FOUND = object()
-
- def __init__(self, stub=None):
- super(StubDiscoveredTests, self).__init__(stub, "discovered")
- self.return_items = []
- self.return_parents = []
-
- def __len__(self):
- self.add_call("__len__", None, None)
- return len(self.return_items)
-
- def __getitem__(self, index):
- self.add_call("__getitem__", (index,), None)
- return self.return_items[index]
-
- @property
- def parents(self):
- self.add_call("parents", None, None)
- return self.return_parents
-
- def reset(self):
- self.add_call("reset", None, None)
-
- def add_test(self, test, parents):
- self.add_call("add_test", None, {"test": test, "parents": parents})
-
-
-class FakeFunc(object):
- def __init__(self, name):
- self.__name__ = name
-
-
-class FakeMarker(object):
- def __init__(self, name):
- self.name = name
-
-
-class StubPytestItem(util.StubProxy):
-
- _debugging = False
- _hasfunc = True
-
- def __init__(self, stub=None, **attrs):
- super(StubPytestItem, self).__init__(stub, "pytest.Item")
- if attrs.get("function") is None:
- attrs.pop("function", None)
- self._hasfunc = False
-
- attrs.setdefault("user_properties", [])
-
- slots = getattr(type(self), "__slots__", None)
- if slots:
- for name, value in attrs.items():
- if name in self.__slots__:
- setattr(self, name, value)
- else:
- self.__dict__[name] = value
- else:
- self.__dict__.update(attrs)
-
- if "own_markers" not in attrs:
- self.own_markers = ()
-
- def __repr__(self):
- return object.__repr__(self)
-
- def __getattr__(self, name):
- if not self._debugging:
- self.add_call(name + " (attr)", None, None)
- if name == "function":
- if not self._hasfunc:
- raise AttributeError(name)
-
- def func(*args, **kwargs):
- self.add_call(name, args or None, kwargs or None)
-
- return func
-
-
-class StubSubtypedItem(StubPytestItem):
- @classmethod
- def from_args(cls, *args, **kwargs):
- if not hasattr(cls, "from_parent"):
- return cls(*args, **kwargs)
- self = cls.from_parent(None, name=kwargs["name"], runner=None, dtest=None)
- self.__init__(*args, **kwargs)
- return self
-
- def __init__(self, *args, **kwargs):
- super(StubSubtypedItem, self).__init__(*args, **kwargs)
- if "nodeid" in self.__dict__:
- self._nodeid = self.__dict__.pop("nodeid")
-
- @property
- def location(self):
- return self.__dict__.get("location")
-
-
-class StubFunctionItem(StubSubtypedItem, pytest.Function):
- @property
- def function(self):
- return self.__dict__.get("function")
-
-
-def create_stub_function_item(*args, **kwargs):
- return StubFunctionItem.from_args(*args, **kwargs)
-
-
-class StubDoctestItem(StubSubtypedItem, _pytest.doctest.DoctestItem):
- pass
-
-
-def create_stub_doctest_item(*args, **kwargs):
- return StubDoctestItem.from_args(*args, **kwargs)
-
-
-class StubPytestSession(util.StubProxy):
- def __init__(self, stub=None):
- super(StubPytestSession, self).__init__(stub, "pytest.Session")
-
- def __getattr__(self, name):
- self.add_call(name + " (attr)", None, None)
-
- def func(*args, **kwargs):
- self.add_call(name, args or None, kwargs or None)
-
- return func
-
-
-class StubPytestConfig(util.StubProxy):
- def __init__(self, stub=None):
- super(StubPytestConfig, self).__init__(stub, "pytest.Config")
-
- def __getattr__(self, name):
- self.add_call(name + " (attr)", None, None)
-
- def func(*args, **kwargs):
- self.add_call(name, args or None, kwargs or None)
-
- return func
-
-
-def generate_parse_item(pathsep):
- if pathsep == "\\":
-
- def normcase(path):
- path = path.lower()
- return path.replace("/", "\\")
-
- else:
- raise NotImplementedError
- ##########
- def _fix_fileid(*args):
- return adapter_util.fix_fileid(
- *args,
- **dict(
- # dependency injection
- _normcase=normcase,
- _pathsep=pathsep,
- )
- )
-
- def _normalize_test_id(*args):
- return pytest_item._normalize_test_id(
- *args,
- **dict(
- # dependency injection
- _fix_fileid=_fix_fileid,
- _pathsep=pathsep,
- )
- )
-
- def _iter_nodes(*args):
- return pytest_item._iter_nodes(
- *args,
- **dict(
- # dependency injection
- _normalize_test_id=_normalize_test_id,
- _normcase=normcase,
- _pathsep=pathsep,
- )
- )
-
- def _parse_node_id(*args):
- return pytest_item._parse_node_id(
- *args,
- **dict(
- # dependency injection
- _iter_nodes=_iter_nodes,
- )
- )
-
- ##########
- def _split_fspath(*args):
- return pytest_item._split_fspath(
- *args,
- **dict(
- # dependency injection
- _normcase=normcase,
- )
- )
-
- ##########
- def _matches_relfile(*args):
- return pytest_item._matches_relfile(
- *args,
- **dict(
- # dependency injection
- _normcase=normcase,
- _pathsep=pathsep,
- )
- )
-
- def _is_legacy_wrapper(*args):
- return pytest_item._is_legacy_wrapper(
- *args,
- **dict(
- # dependency injection
- _pathsep=pathsep,
- )
- )
-
- def _get_location(*args):
- return pytest_item._get_location(
- *args,
- **dict(
- # dependency injection
- _matches_relfile=_matches_relfile,
- _is_legacy_wrapper=_is_legacy_wrapper,
- _pathsep=pathsep,
- )
- )
-
- ##########
- def _parse_item(item):
- return pytest_item.parse_item(
- item,
- **dict(
- # dependency injection
- _parse_node_id=_parse_node_id,
- _split_fspath=_split_fspath,
- _get_location=_get_location,
- )
- )
-
- return _parse_item
-
-
-##################################
-# tests
-
-
-def fake_pytest_main(stub, use_fd, pytest_stdout):
- def ret(args, plugins):
- stub.add_call("pytest.main", None, {"args": args, "plugins": plugins})
- if use_fd:
- os.write(sys.stdout.fileno(), pytest_stdout.encode())
- else:
- print(pytest_stdout, end="")
- return 0
-
- return ret
-
-
-class DiscoverTests(unittest.TestCase):
-
- DEFAULT_ARGS = [
- "--collect-only",
- ]
-
- def test_basic(self):
- stub = util.Stub()
- stubpytest = StubPyTest(stub)
- plugin = StubPlugin(stub)
- expected = []
- plugin.discovered = expected
- calls = [
- ("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
- ("discovered.parents", None, None),
- ("discovered.__len__", None, None),
- ("discovered.__getitem__", (0,), None),
- ]
-
- # In Python 3.8 __len__ is called twice.
- if PYTHON_38_OR_LATER:
- calls.insert(3, ("discovered.__len__", None, None))
-
- parents, tests = _discovery.discover(
- [], _pytest_main=stubpytest.main, _plugin=plugin
- )
-
- self.assertEqual(parents, [])
- self.assertEqual(tests, expected)
- self.assertEqual(stub.calls, calls)
-
- def test_failure(self):
- stub = util.Stub()
- pytest = StubPyTest(stub)
- pytest.return_main = 2
- plugin = StubPlugin(stub)
-
- with self.assertRaises(Exception):
- _discovery.discover([], _pytest_main=pytest.main, _plugin=plugin)
-
- self.assertEqual(
- stub.calls,
- [
- # There's only one call.
- ("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
- ],
- )
-
- def test_no_tests_found(self):
- stub = util.Stub()
- pytest = StubPyTest(stub)
- pytest.return_main = 5
- plugin = StubPlugin(stub)
- expected = []
- plugin.discovered = expected
- calls = [
- ("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
- ("discovered.parents", None, None),
- ("discovered.__len__", None, None),
- ("discovered.__getitem__", (0,), None),
- ]
-
- # In Python 3.8 __len__ is called twice.
- if PYTHON_38_OR_LATER:
- calls.insert(3, ("discovered.__len__", None, None))
-
- parents, tests = _discovery.discover(
- [], _pytest_main=pytest.main, _plugin=plugin
- )
-
- self.assertEqual(parents, [])
- self.assertEqual(tests, expected)
- self.assertEqual(stub.calls, calls)
-
- def test_stdio_hidden_file(self):
- stub = util.Stub()
-
- plugin = StubPlugin(stub)
- plugin.discovered = []
- calls = [
- ("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
- ("discovered.parents", None, None),
- ("discovered.__len__", None, None),
- ("discovered.__getitem__", (0,), None),
- ]
- pytest_stdout = "spamspamspamspamspamspamspammityspam"
-
- # In Python 3.8 __len__ is called twice.
- if PYTHON_38_OR_LATER:
- calls.insert(3, ("discovered.__len__", None, None))
-
- # to simulate stdio behavior in methods like os.dup,
- # use actual files (rather than StringIO)
- with tempfile.TemporaryFile("r+") as mock:
- sys.stdout = mock
- try:
- _discovery.discover(
- [],
- hidestdio=True,
- _pytest_main=fake_pytest_main(stub, False, pytest_stdout),
- _plugin=plugin,
- )
- finally:
- sys.stdout = sys.__stdout__
-
- mock.seek(0)
- captured = mock.read()
-
- self.assertEqual(captured, "")
- self.assertEqual(stub.calls, calls)
-
- def test_stdio_hidden_fd(self):
- # simulate cases where stdout comes from the lower layer than sys.stdout
- # via file descriptors (e.g., from cython)
- stub = util.Stub()
- plugin = StubPlugin(stub)
- pytest_stdout = "spamspamspamspamspamspamspammityspam"
-
- # Replace with contextlib.redirect_stdout() once Python 2.7 support is dropped.
- sys.stdout = StringIO()
- try:
- _discovery.discover(
- [],
- hidestdio=True,
- _pytest_main=fake_pytest_main(stub, True, pytest_stdout),
- _plugin=plugin,
- )
- captured = sys.stdout.read()
- self.assertEqual(captured, "")
- finally:
- sys.stdout = sys.__stdout__
-
- def test_stdio_not_hidden_file(self):
- stub = util.Stub()
-
- plugin = StubPlugin(stub)
- plugin.discovered = []
- calls = [
- ("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
- ("discovered.parents", None, None),
- ("discovered.__len__", None, None),
- ("discovered.__getitem__", (0,), None),
- ]
- pytest_stdout = "spamspamspamspamspamspamspammityspam"
-
- # In Python 3.8 __len__ is called twice.
- if PYTHON_38_OR_LATER:
- calls.insert(3, ("discovered.__len__", None, None))
-
- buf = StringIO()
-
- sys.stdout = buf
- try:
- _discovery.discover(
- [],
- hidestdio=False,
- _pytest_main=fake_pytest_main(stub, False, pytest_stdout),
- _plugin=plugin,
- )
- finally:
- sys.stdout = sys.__stdout__
- captured = buf.getvalue()
-
- self.assertEqual(captured, pytest_stdout)
- self.assertEqual(stub.calls, calls)
-
- def test_stdio_not_hidden_fd(self):
- # simulate cases where stdout comes from the lower layer than sys.stdout
- # via file descriptors (e.g., from cython)
- stub = util.Stub()
- plugin = StubPlugin(stub)
- pytest_stdout = "spamspamspamspamspamspamspammityspam"
- stub.calls = []
- with tempfile.TemporaryFile("r+") as mock:
- sys.stdout = mock
- try:
- _discovery.discover(
- [],
- hidestdio=False,
- _pytest_main=fake_pytest_main(stub, True, pytest_stdout),
- _plugin=plugin,
- )
- finally:
- mock.seek(0)
- captured = sys.stdout.read()
- sys.stdout = sys.__stdout__
- self.assertEqual(captured, pytest_stdout)
-
-
-class CollectorTests(unittest.TestCase):
- def test_modifyitems(self):
- stub = util.Stub()
- discovered = StubDiscoveredTests(stub)
- session = StubPytestSession(stub)
- config = StubPytestConfig(stub)
- collector = _discovery.TestCollector(tests=discovered)
-
- testroot = adapter_util.fix_path("/a/b/c")
- relfile1 = adapter_util.fix_path("./test_spam.py")
- relfile2 = adapter_util.fix_path("x/y/z/test_eggs.py")
-
- collector.pytest_collection_modifyitems(
- session,
- config,
- [
- create_stub_function_item(
- stub,
- nodeid="test_spam.py::SpamTests::test_one",
- name="test_one",
- location=("test_spam.py", 12, "SpamTests.test_one"),
- fspath=adapter_util.PATH_JOIN(testroot, "test_spam.py"),
- function=FakeFunc("test_one"),
- ),
- create_stub_function_item(
- stub,
- nodeid="test_spam.py::SpamTests::test_other",
- name="test_other",
- location=("test_spam.py", 19, "SpamTests.test_other"),
- fspath=adapter_util.PATH_JOIN(testroot, "test_spam.py"),
- function=FakeFunc("test_other"),
- ),
- create_stub_function_item(
- stub,
- nodeid="test_spam.py::test_all",
- name="test_all",
- location=("test_spam.py", 144, "test_all"),
- fspath=adapter_util.PATH_JOIN(testroot, "test_spam.py"),
- function=FakeFunc("test_all"),
- ),
- create_stub_function_item(
- stub,
- nodeid="test_spam.py::test_each[10-10]",
- name="test_each[10-10]",
- location=("test_spam.py", 273, "test_each[10-10]"),
- fspath=adapter_util.PATH_JOIN(testroot, "test_spam.py"),
- function=FakeFunc("test_each"),
- ),
- create_stub_function_item(
- stub,
- nodeid=relfile2 + "::All::BasicTests::test_first",
- name="test_first",
- location=(relfile2, 31, "All.BasicTests.test_first"),
- fspath=adapter_util.PATH_JOIN(testroot, relfile2),
- function=FakeFunc("test_first"),
- ),
- create_stub_function_item(
- stub,
- nodeid=relfile2 + "::All::BasicTests::test_each[1+2-3]",
- name="test_each[1+2-3]",
- location=(relfile2, 62, "All.BasicTests.test_each[1+2-3]"),
- fspath=adapter_util.PATH_JOIN(testroot, relfile2),
- function=FakeFunc("test_each"),
- own_markers=[
- FakeMarker(v)
- for v in [
- # supported
- "skip",
- "skipif",
- "xfail",
- # duplicate
- "skip",
- # ignored (pytest-supported)
- "parameterize",
- "usefixtures",
- "filterwarnings",
- # ignored (custom)
- "timeout",
- ]
- ],
- ),
- ],
- )
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("discovered.reset", None, None),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./test_spam.py::SpamTests", "SpamTests", "suite"),
- ("./test_spam.py", "test_spam.py", "file"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./test_spam.py::SpamTests::test_one",
- name="test_one",
- path=info.SingleTestPath(
- root=testroot,
- relfile=relfile1,
- func="SpamTests.test_one",
- sub=None,
- ),
- source="{}:{}".format(relfile1, 13),
- markers=None,
- parentid="./test_spam.py::SpamTests",
- ),
- ),
- ),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./test_spam.py::SpamTests", "SpamTests", "suite"),
- ("./test_spam.py", "test_spam.py", "file"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./test_spam.py::SpamTests::test_other",
- name="test_other",
- path=info.SingleTestPath(
- root=testroot,
- relfile=relfile1,
- func="SpamTests.test_other",
- sub=None,
- ),
- source="{}:{}".format(relfile1, 20),
- markers=None,
- parentid="./test_spam.py::SpamTests",
- ),
- ),
- ),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./test_spam.py", "test_spam.py", "file"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./test_spam.py::test_all",
- name="test_all",
- path=info.SingleTestPath(
- root=testroot,
- relfile=relfile1,
- func="test_all",
- sub=None,
- ),
- source="{}:{}".format(relfile1, 145),
- markers=None,
- parentid="./test_spam.py",
- ),
- ),
- ),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./test_spam.py::test_each", "test_each", "function"),
- ("./test_spam.py", "test_spam.py", "file"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./test_spam.py::test_each[10-10]",
- name="test_each[10-10]",
- path=info.SingleTestPath(
- root=testroot,
- relfile=relfile1,
- func="test_each",
- sub=["[10-10]"],
- ),
- source="{}:{}".format(relfile1, 274),
- markers=None,
- parentid="./test_spam.py::test_each",
- ),
- ),
- ),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (
- "./x/y/z/test_eggs.py::All::BasicTests",
- "BasicTests",
- "suite",
- ),
- ("./x/y/z/test_eggs.py::All", "All", "suite"),
- ("./x/y/z/test_eggs.py", "test_eggs.py", "file"),
- ("./x/y/z", "z", "folder"),
- ("./x/y", "y", "folder"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/y/z/test_eggs.py::All::BasicTests::test_first",
- name="test_first",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(relfile2),
- func="All.BasicTests.test_first",
- sub=None,
- ),
- source="{}:{}".format(
- adapter_util.fix_relpath(relfile2), 32
- ),
- markers=None,
- parentid="./x/y/z/test_eggs.py::All::BasicTests",
- ),
- ),
- ),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (
- "./x/y/z/test_eggs.py::All::BasicTests::test_each",
- "test_each",
- "function",
- ),
- (
- "./x/y/z/test_eggs.py::All::BasicTests",
- "BasicTests",
- "suite",
- ),
- ("./x/y/z/test_eggs.py::All", "All", "suite"),
- ("./x/y/z/test_eggs.py", "test_eggs.py", "file"),
- ("./x/y/z", "z", "folder"),
- ("./x/y", "y", "folder"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/y/z/test_eggs.py::All::BasicTests::test_each[1+2-3]",
- name="test_each[1+2-3]",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(relfile2),
- func="All.BasicTests.test_each",
- sub=["[1+2-3]"],
- ),
- source="{}:{}".format(
- adapter_util.fix_relpath(relfile2), 63
- ),
- markers=["expected-failure", "skip", "skip-if"],
- parentid="./x/y/z/test_eggs.py::All::BasicTests::test_each",
- ),
- ),
- ),
- ],
- )
-
- def test_finish(self):
- stub = util.Stub()
- discovered = StubDiscoveredTests(stub)
- session = StubPytestSession(stub)
- testroot = adapter_util.fix_path("/a/b/c")
- relfile = adapter_util.fix_path("x/y/z/test_eggs.py")
- session.items = [
- create_stub_function_item(
- stub,
- nodeid=relfile + "::SpamTests::test_spam",
- name="test_spam",
- location=(relfile, 12, "SpamTests.test_spam"),
- fspath=adapter_util.PATH_JOIN(testroot, relfile),
- function=FakeFunc("test_spam"),
- ),
- ]
- collector = _discovery.TestCollector(tests=discovered)
-
- collector.pytest_collection_finish(session)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("discovered.reset", None, None),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./x/y/z/test_eggs.py::SpamTests", "SpamTests", "suite"),
- ("./x/y/z/test_eggs.py", "test_eggs.py", "file"),
- ("./x/y/z", "z", "folder"),
- ("./x/y", "y", "folder"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/y/z/test_eggs.py::SpamTests::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(relfile),
- func="SpamTests.test_spam",
- sub=None,
- ),
- source="{}:{}".format(
- adapter_util.fix_relpath(relfile), 13
- ),
- markers=None,
- parentid="./x/y/z/test_eggs.py::SpamTests",
- ),
- ),
- ),
- ],
- )
-
- def test_doctest(self):
- stub = util.Stub()
- discovered = StubDiscoveredTests(stub)
- session = StubPytestSession(stub)
- testroot = adapter_util.fix_path("/a/b/c")
- doctestfile = adapter_util.fix_path("x/test_doctest.txt")
- relfile = adapter_util.fix_path("x/y/z/test_eggs.py")
- session.items = [
- create_stub_doctest_item(
- stub,
- nodeid=doctestfile + "::test_doctest.txt",
- name="test_doctest.txt",
- location=(doctestfile, 0, "[doctest] test_doctest.txt"),
- fspath=adapter_util.PATH_JOIN(testroot, doctestfile),
- ),
- # With --doctest-modules
- create_stub_doctest_item(
- stub,
- nodeid=relfile + "::test_eggs",
- name="test_eggs",
- location=(relfile, 0, "[doctest] test_eggs"),
- fspath=adapter_util.PATH_JOIN(testroot, relfile),
- ),
- create_stub_doctest_item(
- stub,
- nodeid=relfile + "::test_eggs.TestSpam",
- name="test_eggs.TestSpam",
- location=(relfile, 12, "[doctest] test_eggs.TestSpam"),
- fspath=adapter_util.PATH_JOIN(testroot, relfile),
- ),
- create_stub_doctest_item(
- stub,
- nodeid=relfile + "::test_eggs.TestSpam.TestEggs",
- name="test_eggs.TestSpam.TestEggs",
- location=(relfile, 27, "[doctest] test_eggs.TestSpam.TestEggs"),
- fspath=adapter_util.PATH_JOIN(testroot, relfile),
- ),
- ]
- collector = _discovery.TestCollector(tests=discovered)
-
- collector.pytest_collection_finish(session)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("discovered.reset", None, None),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./x/test_doctest.txt", "test_doctest.txt", "file"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/test_doctest.txt::test_doctest.txt",
- name="test_doctest.txt",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(doctestfile),
- func=None,
- ),
- source="{}:{}".format(
- adapter_util.fix_relpath(doctestfile), 1
- ),
- markers=[],
- parentid="./x/test_doctest.txt",
- ),
- ),
- ),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./x/y/z/test_eggs.py", "test_eggs.py", "file"),
- ("./x/y/z", "z", "folder"),
- ("./x/y", "y", "folder"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/y/z/test_eggs.py::test_eggs",
- name="test_eggs",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(relfile),
- func=None,
- ),
- source="{}:{}".format(adapter_util.fix_relpath(relfile), 1),
- markers=[],
- parentid="./x/y/z/test_eggs.py",
- ),
- ),
- ),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./x/y/z/test_eggs.py", "test_eggs.py", "file"),
- ("./x/y/z", "z", "folder"),
- ("./x/y", "y", "folder"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/y/z/test_eggs.py::test_eggs.TestSpam",
- name="test_eggs.TestSpam",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(relfile),
- func=None,
- ),
- source="{}:{}".format(
- adapter_util.fix_relpath(relfile), 13
- ),
- markers=[],
- parentid="./x/y/z/test_eggs.py",
- ),
- ),
- ),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./x/y/z/test_eggs.py", "test_eggs.py", "file"),
- ("./x/y/z", "z", "folder"),
- ("./x/y", "y", "folder"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/y/z/test_eggs.py::test_eggs.TestSpam.TestEggs",
- name="test_eggs.TestSpam.TestEggs",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(relfile),
- func=None,
- ),
- source="{}:{}".format(
- adapter_util.fix_relpath(relfile), 28
- ),
- markers=[],
- parentid="./x/y/z/test_eggs.py",
- ),
- ),
- ),
- ],
- )
-
- def test_nested_brackets(self):
- stub = util.Stub()
- discovered = StubDiscoveredTests(stub)
- session = StubPytestSession(stub)
- testroot = adapter_util.fix_path("/a/b/c")
- relfile = adapter_util.fix_path("x/y/z/test_eggs.py")
- session.items = [
- create_stub_function_item(
- stub,
- nodeid=relfile + "::SpamTests::test_spam[a-[b]-c]",
- name="test_spam[a-[b]-c]",
- location=(relfile, 12, "SpamTests.test_spam[a-[b]-c]"),
- fspath=adapter_util.PATH_JOIN(testroot, relfile),
- function=FakeFunc("test_spam"),
- ),
- ]
- collector = _discovery.TestCollector(tests=discovered)
-
- collector.pytest_collection_finish(session)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("discovered.reset", None, None),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (
- "./x/y/z/test_eggs.py::SpamTests::test_spam",
- "test_spam",
- "function",
- ),
- ("./x/y/z/test_eggs.py::SpamTests", "SpamTests", "suite"),
- ("./x/y/z/test_eggs.py", "test_eggs.py", "file"),
- ("./x/y/z", "z", "folder"),
- ("./x/y", "y", "folder"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/y/z/test_eggs.py::SpamTests::test_spam[a-[b]-c]",
- name="test_spam[a-[b]-c]",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(relfile),
- func="SpamTests.test_spam",
- sub=["[a-[b]-c]"],
- ),
- source="{}:{}".format(
- adapter_util.fix_relpath(relfile), 13
- ),
- markers=None,
- parentid="./x/y/z/test_eggs.py::SpamTests::test_spam",
- ),
- ),
- ),
- ],
- )
-
- def test_nested_suite(self):
- stub = util.Stub()
- discovered = StubDiscoveredTests(stub)
- session = StubPytestSession(stub)
- testroot = adapter_util.fix_path("/a/b/c")
- relfile = adapter_util.fix_path("x/y/z/test_eggs.py")
- session.items = [
- create_stub_function_item(
- stub,
- nodeid=relfile + "::SpamTests::Ham::Eggs::test_spam",
- name="test_spam",
- location=(relfile, 12, "SpamTests.Ham.Eggs.test_spam"),
- fspath=adapter_util.PATH_JOIN(testroot, relfile),
- function=FakeFunc("test_spam"),
- ),
- ]
- collector = _discovery.TestCollector(tests=discovered)
-
- collector.pytest_collection_finish(session)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("discovered.reset", None, None),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (
- "./x/y/z/test_eggs.py::SpamTests::Ham::Eggs",
- "Eggs",
- "suite",
- ),
- ("./x/y/z/test_eggs.py::SpamTests::Ham", "Ham", "suite"),
- ("./x/y/z/test_eggs.py::SpamTests", "SpamTests", "suite"),
- ("./x/y/z/test_eggs.py", "test_eggs.py", "file"),
- ("./x/y/z", "z", "folder"),
- ("./x/y", "y", "folder"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/y/z/test_eggs.py::SpamTests::Ham::Eggs::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(relfile),
- func="SpamTests.Ham.Eggs.test_spam",
- sub=None,
- ),
- source="{}:{}".format(
- adapter_util.fix_relpath(relfile), 13
- ),
- markers=None,
- parentid="./x/y/z/test_eggs.py::SpamTests::Ham::Eggs",
- ),
- ),
- ),
- ],
- )
-
- def test_windows(self):
- stub = util.Stub()
- discovered = StubDiscoveredTests(stub)
- session = StubPytestSession(stub)
- testroot = r"C:\A\B\C"
- altroot = testroot.replace("\\", "/")
- relfile = r"X\Y\Z\test_Eggs.py"
- session.items = [
- # typical:
- create_stub_function_item(
- stub,
- # pytest always uses "/" as the path separator in node IDs:
- nodeid="X/Y/Z/test_Eggs.py::SpamTests::test_spam",
- name="test_spam",
- # normal path separator (contrast with nodeid):
- location=(relfile, 12, "SpamTests.test_spam"),
- # path separator matches location:
- fspath=testroot + "\\" + relfile,
- function=FakeFunc("test_spam"),
- ),
- ]
- tests = [
- # permutations of path separators
- (r"X/test_a.py", "\\", "\\"), # typical
- (r"X/test_b.py", "\\", "/"),
- (r"X/test_c.py", "/", "\\"),
- (r"X/test_d.py", "/", "/"),
- (r"X\test_e.py", "\\", "\\"),
- (r"X\test_f.py", "\\", "/"),
- (r"X\test_g.py", "/", "\\"),
- (r"X\test_h.py", "/", "/"),
- ]
- for fileid, locfile, fspath in tests:
- if locfile == "/":
- locfile = fileid.replace("\\", "/")
- elif locfile == "\\":
- locfile = fileid.replace("/", "\\")
- if fspath == "/":
- fspath = (testroot + "/" + fileid).replace("\\", "/")
- elif fspath == "\\":
- fspath = (testroot + "/" + fileid).replace("/", "\\")
- session.items.append(
- create_stub_function_item(
- stub,
- nodeid=fileid + "::test_spam",
- name="test_spam",
- location=(locfile, 12, "test_spam"),
- fspath=fspath,
- function=FakeFunc("test_spam"),
- )
- )
- collector = _discovery.TestCollector(tests=discovered)
- if os.name != "nt":
- collector.parse_item = generate_parse_item("\\")
-
- collector.pytest_collection_finish(session)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("discovered.reset", None, None),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (r"./X/Y/Z/test_Eggs.py::SpamTests", "SpamTests", "suite"),
- (r"./X/Y/Z/test_Eggs.py", "test_Eggs.py", "file"),
- (r"./X/Y/Z", "Z", "folder"),
- (r"./X/Y", "Y", "folder"),
- (r"./X", "X", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id=r"./X/Y/Z/test_Eggs.py::SpamTests::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=testroot, # not normalized
- relfile=r".\X\Y\Z\test_Eggs.py", # not normalized
- func="SpamTests.test_spam",
- sub=None,
- ),
- source=r".\X\Y\Z\test_Eggs.py:13", # not normalized
- markers=None,
- parentid=r"./X/Y/Z/test_Eggs.py::SpamTests",
- ),
- ),
- ),
- # permutations
- # (*all* the IDs use "/")
- # (source path separator should match relfile, not location)
- # /, \, \
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (r"./X/test_a.py", "test_a.py", "file"),
- (r"./X", "X", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id=r"./X/test_a.py::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=testroot,
- relfile=r".\X\test_a.py",
- func="test_spam",
- sub=None,
- ),
- source=r".\X\test_a.py:13",
- markers=None,
- parentid=r"./X/test_a.py",
- ),
- ),
- ),
- # /, \, /
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (r"./X/test_b.py", "test_b.py", "file"),
- (r"./X", "X", "folder"),
- (".", altroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id=r"./X/test_b.py::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=altroot,
- relfile=r"./X/test_b.py",
- func="test_spam",
- sub=None,
- ),
- source=r"./X/test_b.py:13",
- markers=None,
- parentid=r"./X/test_b.py",
- ),
- ),
- ),
- # /, /, \
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (r"./X/test_c.py", "test_c.py", "file"),
- (r"./X", "X", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id=r"./X/test_c.py::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=testroot,
- relfile=r".\X\test_c.py",
- func="test_spam",
- sub=None,
- ),
- source=r".\X\test_c.py:13",
- markers=None,
- parentid=r"./X/test_c.py",
- ),
- ),
- ),
- # /, /, /
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (r"./X/test_d.py", "test_d.py", "file"),
- (r"./X", "X", "folder"),
- (".", altroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id=r"./X/test_d.py::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=altroot,
- relfile=r"./X/test_d.py",
- func="test_spam",
- sub=None,
- ),
- source=r"./X/test_d.py:13",
- markers=None,
- parentid=r"./X/test_d.py",
- ),
- ),
- ),
- # \, \, \
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (r"./X/test_e.py", "test_e.py", "file"),
- (r"./X", "X", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id=r"./X/test_e.py::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=testroot,
- relfile=r".\X\test_e.py",
- func="test_spam",
- sub=None,
- ),
- source=r".\X\test_e.py:13",
- markers=None,
- parentid=r"./X/test_e.py",
- ),
- ),
- ),
- # \, \, /
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (r"./X/test_f.py", "test_f.py", "file"),
- (r"./X", "X", "folder"),
- (".", altroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id=r"./X/test_f.py::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=altroot,
- relfile=r"./X/test_f.py",
- func="test_spam",
- sub=None,
- ),
- source=r"./X/test_f.py:13",
- markers=None,
- parentid=r"./X/test_f.py",
- ),
- ),
- ),
- # \, /, \
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (r"./X/test_g.py", "test_g.py", "file"),
- (r"./X", "X", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id=r"./X/test_g.py::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=testroot,
- relfile=r".\X\test_g.py",
- func="test_spam",
- sub=None,
- ),
- source=r".\X\test_g.py:13",
- markers=None,
- parentid=r"./X/test_g.py",
- ),
- ),
- ),
- # \, /, /
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- (r"./X/test_h.py", "test_h.py", "file"),
- (r"./X", "X", "folder"),
- (".", altroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id=r"./X/test_h.py::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=altroot,
- relfile=r"./X/test_h.py",
- func="test_spam",
- sub=None,
- ),
- source=r"./X/test_h.py:13",
- markers=None,
- parentid=r"./X/test_h.py",
- ),
- ),
- ),
- ],
- )
-
- def test_mysterious_parens(self):
- stub = util.Stub()
- discovered = StubDiscoveredTests(stub)
- session = StubPytestSession(stub)
- testroot = adapter_util.fix_path("/a/b/c")
- relfile = adapter_util.fix_path("x/y/z/test_eggs.py")
- session.items = [
- create_stub_function_item(
- stub,
- nodeid=relfile + "::SpamTests::()::()::test_spam",
- name="test_spam",
- location=(relfile, 12, "SpamTests.test_spam"),
- fspath=adapter_util.PATH_JOIN(testroot, relfile),
- function=FakeFunc("test_spam"),
- ),
- ]
- collector = _discovery.TestCollector(tests=discovered)
-
- collector.pytest_collection_finish(session)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("discovered.reset", None, None),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./x/y/z/test_eggs.py::SpamTests", "SpamTests", "suite"),
- ("./x/y/z/test_eggs.py", "test_eggs.py", "file"),
- ("./x/y/z", "z", "folder"),
- ("./x/y", "y", "folder"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/y/z/test_eggs.py::SpamTests::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(relfile),
- func="SpamTests.test_spam",
- sub=[],
- ),
- source="{}:{}".format(
- adapter_util.fix_relpath(relfile), 13
- ),
- markers=None,
- parentid="./x/y/z/test_eggs.py::SpamTests",
- ),
- ),
- ),
- ],
- )
-
- def test_imported_test(self):
- # pytest will even discover tests that were imported from
- # another module!
- stub = util.Stub()
- discovered = StubDiscoveredTests(stub)
- session = StubPytestSession(stub)
- testroot = adapter_util.fix_path("/a/b/c")
- relfile = adapter_util.fix_path("x/y/z/test_eggs.py")
- srcfile = adapter_util.fix_path("x/y/z/_extern.py")
- session.items = [
- create_stub_function_item(
- stub,
- nodeid=relfile + "::SpamTests::test_spam",
- name="test_spam",
- location=(srcfile, 12, "SpamTests.test_spam"),
- fspath=adapter_util.PATH_JOIN(testroot, relfile),
- function=FakeFunc("test_spam"),
- ),
- create_stub_function_item(
- stub,
- nodeid=relfile + "::test_ham",
- name="test_ham",
- location=(srcfile, 3, "test_ham"),
- fspath=adapter_util.PATH_JOIN(testroot, relfile),
- function=FakeFunc("test_spam"),
- ),
- ]
- collector = _discovery.TestCollector(tests=discovered)
-
- collector.pytest_collection_finish(session)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("discovered.reset", None, None),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./x/y/z/test_eggs.py::SpamTests", "SpamTests", "suite"),
- ("./x/y/z/test_eggs.py", "test_eggs.py", "file"),
- ("./x/y/z", "z", "folder"),
- ("./x/y", "y", "folder"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/y/z/test_eggs.py::SpamTests::test_spam",
- name="test_spam",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(relfile),
- func="SpamTests.test_spam",
- sub=None,
- ),
- source="{}:{}".format(
- adapter_util.fix_relpath(srcfile), 13
- ),
- markers=None,
- parentid="./x/y/z/test_eggs.py::SpamTests",
- ),
- ),
- ),
- (
- "discovered.add_test",
- None,
- dict(
- parents=[
- ("./x/y/z/test_eggs.py", "test_eggs.py", "file"),
- ("./x/y/z", "z", "folder"),
- ("./x/y", "y", "folder"),
- ("./x", "x", "folder"),
- (".", testroot, "folder"),
- ],
- test=info.SingleTestInfo(
- id="./x/y/z/test_eggs.py::test_ham",
- name="test_ham",
- path=info.SingleTestPath(
- root=testroot,
- relfile=adapter_util.fix_relpath(relfile),
- func="test_ham",
- sub=None,
- ),
- source="{}:{}".format(adapter_util.fix_relpath(srcfile), 4),
- markers=None,
- parentid="./x/y/z/test_eggs.py",
- ),
- ),
- ),
- ],
- )
diff --git a/pythonFiles/tests/testing_tools/adapter/test___main__.py b/pythonFiles/tests/testing_tools/adapter/test___main__.py
deleted file mode 100644
index 53500a2f4afe..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/test___main__.py
+++ /dev/null
@@ -1,210 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-import unittest
-
-from ...util import Stub, StubProxy
-from testing_tools.adapter.__main__ import (
- parse_args,
- main,
- UnsupportedToolError,
- UnsupportedCommandError,
-)
-
-
-class StubTool(StubProxy):
- def __init__(self, name, stub=None):
- super(StubTool, self).__init__(stub, name)
- self.return_discover = None
-
- def discover(self, args, **kwargs):
- self.add_call("discover", (args,), kwargs)
- if self.return_discover is None:
- raise NotImplementedError
- return self.return_discover
-
-
-class StubReporter(StubProxy):
- def __init__(self, stub=None):
- super(StubReporter, self).__init__(stub, "reporter")
-
- def report(self, tests, parents, **kwargs):
- self.add_call("report", (tests, parents), kwargs or None)
-
-
-##################################
-# tests
-
-
-class ParseGeneralTests(unittest.TestCase):
- def test_unsupported_command(self):
- with self.assertRaises(SystemExit):
- parse_args(["run", "pytest"])
- with self.assertRaises(SystemExit):
- parse_args(["debug", "pytest"])
- with self.assertRaises(SystemExit):
- parse_args(["???", "pytest"])
-
-
-class ParseDiscoverTests(unittest.TestCase):
- def test_pytest_default(self):
- tool, cmd, args, toolargs = parse_args(
- [
- "discover",
- "pytest",
- ]
- )
-
- self.assertEqual(tool, "pytest")
- self.assertEqual(cmd, "discover")
- self.assertEqual(args, {"pretty": False, "hidestdio": True, "simple": False})
- self.assertEqual(toolargs, [])
-
- def test_pytest_full(self):
- tool, cmd, args, toolargs = parse_args(
- [
- "discover",
- "pytest",
- # no adapter-specific options yet
- "--",
- "--strict",
- "--ignore",
- "spam,ham,eggs",
- "--pastebin=xyz",
- "--no-cov",
- "-d",
- ]
- )
-
- self.assertEqual(tool, "pytest")
- self.assertEqual(cmd, "discover")
- self.assertEqual(args, {"pretty": False, "hidestdio": True, "simple": False})
- self.assertEqual(
- toolargs,
- [
- "--strict",
- "--ignore",
- "spam,ham,eggs",
- "--pastebin=xyz",
- "--no-cov",
- "-d",
- ],
- )
-
- def test_pytest_opts(self):
- tool, cmd, args, toolargs = parse_args(
- [
- "discover",
- "pytest",
- "--simple",
- "--no-hide-stdio",
- "--pretty",
- ]
- )
-
- self.assertEqual(tool, "pytest")
- self.assertEqual(cmd, "discover")
- self.assertEqual(args, {"pretty": True, "hidestdio": False, "simple": True})
- self.assertEqual(toolargs, [])
-
- def test_unsupported_tool(self):
- with self.assertRaises(SystemExit):
- parse_args(["discover", "unittest"])
- with self.assertRaises(SystemExit):
- parse_args(["discover", "nose"])
- with self.assertRaises(SystemExit):
- parse_args(["discover", "???"])
-
-
-class MainTests(unittest.TestCase):
-
- # TODO: We could use an integration test for pytest.discover().
-
- def test_discover(self):
- stub = Stub()
- tool = StubTool("spamspamspam", stub)
- tests, parents = object(), object()
- tool.return_discover = (parents, tests)
- reporter = StubReporter(stub)
- main(
- tool.name,
- "discover",
- {"spam": "eggs"},
- [],
- _tools={
- tool.name: {
- "discover": tool.discover,
- }
- },
- _reporters={
- "discover": reporter.report,
- },
- )
-
- self.assertEqual(
- tool.calls,
- [
- ("spamspamspam.discover", ([],), {"spam": "eggs"}),
- ("reporter.report", (tests, parents), {"spam": "eggs"}),
- ],
- )
-
- def test_unsupported_tool(self):
- with self.assertRaises(UnsupportedToolError):
- main(
- "unittest",
- "discover",
- {"spam": "eggs"},
- [],
- _tools={"pytest": None},
- _reporters=None,
- )
- with self.assertRaises(UnsupportedToolError):
- main(
- "nose",
- "discover",
- {"spam": "eggs"},
- [],
- _tools={"pytest": None},
- _reporters=None,
- )
- with self.assertRaises(UnsupportedToolError):
- main(
- "???",
- "discover",
- {"spam": "eggs"},
- [],
- _tools={"pytest": None},
- _reporters=None,
- )
-
- def test_unsupported_command(self):
- tool = StubTool("pytest")
- with self.assertRaises(UnsupportedCommandError):
- main(
- "pytest",
- "run",
- {"spam": "eggs"},
- [],
- _tools={"pytest": {"discover": tool.discover}},
- _reporters=None,
- )
- with self.assertRaises(UnsupportedCommandError):
- main(
- "pytest",
- "debug",
- {"spam": "eggs"},
- [],
- _tools={"pytest": {"discover": tool.discover}},
- _reporters=None,
- )
- with self.assertRaises(UnsupportedCommandError):
- main(
- "pytest",
- "???",
- {"spam": "eggs"},
- [],
- _tools={"pytest": {"discover": tool.discover}},
- _reporters=None,
- )
- self.assertEqual(tool.calls, [])
diff --git a/pythonFiles/tests/testing_tools/adapter/test_discovery.py b/pythonFiles/tests/testing_tools/adapter/test_discovery.py
deleted file mode 100644
index ec3d198b0108..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/test_discovery.py
+++ /dev/null
@@ -1,675 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-from __future__ import absolute_import, print_function
-
-import unittest
-
-from testing_tools.adapter.util import fix_path, fix_relpath
-from testing_tools.adapter.info import SingleTestInfo, SingleTestPath, ParentInfo
-from testing_tools.adapter.discovery import fix_nodeid, DiscoveredTests
-
-
-def _fix_nodeid(nodeid):
-
- nodeid = nodeid.replace("\\", "/")
- if not nodeid.startswith("./"):
- nodeid = "./" + nodeid
- return nodeid
-
-
-class DiscoveredTestsTests(unittest.TestCase):
- def test_list(self):
- testroot = fix_path("/a/b/c")
- relfile = fix_path("./test_spam.py")
- tests = [
- SingleTestInfo(
- # missing "./":
- id="test_spam.py::test_each[10-10]",
- name="test_each[10-10]",
- path=SingleTestPath(
- root=testroot,
- relfile=relfile,
- func="test_each",
- sub=["[10-10]"],
- ),
- source="{}:{}".format(relfile, 10),
- markers=None,
- # missing "./":
- parentid="test_spam.py::test_each",
- ),
- SingleTestInfo(
- id="test_spam.py::All::BasicTests::test_first",
- name="test_first",
- path=SingleTestPath(
- root=testroot,
- relfile=relfile,
- func="All.BasicTests.test_first",
- sub=None,
- ),
- source="{}:{}".format(relfile, 62),
- markers=None,
- parentid="test_spam.py::All::BasicTests",
- ),
- ]
- allparents = [
- [
- (fix_path("./test_spam.py::test_each"), "test_each", "function"),
- (fix_path("./test_spam.py"), "test_spam.py", "file"),
- (".", testroot, "folder"),
- ],
- [
- (fix_path("./test_spam.py::All::BasicTests"), "BasicTests", "suite"),
- (fix_path("./test_spam.py::All"), "All", "suite"),
- (fix_path("./test_spam.py"), "test_spam.py", "file"),
- (".", testroot, "folder"),
- ],
- ]
- expected = [
- test._replace(id=_fix_nodeid(test.id), parentid=_fix_nodeid(test.parentid))
- for test in tests
- ]
- discovered = DiscoveredTests()
- for test, parents in zip(tests, allparents):
- discovered.add_test(test, parents)
- size = len(discovered)
- items = [discovered[0], discovered[1]]
- snapshot = list(discovered)
-
- self.maxDiff = None
- self.assertEqual(size, 2)
- self.assertEqual(items, expected)
- self.assertEqual(snapshot, expected)
-
- def test_reset(self):
- testroot = fix_path("/a/b/c")
- discovered = DiscoveredTests()
- discovered.add_test(
- SingleTestInfo(
- id="./test_spam.py::test_each",
- name="test_each",
- path=SingleTestPath(
- root=testroot,
- relfile="test_spam.py",
- func="test_each",
- ),
- source="test_spam.py:11",
- markers=[],
- parentid="./test_spam.py",
- ),
- [
- ("./test_spam.py", "test_spam.py", "file"),
- (".", testroot, "folder"),
- ],
- )
-
- before = len(discovered), len(discovered.parents)
- discovered.reset()
- after = len(discovered), len(discovered.parents)
-
- self.assertEqual(before, (1, 2))
- self.assertEqual(after, (0, 0))
-
- def test_parents(self):
- testroot = fix_path("/a/b/c")
- relfile = fix_path("x/y/z/test_spam.py")
- tests = [
- SingleTestInfo(
- # missing "./", using pathsep:
- id=relfile + "::test_each[10-10]",
- name="test_each[10-10]",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_relpath(relfile),
- func="test_each",
- sub=["[10-10]"],
- ),
- source="{}:{}".format(relfile, 10),
- markers=None,
- # missing "./", using pathsep:
- parentid=relfile + "::test_each",
- ),
- SingleTestInfo(
- # missing "./", using pathsep:
- id=relfile + "::All::BasicTests::test_first",
- name="test_first",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_relpath(relfile),
- func="All.BasicTests.test_first",
- sub=None,
- ),
- source="{}:{}".format(relfile, 61),
- markers=None,
- # missing "./", using pathsep:
- parentid=relfile + "::All::BasicTests",
- ),
- ]
- allparents = [
- # missing "./", using pathsep:
- [
- (relfile + "::test_each", "test_each", "function"),
- (relfile, relfile, "file"),
- (".", testroot, "folder"),
- ],
- # missing "./", using pathsep:
- [
- (relfile + "::All::BasicTests", "BasicTests", "suite"),
- (relfile + "::All", "All", "suite"),
- (relfile, "test_spam.py", "file"),
- (fix_path("x/y/z"), "z", "folder"),
- (fix_path("x/y"), "y", "folder"),
- (fix_path("./x"), "x", "folder"),
- (".", testroot, "folder"),
- ],
- ]
- discovered = DiscoveredTests()
- for test, parents in zip(tests, allparents):
- discovered.add_test(test, parents)
-
- parents = discovered.parents
-
- self.maxDiff = None
- self.assertEqual(
- parents,
- [
- ParentInfo(
- id=".",
- kind="folder",
- name=testroot,
- ),
- ParentInfo(
- id="./x",
- kind="folder",
- name="x",
- root=testroot,
- relpath=fix_path("./x"),
- parentid=".",
- ),
- ParentInfo(
- id="./x/y",
- kind="folder",
- name="y",
- root=testroot,
- relpath=fix_path("./x/y"),
- parentid="./x",
- ),
- ParentInfo(
- id="./x/y/z",
- kind="folder",
- name="z",
- root=testroot,
- relpath=fix_path("./x/y/z"),
- parentid="./x/y",
- ),
- ParentInfo(
- id="./x/y/z/test_spam.py",
- kind="file",
- name="test_spam.py",
- root=testroot,
- relpath=fix_relpath(relfile),
- parentid="./x/y/z",
- ),
- ParentInfo(
- id="./x/y/z/test_spam.py::All",
- kind="suite",
- name="All",
- root=testroot,
- parentid="./x/y/z/test_spam.py",
- ),
- ParentInfo(
- id="./x/y/z/test_spam.py::All::BasicTests",
- kind="suite",
- name="BasicTests",
- root=testroot,
- parentid="./x/y/z/test_spam.py::All",
- ),
- ParentInfo(
- id="./x/y/z/test_spam.py::test_each",
- kind="function",
- name="test_each",
- root=testroot,
- parentid="./x/y/z/test_spam.py",
- ),
- ],
- )
-
- def test_add_test_simple(self):
- testroot = fix_path("/a/b/c")
- relfile = "test_spam.py"
- test = SingleTestInfo(
- # missing "./":
- id=relfile + "::test_spam",
- name="test_spam",
- path=SingleTestPath(
- root=testroot,
- # missing "./":
- relfile=relfile,
- func="test_spam",
- ),
- # missing "./":
- source="{}:{}".format(relfile, 11),
- markers=[],
- # missing "./":
- parentid=relfile,
- )
- expected = test._replace(
- id=_fix_nodeid(test.id), parentid=_fix_nodeid(test.parentid)
- )
- discovered = DiscoveredTests()
-
- before = list(discovered), discovered.parents
- discovered.add_test(
- test,
- [
- (relfile, relfile, "file"),
- (".", testroot, "folder"),
- ],
- )
- after = list(discovered), discovered.parents
-
- self.maxDiff = None
- self.assertEqual(before, ([], []))
- self.assertEqual(
- after,
- (
- [expected],
- [
- ParentInfo(
- id=".",
- kind="folder",
- name=testroot,
- ),
- ParentInfo(
- id="./test_spam.py",
- kind="file",
- name=relfile,
- root=testroot,
- relpath=relfile,
- parentid=".",
- ),
- ],
- ),
- )
-
- def test_multiroot(self):
- # the first root
- testroot1 = fix_path("/a/b/c")
- relfile1 = "test_spam.py"
- alltests = [
- SingleTestInfo(
- # missing "./":
- id=relfile1 + "::test_spam",
- name="test_spam",
- path=SingleTestPath(
- root=testroot1,
- relfile=fix_relpath(relfile1),
- func="test_spam",
- ),
- source="{}:{}".format(relfile1, 10),
- markers=[],
- # missing "./":
- parentid=relfile1,
- ),
- ]
- allparents = [
- # missing "./":
- [
- (relfile1, "test_spam.py", "file"),
- (".", testroot1, "folder"),
- ],
- ]
- # the second root
- testroot2 = fix_path("/x/y/z")
- relfile2 = fix_path("w/test_eggs.py")
- alltests.extend(
- [
- SingleTestInfo(
- id=relfile2 + "::BasicTests::test_first",
- name="test_first",
- path=SingleTestPath(
- root=testroot2,
- relfile=fix_relpath(relfile2),
- func="BasicTests.test_first",
- ),
- source="{}:{}".format(relfile2, 61),
- markers=[],
- parentid=relfile2 + "::BasicTests",
- ),
- ]
- )
- allparents.extend(
- [
- # missing "./", using pathsep:
- [
- (relfile2 + "::BasicTests", "BasicTests", "suite"),
- (relfile2, "test_eggs.py", "file"),
- (fix_path("./w"), "w", "folder"),
- (".", testroot2, "folder"),
- ],
- ]
- )
-
- discovered = DiscoveredTests()
- for test, parents in zip(alltests, allparents):
- discovered.add_test(test, parents)
- tests = list(discovered)
- parents = discovered.parents
-
- self.maxDiff = None
- self.assertEqual(
- tests,
- [
- # the first root
- SingleTestInfo(
- id="./test_spam.py::test_spam",
- name="test_spam",
- path=SingleTestPath(
- root=testroot1,
- relfile=fix_relpath(relfile1),
- func="test_spam",
- ),
- source="{}:{}".format(relfile1, 10),
- markers=[],
- parentid="./test_spam.py",
- ),
- # the secondroot
- SingleTestInfo(
- id="./w/test_eggs.py::BasicTests::test_first",
- name="test_first",
- path=SingleTestPath(
- root=testroot2,
- relfile=fix_relpath(relfile2),
- func="BasicTests.test_first",
- ),
- source="{}:{}".format(relfile2, 61),
- markers=[],
- parentid="./w/test_eggs.py::BasicTests",
- ),
- ],
- )
- self.assertEqual(
- parents,
- [
- # the first root
- ParentInfo(
- id=".",
- kind="folder",
- name=testroot1,
- ),
- ParentInfo(
- id="./test_spam.py",
- kind="file",
- name="test_spam.py",
- root=testroot1,
- relpath=fix_relpath(relfile1),
- parentid=".",
- ),
- # the secondroot
- ParentInfo(
- id=".",
- kind="folder",
- name=testroot2,
- ),
- ParentInfo(
- id="./w",
- kind="folder",
- name="w",
- root=testroot2,
- relpath=fix_path("./w"),
- parentid=".",
- ),
- ParentInfo(
- id="./w/test_eggs.py",
- kind="file",
- name="test_eggs.py",
- root=testroot2,
- relpath=fix_relpath(relfile2),
- parentid="./w",
- ),
- ParentInfo(
- id="./w/test_eggs.py::BasicTests",
- kind="suite",
- name="BasicTests",
- root=testroot2,
- parentid="./w/test_eggs.py",
- ),
- ],
- )
-
- def test_doctest(self):
- testroot = fix_path("/a/b/c")
- doctestfile = fix_path("./x/test_doctest.txt")
- relfile = fix_path("./x/y/z/test_eggs.py")
- alltests = [
- SingleTestInfo(
- id=doctestfile + "::test_doctest.txt",
- name="test_doctest.txt",
- path=SingleTestPath(
- root=testroot,
- relfile=doctestfile,
- func=None,
- ),
- source="{}:{}".format(doctestfile, 0),
- markers=[],
- parentid=doctestfile,
- ),
- # With --doctest-modules
- SingleTestInfo(
- id=relfile + "::test_eggs",
- name="test_eggs",
- path=SingleTestPath(
- root=testroot,
- relfile=relfile,
- func=None,
- ),
- source="{}:{}".format(relfile, 0),
- markers=[],
- parentid=relfile,
- ),
- SingleTestInfo(
- id=relfile + "::test_eggs.TestSpam",
- name="test_eggs.TestSpam",
- path=SingleTestPath(
- root=testroot,
- relfile=relfile,
- func=None,
- ),
- source="{}:{}".format(relfile, 12),
- markers=[],
- parentid=relfile,
- ),
- SingleTestInfo(
- id=relfile + "::test_eggs.TestSpam.TestEggs",
- name="test_eggs.TestSpam.TestEggs",
- path=SingleTestPath(
- root=testroot,
- relfile=relfile,
- func=None,
- ),
- source="{}:{}".format(relfile, 27),
- markers=[],
- parentid=relfile,
- ),
- ]
- allparents = [
- [
- (doctestfile, "test_doctest.txt", "file"),
- (fix_path("./x"), "x", "folder"),
- (".", testroot, "folder"),
- ],
- [
- (relfile, "test_eggs.py", "file"),
- (fix_path("./x/y/z"), "z", "folder"),
- (fix_path("./x/y"), "y", "folder"),
- (fix_path("./x"), "x", "folder"),
- (".", testroot, "folder"),
- ],
- [
- (relfile, "test_eggs.py", "file"),
- (fix_path("./x/y/z"), "z", "folder"),
- (fix_path("./x/y"), "y", "folder"),
- (fix_path("./x"), "x", "folder"),
- (".", testroot, "folder"),
- ],
- [
- (relfile, "test_eggs.py", "file"),
- (fix_path("./x/y/z"), "z", "folder"),
- (fix_path("./x/y"), "y", "folder"),
- (fix_path("./x"), "x", "folder"),
- (".", testroot, "folder"),
- ],
- ]
- expected = [
- test._replace(id=_fix_nodeid(test.id), parentid=_fix_nodeid(test.parentid))
- for test in alltests
- ]
-
- discovered = DiscoveredTests()
-
- for test, parents in zip(alltests, allparents):
- discovered.add_test(test, parents)
- tests = list(discovered)
- parents = discovered.parents
-
- self.maxDiff = None
- self.assertEqual(tests, expected)
- self.assertEqual(
- parents,
- [
- ParentInfo(
- id=".",
- kind="folder",
- name=testroot,
- ),
- ParentInfo(
- id="./x",
- kind="folder",
- name="x",
- root=testroot,
- relpath=fix_path("./x"),
- parentid=".",
- ),
- ParentInfo(
- id="./x/test_doctest.txt",
- kind="file",
- name="test_doctest.txt",
- root=testroot,
- relpath=fix_path(doctestfile),
- parentid="./x",
- ),
- ParentInfo(
- id="./x/y",
- kind="folder",
- name="y",
- root=testroot,
- relpath=fix_path("./x/y"),
- parentid="./x",
- ),
- ParentInfo(
- id="./x/y/z",
- kind="folder",
- name="z",
- root=testroot,
- relpath=fix_path("./x/y/z"),
- parentid="./x/y",
- ),
- ParentInfo(
- id="./x/y/z/test_eggs.py",
- kind="file",
- name="test_eggs.py",
- root=testroot,
- relpath=fix_relpath(relfile),
- parentid="./x/y/z",
- ),
- ],
- )
-
- def test_nested_suite_simple(self):
- testroot = fix_path("/a/b/c")
- relfile = fix_path("./test_eggs.py")
- alltests = [
- SingleTestInfo(
- id=relfile + "::TestOuter::TestInner::test_spam",
- name="test_spam",
- path=SingleTestPath(
- root=testroot,
- relfile=relfile,
- func="TestOuter.TestInner.test_spam",
- ),
- source="{}:{}".format(relfile, 10),
- markers=None,
- parentid=relfile + "::TestOuter::TestInner",
- ),
- SingleTestInfo(
- id=relfile + "::TestOuter::TestInner::test_eggs",
- name="test_eggs",
- path=SingleTestPath(
- root=testroot,
- relfile=relfile,
- func="TestOuter.TestInner.test_eggs",
- ),
- source="{}:{}".format(relfile, 21),
- markers=None,
- parentid=relfile + "::TestOuter::TestInner",
- ),
- ]
- allparents = [
- [
- (relfile + "::TestOuter::TestInner", "TestInner", "suite"),
- (relfile + "::TestOuter", "TestOuter", "suite"),
- (relfile, "test_eggs.py", "file"),
- (".", testroot, "folder"),
- ],
- [
- (relfile + "::TestOuter::TestInner", "TestInner", "suite"),
- (relfile + "::TestOuter", "TestOuter", "suite"),
- (relfile, "test_eggs.py", "file"),
- (".", testroot, "folder"),
- ],
- ]
- expected = [
- test._replace(id=_fix_nodeid(test.id), parentid=_fix_nodeid(test.parentid))
- for test in alltests
- ]
-
- discovered = DiscoveredTests()
- for test, parents in zip(alltests, allparents):
- discovered.add_test(test, parents)
- tests = list(discovered)
- parents = discovered.parents
-
- self.maxDiff = None
- self.assertEqual(tests, expected)
- self.assertEqual(
- parents,
- [
- ParentInfo(
- id=".",
- kind="folder",
- name=testroot,
- ),
- ParentInfo(
- id="./test_eggs.py",
- kind="file",
- name="test_eggs.py",
- root=testroot,
- relpath=fix_relpath(relfile),
- parentid=".",
- ),
- ParentInfo(
- id="./test_eggs.py::TestOuter",
- kind="suite",
- name="TestOuter",
- root=testroot,
- parentid="./test_eggs.py",
- ),
- ParentInfo(
- id="./test_eggs.py::TestOuter::TestInner",
- kind="suite",
- name="TestInner",
- root=testroot,
- parentid="./test_eggs.py::TestOuter",
- ),
- ],
- )
diff --git a/pythonFiles/tests/testing_tools/adapter/test_functional.py b/pythonFiles/tests/testing_tools/adapter/test_functional.py
deleted file mode 100644
index 153ad5508d9b..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/test_functional.py
+++ /dev/null
@@ -1,1535 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-from __future__ import absolute_import, unicode_literals
-
-import json
-import os
-import os.path
-import subprocess
-import sys
-import unittest
-
-from ...__main__ import TESTING_TOOLS_ROOT
-from testing_tools.adapter.util import fix_path, PATH_SEP
-
-# Pytest 3.7 and later uses pathlib/pathlib2 for path resolution.
-try:
- from pathlib import Path
-except ImportError:
- from pathlib2 import Path # type: ignore (for Pylance)
-
-
-CWD = os.getcwd()
-DATA_DIR = os.path.join(os.path.dirname(__file__), ".data")
-SCRIPT = os.path.join(TESTING_TOOLS_ROOT, "run_adapter.py")
-
-
-def resolve_testroot(name):
- projroot = os.path.join(DATA_DIR, name)
- testroot = os.path.join(projroot, "tests")
- return str(Path(projroot).resolve()), str(Path(testroot).resolve())
-
-
-def run_adapter(cmd, tool, *cliargs):
- try:
- return _run_adapter(cmd, tool, *cliargs)
- except subprocess.CalledProcessError as exc:
- print(exc.output)
-
-
-def _run_adapter(cmd, tool, *cliargs, **kwargs):
- hidestdio = kwargs.pop("hidestdio", True)
- assert not kwargs or tuple(kwargs) == ("stderr",)
- kwds = kwargs
- argv = [sys.executable, SCRIPT, cmd, tool, "--"] + list(cliargs)
- if not hidestdio:
- argv.insert(4, "--no-hide-stdio")
- kwds["stderr"] = subprocess.STDOUT
- argv.append("--cache-clear")
- print(
- "running {!r}".format(" ".join(arg.rpartition(CWD + "/")[-1] for arg in argv))
- )
- output = subprocess.check_output(argv, universal_newlines=True, **kwds)
- return output
-
-
-def fix_test_order(tests):
- if sys.version_info >= (3, 6):
- return tests
- fixed = []
- curfile = None
- group = []
- for test in tests:
- if (curfile or "???") not in test["id"]:
- fixed.extend(sorted(group, key=lambda t: t["id"]))
- group = []
- curfile = test["id"].partition(".py::")[0] + ".py"
- group.append(test)
- fixed.extend(sorted(group, key=lambda t: t["id"]))
- return fixed
-
-
-def fix_source(tests, testid, srcfile, lineno):
- for test in tests:
- if test["id"] == testid:
- break
- else:
- raise KeyError("test {!r} not found".format(testid))
- if not srcfile:
- srcfile = test["source"].rpartition(":")[0]
- test["source"] = fix_path("{}:{}".format(srcfile, lineno))
-
-
-def sorted_object(obj):
- if isinstance(obj, dict):
- return sorted((key, sorted_object(obj[key])) for key in obj.keys())
- if isinstance(obj, list):
- return sorted((sorted_object(x) for x in obj))
- else:
- return obj
-
-
-# Note that these tests are skipped if util.PATH_SEP is not os.path.sep.
-# This is because the functional tests should reflect the actual
-# operating environment.
-
-
-class PytestTests(unittest.TestCase):
- def setUp(self):
- if PATH_SEP is not os.path.sep:
- raise unittest.SkipTest("functional tests require unmodified env")
- super(PytestTests, self).setUp()
-
- def complex(self, testroot):
- results = COMPLEX.copy()
- results["root"] = testroot
- return [results]
-
- def test_discover_simple(self):
- projroot, testroot = resolve_testroot("simple")
-
- out = run_adapter("discover", "pytest", "--rootdir", projroot, testroot)
- result = json.loads(out)
-
- self.maxDiff = None
- self.assertEqual(
- result,
- [
- {
- "root": projroot,
- "rootid": ".",
- "parents": [
- {
- "id": "./tests",
- "kind": "folder",
- "name": "tests",
- "relpath": fix_path("./tests"),
- "parentid": ".",
- },
- {
- "id": "./tests/test_spam.py",
- "kind": "file",
- "name": "test_spam.py",
- "relpath": fix_path("./tests/test_spam.py"),
- "parentid": "./tests",
- },
- ],
- "tests": [
- {
- "id": "./tests/test_spam.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_spam.py:2"),
- "markers": [],
- "parentid": "./tests/test_spam.py",
- },
- ],
- }
- ],
- )
-
- def test_discover_complex_default(self):
- projroot, testroot = resolve_testroot("complex")
- expected = self.complex(projroot)
- expected[0]["tests"] = fix_test_order(expected[0]["tests"])
- if sys.version_info < (3,):
- decorated = [
- "./tests/test_unittest.py::MyTests::test_skipped",
- "./tests/test_unittest.py::MyTests::test_maybe_skipped",
- "./tests/test_unittest.py::MyTests::test_maybe_not_skipped",
- ]
- for testid in decorated:
- fix_source(expected[0]["tests"], testid, None, 0)
-
- out = run_adapter("discover", "pytest", "--rootdir", projroot, testroot)
- result = json.loads(out)
- result[0]["tests"] = fix_test_order(result[0]["tests"])
-
- self.maxDiff = None
- self.assertEqual(sorted_object(result), sorted_object(expected))
-
- def test_discover_complex_doctest(self):
- projroot, _ = resolve_testroot("complex")
- expected = self.complex(projroot)
- # add in doctests from test suite
- expected[0]["parents"].insert(
- 3,
- {
- "id": "./tests/test_doctest.py",
- "kind": "file",
- "name": "test_doctest.py",
- "relpath": fix_path("./tests/test_doctest.py"),
- "parentid": "./tests",
- },
- )
- expected[0]["tests"].insert(
- 2,
- {
- "id": "./tests/test_doctest.py::tests.test_doctest",
- "name": "tests.test_doctest",
- "source": fix_path("./tests/test_doctest.py:1"),
- "markers": [],
- "parentid": "./tests/test_doctest.py",
- },
- )
- # add in doctests from non-test module
- expected[0]["parents"].insert(
- 0,
- {
- "id": "./mod.py",
- "kind": "file",
- "name": "mod.py",
- "relpath": fix_path("./mod.py"),
- "parentid": ".",
- },
- )
- expected[0]["tests"] = [
- {
- "id": "./mod.py::mod",
- "name": "mod",
- "source": fix_path("./mod.py:1"),
- "markers": [],
- "parentid": "./mod.py",
- },
- {
- "id": "./mod.py::mod.Spam",
- "name": "mod.Spam",
- "source": fix_path("./mod.py:33"),
- "markers": [],
- "parentid": "./mod.py",
- },
- {
- "id": "./mod.py::mod.Spam.eggs",
- "name": "mod.Spam.eggs",
- "source": fix_path("./mod.py:43"),
- "markers": [],
- "parentid": "./mod.py",
- },
- {
- "id": "./mod.py::mod.square",
- "name": "mod.square",
- "source": fix_path("./mod.py:18"),
- "markers": [],
- "parentid": "./mod.py",
- },
- ] + expected[0]["tests"]
- expected[0]["tests"] = fix_test_order(expected[0]["tests"])
- if sys.version_info < (3,):
- decorated = [
- "./tests/test_unittest.py::MyTests::test_skipped",
- "./tests/test_unittest.py::MyTests::test_maybe_skipped",
- "./tests/test_unittest.py::MyTests::test_maybe_not_skipped",
- ]
- for testid in decorated:
- fix_source(expected[0]["tests"], testid, None, 0)
-
- out = run_adapter(
- "discover", "pytest", "--rootdir", projroot, "--doctest-modules", projroot
- )
- result = json.loads(out)
- result[0]["tests"] = fix_test_order(result[0]["tests"])
-
- self.maxDiff = None
- self.assertEqual(sorted_object(result), sorted_object(expected))
-
- def test_discover_not_found(self):
- projroot, testroot = resolve_testroot("notests")
-
- out = run_adapter("discover", "pytest", "--rootdir", projroot, testroot)
- result = json.loads(out)
-
- self.maxDiff = None
- self.assertEqual(result, [])
- # TODO: Expect the following instead?
- # self.assertEqual(result, [{
- # 'root': projroot,
- # 'rootid': '.',
- # 'parents': [],
- # 'tests': [],
- # }])
-
- @unittest.skip("broken in CI")
- def test_discover_bad_args(self):
- projroot, testroot = resolve_testroot("simple")
-
- with self.assertRaises(subprocess.CalledProcessError) as cm:
- _run_adapter(
- "discover",
- "pytest",
- "--spam",
- "--rootdir",
- projroot,
- testroot,
- stderr=subprocess.STDOUT,
- )
- self.assertIn("(exit code 4)", cm.exception.output)
-
- def test_discover_syntax_error(self):
- projroot, testroot = resolve_testroot("syntax-error")
-
- with self.assertRaises(subprocess.CalledProcessError) as cm:
- _run_adapter(
- "discover",
- "pytest",
- "--rootdir",
- projroot,
- testroot,
- stderr=subprocess.STDOUT,
- )
- self.assertIn("(exit code 2)", cm.exception.output)
-
- def test_discover_normcase(self):
- projroot, testroot = resolve_testroot("NormCase")
-
- out = run_adapter("discover", "pytest", "--rootdir", projroot, testroot)
- result = json.loads(out)
-
- self.maxDiff = None
- self.assertTrue(projroot.endswith("NormCase"))
- self.assertEqual(
- result,
- [
- {
- "root": projroot,
- "rootid": ".",
- "parents": [
- {
- "id": "./tests",
- "kind": "folder",
- "name": "tests",
- "relpath": fix_path("./tests"),
- "parentid": ".",
- },
- {
- "id": "./tests/A",
- "kind": "folder",
- "name": "A",
- "relpath": fix_path("./tests/A"),
- "parentid": "./tests",
- },
- {
- "id": "./tests/A/b",
- "kind": "folder",
- "name": "b",
- "relpath": fix_path("./tests/A/b"),
- "parentid": "./tests/A",
- },
- {
- "id": "./tests/A/b/C",
- "kind": "folder",
- "name": "C",
- "relpath": fix_path("./tests/A/b/C"),
- "parentid": "./tests/A/b",
- },
- {
- "id": "./tests/A/b/C/test_Spam.py",
- "kind": "file",
- "name": "test_Spam.py",
- "relpath": fix_path("./tests/A/b/C/test_Spam.py"),
- "parentid": "./tests/A/b/C",
- },
- ],
- "tests": [
- {
- "id": "./tests/A/b/C/test_Spam.py::test_okay",
- "name": "test_okay",
- "source": fix_path("./tests/A/b/C/test_Spam.py:2"),
- "markers": [],
- "parentid": "./tests/A/b/C/test_Spam.py",
- },
- ],
- }
- ],
- )
-
-
-COMPLEX = {
- "root": None,
- "rootid": ".",
- "parents": [
- #
- {
- "id": "./tests",
- "kind": "folder",
- "name": "tests",
- "relpath": fix_path("./tests"),
- "parentid": ".",
- },
- # +++
- {
- "id": "./tests/test_42-43.py",
- "kind": "file",
- "name": "test_42-43.py",
- "relpath": fix_path("./tests/test_42-43.py"),
- "parentid": "./tests",
- },
- # +++
- {
- "id": "./tests/test_42.py",
- "kind": "file",
- "name": "test_42.py",
- "relpath": fix_path("./tests/test_42.py"),
- "parentid": "./tests",
- },
- # +++
- {
- "id": "./tests/test_doctest.txt",
- "kind": "file",
- "name": "test_doctest.txt",
- "relpath": fix_path("./tests/test_doctest.txt"),
- "parentid": "./tests",
- },
- # +++
- {
- "id": "./tests/test_foo.py",
- "kind": "file",
- "name": "test_foo.py",
- "relpath": fix_path("./tests/test_foo.py"),
- "parentid": "./tests",
- },
- # +++
- {
- "id": "./tests/test_mixed.py",
- "kind": "file",
- "name": "test_mixed.py",
- "relpath": fix_path("./tests/test_mixed.py"),
- "parentid": "./tests",
- },
- {
- "id": "./tests/test_mixed.py::MyTests",
- "kind": "suite",
- "name": "MyTests",
- "parentid": "./tests/test_mixed.py",
- },
- {
- "id": "./tests/test_mixed.py::TestMySuite",
- "kind": "suite",
- "name": "TestMySuite",
- "parentid": "./tests/test_mixed.py",
- },
- # +++
- {
- "id": "./tests/test_pytest.py",
- "kind": "file",
- "name": "test_pytest.py",
- "relpath": fix_path("./tests/test_pytest.py"),
- "parentid": "./tests",
- },
- {
- "id": "./tests/test_pytest.py::TestEggs",
- "kind": "suite",
- "name": "TestEggs",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::TestParam",
- "kind": "suite",
- "name": "TestParam",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::TestParam::test_param_13",
- "kind": "function",
- "name": "test_param_13",
- "parentid": "./tests/test_pytest.py::TestParam",
- },
- {
- "id": "./tests/test_pytest.py::TestParamAll",
- "kind": "suite",
- "name": "TestParamAll",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::TestParamAll::test_param_13",
- "kind": "function",
- "name": "test_param_13",
- "parentid": "./tests/test_pytest.py::TestParamAll",
- },
- {
- "id": "./tests/test_pytest.py::TestParamAll::test_spam_13",
- "kind": "function",
- "name": "test_spam_13",
- "parentid": "./tests/test_pytest.py::TestParamAll",
- },
- {
- "id": "./tests/test_pytest.py::TestSpam",
- "kind": "suite",
- "name": "TestSpam",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::TestSpam::TestHam",
- "kind": "suite",
- "name": "TestHam",
- "parentid": "./tests/test_pytest.py::TestSpam",
- },
- {
- "id": "./tests/test_pytest.py::TestSpam::TestHam::TestEggs",
- "kind": "suite",
- "name": "TestEggs",
- "parentid": "./tests/test_pytest.py::TestSpam::TestHam",
- },
- {
- "id": "./tests/test_pytest.py::test_fixture_param",
- "kind": "function",
- "name": "test_fixture_param",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_01",
- "kind": "function",
- "name": "test_param_01",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_11",
- "kind": "function",
- "name": "test_param_11",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13",
- "kind": "function",
- "name": "test_param_13",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_markers",
- "kind": "function",
- "name": "test_param_13_markers",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_repeat",
- "kind": "function",
- "name": "test_param_13_repeat",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_skipped",
- "kind": "function",
- "name": "test_param_13_skipped",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_13",
- "kind": "function",
- "name": "test_param_23_13",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_raises",
- "kind": "function",
- "name": "test_param_23_raises",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_33",
- "kind": "function",
- "name": "test_param_33",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_33_ids",
- "kind": "function",
- "name": "test_param_33_ids",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_fixture",
- "kind": "function",
- "name": "test_param_fixture",
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_mark_fixture",
- "kind": "function",
- "name": "test_param_mark_fixture",
- "parentid": "./tests/test_pytest.py",
- },
- # +++
- {
- "id": "./tests/test_pytest_param.py",
- "kind": "file",
- "name": "test_pytest_param.py",
- "relpath": fix_path("./tests/test_pytest_param.py"),
- "parentid": "./tests",
- },
- {
- "id": "./tests/test_pytest_param.py::TestParamAll",
- "kind": "suite",
- "name": "TestParamAll",
- "parentid": "./tests/test_pytest_param.py",
- },
- {
- "id": "./tests/test_pytest_param.py::TestParamAll::test_param_13",
- "kind": "function",
- "name": "test_param_13",
- "parentid": "./tests/test_pytest_param.py::TestParamAll",
- },
- {
- "id": "./tests/test_pytest_param.py::TestParamAll::test_spam_13",
- "kind": "function",
- "name": "test_spam_13",
- "parentid": "./tests/test_pytest_param.py::TestParamAll",
- },
- {
- "id": "./tests/test_pytest_param.py::test_param_13",
- "kind": "function",
- "name": "test_param_13",
- "parentid": "./tests/test_pytest_param.py",
- },
- # +++
- {
- "id": "./tests/test_unittest.py",
- "kind": "file",
- "name": "test_unittest.py",
- "relpath": fix_path("./tests/test_unittest.py"),
- "parentid": "./tests",
- },
- {
- "id": "./tests/test_unittest.py::MyTests",
- "kind": "suite",
- "name": "MyTests",
- "parentid": "./tests/test_unittest.py",
- },
- {
- "id": "./tests/test_unittest.py::OtherTests",
- "kind": "suite",
- "name": "OtherTests",
- "parentid": "./tests/test_unittest.py",
- },
- ##
- {
- "id": "./tests/v",
- "kind": "folder",
- "name": "v",
- "relpath": fix_path("./tests/v"),
- "parentid": "./tests",
- },
- ## +++
- {
- "id": "./tests/v/test_eggs.py",
- "kind": "file",
- "name": "test_eggs.py",
- "relpath": fix_path("./tests/v/test_eggs.py"),
- "parentid": "./tests/v",
- },
- {
- "id": "./tests/v/test_eggs.py::TestSimple",
- "kind": "suite",
- "name": "TestSimple",
- "parentid": "./tests/v/test_eggs.py",
- },
- ## +++
- {
- "id": "./tests/v/test_ham.py",
- "kind": "file",
- "name": "test_ham.py",
- "relpath": fix_path("./tests/v/test_ham.py"),
- "parentid": "./tests/v",
- },
- ## +++
- {
- "id": "./tests/v/test_spam.py",
- "kind": "file",
- "name": "test_spam.py",
- "relpath": fix_path("./tests/v/test_spam.py"),
- "parentid": "./tests/v",
- },
- ##
- {
- "id": "./tests/w",
- "kind": "folder",
- "name": "w",
- "relpath": fix_path("./tests/w"),
- "parentid": "./tests",
- },
- ## +++
- {
- "id": "./tests/w/test_spam.py",
- "kind": "file",
- "name": "test_spam.py",
- "relpath": fix_path("./tests/w/test_spam.py"),
- "parentid": "./tests/w",
- },
- ## +++
- {
- "id": "./tests/w/test_spam_ex.py",
- "kind": "file",
- "name": "test_spam_ex.py",
- "relpath": fix_path("./tests/w/test_spam_ex.py"),
- "parentid": "./tests/w",
- },
- ##
- {
- "id": "./tests/x",
- "kind": "folder",
- "name": "x",
- "relpath": fix_path("./tests/x"),
- "parentid": "./tests",
- },
- ###
- {
- "id": "./tests/x/y",
- "kind": "folder",
- "name": "y",
- "relpath": fix_path("./tests/x/y"),
- "parentid": "./tests/x",
- },
- ####
- {
- "id": "./tests/x/y/z",
- "kind": "folder",
- "name": "z",
- "relpath": fix_path("./tests/x/y/z"),
- "parentid": "./tests/x/y",
- },
- #####
- {
- "id": "./tests/x/y/z/a",
- "kind": "folder",
- "name": "a",
- "relpath": fix_path("./tests/x/y/z/a"),
- "parentid": "./tests/x/y/z",
- },
- ##### +++
- {
- "id": "./tests/x/y/z/a/test_spam.py",
- "kind": "file",
- "name": "test_spam.py",
- "relpath": fix_path("./tests/x/y/z/a/test_spam.py"),
- "parentid": "./tests/x/y/z/a",
- },
- #####
- {
- "id": "./tests/x/y/z/b",
- "kind": "folder",
- "name": "b",
- "relpath": fix_path("./tests/x/y/z/b"),
- "parentid": "./tests/x/y/z",
- },
- ##### +++
- {
- "id": "./tests/x/y/z/b/test_spam.py",
- "kind": "file",
- "name": "test_spam.py",
- "relpath": fix_path("./tests/x/y/z/b/test_spam.py"),
- "parentid": "./tests/x/y/z/b",
- },
- #### +++
- {
- "id": "./tests/x/y/z/test_ham.py",
- "kind": "file",
- "name": "test_ham.py",
- "relpath": fix_path("./tests/x/y/z/test_ham.py"),
- "parentid": "./tests/x/y/z",
- },
- ],
- "tests": [
- ##########
- {
- "id": "./tests/test_42-43.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_42-43.py:2"),
- "markers": [],
- "parentid": "./tests/test_42-43.py",
- },
- #####
- {
- "id": "./tests/test_42.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_42.py:2"),
- "markers": [],
- "parentid": "./tests/test_42.py",
- },
- #####
- {
- "id": "./tests/test_doctest.txt::test_doctest.txt",
- "name": "test_doctest.txt",
- "source": fix_path("./tests/test_doctest.txt:1"),
- "markers": [],
- "parentid": "./tests/test_doctest.txt",
- },
- #####
- {
- "id": "./tests/test_foo.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_foo.py:3"),
- "markers": [],
- "parentid": "./tests/test_foo.py",
- },
- #####
- {
- "id": "./tests/test_mixed.py::test_top_level",
- "name": "test_top_level",
- "source": fix_path("./tests/test_mixed.py:5"),
- "markers": [],
- "parentid": "./tests/test_mixed.py",
- },
- {
- "id": "./tests/test_mixed.py::test_skipped",
- "name": "test_skipped",
- "source": fix_path("./tests/test_mixed.py:9"),
- "markers": ["skip"],
- "parentid": "./tests/test_mixed.py",
- },
- {
- "id": "./tests/test_mixed.py::TestMySuite::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_mixed.py:16"),
- "markers": [],
- "parentid": "./tests/test_mixed.py::TestMySuite",
- },
- {
- "id": "./tests/test_mixed.py::MyTests::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_mixed.py:22"),
- "markers": [],
- "parentid": "./tests/test_mixed.py::MyTests",
- },
- {
- "id": "./tests/test_mixed.py::MyTests::test_skipped",
- "name": "test_skipped",
- "source": fix_path("./tests/test_mixed.py:25"),
- "markers": ["skip"],
- "parentid": "./tests/test_mixed.py::MyTests",
- },
- #####
- {
- "id": "./tests/test_pytest.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_pytest.py:6"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_failure",
- "name": "test_failure",
- "source": fix_path("./tests/test_pytest.py:10"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_runtime_skipped",
- "name": "test_runtime_skipped",
- "source": fix_path("./tests/test_pytest.py:14"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_runtime_failed",
- "name": "test_runtime_failed",
- "source": fix_path("./tests/test_pytest.py:18"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_raises",
- "name": "test_raises",
- "source": fix_path("./tests/test_pytest.py:22"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_skipped",
- "name": "test_skipped",
- "source": fix_path("./tests/test_pytest.py:26"),
- "markers": ["skip"],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_maybe_skipped",
- "name": "test_maybe_skipped",
- "source": fix_path("./tests/test_pytest.py:31"),
- "markers": ["skip-if"],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_known_failure",
- "name": "test_known_failure",
- "source": fix_path("./tests/test_pytest.py:36"),
- "markers": ["expected-failure"],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_warned",
- "name": "test_warned",
- "source": fix_path("./tests/test_pytest.py:41"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_custom_marker",
- "name": "test_custom_marker",
- "source": fix_path("./tests/test_pytest.py:46"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_multiple_markers",
- "name": "test_multiple_markers",
- "source": fix_path("./tests/test_pytest.py:51"),
- "markers": ["expected-failure", "skip", "skip-if"],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_dynamic_1",
- "name": "test_dynamic_1",
- "source": fix_path("./tests/test_pytest.py:62"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_dynamic_2",
- "name": "test_dynamic_2",
- "source": fix_path("./tests/test_pytest.py:62"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_dynamic_3",
- "name": "test_dynamic_3",
- "source": fix_path("./tests/test_pytest.py:62"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::TestSpam::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_pytest.py:70"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestSpam",
- },
- {
- "id": "./tests/test_pytest.py::TestSpam::test_skipped",
- "name": "test_skipped",
- "source": fix_path("./tests/test_pytest.py:73"),
- "markers": ["skip"],
- "parentid": "./tests/test_pytest.py::TestSpam",
- },
- {
- "id": "./tests/test_pytest.py::TestSpam::TestHam::TestEggs::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_pytest.py:81"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestSpam::TestHam::TestEggs",
- },
- {
- "id": "./tests/test_pytest.py::TestEggs::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_pytest.py:93"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestEggs",
- },
- {
- "id": "./tests/test_pytest.py::test_param_01[]",
- "name": "test_param_01[]",
- "source": fix_path("./tests/test_pytest.py:103"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_01",
- },
- {
- "id": "./tests/test_pytest.py::test_param_11[x0]",
- "name": "test_param_11[x0]",
- "source": fix_path("./tests/test_pytest.py:108"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_11",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13[x0]",
- "name": "test_param_13[x0]",
- "source": fix_path("./tests/test_pytest.py:113"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13[x1]",
- "name": "test_param_13[x1]",
- "source": fix_path("./tests/test_pytest.py:113"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13[x2]",
- "name": "test_param_13[x2]",
- "source": fix_path("./tests/test_pytest.py:113"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_repeat[x0]",
- "name": "test_param_13_repeat[x0]",
- "source": fix_path("./tests/test_pytest.py:118"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_13_repeat",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_repeat[x1]",
- "name": "test_param_13_repeat[x1]",
- "source": fix_path("./tests/test_pytest.py:118"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_13_repeat",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_repeat[x2]",
- "name": "test_param_13_repeat[x2]",
- "source": fix_path("./tests/test_pytest.py:118"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_13_repeat",
- },
- {
- "id": "./tests/test_pytest.py::test_param_33[1-1-1]",
- "name": "test_param_33[1-1-1]",
- "source": fix_path("./tests/test_pytest.py:123"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_33",
- },
- {
- "id": "./tests/test_pytest.py::test_param_33[3-4-5]",
- "name": "test_param_33[3-4-5]",
- "source": fix_path("./tests/test_pytest.py:123"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_33",
- },
- {
- "id": "./tests/test_pytest.py::test_param_33[0-0-0]",
- "name": "test_param_33[0-0-0]",
- "source": fix_path("./tests/test_pytest.py:123"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_33",
- },
- {
- "id": "./tests/test_pytest.py::test_param_33_ids[v1]",
- "name": "test_param_33_ids[v1]",
- "source": fix_path("./tests/test_pytest.py:128"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_33_ids",
- },
- {
- "id": "./tests/test_pytest.py::test_param_33_ids[v2]",
- "name": "test_param_33_ids[v2]",
- "source": fix_path("./tests/test_pytest.py:128"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_33_ids",
- },
- {
- "id": "./tests/test_pytest.py::test_param_33_ids[v3]",
- "name": "test_param_33_ids[v3]",
- "source": fix_path("./tests/test_pytest.py:128"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_33_ids",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_13[1-1-z0]",
- "name": "test_param_23_13[1-1-z0]",
- "source": fix_path("./tests/test_pytest.py:134"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_13[1-1-z1]",
- "name": "test_param_23_13[1-1-z1]",
- "source": fix_path("./tests/test_pytest.py:134"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_13[1-1-z2]",
- "name": "test_param_23_13[1-1-z2]",
- "source": fix_path("./tests/test_pytest.py:134"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_13[3-4-z0]",
- "name": "test_param_23_13[3-4-z0]",
- "source": fix_path("./tests/test_pytest.py:134"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_13[3-4-z1]",
- "name": "test_param_23_13[3-4-z1]",
- "source": fix_path("./tests/test_pytest.py:134"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_13[3-4-z2]",
- "name": "test_param_23_13[3-4-z2]",
- "source": fix_path("./tests/test_pytest.py:134"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_13[0-0-z0]",
- "name": "test_param_23_13[0-0-z0]",
- "source": fix_path("./tests/test_pytest.py:134"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_13[0-0-z1]",
- "name": "test_param_23_13[0-0-z1]",
- "source": fix_path("./tests/test_pytest.py:134"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_13[0-0-z2]",
- "name": "test_param_23_13[0-0-z2]",
- "source": fix_path("./tests/test_pytest.py:134"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_13",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_markers[x0]",
- "name": "test_param_13_markers[x0]",
- "source": fix_path("./tests/test_pytest.py:140"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_13_markers",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_markers[???]",
- "name": "test_param_13_markers[???]",
- "source": fix_path("./tests/test_pytest.py:140"),
- "markers": ["skip"],
- "parentid": "./tests/test_pytest.py::test_param_13_markers",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_markers[2]",
- "name": "test_param_13_markers[2]",
- "source": fix_path("./tests/test_pytest.py:140"),
- "markers": ["expected-failure"],
- "parentid": "./tests/test_pytest.py::test_param_13_markers",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_skipped[x0]",
- "name": "test_param_13_skipped[x0]",
- "source": fix_path("./tests/test_pytest.py:149"),
- "markers": ["skip"],
- "parentid": "./tests/test_pytest.py::test_param_13_skipped",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_skipped[x1]",
- "name": "test_param_13_skipped[x1]",
- "source": fix_path("./tests/test_pytest.py:149"),
- "markers": ["skip"],
- "parentid": "./tests/test_pytest.py::test_param_13_skipped",
- },
- {
- "id": "./tests/test_pytest.py::test_param_13_skipped[x2]",
- "name": "test_param_13_skipped[x2]",
- "source": fix_path("./tests/test_pytest.py:149"),
- "markers": ["skip"],
- "parentid": "./tests/test_pytest.py::test_param_13_skipped",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_raises[1-None]",
- "name": "test_param_23_raises[1-None]",
- "source": fix_path("./tests/test_pytest.py:155"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_raises",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_raises[1.0-None]",
- "name": "test_param_23_raises[1.0-None]",
- "source": fix_path("./tests/test_pytest.py:155"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_raises",
- },
- {
- "id": "./tests/test_pytest.py::test_param_23_raises[2-catch2]",
- "name": "test_param_23_raises[2-catch2]",
- "source": fix_path("./tests/test_pytest.py:155"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_23_raises",
- },
- {
- "id": "./tests/test_pytest.py::TestParam::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_pytest.py:164"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestParam",
- },
- {
- "id": "./tests/test_pytest.py::TestParam::test_param_13[x0]",
- "name": "test_param_13[x0]",
- "source": fix_path("./tests/test_pytest.py:167"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestParam::test_param_13",
- },
- {
- "id": "./tests/test_pytest.py::TestParam::test_param_13[x1]",
- "name": "test_param_13[x1]",
- "source": fix_path("./tests/test_pytest.py:167"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestParam::test_param_13",
- },
- {
- "id": "./tests/test_pytest.py::TestParam::test_param_13[x2]",
- "name": "test_param_13[x2]",
- "source": fix_path("./tests/test_pytest.py:167"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestParam::test_param_13",
- },
- {
- "id": "./tests/test_pytest.py::TestParamAll::test_param_13[x0]",
- "name": "test_param_13[x0]",
- "source": fix_path("./tests/test_pytest.py:175"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestParamAll::test_param_13",
- },
- {
- "id": "./tests/test_pytest.py::TestParamAll::test_param_13[x1]",
- "name": "test_param_13[x1]",
- "source": fix_path("./tests/test_pytest.py:175"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestParamAll::test_param_13",
- },
- {
- "id": "./tests/test_pytest.py::TestParamAll::test_param_13[x2]",
- "name": "test_param_13[x2]",
- "source": fix_path("./tests/test_pytest.py:175"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestParamAll::test_param_13",
- },
- {
- "id": "./tests/test_pytest.py::TestParamAll::test_spam_13[x0]",
- "name": "test_spam_13[x0]",
- "source": fix_path("./tests/test_pytest.py:178"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestParamAll::test_spam_13",
- },
- {
- "id": "./tests/test_pytest.py::TestParamAll::test_spam_13[x1]",
- "name": "test_spam_13[x1]",
- "source": fix_path("./tests/test_pytest.py:178"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestParamAll::test_spam_13",
- },
- {
- "id": "./tests/test_pytest.py::TestParamAll::test_spam_13[x2]",
- "name": "test_spam_13[x2]",
- "source": fix_path("./tests/test_pytest.py:178"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::TestParamAll::test_spam_13",
- },
- {
- "id": "./tests/test_pytest.py::test_fixture",
- "name": "test_fixture",
- "source": fix_path("./tests/test_pytest.py:192"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_mark_fixture",
- "name": "test_mark_fixture",
- "source": fix_path("./tests/test_pytest.py:196"),
- "markers": [],
- "parentid": "./tests/test_pytest.py",
- },
- {
- "id": "./tests/test_pytest.py::test_param_fixture[x0]",
- "name": "test_param_fixture[x0]",
- "source": fix_path("./tests/test_pytest.py:201"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_fixture",
- },
- {
- "id": "./tests/test_pytest.py::test_param_fixture[x1]",
- "name": "test_param_fixture[x1]",
- "source": fix_path("./tests/test_pytest.py:201"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_fixture",
- },
- {
- "id": "./tests/test_pytest.py::test_param_fixture[x2]",
- "name": "test_param_fixture[x2]",
- "source": fix_path("./tests/test_pytest.py:201"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_fixture",
- },
- {
- "id": "./tests/test_pytest.py::test_param_mark_fixture[x0]",
- "name": "test_param_mark_fixture[x0]",
- "source": fix_path("./tests/test_pytest.py:207"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_mark_fixture",
- },
- {
- "id": "./tests/test_pytest.py::test_param_mark_fixture[x1]",
- "name": "test_param_mark_fixture[x1]",
- "source": fix_path("./tests/test_pytest.py:207"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_mark_fixture",
- },
- {
- "id": "./tests/test_pytest.py::test_param_mark_fixture[x2]",
- "name": "test_param_mark_fixture[x2]",
- "source": fix_path("./tests/test_pytest.py:207"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_param_mark_fixture",
- },
- {
- "id": "./tests/test_pytest.py::test_fixture_param[spam]",
- "name": "test_fixture_param[spam]",
- "source": fix_path("./tests/test_pytest.py:216"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_fixture_param",
- },
- {
- "id": "./tests/test_pytest.py::test_fixture_param[eggs]",
- "name": "test_fixture_param[eggs]",
- "source": fix_path("./tests/test_pytest.py:216"),
- "markers": [],
- "parentid": "./tests/test_pytest.py::test_fixture_param",
- },
- ######
- {
- "id": "./tests/test_pytest_param.py::test_param_13[x0]",
- "name": "test_param_13[x0]",
- "source": fix_path("./tests/test_pytest_param.py:8"),
- "markers": [],
- "parentid": "./tests/test_pytest_param.py::test_param_13",
- },
- {
- "id": "./tests/test_pytest_param.py::test_param_13[x1]",
- "name": "test_param_13[x1]",
- "source": fix_path("./tests/test_pytest_param.py:8"),
- "markers": [],
- "parentid": "./tests/test_pytest_param.py::test_param_13",
- },
- {
- "id": "./tests/test_pytest_param.py::test_param_13[x2]",
- "name": "test_param_13[x2]",
- "source": fix_path("./tests/test_pytest_param.py:8"),
- "markers": [],
- "parentid": "./tests/test_pytest_param.py::test_param_13",
- },
- {
- "id": "./tests/test_pytest_param.py::TestParamAll::test_param_13[x0]",
- "name": "test_param_13[x0]",
- "source": fix_path("./tests/test_pytest_param.py:14"),
- "markers": [],
- "parentid": "./tests/test_pytest_param.py::TestParamAll::test_param_13",
- },
- {
- "id": "./tests/test_pytest_param.py::TestParamAll::test_param_13[x1]",
- "name": "test_param_13[x1]",
- "source": fix_path("./tests/test_pytest_param.py:14"),
- "markers": [],
- "parentid": "./tests/test_pytest_param.py::TestParamAll::test_param_13",
- },
- {
- "id": "./tests/test_pytest_param.py::TestParamAll::test_param_13[x2]",
- "name": "test_param_13[x2]",
- "source": fix_path("./tests/test_pytest_param.py:14"),
- "markers": [],
- "parentid": "./tests/test_pytest_param.py::TestParamAll::test_param_13",
- },
- {
- "id": "./tests/test_pytest_param.py::TestParamAll::test_spam_13[x0]",
- "name": "test_spam_13[x0]",
- "source": fix_path("./tests/test_pytest_param.py:17"),
- "markers": [],
- "parentid": "./tests/test_pytest_param.py::TestParamAll::test_spam_13",
- },
- {
- "id": "./tests/test_pytest_param.py::TestParamAll::test_spam_13[x1]",
- "name": "test_spam_13[x1]",
- "source": fix_path("./tests/test_pytest_param.py:17"),
- "markers": [],
- "parentid": "./tests/test_pytest_param.py::TestParamAll::test_spam_13",
- },
- {
- "id": "./tests/test_pytest_param.py::TestParamAll::test_spam_13[x2]",
- "name": "test_spam_13[x2]",
- "source": fix_path("./tests/test_pytest_param.py:17"),
- "markers": [],
- "parentid": "./tests/test_pytest_param.py::TestParamAll::test_spam_13",
- },
- ######
- {
- "id": "./tests/test_unittest.py::MyTests::test_dynamic_",
- "name": "test_dynamic_",
- "source": fix_path("./tests/test_unittest.py:54"),
- "markers": [],
- "parentid": "./tests/test_unittest.py::MyTests",
- },
- {
- "id": "./tests/test_unittest.py::MyTests::test_failure",
- "name": "test_failure",
- "source": fix_path("./tests/test_unittest.py:34"),
- "markers": [],
- "parentid": "./tests/test_unittest.py::MyTests",
- },
- {
- "id": "./tests/test_unittest.py::MyTests::test_known_failure",
- "name": "test_known_failure",
- "source": fix_path("./tests/test_unittest.py:37"),
- "markers": [],
- "parentid": "./tests/test_unittest.py::MyTests",
- },
- {
- "id": "./tests/test_unittest.py::MyTests::test_maybe_not_skipped",
- "name": "test_maybe_not_skipped",
- "source": fix_path("./tests/test_unittest.py:17"),
- "markers": [],
- "parentid": "./tests/test_unittest.py::MyTests",
- },
- {
- "id": "./tests/test_unittest.py::MyTests::test_maybe_skipped",
- "name": "test_maybe_skipped",
- "source": fix_path("./tests/test_unittest.py:13"),
- "markers": [],
- "parentid": "./tests/test_unittest.py::MyTests",
- },
- {
- "id": "./tests/test_unittest.py::MyTests::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_unittest.py:6"),
- "markers": [],
- "parentid": "./tests/test_unittest.py::MyTests",
- },
- {
- "id": "./tests/test_unittest.py::MyTests::test_skipped",
- "name": "test_skipped",
- "source": fix_path("./tests/test_unittest.py:9"),
- "markers": [],
- "parentid": "./tests/test_unittest.py::MyTests",
- },
- {
- "id": "./tests/test_unittest.py::MyTests::test_skipped_inside",
- "name": "test_skipped_inside",
- "source": fix_path("./tests/test_unittest.py:21"),
- "markers": [],
- "parentid": "./tests/test_unittest.py::MyTests",
- },
- {
- "id": "./tests/test_unittest.py::MyTests::test_with_nested_subtests",
- "name": "test_with_nested_subtests",
- "source": fix_path("./tests/test_unittest.py:46"),
- "markers": [],
- "parentid": "./tests/test_unittest.py::MyTests",
- },
- {
- "id": "./tests/test_unittest.py::MyTests::test_with_subtests",
- "name": "test_with_subtests",
- "source": fix_path("./tests/test_unittest.py:41"),
- "markers": [],
- "parentid": "./tests/test_unittest.py::MyTests",
- },
- {
- "id": "./tests/test_unittest.py::OtherTests::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/test_unittest.py:61"),
- "markers": [],
- "parentid": "./tests/test_unittest.py::OtherTests",
- },
- ###########
- {
- "id": "./tests/v/test_eggs.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/v/spam.py:2"),
- "markers": [],
- "parentid": "./tests/v/test_eggs.py",
- },
- {
- "id": "./tests/v/test_eggs.py::TestSimple::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/v/spam.py:8"),
- "markers": [],
- "parentid": "./tests/v/test_eggs.py::TestSimple",
- },
- ######
- {
- "id": "./tests/v/test_ham.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/v/spam.py:2"),
- "markers": [],
- "parentid": "./tests/v/test_ham.py",
- },
- {
- "id": "./tests/v/test_ham.py::test_not_hard",
- "name": "test_not_hard",
- "source": fix_path("./tests/v/spam.py:2"),
- "markers": [],
- "parentid": "./tests/v/test_ham.py",
- },
- ######
- {
- "id": "./tests/v/test_spam.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/v/spam.py:2"),
- "markers": [],
- "parentid": "./tests/v/test_spam.py",
- },
- {
- "id": "./tests/v/test_spam.py::test_simpler",
- "name": "test_simpler",
- "source": fix_path("./tests/v/test_spam.py:4"),
- "markers": [],
- "parentid": "./tests/v/test_spam.py",
- },
- ###########
- {
- "id": "./tests/w/test_spam.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/w/test_spam.py:4"),
- "markers": [],
- "parentid": "./tests/w/test_spam.py",
- },
- {
- "id": "./tests/w/test_spam_ex.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/w/test_spam_ex.py:4"),
- "markers": [],
- "parentid": "./tests/w/test_spam_ex.py",
- },
- ###########
- {
- "id": "./tests/x/y/z/test_ham.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/x/y/z/test_ham.py:2"),
- "markers": [],
- "parentid": "./tests/x/y/z/test_ham.py",
- },
- ######
- {
- "id": "./tests/x/y/z/a/test_spam.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/x/y/z/a/test_spam.py:11"),
- "markers": [],
- "parentid": "./tests/x/y/z/a/test_spam.py",
- },
- {
- "id": "./tests/x/y/z/b/test_spam.py::test_simple",
- "name": "test_simple",
- "source": fix_path("./tests/x/y/z/b/test_spam.py:7"),
- "markers": [],
- "parentid": "./tests/x/y/z/b/test_spam.py",
- },
- ],
-}
diff --git a/pythonFiles/tests/testing_tools/adapter/test_report.py b/pythonFiles/tests/testing_tools/adapter/test_report.py
deleted file mode 100644
index bb68c8a65e79..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/test_report.py
+++ /dev/null
@@ -1,1179 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-import json
-import unittest
-
-from ...util import StubProxy
-from testing_tools.adapter.util import fix_path, fix_relpath
-from testing_tools.adapter.info import SingleTestInfo, SingleTestPath, ParentInfo
-from testing_tools.adapter.report import report_discovered
-
-
-class StubSender(StubProxy):
- def send(self, outstr):
- self.add_call("send", (json.loads(outstr),), None)
-
-
-##################################
-# tests
-
-
-class ReportDiscoveredTests(unittest.TestCase):
- def test_basic(self):
- stub = StubSender()
- testroot = fix_path("/a/b/c")
- relfile = "test_spam.py"
- relpath = fix_relpath(relfile)
- tests = [
- SingleTestInfo(
- id="test#1",
- name="test_spam",
- path=SingleTestPath(
- root=testroot,
- relfile=relfile,
- func="test_spam",
- ),
- source="{}:{}".format(relfile, 10),
- markers=[],
- parentid="file#1",
- ),
- ]
- parents = [
- ParentInfo(
- id="",
- kind="folder",
- name=testroot,
- ),
- ParentInfo(
- id="file#1",
- kind="file",
- name=relfile,
- root=testroot,
- relpath=relpath,
- parentid="",
- ),
- ]
- expected = [
- {
- "rootid": "",
- "root": testroot,
- "parents": [
- {
- "id": "file#1",
- "kind": "file",
- "name": relfile,
- "relpath": relpath,
- "parentid": "",
- },
- ],
- "tests": [
- {
- "id": "test#1",
- "name": "test_spam",
- "source": "{}:{}".format(relfile, 10),
- "markers": [],
- "parentid": "file#1",
- }
- ],
- }
- ]
-
- report_discovered(tests, parents, _send=stub.send)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("send", (expected,), None),
- ],
- )
-
- def test_multiroot(self):
- stub = StubSender()
- # the first root
- testroot1 = fix_path("/a/b/c")
- relfileid1 = "./test_spam.py"
- relpath1 = fix_path(relfileid1)
- relfile1 = relpath1[2:]
- tests = [
- SingleTestInfo(
- id=relfileid1 + "::test_spam",
- name="test_spam",
- path=SingleTestPath(
- root=testroot1,
- relfile=relfile1,
- func="test_spam",
- ),
- source="{}:{}".format(relfile1, 10),
- markers=[],
- parentid=relfileid1,
- ),
- ]
- parents = [
- ParentInfo(
- id=".",
- kind="folder",
- name=testroot1,
- ),
- ParentInfo(
- id=relfileid1,
- kind="file",
- name="test_spam.py",
- root=testroot1,
- relpath=relpath1,
- parentid=".",
- ),
- ]
- expected = [
- {
- "rootid": ".",
- "root": testroot1,
- "parents": [
- {
- "id": relfileid1,
- "kind": "file",
- "name": "test_spam.py",
- "relpath": relpath1,
- "parentid": ".",
- },
- ],
- "tests": [
- {
- "id": relfileid1 + "::test_spam",
- "name": "test_spam",
- "source": "{}:{}".format(relfile1, 10),
- "markers": [],
- "parentid": relfileid1,
- }
- ],
- },
- ]
- # the second root
- testroot2 = fix_path("/x/y/z")
- relfileid2 = "./w/test_eggs.py"
- relpath2 = fix_path(relfileid2)
- relfile2 = relpath2[2:]
- tests.extend(
- [
- SingleTestInfo(
- id=relfileid2 + "::BasicTests::test_first",
- name="test_first",
- path=SingleTestPath(
- root=testroot2,
- relfile=relfile2,
- func="BasicTests.test_first",
- ),
- source="{}:{}".format(relfile2, 61),
- markers=[],
- parentid=relfileid2 + "::BasicTests",
- ),
- ]
- )
- parents.extend(
- [
- ParentInfo(
- id=".",
- kind="folder",
- name=testroot2,
- ),
- ParentInfo(
- id="./w",
- kind="folder",
- name="w",
- root=testroot2,
- relpath=fix_path("./w"),
- parentid=".",
- ),
- ParentInfo(
- id=relfileid2,
- kind="file",
- name="test_eggs.py",
- root=testroot2,
- relpath=relpath2,
- parentid="./w",
- ),
- ParentInfo(
- id=relfileid2 + "::BasicTests",
- kind="suite",
- name="BasicTests",
- root=testroot2,
- parentid=relfileid2,
- ),
- ]
- )
- expected.extend(
- [
- {
- "rootid": ".",
- "root": testroot2,
- "parents": [
- {
- "id": "./w",
- "kind": "folder",
- "name": "w",
- "relpath": fix_path("./w"),
- "parentid": ".",
- },
- {
- "id": relfileid2,
- "kind": "file",
- "name": "test_eggs.py",
- "relpath": relpath2,
- "parentid": "./w",
- },
- {
- "id": relfileid2 + "::BasicTests",
- "kind": "suite",
- "name": "BasicTests",
- "parentid": relfileid2,
- },
- ],
- "tests": [
- {
- "id": relfileid2 + "::BasicTests::test_first",
- "name": "test_first",
- "source": "{}:{}".format(relfile2, 61),
- "markers": [],
- "parentid": relfileid2 + "::BasicTests",
- }
- ],
- },
- ]
- )
-
- report_discovered(tests, parents, _send=stub.send)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("send", (expected,), None),
- ],
- )
-
- def test_complex(self):
- """
- /a/b/c/
- test_ham.py
- MySuite
- test_x1
- test_x2
- /a/b/e/f/g/
- w/
- test_ham.py
- test_ham1
- HamTests
- test_uh_oh
- test_whoa
- MoreHam
- test_yay
- sub1
- sub2
- sub3
- test_eggs.py
- SpamTests
- test_okay
- x/
- y/
- a/
- test_spam.py
- SpamTests
- test_okay
- b/
- test_spam.py
- SpamTests
- test_okay
- test_spam.py
- SpamTests
- test_okay
- """
- stub = StubSender()
- testroot = fix_path("/a/b/c")
- relfileid1 = "./test_ham.py"
- relfileid2 = "./test_spam.py"
- relfileid3 = "./w/test_ham.py"
- relfileid4 = "./w/test_eggs.py"
- relfileid5 = "./x/y/a/test_spam.py"
- relfileid6 = "./x/y/b/test_spam.py"
- tests = [
- SingleTestInfo(
- id=relfileid1 + "::MySuite::test_x1",
- name="test_x1",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_path(relfileid1),
- func="MySuite.test_x1",
- ),
- source="{}:{}".format(fix_path(relfileid1), 10),
- markers=None,
- parentid=relfileid1 + "::MySuite",
- ),
- SingleTestInfo(
- id=relfileid1 + "::MySuite::test_x2",
- name="test_x2",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_path(relfileid1),
- func="MySuite.test_x2",
- ),
- source="{}:{}".format(fix_path(relfileid1), 21),
- markers=None,
- parentid=relfileid1 + "::MySuite",
- ),
- SingleTestInfo(
- id=relfileid2 + "::SpamTests::test_okay",
- name="test_okay",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_path(relfileid2),
- func="SpamTests.test_okay",
- ),
- source="{}:{}".format(fix_path(relfileid2), 17),
- markers=None,
- parentid=relfileid2 + "::SpamTests",
- ),
- SingleTestInfo(
- id=relfileid3 + "::test_ham1",
- name="test_ham1",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_path(relfileid3),
- func="test_ham1",
- ),
- source="{}:{}".format(fix_path(relfileid3), 8),
- markers=None,
- parentid=relfileid3,
- ),
- SingleTestInfo(
- id=relfileid3 + "::HamTests::test_uh_oh",
- name="test_uh_oh",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_path(relfileid3),
- func="HamTests.test_uh_oh",
- ),
- source="{}:{}".format(fix_path(relfileid3), 19),
- markers=["expected-failure"],
- parentid=relfileid3 + "::HamTests",
- ),
- SingleTestInfo(
- id=relfileid3 + "::HamTests::test_whoa",
- name="test_whoa",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_path(relfileid3),
- func="HamTests.test_whoa",
- ),
- source="{}:{}".format(fix_path(relfileid3), 35),
- markers=None,
- parentid=relfileid3 + "::HamTests",
- ),
- SingleTestInfo(
- id=relfileid3 + "::MoreHam::test_yay[1-2]",
- name="test_yay[1-2]",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_path(relfileid3),
- func="MoreHam.test_yay",
- sub=["[1-2]"],
- ),
- source="{}:{}".format(fix_path(relfileid3), 57),
- markers=None,
- parentid=relfileid3 + "::MoreHam::test_yay",
- ),
- SingleTestInfo(
- id=relfileid3 + "::MoreHam::test_yay[1-2][3-4]",
- name="test_yay[1-2][3-4]",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_path(relfileid3),
- func="MoreHam.test_yay",
- sub=["[1-2]", "[3=4]"],
- ),
- source="{}:{}".format(fix_path(relfileid3), 72),
- markers=None,
- parentid=relfileid3 + "::MoreHam::test_yay[1-2]",
- ),
- SingleTestInfo(
- id=relfileid4 + "::SpamTests::test_okay",
- name="test_okay",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_path(relfileid4),
- func="SpamTests.test_okay",
- ),
- source="{}:{}".format(fix_path(relfileid4), 15),
- markers=None,
- parentid=relfileid4 + "::SpamTests",
- ),
- SingleTestInfo(
- id=relfileid5 + "::SpamTests::test_okay",
- name="test_okay",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_path(relfileid5),
- func="SpamTests.test_okay",
- ),
- source="{}:{}".format(fix_path(relfileid5), 12),
- markers=None,
- parentid=relfileid5 + "::SpamTests",
- ),
- SingleTestInfo(
- id=relfileid6 + "::SpamTests::test_okay",
- name="test_okay",
- path=SingleTestPath(
- root=testroot,
- relfile=fix_path(relfileid6),
- func="SpamTests.test_okay",
- ),
- source="{}:{}".format(fix_path(relfileid6), 27),
- markers=None,
- parentid=relfileid6 + "::SpamTests",
- ),
- ]
- parents = [
- ParentInfo(
- id=".",
- kind="folder",
- name=testroot,
- ),
- ParentInfo(
- id=relfileid1,
- kind="file",
- name="test_ham.py",
- root=testroot,
- relpath=fix_path(relfileid1),
- parentid=".",
- ),
- ParentInfo(
- id=relfileid1 + "::MySuite",
- kind="suite",
- name="MySuite",
- root=testroot,
- parentid=relfileid1,
- ),
- ParentInfo(
- id=relfileid2,
- kind="file",
- name="test_spam.py",
- root=testroot,
- relpath=fix_path(relfileid2),
- parentid=".",
- ),
- ParentInfo(
- id=relfileid2 + "::SpamTests",
- kind="suite",
- name="SpamTests",
- root=testroot,
- parentid=relfileid2,
- ),
- ParentInfo(
- id="./w",
- kind="folder",
- name="w",
- root=testroot,
- relpath=fix_path("./w"),
- parentid=".",
- ),
- ParentInfo(
- id=relfileid3,
- kind="file",
- name="test_ham.py",
- root=testroot,
- relpath=fix_path(relfileid3),
- parentid="./w",
- ),
- ParentInfo(
- id=relfileid3 + "::HamTests",
- kind="suite",
- name="HamTests",
- root=testroot,
- parentid=relfileid3,
- ),
- ParentInfo(
- id=relfileid3 + "::MoreHam",
- kind="suite",
- name="MoreHam",
- root=testroot,
- parentid=relfileid3,
- ),
- ParentInfo(
- id=relfileid3 + "::MoreHam::test_yay",
- kind="function",
- name="test_yay",
- root=testroot,
- parentid=relfileid3 + "::MoreHam",
- ),
- ParentInfo(
- id=relfileid3 + "::MoreHam::test_yay[1-2]",
- kind="subtest",
- name="test_yay[1-2]",
- root=testroot,
- parentid=relfileid3 + "::MoreHam::test_yay",
- ),
- ParentInfo(
- id=relfileid4,
- kind="file",
- name="test_eggs.py",
- root=testroot,
- relpath=fix_path(relfileid4),
- parentid="./w",
- ),
- ParentInfo(
- id=relfileid4 + "::SpamTests",
- kind="suite",
- name="SpamTests",
- root=testroot,
- parentid=relfileid4,
- ),
- ParentInfo(
- id="./x",
- kind="folder",
- name="x",
- root=testroot,
- relpath=fix_path("./x"),
- parentid=".",
- ),
- ParentInfo(
- id="./x/y",
- kind="folder",
- name="y",
- root=testroot,
- relpath=fix_path("./x/y"),
- parentid="./x",
- ),
- ParentInfo(
- id="./x/y/a",
- kind="folder",
- name="a",
- root=testroot,
- relpath=fix_path("./x/y/a"),
- parentid="./x/y",
- ),
- ParentInfo(
- id=relfileid5,
- kind="file",
- name="test_spam.py",
- root=testroot,
- relpath=fix_path(relfileid5),
- parentid="./x/y/a",
- ),
- ParentInfo(
- id=relfileid5 + "::SpamTests",
- kind="suite",
- name="SpamTests",
- root=testroot,
- parentid=relfileid5,
- ),
- ParentInfo(
- id="./x/y/b",
- kind="folder",
- name="b",
- root=testroot,
- relpath=fix_path("./x/y/b"),
- parentid="./x/y",
- ),
- ParentInfo(
- id=relfileid6,
- kind="file",
- name="test_spam.py",
- root=testroot,
- relpath=fix_path(relfileid6),
- parentid="./x/y/b",
- ),
- ParentInfo(
- id=relfileid6 + "::SpamTests",
- kind="suite",
- name="SpamTests",
- root=testroot,
- parentid=relfileid6,
- ),
- ]
- expected = [
- {
- "rootid": ".",
- "root": testroot,
- "parents": [
- {
- "id": relfileid1,
- "kind": "file",
- "name": "test_ham.py",
- "relpath": fix_path(relfileid1),
- "parentid": ".",
- },
- {
- "id": relfileid1 + "::MySuite",
- "kind": "suite",
- "name": "MySuite",
- "parentid": relfileid1,
- },
- {
- "id": relfileid2,
- "kind": "file",
- "name": "test_spam.py",
- "relpath": fix_path(relfileid2),
- "parentid": ".",
- },
- {
- "id": relfileid2 + "::SpamTests",
- "kind": "suite",
- "name": "SpamTests",
- "parentid": relfileid2,
- },
- {
- "id": "./w",
- "kind": "folder",
- "name": "w",
- "relpath": fix_path("./w"),
- "parentid": ".",
- },
- {
- "id": relfileid3,
- "kind": "file",
- "name": "test_ham.py",
- "relpath": fix_path(relfileid3),
- "parentid": "./w",
- },
- {
- "id": relfileid3 + "::HamTests",
- "kind": "suite",
- "name": "HamTests",
- "parentid": relfileid3,
- },
- {
- "id": relfileid3 + "::MoreHam",
- "kind": "suite",
- "name": "MoreHam",
- "parentid": relfileid3,
- },
- {
- "id": relfileid3 + "::MoreHam::test_yay",
- "kind": "function",
- "name": "test_yay",
- "parentid": relfileid3 + "::MoreHam",
- },
- {
- "id": relfileid3 + "::MoreHam::test_yay[1-2]",
- "kind": "subtest",
- "name": "test_yay[1-2]",
- "parentid": relfileid3 + "::MoreHam::test_yay",
- },
- {
- "id": relfileid4,
- "kind": "file",
- "name": "test_eggs.py",
- "relpath": fix_path(relfileid4),
- "parentid": "./w",
- },
- {
- "id": relfileid4 + "::SpamTests",
- "kind": "suite",
- "name": "SpamTests",
- "parentid": relfileid4,
- },
- {
- "id": "./x",
- "kind": "folder",
- "name": "x",
- "relpath": fix_path("./x"),
- "parentid": ".",
- },
- {
- "id": "./x/y",
- "kind": "folder",
- "name": "y",
- "relpath": fix_path("./x/y"),
- "parentid": "./x",
- },
- {
- "id": "./x/y/a",
- "kind": "folder",
- "name": "a",
- "relpath": fix_path("./x/y/a"),
- "parentid": "./x/y",
- },
- {
- "id": relfileid5,
- "kind": "file",
- "name": "test_spam.py",
- "relpath": fix_path(relfileid5),
- "parentid": "./x/y/a",
- },
- {
- "id": relfileid5 + "::SpamTests",
- "kind": "suite",
- "name": "SpamTests",
- "parentid": relfileid5,
- },
- {
- "id": "./x/y/b",
- "kind": "folder",
- "name": "b",
- "relpath": fix_path("./x/y/b"),
- "parentid": "./x/y",
- },
- {
- "id": relfileid6,
- "kind": "file",
- "name": "test_spam.py",
- "relpath": fix_path(relfileid6),
- "parentid": "./x/y/b",
- },
- {
- "id": relfileid6 + "::SpamTests",
- "kind": "suite",
- "name": "SpamTests",
- "parentid": relfileid6,
- },
- ],
- "tests": [
- {
- "id": relfileid1 + "::MySuite::test_x1",
- "name": "test_x1",
- "source": "{}:{}".format(fix_path(relfileid1), 10),
- "markers": [],
- "parentid": relfileid1 + "::MySuite",
- },
- {
- "id": relfileid1 + "::MySuite::test_x2",
- "name": "test_x2",
- "source": "{}:{}".format(fix_path(relfileid1), 21),
- "markers": [],
- "parentid": relfileid1 + "::MySuite",
- },
- {
- "id": relfileid2 + "::SpamTests::test_okay",
- "name": "test_okay",
- "source": "{}:{}".format(fix_path(relfileid2), 17),
- "markers": [],
- "parentid": relfileid2 + "::SpamTests",
- },
- {
- "id": relfileid3 + "::test_ham1",
- "name": "test_ham1",
- "source": "{}:{}".format(fix_path(relfileid3), 8),
- "markers": [],
- "parentid": relfileid3,
- },
- {
- "id": relfileid3 + "::HamTests::test_uh_oh",
- "name": "test_uh_oh",
- "source": "{}:{}".format(fix_path(relfileid3), 19),
- "markers": ["expected-failure"],
- "parentid": relfileid3 + "::HamTests",
- },
- {
- "id": relfileid3 + "::HamTests::test_whoa",
- "name": "test_whoa",
- "source": "{}:{}".format(fix_path(relfileid3), 35),
- "markers": [],
- "parentid": relfileid3 + "::HamTests",
- },
- {
- "id": relfileid3 + "::MoreHam::test_yay[1-2]",
- "name": "test_yay[1-2]",
- "source": "{}:{}".format(fix_path(relfileid3), 57),
- "markers": [],
- "parentid": relfileid3 + "::MoreHam::test_yay",
- },
- {
- "id": relfileid3 + "::MoreHam::test_yay[1-2][3-4]",
- "name": "test_yay[1-2][3-4]",
- "source": "{}:{}".format(fix_path(relfileid3), 72),
- "markers": [],
- "parentid": relfileid3 + "::MoreHam::test_yay[1-2]",
- },
- {
- "id": relfileid4 + "::SpamTests::test_okay",
- "name": "test_okay",
- "source": "{}:{}".format(fix_path(relfileid4), 15),
- "markers": [],
- "parentid": relfileid4 + "::SpamTests",
- },
- {
- "id": relfileid5 + "::SpamTests::test_okay",
- "name": "test_okay",
- "source": "{}:{}".format(fix_path(relfileid5), 12),
- "markers": [],
- "parentid": relfileid5 + "::SpamTests",
- },
- {
- "id": relfileid6 + "::SpamTests::test_okay",
- "name": "test_okay",
- "source": "{}:{}".format(fix_path(relfileid6), 27),
- "markers": [],
- "parentid": relfileid6 + "::SpamTests",
- },
- ],
- }
- ]
-
- report_discovered(tests, parents, _send=stub.send)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("send", (expected,), None),
- ],
- )
-
- def test_simple_basic(self):
- stub = StubSender()
- testroot = fix_path("/a/b/c")
- relfile = fix_path("x/y/z/test_spam.py")
- tests = [
- SingleTestInfo(
- id="test#1",
- name="test_spam_1",
- path=SingleTestPath(
- root=testroot,
- relfile=relfile,
- func="MySuite.test_spam_1",
- sub=None,
- ),
- source="{}:{}".format(relfile, 10),
- markers=None,
- parentid="suite#1",
- ),
- ]
- parents = None
- expected = [
- {
- "id": "test#1",
- "name": "test_spam_1",
- "testroot": testroot,
- "relfile": relfile,
- "lineno": 10,
- "testfunc": "MySuite.test_spam_1",
- "subtest": None,
- "markers": [],
- }
- ]
-
- report_discovered(tests, parents, simple=True, _send=stub.send)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("send", (expected,), None),
- ],
- )
-
- def test_simple_complex(self):
- """
- /a/b/c/
- test_ham.py
- MySuite
- test_x1
- test_x2
- /a/b/e/f/g/
- w/
- test_ham.py
- test_ham1
- HamTests
- test_uh_oh
- test_whoa
- MoreHam
- test_yay
- sub1
- sub2
- sub3
- test_eggs.py
- SpamTests
- test_okay
- x/
- y/
- a/
- test_spam.py
- SpamTests
- test_okay
- b/
- test_spam.py
- SpamTests
- test_okay
- test_spam.py
- SpamTests
- test_okay
- """
- stub = StubSender()
- testroot1 = fix_path("/a/b/c")
- relfile1 = fix_path("./test_ham.py")
- testroot2 = fix_path("/a/b/e/f/g")
- relfile2 = fix_path("./test_spam.py")
- relfile3 = fix_path("w/test_ham.py")
- relfile4 = fix_path("w/test_eggs.py")
- relfile5 = fix_path("x/y/a/test_spam.py")
- relfile6 = fix_path("x/y/b/test_spam.py")
- tests = [
- # under first root folder
- SingleTestInfo(
- id="test#1",
- name="test_x1",
- path=SingleTestPath(
- root=testroot1,
- relfile=relfile1,
- func="MySuite.test_x1",
- sub=None,
- ),
- source="{}:{}".format(relfile1, 10),
- markers=None,
- parentid="suite#1",
- ),
- SingleTestInfo(
- id="test#2",
- name="test_x2",
- path=SingleTestPath(
- root=testroot1,
- relfile=relfile1,
- func="MySuite.test_x2",
- sub=None,
- ),
- source="{}:{}".format(relfile1, 21),
- markers=None,
- parentid="suite#1",
- ),
- # under second root folder
- SingleTestInfo(
- id="test#3",
- name="test_okay",
- path=SingleTestPath(
- root=testroot2,
- relfile=relfile2,
- func="SpamTests.test_okay",
- sub=None,
- ),
- source="{}:{}".format(relfile2, 17),
- markers=None,
- parentid="suite#2",
- ),
- SingleTestInfo(
- id="test#4",
- name="test_ham1",
- path=SingleTestPath(
- root=testroot2,
- relfile=relfile3,
- func="test_ham1",
- sub=None,
- ),
- source="{}:{}".format(relfile3, 8),
- markers=None,
- parentid="file#3",
- ),
- SingleTestInfo(
- id="test#5",
- name="test_uh_oh",
- path=SingleTestPath(
- root=testroot2,
- relfile=relfile3,
- func="HamTests.test_uh_oh",
- sub=None,
- ),
- source="{}:{}".format(relfile3, 19),
- markers=["expected-failure"],
- parentid="suite#3",
- ),
- SingleTestInfo(
- id="test#6",
- name="test_whoa",
- path=SingleTestPath(
- root=testroot2,
- relfile=relfile3,
- func="HamTests.test_whoa",
- sub=None,
- ),
- source="{}:{}".format(relfile3, 35),
- markers=None,
- parentid="suite#3",
- ),
- SingleTestInfo(
- id="test#7",
- name="test_yay (sub1)",
- path=SingleTestPath(
- root=testroot2,
- relfile=relfile3,
- func="MoreHam.test_yay",
- sub=["sub1"],
- ),
- source="{}:{}".format(relfile3, 57),
- markers=None,
- parentid="suite#4",
- ),
- SingleTestInfo(
- id="test#8",
- name="test_yay (sub2) (sub3)",
- path=SingleTestPath(
- root=testroot2,
- relfile=relfile3,
- func="MoreHam.test_yay",
- sub=["sub2", "sub3"],
- ),
- source="{}:{}".format(relfile3, 72),
- markers=None,
- parentid="suite#3",
- ),
- SingleTestInfo(
- id="test#9",
- name="test_okay",
- path=SingleTestPath(
- root=testroot2,
- relfile=relfile4,
- func="SpamTests.test_okay",
- sub=None,
- ),
- source="{}:{}".format(relfile4, 15),
- markers=None,
- parentid="suite#5",
- ),
- SingleTestInfo(
- id="test#10",
- name="test_okay",
- path=SingleTestPath(
- root=testroot2,
- relfile=relfile5,
- func="SpamTests.test_okay",
- sub=None,
- ),
- source="{}:{}".format(relfile5, 12),
- markers=None,
- parentid="suite#6",
- ),
- SingleTestInfo(
- id="test#11",
- name="test_okay",
- path=SingleTestPath(
- root=testroot2,
- relfile=relfile6,
- func="SpamTests.test_okay",
- sub=None,
- ),
- source="{}:{}".format(relfile6, 27),
- markers=None,
- parentid="suite#7",
- ),
- ]
- expected = [
- {
- "id": "test#1",
- "name": "test_x1",
- "testroot": testroot1,
- "relfile": relfile1,
- "lineno": 10,
- "testfunc": "MySuite.test_x1",
- "subtest": None,
- "markers": [],
- },
- {
- "id": "test#2",
- "name": "test_x2",
- "testroot": testroot1,
- "relfile": relfile1,
- "lineno": 21,
- "testfunc": "MySuite.test_x2",
- "subtest": None,
- "markers": [],
- },
- {
- "id": "test#3",
- "name": "test_okay",
- "testroot": testroot2,
- "relfile": relfile2,
- "lineno": 17,
- "testfunc": "SpamTests.test_okay",
- "subtest": None,
- "markers": [],
- },
- {
- "id": "test#4",
- "name": "test_ham1",
- "testroot": testroot2,
- "relfile": relfile3,
- "lineno": 8,
- "testfunc": "test_ham1",
- "subtest": None,
- "markers": [],
- },
- {
- "id": "test#5",
- "name": "test_uh_oh",
- "testroot": testroot2,
- "relfile": relfile3,
- "lineno": 19,
- "testfunc": "HamTests.test_uh_oh",
- "subtest": None,
- "markers": ["expected-failure"],
- },
- {
- "id": "test#6",
- "name": "test_whoa",
- "testroot": testroot2,
- "relfile": relfile3,
- "lineno": 35,
- "testfunc": "HamTests.test_whoa",
- "subtest": None,
- "markers": [],
- },
- {
- "id": "test#7",
- "name": "test_yay (sub1)",
- "testroot": testroot2,
- "relfile": relfile3,
- "lineno": 57,
- "testfunc": "MoreHam.test_yay",
- "subtest": ["sub1"],
- "markers": [],
- },
- {
- "id": "test#8",
- "name": "test_yay (sub2) (sub3)",
- "testroot": testroot2,
- "relfile": relfile3,
- "lineno": 72,
- "testfunc": "MoreHam.test_yay",
- "subtest": ["sub2", "sub3"],
- "markers": [],
- },
- {
- "id": "test#9",
- "name": "test_okay",
- "testroot": testroot2,
- "relfile": relfile4,
- "lineno": 15,
- "testfunc": "SpamTests.test_okay",
- "subtest": None,
- "markers": [],
- },
- {
- "id": "test#10",
- "name": "test_okay",
- "testroot": testroot2,
- "relfile": relfile5,
- "lineno": 12,
- "testfunc": "SpamTests.test_okay",
- "subtest": None,
- "markers": [],
- },
- {
- "id": "test#11",
- "name": "test_okay",
- "testroot": testroot2,
- "relfile": relfile6,
- "lineno": 27,
- "testfunc": "SpamTests.test_okay",
- "subtest": None,
- "markers": [],
- },
- ]
- parents = None
-
- report_discovered(tests, parents, simple=True, _send=stub.send)
-
- self.maxDiff = None
- self.assertEqual(
- stub.calls,
- [
- ("send", (expected,), None),
- ],
- )
diff --git a/pythonFiles/tests/testing_tools/adapter/test_util.py b/pythonFiles/tests/testing_tools/adapter/test_util.py
deleted file mode 100644
index 822ba2ed1b22..000000000000
--- a/pythonFiles/tests/testing_tools/adapter/test_util.py
+++ /dev/null
@@ -1,330 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-from __future__ import absolute_import, print_function
-
-import ntpath
-import os
-import os.path
-import posixpath
-import shlex
-import sys
-import unittest
-
-import pytest
-
-# Pytest 3.7 and later uses pathlib/pathlib2 for path resolution.
-try:
- from pathlib import Path
-except ImportError:
- from pathlib2 import Path # type: ignore (for Pylance)
-
-from testing_tools.adapter.util import (
- fix_path,
- fix_relpath,
- fix_fileid,
- shlex_unsplit,
-)
-
-
-@unittest.skipIf(sys.version_info < (3,), "Python 2 does not have subTest")
-class FilePathTests(unittest.TestCase):
- def test_isolated_imports(self):
- import testing_tools.adapter
- from testing_tools.adapter import util
- from . import test_functional
-
- ignored = {
- str(Path(os.path.abspath(__file__)).resolve()),
- str(Path(os.path.abspath(util.__file__)).resolve()),
- str(Path(os.path.abspath(test_functional.__file__)).resolve()),
- }
- adapter = os.path.abspath(os.path.dirname(testing_tools.adapter.__file__))
- tests = os.path.join(
- os.path.abspath(os.path.dirname(os.path.dirname(testing_tools.__file__))),
- "tests",
- "testing_tools",
- "adapter",
- )
- found = []
- for root in [adapter, tests]:
- for dirname, _, files in os.walk(root):
- if ".data" in dirname:
- continue
- for basename in files:
- if not basename.endswith(".py"):
- continue
- filename = os.path.join(dirname, basename)
- if filename in ignored:
- continue
- with open(filename) as srcfile:
- for line in srcfile:
- if line.strip() == "import os.path":
- found.append(filename)
- break
-
- if found:
- self.fail(
- os.linesep.join(
- [
- "",
- "Please only use path-related API from testing_tools.adapter.util.",
- 'Found use of "os.path" in the following files:',
- ]
- + [" " + file for file in found]
- )
- )
-
- def test_fix_path(self):
- tests = [
- ("./spam.py", r".\spam.py"),
- ("./some-dir", r".\some-dir"),
- ("./some-dir/", ".\\some-dir\\"),
- ("./some-dir/eggs", r".\some-dir\eggs"),
- ("./some-dir/eggs/spam.py", r".\some-dir\eggs\spam.py"),
- ("X/y/Z/a.B.c.PY", r"X\y\Z\a.B.c.PY"),
- ("/", "\\"),
- ("/spam", r"\spam"),
- ("C:/spam", r"C:\spam"),
- ]
- for path, expected in tests:
- pathsep = ntpath.sep
- with self.subTest(r"fixed for \: {!r}".format(path)):
- fixed = fix_path(path, _pathsep=pathsep)
- self.assertEqual(fixed, expected)
-
- pathsep = posixpath.sep
- with self.subTest("unchanged for /: {!r}".format(path)):
- unchanged = fix_path(path, _pathsep=pathsep)
- self.assertEqual(unchanged, path)
-
- # no path -> "."
- for path in ["", None]:
- for pathsep in [ntpath.sep, posixpath.sep]:
- with self.subTest(r"fixed for {}: {!r}".format(pathsep, path)):
- fixed = fix_path(path, _pathsep=pathsep)
- self.assertEqual(fixed, ".")
-
- # no-op paths
- paths = [path for _, path in tests]
- paths.extend(
- [
- ".",
- "..",
- "some-dir",
- "spam.py",
- ]
- )
- for path in paths:
- for pathsep in [ntpath.sep, posixpath.sep]:
- with self.subTest(r"unchanged for {}: {!r}".format(pathsep, path)):
- unchanged = fix_path(path, _pathsep=pathsep)
- self.assertEqual(unchanged, path)
-
- def test_fix_relpath(self):
- tests = [
- ("spam.py", posixpath, "./spam.py"),
- ("eggs/spam.py", posixpath, "./eggs/spam.py"),
- ("eggs/spam/", posixpath, "./eggs/spam/"),
- (r"\spam.py", posixpath, r"./\spam.py"),
- ("spam.py", ntpath, r".\spam.py"),
- (r"eggs\spam.py", ntpath, r".\eggs\spam.py"),
- ("eggs\\spam\\", ntpath, ".\\eggs\\spam\\"),
- ("/spam.py", ntpath, r"\spam.py"), # Note the fixed "/".
- # absolute
- ("/", posixpath, "/"),
- ("/spam.py", posixpath, "/spam.py"),
- ("\\", ntpath, "\\"),
- (r"\spam.py", ntpath, r"\spam.py"),
- (r"C:\spam.py", ntpath, r"C:\spam.py"),
- # no-op
- ("./spam.py", posixpath, "./spam.py"),
- (r".\spam.py", ntpath, r".\spam.py"),
- ]
- # no-op
- for path in [".", ".."]:
- tests.extend(
- [
- (path, posixpath, path),
- (path, ntpath, path),
- ]
- )
- for path, _os_path, expected in tests:
- with self.subTest((path, _os_path.sep)):
- fixed = fix_relpath(
- path,
- _fix_path=(lambda p: fix_path(p, _pathsep=_os_path.sep)),
- _path_isabs=_os_path.isabs,
- _pathsep=_os_path.sep,
- )
- self.assertEqual(fixed, expected)
-
- def test_fix_fileid(self):
- common = [
- ("spam.py", "./spam.py"),
- ("eggs/spam.py", "./eggs/spam.py"),
- ("eggs/spam/", "./eggs/spam/"),
- # absolute (no-op)
- ("/", "/"),
- ("//", "//"),
- ("/spam.py", "/spam.py"),
- # no-op
- (None, None),
- ("", ""),
- (".", "."),
- ("./spam.py", "./spam.py"),
- ]
- tests = [(p, posixpath, e) for p, e in common]
- tests.extend(
- (p, posixpath, e)
- for p, e in [
- (r"\spam.py", r"./\spam.py"),
- ]
- )
- tests.extend((p, ntpath, e) for p, e in common)
- tests.extend(
- (p, ntpath, e)
- for p, e in [
- (r"eggs\spam.py", "./eggs/spam.py"),
- ("eggs\\spam\\", "./eggs/spam/"),
- (r".\spam.py", r"./spam.py"),
- # absolute
- (r"\spam.py", "/spam.py"),
- (r"C:\spam.py", "C:/spam.py"),
- ("\\", "/"),
- ("\\\\", "//"),
- ("C:\\\\", "C://"),
- ("C:/", "C:/"),
- ("C://", "C://"),
- ("C:/spam.py", "C:/spam.py"),
- ]
- )
- for fileid, _os_path, expected in tests:
- pathsep = _os_path.sep
- with self.subTest(r"for {}: {!r}".format(pathsep, fileid)):
- fixed = fix_fileid(
- fileid,
- _path_isabs=_os_path.isabs,
- _normcase=_os_path.normcase,
- _pathsep=pathsep,
- )
- self.assertEqual(fixed, expected)
-
- # with rootdir
- common = [
- ("spam.py", "/eggs", "./spam.py"),
- ("spam.py", r"\eggs", "./spam.py"),
- # absolute
- ("/spam.py", "/", "./spam.py"),
- ("/eggs/spam.py", "/eggs", "./spam.py"),
- ("/eggs/spam.py", "/eggs/", "./spam.py"),
- # no-op
- ("/spam.py", "/eggs", "/spam.py"),
- ("/spam.py", "/eggs/", "/spam.py"),
- # root-only (no-op)
- ("/", "/", "/"),
- ("/", "/spam", "/"),
- ("//", "/", "//"),
- ("//", "//", "//"),
- ("//", "//spam", "//"),
- ]
- tests = [(p, r, posixpath, e) for p, r, e in common]
- tests = [(p, r, ntpath, e) for p, r, e in common]
- tests.extend(
- (p, r, ntpath, e)
- for p, r, e in [
- ("spam.py", r"\eggs", "./spam.py"),
- # absolute
- (r"\spam.py", "\\", r"./spam.py"),
- (r"C:\spam.py", "C:\\", r"./spam.py"),
- (r"\eggs\spam.py", r"\eggs", r"./spam.py"),
- (r"\eggs\spam.py", "\\eggs\\", r"./spam.py"),
- # normcase
- (r"C:\spam.py", "c:\\", r"./spam.py"),
- (r"\Eggs\Spam.py", "\\eggs", r"./Spam.py"),
- (r"\eggs\spam.py", "\\Eggs", r"./spam.py"),
- (r"\eggs\Spam.py", "\\Eggs", r"./Spam.py"),
- # no-op
- (r"\spam.py", r"\eggs", r"/spam.py"),
- (r"C:\spam.py", r"C:\eggs", r"C:/spam.py"),
- # TODO: Should these be supported.
- (r"C:\spam.py", "\\", r"C:/spam.py"),
- (r"\spam.py", "C:\\", r"/spam.py"),
- # root-only
- ("\\", "\\", "/"),
- ("\\\\", "\\", "//"),
- ("C:\\", "C:\\eggs", "C:/"),
- ("C:\\", "C:\\", "C:/"),
- (r"C:\spam.py", "D:\\", r"C:/spam.py"),
- ]
- )
- for fileid, rootdir, _os_path, expected in tests:
- pathsep = _os_path.sep
- with self.subTest(
- r"for {} (with rootdir {!r}): {!r}".format(pathsep, rootdir, fileid)
- ):
- fixed = fix_fileid(
- fileid,
- rootdir,
- _path_isabs=_os_path.isabs,
- _normcase=_os_path.normcase,
- _pathsep=pathsep,
- )
- self.assertEqual(fixed, expected)
-
-
-class ShlexUnsplitTests(unittest.TestCase):
- def test_no_args(self):
- argv = []
- joined = shlex_unsplit(argv)
-
- self.assertEqual(joined, "")
- self.assertEqual(shlex.split(joined), argv)
-
- def test_one_arg(self):
- argv = ["spam"]
- joined = shlex_unsplit(argv)
-
- self.assertEqual(joined, "spam")
- self.assertEqual(shlex.split(joined), argv)
-
- def test_multiple_args(self):
- argv = [
- "-x",
- "X",
- "-xyz",
- "spam",
- "eggs",
- ]
- joined = shlex_unsplit(argv)
-
- self.assertEqual(joined, "-x X -xyz spam eggs")
- self.assertEqual(shlex.split(joined), argv)
-
- def test_whitespace(self):
- argv = [
- "-x",
- "X Y Z",
- "spam spam\tspam",
- "eggs",
- ]
- joined = shlex_unsplit(argv)
-
- self.assertEqual(joined, "-x 'X Y Z' 'spam spam\tspam' eggs")
- self.assertEqual(shlex.split(joined), argv)
-
- def test_quotation_marks(self):
- argv = [
- "-x",
- "''",
- 'spam"spam"spam',
- "ham'ham'ham",
- "eggs",
- ]
- joined = shlex_unsplit(argv)
-
- self.assertEqual(
- joined,
- "-x ''\"'\"''\"'\"'' 'spam\"spam\"spam' 'ham'\"'\"'ham'\"'\"'ham' eggs",
- )
- self.assertEqual(shlex.split(joined), argv)
diff --git a/pythonFiles/tests/util.py b/pythonFiles/tests/util.py
deleted file mode 100644
index 45c3536145cf..000000000000
--- a/pythonFiles/tests/util.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-
-class Stub(object):
- def __init__(self):
- self.calls = []
-
- def add_call(self, name, args=None, kwargs=None):
- self.calls.append((name, args, kwargs))
-
-
-class StubProxy(object):
- def __init__(self, stub=None, name=None):
- self.name = name
- self.stub = stub if stub is not None else Stub()
-
- @property
- def calls(self):
- return self.stub.calls
-
- def add_call(self, funcname, *args, **kwargs):
- callname = funcname
- if self.name:
- callname = "{}.{}".format(self.name, funcname)
- return self.stub.add_call(callname, *args, **kwargs)
diff --git a/pythonFiles/visualstudio_py_testlauncher.py b/pythonFiles/visualstudio_py_testlauncher.py
deleted file mode 100644
index 3a43c1e1be34..000000000000
--- a/pythonFiles/visualstudio_py_testlauncher.py
+++ /dev/null
@@ -1,392 +0,0 @@
-# Python Tools for Visual Studio
-# Copyright(c) Microsoft Corporation
-# 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
-#
-# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
-# OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
-# IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
-# MERCHANTABLITY OR NON-INFRINGEMENT.
-#
-# See the Apache Version 2.0 License for specific language governing
-# permissions and limitations under the License.
-
-__author__ = "Microsoft Corporation "
-__version__ = "3.0.0.0"
-
-import os
-import sys
-import json
-import unittest
-import socket
-import traceback
-from types import CodeType, FunctionType
-import signal
-
-try:
- import thread
-except:
- import _thread as thread
-
-
-class _TestOutput(object):
- """file like object which redirects output to the repl window."""
-
- errors = "strict"
-
- def __init__(self, old_out, is_stdout):
- self.is_stdout = is_stdout
- self.old_out = old_out
- if sys.version >= "3." and hasattr(old_out, "buffer"):
- self.buffer = _TestOutputBuffer(old_out.buffer, is_stdout)
-
- def flush(self):
- if self.old_out:
- self.old_out.flush()
-
- def writelines(self, lines):
- for line in lines:
- self.write(line)
-
- @property
- def encoding(self):
- return "utf8"
-
- def write(self, value):
- _channel.send_event("stdout" if self.is_stdout else "stderr", content=value)
- if self.old_out:
- self.old_out.write(value)
- # flush immediately, else things go wonky and out of order
- self.flush()
-
- def isatty(self):
- return True
-
- def next(self):
- pass
-
- @property
- def name(self):
- if self.is_stdout:
- return ""
- else:
- return ""
-
- def __getattr__(self, name):
- return getattr(self.old_out, name)
-
-
-class _TestOutputBuffer(object):
- def __init__(self, old_buffer, is_stdout):
- self.buffer = old_buffer
- self.is_stdout = is_stdout
-
- def write(self, data):
- _channel.send_event("stdout" if self.is_stdout else "stderr", content=data)
- self.buffer.write(data)
-
- def flush(self):
- self.buffer.flush()
-
- def truncate(self, pos=None):
- return self.buffer.truncate(pos)
-
- def tell(self):
- return self.buffer.tell()
-
- def seek(self, pos, whence=0):
- return self.buffer.seek(pos, whence)
-
-
-class _IpcChannel(object):
- def __init__(self, socket, callback):
- self.socket = socket
- self.seq = 0
- self.callback = callback
- self.lock = thread.allocate_lock()
- self._closed = False
- # start the testing reader thread loop
- self.test_thread_id = thread.start_new_thread(self.readSocket, ())
-
- def close(self):
- self._closed = True
-
- def readSocket(self):
- try:
- data = self.socket.recv(1024)
- self.callback()
- except OSError:
- if not self._closed:
- raise
-
- def receive(self):
- pass
-
- def send_event(self, name, **args):
- with self.lock:
- body = {"type": "event", "seq": self.seq, "event": name, "body": args}
- self.seq += 1
- content = json.dumps(body).encode("utf8")
- headers = ("Content-Length: %d\n\n" % (len(content),)).encode("utf8")
- self.socket.send(headers)
- self.socket.send(content)
-
-
-_channel = None
-
-
-class VsTestResult(unittest.TextTestResult):
- def startTest(self, test):
- super(VsTestResult, self).startTest(test)
- if _channel is not None:
- _channel.send_event(name="start", test=test.id())
-
- def addError(self, test, err):
- super(VsTestResult, self).addError(test, err)
- self.sendResult(test, "error", err)
-
- def addFailure(self, test, err):
- super(VsTestResult, self).addFailure(test, err)
- self.sendResult(test, "failed", err)
-
- def addSuccess(self, test):
- super(VsTestResult, self).addSuccess(test)
- self.sendResult(test, "passed")
-
- def addSkip(self, test, reason):
- super(VsTestResult, self).addSkip(test, reason)
- self.sendResult(test, "skipped")
-
- def addExpectedFailure(self, test, err):
- super(VsTestResult, self).addExpectedFailure(test, err)
- self.sendResult(test, "failed", err)
-
- def addUnexpectedSuccess(self, test):
- super(VsTestResult, self).addUnexpectedSuccess(test)
- self.sendResult(test, "passed")
-
- def sendResult(self, test, outcome, trace=None):
- if _channel is not None:
- tb = None
- message = None
- if trace is not None:
- traceback.print_exc()
- formatted = traceback.format_exception(*trace)
- # Remove the 'Traceback (most recent call last)'
- formatted = formatted[1:]
- tb = "".join(formatted)
- message = str(trace[1])
- _channel.send_event(
- name="result",
- outcome=outcome,
- traceback=tb,
- message=message,
- test=test.id(),
- )
-
-
-def stopTests():
- try:
- os.kill(os.getpid(), signal.SIGUSR1)
- except:
- try:
- os.kill(os.getpid(), signal.SIGTERM)
- except:
- pass
-
-
-class ExitCommand(Exception):
- pass
-
-
-def signal_handler(signal, frame):
- raise ExitCommand()
-
-
-def main():
- import os
- import sys
- import unittest
- from optparse import OptionParser
-
- global _channel
-
- parser = OptionParser(
- prog="visualstudio_py_testlauncher",
- usage="Usage: %prog [] ... ",
- )
- parser.add_option(
- "--debug", action="store_true", help="Whether debugging the unit tests"
- )
- parser.add_option(
- "-x",
- "--mixed-mode",
- action="store_true",
- help="wait for mixed-mode debugger to attach",
- )
- parser.add_option(
- "-t",
- "--test",
- type="str",
- dest="tests",
- action="append",
- help="specifies a test to run",
- )
- parser.add_option(
- "--testFile", type="str", help="Fully qualitified path to file name"
- )
- parser.add_option(
- "-c", "--coverage", type="str", help="enable code coverage and specify filename"
- )
- parser.add_option(
- "-r",
- "--result-port",
- type="int",
- help="connect to port on localhost and send test results",
- )
- parser.add_option("--us", type="str", help="Directory to start discovery")
- parser.add_option(
- "--up", type="str", help="Pattern to match test files (" "test*.py" " default)"
- )
- parser.add_option(
- "--ut",
- type="str",
- help="Top level directory of project (default to start directory)",
- )
- parser.add_option(
- "--uvInt",
- "--verboseInt",
- type="int",
- help="Verbose output (0 none, 1 (no -v) simple, 2 (-v) full)",
- )
- parser.add_option("--uf", "--failfast", type="str", help="Stop on first failure")
- parser.add_option(
- "--uc", "--catch", type="str", help="Catch control-C and display results"
- )
- (opts, _) = parser.parse_args()
-
- sys.path[0] = os.getcwd()
- if opts.result_port:
- try:
- signal.signal(signal.SIGUSR1, signal_handler)
- except:
- try:
- signal.signal(signal.SIGTERM, signal_handler)
- except:
- pass
- _channel = _IpcChannel(
- socket.create_connection(("127.0.0.1", opts.result_port)), stopTests
- )
- sys.stdout = _TestOutput(sys.stdout, is_stdout=True)
- sys.stderr = _TestOutput(sys.stderr, is_stdout=False)
-
- if opts.mixed_mode:
- # For mixed-mode attach, there's no ptvsd and hence no wait_for_attach(),
- # so we have to use Win32 API in a loop to do the same thing.
- from time import sleep
- from ctypes import windll, c_char
-
- while True:
- if windll.kernel32.IsDebuggerPresent() != 0:
- break
- sleep(0.1)
- try:
- debugger_helper = windll["Microsoft.PythonTools.Debugger.Helper.x86.dll"]
- except WindowsError:
- debugger_helper = windll["Microsoft.PythonTools.Debugger.Helper.x64.dll"]
- isTracing = c_char.in_dll(debugger_helper, "isTracing")
- while True:
- if isTracing.value != 0:
- break
- sleep(0.1)
-
- cov = None
- try:
- if opts.coverage:
- try:
- import coverage
-
- cov = coverage.coverage(opts.coverage)
- cov.load()
- cov.start()
- except:
- pass
- if opts.tests is None and opts.testFile is None:
- if opts.us is None:
- opts.us = "."
- if opts.up is None:
- opts.up = "test*.py"
- tests = unittest.defaultTestLoader.discover(opts.us, opts.up)
- else:
- # loadTestsFromNames doesn't work well (with duplicate file names or class names)
- # Easier approach is find the test suite and use that for running
- loader = unittest.TestLoader()
- # opts.us will be passed in
- suites = loader.discover(opts.us, pattern=os.path.basename(opts.testFile))
- suite = None
- tests = None
- if opts.tests is None:
- # Run everything in the test file
- tests = suites
- else:
- # Run a specific test class or test method
- for test_suite in suites._tests:
- for cls in test_suite._tests:
- try:
- for m in cls._tests:
- testId = m.id()
- if testId.startswith(opts.tests[0]):
- suite = cls
- if testId == opts.tests[0]:
- tests = unittest.TestSuite([m])
- break
- except Exception as err:
- errorMessage = traceback.format_exc()
- if tests is None:
- tests = suite
- if tests is None and suite is None:
- _channel.send_event(
- name="error",
- outcome="",
- traceback="",
- message="Failed to identify the test",
- test="",
- )
- if opts.uvInt is None:
- opts.uvInt = 0
- if opts.uf is not None:
- runner = unittest.TextTestRunner(
- verbosity=opts.uvInt, resultclass=VsTestResult, failfast=True
- )
- else:
- runner = unittest.TextTestRunner(
- verbosity=opts.uvInt, resultclass=VsTestResult
- )
- result = runner.run(tests)
- if _channel is not None:
- _channel.close()
- sys.exit(not result.wasSuccessful())
- finally:
- if cov is not None:
- cov.stop()
- cov.save()
- cov.xml_report(outfile=opts.coverage + ".xml", omit=__file__)
- if _channel is not None:
- _channel.send_event(name="done")
- _channel.socket.close()
- # prevent generation of the error 'Error in sys.exitfunc:'
- try:
- sys.stdout.close()
- except:
- pass
- try:
- sys.stderr.close()
- except:
- pass
-
-
-if __name__ == "__main__":
- main()
diff --git a/pythonFiles/vscode_datascience_helpers/tests/logParser.py b/pythonFiles/vscode_datascience_helpers/tests/logParser.py
deleted file mode 100644
index 767f837c5136..000000000000
--- a/pythonFiles/vscode_datascience_helpers/tests/logParser.py
+++ /dev/null
@@ -1,96 +0,0 @@
-from io import TextIOWrapper
-import sys
-import argparse
-import os
-
-os.system("color")
-from pathlib import Path
-import re
-
-parser = argparse.ArgumentParser(description="Parse a test log into its parts")
-parser.add_argument("testlog", type=str, nargs=1, help="Log to parse")
-parser.add_argument(
- "--testoutput", action="store_true", help="Show all failures and passes"
-)
-parser.add_argument(
- "--split",
- action="store_true",
- help="Split into per process files. Each file will have the pid appended",
-)
-ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
-pid_regex = re.compile(r"(\d+).*")
-timestamp_regex = re.compile(r"\d{4}-\d{2}-\d{2}T.*\dZ")
-
-
-def stripTimestamp(line: str):
- match = timestamp_regex.match(line)
- if match:
- return line[match.end() :]
- return line
-
-
-def readStripLines(f: TextIOWrapper):
- return map(stripTimestamp, f.readlines())
-
-
-def printTestOutput(testlog):
- # Find all the lines that don't have a PID in them. These are the test output
- p = Path(testlog[0])
- with p.open() as f:
- for line in readStripLines(f):
- stripped = line.strip()
- if len(stripped) > 2 and stripped[0] == "\x1B" and stripped[1] == "[":
- print(line.rstrip()) # Should be a test line as it has color encoding
-
-
-def splitByPid(testlog):
- # Split testlog into prefixed logs based on pid
- baseFile = os.path.splitext(testlog[0])[0]
- p = Path(testlog[0])
- pids = set()
- logs = {}
- pid = None
- with p.open() as f:
- for line in readStripLines(f):
- stripped = ansi_escape.sub("", line.strip())
- if len(stripped) > 0:
- # Pull out the pid
- match = pid_regex.match(stripped)
-
- # Pids are at least two digits
- if match and len(match.group(1)) > 2:
- # Pid is found
- pid = int(match.group(1))
-
- # See if we've created a log for this pid or not
- if not pid in pids:
- pids.add(pid)
- logFile = "{}_{}.log".format(baseFile, pid)
- print("Writing to new log: " + logFile)
- logs[pid] = Path(logFile).open(mode="w")
-
- # Add this line to the log
- if pid != None:
- logs[pid].write(line)
- # Close all of the open logs
- for key in logs:
- logs[key].close()
-
-
-def doWork(args):
- if not args.testlog:
- print("Test log should be passed")
- elif args.testoutput:
- printTestOutput(args.testlog)
- elif args.split:
- splitByPid(args.testlog)
- else:
- parser.print_usage()
-
-
-def main():
- doWork(parser.parse_args())
-
-
-if __name__ == "__main__":
- main()
diff --git a/pythonFiles/.env b/python_files/.env
similarity index 100%
rename from pythonFiles/.env
rename to python_files/.env
diff --git a/pythonFiles/.vscode/settings.json b/python_files/.vscode/settings.json
similarity index 100%
rename from pythonFiles/.vscode/settings.json
rename to python_files/.vscode/settings.json
diff --git a/pythonFiles/Notebooks intro.ipynb b/python_files/Notebooks intro.ipynb
similarity index 81%
rename from pythonFiles/Notebooks intro.ipynb
rename to python_files/Notebooks intro.ipynb
index 850d7f5a86f9..0e8aadad1919 100644
--- a/pythonFiles/Notebooks intro.ipynb
+++ b/python_files/Notebooks intro.ipynb
@@ -11,7 +11,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "1. Open the command palette with the shortcut: `Ctrl/Command` + `Shift` + `P`\r\n",
+ "1. Open the command palette with the shortcut: `Ctrl/Command` + `Shift` + `P`\n",
"2. Search for the command `Create New Blank Notebook`"
]
},
@@ -26,8 +26,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "1. Open the command palette with the shortcut: `Ctrl/Command` + `Shift` + `P`\r\n",
- "\r\n",
+ "1. Open the command palette with the shortcut: `Ctrl/Command` + `Shift` + `P`\n",
+ "\n",
"2. Search for the command `Python: Open Start Page`"
]
},
@@ -42,10 +42,10 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "You are currently viewing what we call our Notebook Editor. It is an interactive document based on Jupyter Notebooks that supports the intermixing of code, outputs and markdown documentation. \r\n",
- "\r\n",
- "This cell is a markdown cell. To edit the text in this cell, simply double click on the cell to change it into edit mode.\r\n",
- "\r\n",
+ "You are currently viewing what we call our Notebook Editor. It is an interactive document based on Jupyter Notebooks that supports the intermixing of code, outputs and markdown documentation. \n",
+ "\n",
+ "This cell is a markdown cell. To edit the text in this cell, simply double click on the cell to change it into edit mode.\n",
+ "\n",
"The next cell below is a code cell. You can switch a cell between code and markdown by clicking on the code  /markdown  icons or using the keyboard shortcut `M` and `Y` respectively."
]
},
@@ -55,16 +55,16 @@
"metadata": {},
"outputs": [],
"source": [
- "print('hello world')"
+ "print(\"hello world\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "* To execute the code in the cell above, click on the cell to select it and then either press the play  button in the cell toolbar, or use the keyboard shortcut `Ctrl/Command` + `Enter`.\r\n",
- "* To edit the code, just click in cell and start editing.\r\n",
- "* To add a new cell below, click the `Add Cell` icon  at the bottom left of the cell or enter command mode with the `ESC` Key and then use the keyboard shortcut `B` to create the new cell below.\r\n"
+ "* To execute the code in the cell above, click on the cell to select it and then either press the play  button in the cell toolbar, or use the keyboard shortcut `Ctrl/Command` + `Enter`.\n",
+ "* To edit the code, just click in cell and start editing.\n",
+ "* To add a new cell below, click the `Add Cell` icon  at the bottom left of the cell or enter command mode with the `ESC` Key and then use the keyboard shortcut `B` to create the new cell below.\n"
]
},
{
@@ -78,40 +78,40 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "**Variable explorer**\r\n",
- "\r\n",
- "To view all your active variables and their current values in the notebook, click on the variable explorer icon  in the top toolbar.\r\n",
- "\r\n",
- "\r\n",
- "\r\n",
- "**Data Viewer**\r\n",
- "\r\n",
- "To view your data frame in a more visual \"Excel\" like format, open the variable explorer and to the left of any dataframe object, you will see the data viewer icon  which you can click to open the data viewer.\r\n",
- "\r\n",
- "\r\n",
- "\r\n",
- "**Convert to Python File**\r\n",
- "\r\n",
- "To export your notebook to a Python file (.py), click on the `Convert to Python script` icon  in the top toolbar \r\n",
- "\r\n",
- "\r\n",
- "\r\n",
- "**Plot Viewer**\r\n",
- "\r\n",
- "If you have a graph (such as matplotlib) in your output, you'll notice if you hover over the graph, the `Plot Viewer` icon  will appear in the top left. Click the icon to open up the graph in the Plotviewer which allows you to zoom on your plots and export it in formats such as png and jpeg.\r\n",
- "\r\n",
- "\r\n",
- "\r\n",
- "**Switching Kernels**\r\n",
- "\r\n",
- "The notebook editor will detect all kernels in your system by default. To change your notebook kernel, click on the kernel status in the top toolbar at the far right. For example, your kernel status may say \"Python 3: Idle\". This will open up the kernel selector where you can choose your desired kernel.\r\n",
- "\r\n",
- "\r\n",
- "\r\n",
- "**Remote Jupyter Server**\r\n",
- "\r\n",
- "To connect to a remote Jupyter server, open the command prompt and search for the command `Specify remote or local Jupyter server for connections`. Then select `Existing` and enter the remote Jupyter server URL. Afterwards, you'll be prompted to reload the window and the Notebook will be opened connected to the remote Jupyter server.\r\n",
- "\r\n",
+ "**Variable explorer**\n",
+ "\n",
+ "To view all your active variables and their current values in the notebook, click on the variable explorer icon  in the top toolbar.\n",
+ "\n",
+ "\n",
+ "\n",
+ "**Data Viewer**\n",
+ "\n",
+ "To view your data frame in a more visual \"Excel\" like format, open the variable explorer and to the left of any dataframe object, you will see the data viewer icon  which you can click to open the data viewer.\n",
+ "\n",
+ "\n",
+ "\n",
+ "**Convert to Python File**\n",
+ "\n",
+ "To export your notebook to a Python file (.py), click on the `Convert to Python script` icon  in the top toolbar \n",
+ "\n",
+ "\n",
+ "\n",
+ "**Plot Viewer**\n",
+ "\n",
+ "If you have a graph (such as matplotlib) in your output, you'll notice if you hover over the graph, the `Plot Viewer` icon  will appear in the top left. Click the icon to open up the graph in the Plotviewer which allows you to zoom on your plots and export it in formats such as png and jpeg.\n",
+ "\n",
+ "\n",
+ "\n",
+ "**Switching Kernels**\n",
+ "\n",
+ "The notebook editor will detect all kernels in your system by default. To change your notebook kernel, click on the kernel status in the top toolbar at the far right. For example, your kernel status may say \"Python 3: Idle\". This will open up the kernel selector where you can choose your desired kernel.\n",
+ "\n",
+ "\n",
+ "\n",
+ "**Remote Jupyter Server**\n",
+ "\n",
+ "To connect to a remote Jupyter server, open the command prompt and search for the command `Specify remote or local Jupyter server for connections`. Then select `Existing` and enter the remote Jupyter server URL. Afterwards, you'll be prompted to reload the window and the Notebook will be opened connected to the remote Jupyter server.\n",
+ "\n",
""
]
},
@@ -129,7 +129,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "- [Data science tutorial for Visual Studio Code](https://code.visualstudio.com/docs/python/data-science-tutorial)\r\n",
+ "- [Data science tutorial for Visual Studio Code](https://code.visualstudio.com/docs/python/data-science-tutorial)\n",
"- [Jupyter Notebooks in Visual Studio Code documentation](https://code.visualstudio.com/docs/python/jupyter-support)"
]
}
@@ -145,9 +145,10 @@
"name": "python3"
},
"language_info": {
+ "name": "python",
"version": "3.8.6-final"
}
},
"nbformat": 4,
"nbformat_minor": 0
-}
\ No newline at end of file
+}
diff --git a/python_files/create_conda.py b/python_files/create_conda.py
new file mode 100644
index 000000000000..284f734081b2
--- /dev/null
+++ b/python_files/create_conda.py
@@ -0,0 +1,130 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+import argparse
+import os
+import pathlib
+import subprocess
+import sys
+from typing import Optional, Sequence, Union
+
+CONDA_ENV_NAME = ".conda"
+CWD = pathlib.Path.cwd()
+
+
+class VenvError(Exception):
+ pass
+
+
+def parse_args(argv: Sequence[str]) -> argparse.Namespace:
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--python",
+ action="store",
+ help="Python version to install in the virtual environment.",
+ default=f"{sys.version_info.major}.{sys.version_info.minor}",
+ )
+ parser.add_argument(
+ "--install",
+ action="store_true",
+ default=False,
+ help="Install packages into the virtual environment.",
+ )
+ parser.add_argument(
+ "--git-ignore",
+ action="store_true",
+ default=False,
+ help="Add .gitignore to the newly created virtual environment.",
+ )
+ parser.add_argument(
+ "--name",
+ default=CONDA_ENV_NAME,
+ type=str,
+ help="Name of the virtual environment.",
+ metavar="NAME",
+ action="store",
+ )
+ return parser.parse_args(argv)
+
+
+def file_exists(path: Union[str, pathlib.PurePath]) -> bool:
+ return os.path.exists(path) # noqa: PTH110
+
+
+def conda_env_exists(name: Union[str, pathlib.PurePath]) -> bool:
+ return os.path.exists(CWD / name) # noqa: PTH110
+
+
+def run_process(args: Sequence[str], error_message: str) -> None:
+ try:
+ print("Running: " + " ".join(args))
+ subprocess.run(args, cwd=os.getcwd(), check=True) # noqa: PTH109
+ except subprocess.CalledProcessError as exc:
+ raise VenvError(error_message) from exc
+
+
+def get_conda_env_path(name: str) -> str:
+ return os.fspath(CWD / name)
+
+
+def install_packages(env_path: str) -> None:
+ yml = os.fspath(CWD / "environment.yml")
+ if file_exists(yml):
+ print(f"CONDA_INSTALLING_YML: {yml}")
+ run_process(
+ [
+ sys.executable,
+ "-m",
+ "conda",
+ "env",
+ "update",
+ "--prefix",
+ env_path,
+ "--file",
+ yml,
+ ],
+ "CREATE_CONDA.FAILED_INSTALL_YML",
+ )
+ print("CREATE_CONDA.INSTALLED_YML")
+
+
+def add_gitignore(name: str) -> None:
+ git_ignore = CWD / name / ".gitignore"
+ if not git_ignore.is_file():
+ print(f"Creating: {os.fsdecode(git_ignore)}")
+ git_ignore.write_text("*")
+
+
+def main(argv: Optional[Sequence[str]] = None) -> None:
+ if argv is None:
+ argv = []
+ args = parse_args(argv)
+
+ if conda_env_exists(args.name):
+ env_path = get_conda_env_path(args.name)
+ print(f"EXISTING_CONDA_ENV:{env_path}")
+ else:
+ run_process(
+ [
+ sys.executable,
+ "-m",
+ "conda",
+ "create",
+ "--yes",
+ "--prefix",
+ args.name,
+ f"python={args.python}",
+ ],
+ "CREATE_CONDA.ENV_FAILED_CREATION",
+ )
+ env_path = get_conda_env_path(args.name)
+ print(f"CREATED_CONDA_ENV:{env_path}")
+ if args.git_ignore:
+ add_gitignore(args.name)
+
+ if args.install:
+ install_packages(env_path)
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/python_files/create_microvenv.py b/python_files/create_microvenv.py
new file mode 100644
index 000000000000..2f2135444bc1
--- /dev/null
+++ b/python_files/create_microvenv.py
@@ -0,0 +1,60 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+import argparse
+import os
+import pathlib
+import subprocess
+import sys
+from typing import Optional, Sequence
+
+VENV_NAME = ".venv"
+LIB_ROOT = pathlib.Path(__file__).parent / "lib" / "python"
+CWD = pathlib.Path.cwd()
+
+
+class MicroVenvError(Exception):
+ pass
+
+
+def run_process(args: Sequence[str], error_message: str) -> None:
+ try:
+ print("Running: " + " ".join(args))
+ subprocess.run(args, cwd=os.getcwd(), check=True) # noqa: PTH109
+ except subprocess.CalledProcessError as exc:
+ raise MicroVenvError(error_message) from exc
+
+
+def parse_args(argv: Sequence[str]) -> argparse.Namespace:
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument(
+ "--name",
+ default=VENV_NAME,
+ type=str,
+ help="Name of the virtual environment.",
+ metavar="NAME",
+ action="store",
+ )
+ return parser.parse_args(argv)
+
+
+def create_microvenv(name: str):
+ run_process(
+ [sys.executable, os.fspath(LIB_ROOT / "microvenv.py"), name],
+ "CREATE_MICROVENV.MICROVENV_FAILED_CREATION",
+ )
+
+
+def main(argv: Optional[Sequence[str]] = None) -> None:
+ if argv is None:
+ argv = []
+ args = parse_args(argv)
+
+ print("CREATE_MICROVENV.CREATING_MICROVENV")
+ create_microvenv(args.name)
+ print("CREATE_MICROVENV.CREATED_MICROVENV")
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/python_files/create_venv.py b/python_files/create_venv.py
new file mode 100644
index 000000000000..83106bd889f8
--- /dev/null
+++ b/python_files/create_venv.py
@@ -0,0 +1,271 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+import argparse
+import importlib.util as import_util
+import json
+import os
+import pathlib
+import subprocess
+import sys
+import urllib.request as url_lib
+from typing import List, Optional, Sequence, Union
+
+VENV_NAME = ".venv"
+CWD = pathlib.Path.cwd()
+MICROVENV_SCRIPT_PATH = pathlib.Path(__file__).parent / "create_microvenv.py"
+
+
+class VenvError(Exception):
+ pass
+
+
+def parse_args(argv: Sequence[str]) -> argparse.Namespace:
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument(
+ "--requirements",
+ action="append",
+ default=[],
+ help="Install additional dependencies into the virtual environment.",
+ )
+
+ parser.add_argument(
+ "--toml",
+ action="store",
+ default=None,
+ help="Install additional dependencies from sources like `pyproject.toml` into the virtual environment.",
+ )
+
+ parser.add_argument(
+ "--extras",
+ action="append",
+ default=[],
+ help="Install specific package groups from `pyproject.toml` into the virtual environment.",
+ )
+
+ parser.add_argument(
+ "--git-ignore",
+ action="store_true",
+ default=False,
+ help="Add .gitignore to the newly created virtual environment.",
+ )
+
+ parser.add_argument(
+ "--name",
+ default=VENV_NAME,
+ type=str,
+ help="Name of the virtual environment.",
+ metavar="NAME",
+ action="store",
+ )
+
+ parser.add_argument(
+ "--stdin",
+ action="store_true",
+ default=False,
+ help="Read arguments from stdin.",
+ )
+
+ return parser.parse_args(argv)
+
+
+def is_installed(module: str) -> bool:
+ return import_util.find_spec(module) is not None
+
+
+def file_exists(path: Union[str, pathlib.PurePath]) -> bool:
+ return pathlib.Path(path).exists()
+
+
+def is_file(path: Union[str, pathlib.PurePath]) -> bool:
+ return pathlib.Path(path).is_file()
+
+
+def venv_exists(name: str) -> bool:
+ return (
+ (CWD / name).exists()
+ and (CWD / name / "pyvenv.cfg").exists()
+ and file_exists(get_venv_path(name))
+ )
+
+
+def run_process(args: Sequence[str], error_message: str) -> None:
+ try:
+ print("Running: " + " ".join(args))
+ subprocess.run(args, cwd=os.getcwd(), check=True) # noqa: PTH109
+ except subprocess.CalledProcessError as exc:
+ raise VenvError(error_message) from exc
+
+
+def get_win_venv_path(name: str) -> str:
+ venv_dir = CWD / name
+ # If using MSYS2 Python, the Python executable is located in the 'bin' directory.
+ if file_exists(venv_dir / "bin" / "python.exe"):
+ return os.fspath(venv_dir / "bin" / "python.exe")
+ else:
+ return os.fspath(venv_dir / "Scripts" / "python.exe")
+
+
+def get_venv_path(name: str) -> str:
+ # See `venv` doc here for more details on binary location:
+ # https://docs.python.org/3/library/venv.html#creating-virtual-environments
+ if sys.platform == "win32":
+ return get_win_venv_path(name)
+ else:
+ return os.fspath(CWD / name / "bin" / "python")
+
+
+def install_requirements(venv_path: str, requirements: List[str]) -> None:
+ if not requirements:
+ return
+
+ for requirement in requirements:
+ print(f"VENV_INSTALLING_REQUIREMENTS: {requirement}")
+ run_process(
+ [venv_path, "-m", "pip", "install", "-r", requirement],
+ "CREATE_VENV.PIP_FAILED_INSTALL_REQUIREMENTS",
+ )
+ print("CREATE_VENV.PIP_INSTALLED_REQUIREMENTS")
+
+
+def install_toml(venv_path: str, extras: List[str]) -> None:
+ args = "." if len(extras) == 0 else f".[{','.join(extras)}]"
+ run_process(
+ [venv_path, "-m", "pip", "install", "-e", args],
+ "CREATE_VENV.PIP_FAILED_INSTALL_PYPROJECT",
+ )
+ print("CREATE_VENV.PIP_INSTALLED_PYPROJECT")
+
+
+def upgrade_pip(venv_path: str) -> None:
+ print("CREATE_VENV.UPGRADING_PIP")
+ run_process(
+ [venv_path, "-m", "pip", "install", "--upgrade", "pip"],
+ "CREATE_VENV.UPGRADE_PIP_FAILED",
+ )
+ print("CREATE_VENV.UPGRADED_PIP")
+
+
+def create_gitignore(git_ignore: Union[str, pathlib.PurePath]):
+ print("Creating:", os.fspath(git_ignore))
+ pathlib.Path(git_ignore).write_text("*")
+
+
+def add_gitignore(name: str) -> None:
+ git_ignore = CWD / name / ".gitignore"
+ if not is_file(git_ignore):
+ create_gitignore(git_ignore)
+
+
+def download_pip_pyz(name: str):
+ url = "https://bootstrap.pypa.io/pip/pip.pyz"
+ print("CREATE_VENV.DOWNLOADING_PIP")
+
+ try:
+ with url_lib.urlopen(url) as response:
+ pip_pyz_path = CWD / name / "pip.pyz"
+ pip_pyz_path.write_bytes(data=response.read())
+ except Exception as exc:
+ raise VenvError("CREATE_VENV.DOWNLOAD_PIP_FAILED") from exc
+
+
+def install_pip(name: str):
+ pip_pyz_path = os.fspath(CWD / name / "pip.pyz")
+ executable = get_venv_path(name)
+ print("CREATE_VENV.INSTALLING_PIP")
+ run_process(
+ [executable, pip_pyz_path, "install", "pip"],
+ "CREATE_VENV.INSTALL_PIP_FAILED",
+ )
+
+
+def get_requirements_from_args(args: argparse.Namespace) -> List[str]:
+ requirements = []
+ if args.stdin:
+ data = json.loads(sys.stdin.read())
+ requirements = data.get("requirements", [])
+ if args.requirements:
+ requirements.extend(args.requirements)
+ return requirements
+
+
+def main(argv: Optional[Sequence[str]] = None) -> None:
+ if argv is None:
+ argv = []
+ args = parse_args(argv)
+
+ use_micro_venv = False
+ venv_installed = is_installed("venv")
+ pip_installed = is_installed("pip")
+ ensure_pip_installed = is_installed("ensurepip")
+ distutils_installed = is_installed("distutils")
+
+ if not venv_installed:
+ if sys.platform == "win32":
+ raise VenvError("CREATE_VENV.VENV_NOT_FOUND")
+ else:
+ use_micro_venv = True
+ if not distutils_installed:
+ print("Install `python3-distutils` package or equivalent for your OS.")
+ print("On Debian/Ubuntu: `sudo apt install python3-distutils`")
+ raise VenvError("CREATE_VENV.DISTUTILS_NOT_INSTALLED")
+
+ if venv_exists(args.name):
+ # A virtual environment with same name exists.
+ # We will use the existing virtual environment.
+ venv_path = get_venv_path(args.name)
+ print(f"EXISTING_VENV:{venv_path}")
+ else:
+ if use_micro_venv:
+ # `venv` was not found but on this platform we can use `microvenv`
+ run_process(
+ [
+ sys.executable,
+ os.fspath(MICROVENV_SCRIPT_PATH),
+ "--name",
+ args.name,
+ ],
+ "CREATE_VENV.MICROVENV_FAILED_CREATION",
+ )
+ elif not pip_installed or not ensure_pip_installed:
+ # `venv` was found but `pip` or `ensurepip` was not found.
+ # We create a venv without `pip` in it. We will later install `pip`.
+ run_process(
+ [sys.executable, "-m", "venv", "--without-pip", args.name],
+ "CREATE_VENV.VENV_FAILED_CREATION",
+ )
+ else:
+ # Both `venv` and `pip` were found. So create a .venv normally
+ run_process(
+ [sys.executable, "-m", "venv", args.name],
+ "CREATE_VENV.VENV_FAILED_CREATION",
+ )
+
+ venv_path = get_venv_path(args.name)
+ print(f"CREATED_VENV:{venv_path}")
+
+ if args.git_ignore:
+ add_gitignore(args.name)
+
+ # At this point we have a .venv. Now we handle installing `pip`.
+ if pip_installed and ensure_pip_installed:
+ # We upgrade pip if it is already installed.
+ upgrade_pip(venv_path)
+ else:
+ # `pip` was not found, so we download it and install it.
+ download_pip_pyz(args.name)
+ install_pip(args.name)
+
+ requirements = get_requirements_from_args(args)
+ if requirements:
+ print(f"VENV_INSTALLING_REQUIREMENTS: {requirements}")
+ install_requirements(venv_path, requirements)
+
+ if args.toml:
+ print(f"VENV_INSTALLING_PYPROJECT: {args.toml}")
+ install_toml(venv_path, args.extras)
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/python_files/deactivate/bash/deactivate b/python_files/deactivate/bash/deactivate
new file mode 100755
index 000000000000..f6dd33425d1a
--- /dev/null
+++ b/python_files/deactivate/bash/deactivate
@@ -0,0 +1,44 @@
+# Same as deactivate in "/bin/activate"
+deactivate () {
+ if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
+ PATH="${_OLD_VIRTUAL_PATH:-}"
+ export PATH
+ unset _OLD_VIRTUAL_PATH
+ fi
+ if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
+ PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
+ export PYTHONHOME
+ unset _OLD_VIRTUAL_PYTHONHOME
+ fi
+ if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
+ hash -r 2> /dev/null
+ fi
+ if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
+ PS1="${_OLD_VIRTUAL_PS1:-}"
+ export PS1
+ unset _OLD_VIRTUAL_PS1
+ fi
+ unset VIRTUAL_ENV
+ unset VIRTUAL_ENV_PROMPT
+ if [ ! "${1:-}" = "nondestructive" ] ; then
+ unset -f deactivate
+ fi
+}
+
+# Get the directory of the current script
+SCRIPT_DIR=$(dirname "$0")
+# Construct the path to envVars.txt relative to the script directory
+ENV_FILE="$SCRIPT_DIR/envVars.txt"
+
+# Read the JSON file and set the variables
+TEMP_PS1=$(grep '^PS1=' $ENV_FILE | cut -d '=' -f 2)
+TEMP_PATH=$(grep '^PATH=' $ENV_FILE | cut -d '=' -f 2)
+TEMP_PYTHONHOME=$(grep '^PYTHONHOME=' $ENV_FILE | cut -d '=' -f 2)
+# Initialize the variables required by deactivate function
+_OLD_VIRTUAL_PS1="${TEMP_PS1:-}"
+_OLD_VIRTUAL_PATH="$TEMP_PATH"
+if [ -n "${PYTHONHOME:-}" ] ; then
+ _OLD_VIRTUAL_PYTHONHOME="${TEMP_PYTHONHOME:-}"
+fi
+deactivate
+bash
diff --git a/python_files/deactivate/fish/deactivate b/python_files/deactivate/fish/deactivate
new file mode 100755
index 000000000000..3a9d50ccde2b
--- /dev/null
+++ b/python_files/deactivate/fish/deactivate
@@ -0,0 +1,44 @@
+# Same as deactivate in "/bin/activate"
+deactivate () {
+ if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
+ PATH="${_OLD_VIRTUAL_PATH:-}"
+ export PATH
+ unset _OLD_VIRTUAL_PATH
+ fi
+ if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
+ PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
+ export PYTHONHOME
+ unset _OLD_VIRTUAL_PYTHONHOME
+ fi
+ if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
+ hash -r 2> /dev/null
+ fi
+ if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
+ PS1="${_OLD_VIRTUAL_PS1:-}"
+ export PS1
+ unset _OLD_VIRTUAL_PS1
+ fi
+ unset VIRTUAL_ENV
+ unset VIRTUAL_ENV_PROMPT
+ if [ ! "${1:-}" = "nondestructive" ] ; then
+ unset -f deactivate
+ fi
+}
+
+# Get the directory of the current script
+SCRIPT_DIR=$(dirname "$0")
+# Construct the path to envVars.txt relative to the script directory
+ENV_FILE="$SCRIPT_DIR/envVars.txt"
+
+# Read the JSON file and set the variables
+TEMP_PS1=$(grep '^PS1=' $ENV_FILE | cut -d '=' -f 2)
+TEMP_PATH=$(grep '^PATH=' $ENV_FILE | cut -d '=' -f 2)
+TEMP_PYTHONHOME=$(grep '^PYTHONHOME=' $ENV_FILE | cut -d '=' -f 2)
+# Initialize the variables required by deactivate function
+_OLD_VIRTUAL_PS1="${TEMP_PS1:-}"
+_OLD_VIRTUAL_PATH="$TEMP_PATH"
+if [ -n "${PYTHONHOME:-}" ] ; then
+ _OLD_VIRTUAL_PYTHONHOME="${TEMP_PYTHONHOME:-}"
+fi
+deactivate
+fish
diff --git a/python_files/deactivate/powershell/deactivate.ps1 b/python_files/deactivate/powershell/deactivate.ps1
new file mode 100644
index 000000000000..49365e0fbeff
--- /dev/null
+++ b/python_files/deactivate/powershell/deactivate.ps1
@@ -0,0 +1,11 @@
+# Load dotenv-style file and restore environment variables
+Get-Content -Path "$PSScriptRoot\envVars.txt" | ForEach-Object {
+ # Split each line into key and value at the first '='
+ $parts = $_ -split '=', 2
+ if ($parts.Count -eq 2) {
+ $key = $parts[0].Trim()
+ $value = $parts[1].Trim()
+ # Set the environment variable
+ Set-Item -Path "env:$key" -Value $value
+ }
+}
diff --git a/python_files/deactivate/zsh/deactivate b/python_files/deactivate/zsh/deactivate
new file mode 100755
index 000000000000..8b059318f988
--- /dev/null
+++ b/python_files/deactivate/zsh/deactivate
@@ -0,0 +1,44 @@
+# Same as deactivate in "/bin/activate"
+deactivate () {
+ if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
+ PATH="${_OLD_VIRTUAL_PATH:-}"
+ export PATH
+ unset _OLD_VIRTUAL_PATH
+ fi
+ if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
+ PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
+ export PYTHONHOME
+ unset _OLD_VIRTUAL_PYTHONHOME
+ fi
+ if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
+ hash -r 2> /dev/null
+ fi
+ if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
+ PS1="${_OLD_VIRTUAL_PS1:-}"
+ export PS1
+ unset _OLD_VIRTUAL_PS1
+ fi
+ unset VIRTUAL_ENV
+ unset VIRTUAL_ENV_PROMPT
+ if [ ! "${1:-}" = "nondestructive" ] ; then
+ unset -f deactivate
+ fi
+}
+
+# Get the directory of the current script
+SCRIPT_DIR=$(dirname "$0")
+# Construct the path to envVars.txt relative to the script directory
+ENV_FILE="$SCRIPT_DIR/envVars.txt"
+
+# Read the JSON file and set the variables
+TEMP_PS1=$(grep '^PS1=' $ENV_FILE | cut -d '=' -f 2)
+TEMP_PATH=$(grep '^PATH=' $ENV_FILE | cut -d '=' -f 2)
+TEMP_PYTHONHOME=$(grep '^PYTHONHOME=' $ENV_FILE | cut -d '=' -f 2)
+# Initialize the variables required by deactivate function
+_OLD_VIRTUAL_PS1="${TEMP_PS1:-}"
+_OLD_VIRTUAL_PATH="$TEMP_PATH"
+if [ -n "${PYTHONHOME:-}" ] ; then
+ _OLD_VIRTUAL_PYTHONHOME="${TEMP_PYTHONHOME:-}"
+fi
+deactivate
+zsh
diff --git a/python_files/download_get_pip.py b/python_files/download_get_pip.py
new file mode 100644
index 000000000000..012284e7a354
--- /dev/null
+++ b/python_files/download_get_pip.py
@@ -0,0 +1,75 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+# This file is now a standalone Python script that
+# updates the vendored get-pip.py and cgmanifest.json
+# to the latest pip release.
+
+import argparse
+import json
+import pathlib
+import urllib.request
+from typing import Optional
+
+EXTENSION_ROOT = pathlib.Path(__file__).parent.parent
+GET_PIP_DEST = EXTENSION_ROOT / "python_files" / "get-pip.py"
+CGMANIFEST_PATH = EXTENSION_ROOT / "cgmanifest.json"
+PIP_METADATA_URL = "https://pypi.org/pypi/pip/json"
+GET_PIP_URL = "https://raw.githubusercontent.com/pypa/get-pip/{version}/public/get-pip.py"
+
+
+def _get_latest_version() -> str:
+ with urllib.request.urlopen(PIP_METADATA_URL) as response:
+ metadata = json.load(response)
+
+ version = metadata.get("info", {}).get("version")
+ if not isinstance(version, str) or not version:
+ raise ValueError(f"PyPI metadata from {PIP_METADATA_URL} did not contain a version")
+ return version
+
+
+def _download_get_pip(version: str) -> bytes:
+ url = GET_PIP_URL.format(version=version)
+ print(f"Downloading {url}")
+ with urllib.request.urlopen(url) as response:
+ get_pip = response.read()
+
+ expected_version = f"pip (version {version})".encode()
+ if expected_version not in get_pip[:1024]:
+ raise ValueError(f"Downloaded get-pip.py did not contain pip {version}")
+ return get_pip
+
+
+def _update_cgmanifest(version: str) -> str:
+ manifest = json.loads(CGMANIFEST_PATH.read_text(encoding="utf-8"))
+ for registration in manifest["Registrations"]:
+ component = registration.get("Component", {}).get("Other", {})
+ if component.get("Name") == "get-pip":
+ component["Version"] = version
+ return f"{json.dumps(manifest, indent=4)}\n"
+
+ raise ValueError(f"get-pip registration was not found in {CGMANIFEST_PATH}")
+
+
+def refresh_get_pip(version: Optional[str] = None) -> None:
+ version = version or _get_latest_version()
+ get_pip = _download_get_pip(version)
+ cgmanifest = _update_cgmanifest(version)
+
+ GET_PIP_DEST.write_bytes(get_pip)
+ CGMANIFEST_PATH.write_text(cgmanifest, encoding="utf-8")
+ print(f"Updated {GET_PIP_DEST} and {CGMANIFEST_PATH} to get-pip {version}")
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser(description="Refresh the vendored get-pip.py")
+ parser.add_argument(
+ "--version",
+ help="pip release to vendor; defaults to the latest release on PyPI",
+ )
+ args = parser.parse_args()
+ refresh_get_pip(args.version)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/python_files/get-pip.py b/python_files/get-pip.py
new file mode 100644
index 000000000000..ad82d8a58980
--- /dev/null
+++ b/python_files/get-pip.py
@@ -0,0 +1,27969 @@
+#!/usr/bin/env python
+#
+# Hi There!
+#
+# You may be wondering what this giant blob of binary data here is, you might
+# even be worried that we're up to something nefarious (good for you for being
+# paranoid!). This is a base85 encoding of a zip file, this zip file contains
+# an entire copy of pip (version 26.2.1).
+#
+# Pip is a thing that installs packages, pip itself is a package that someone
+# might want to install, especially if they're looking to run this get-pip.py
+# script. Pip has a lot of code to deal with the security of installing
+# packages, various edge cases on various platforms, and other such sort of
+# "tribal knowledge" that has been encoded in its code base. Because of this
+# we basically include an entire copy of pip inside this blob. We do this
+# because the alternatives are attempt to implement a "minipip" that probably
+# doesn't do things correctly and has weird edge cases, or compress pip itself
+# down into a single file.
+#
+# If you're wondering how this is created, it is generated using
+# `scripts/generate.py` in https://github.com/pypa/get-pip.
+
+import sys
+
+this_python = sys.version_info[:2]
+min_version = (3, 10)
+if this_python < min_version:
+ message_parts = [
+ "This script does not work on Python {}.{}.".format(*this_python),
+ "The minimum supported Python version is {}.{}.".format(*min_version),
+ "Please use https://bootstrap.pypa.io/pip/{}.{}/get-pip.py instead.".format(*this_python),
+ ]
+ print("ERROR: " + " ".join(message_parts))
+ sys.exit(1)
+
+
+import os.path
+import pkgutil
+import shutil
+import tempfile
+import argparse
+import importlib
+from base64 import b85decode
+
+
+def include_setuptools(args):
+ """
+ Install setuptools only if absent, not excluded and when using Python <3.12.
+ """
+ cli = not args.no_setuptools
+ env = not os.environ.get("PIP_NO_SETUPTOOLS")
+ absent = not importlib.util.find_spec("setuptools")
+ python_lt_3_12 = this_python < (3, 12)
+ return cli and env and absent and python_lt_3_12
+
+
+def include_wheel(args):
+ """
+ Install wheel only if absent, not excluded and when using Python <3.12.
+ """
+ cli = not args.no_wheel
+ env = not os.environ.get("PIP_NO_WHEEL")
+ absent = not importlib.util.find_spec("wheel")
+ python_lt_3_12 = this_python < (3, 12)
+ return cli and env and absent and python_lt_3_12
+
+
+def determine_pip_install_arguments():
+ pre_parser = argparse.ArgumentParser()
+ pre_parser.add_argument("--no-setuptools", action="store_true")
+ pre_parser.add_argument("--no-wheel", action="store_true")
+ pre, args = pre_parser.parse_known_args()
+
+ args.append("pip")
+
+ if include_setuptools(pre):
+ args.append("setuptools")
+
+ if include_wheel(pre):
+ args.append("wheel")
+
+ return ["install", "--upgrade", "--force-reinstall"] + args
+
+
+def monkeypatch_for_cert(tmpdir):
+ """Patches `pip install` to provide default certificate with the lowest priority.
+
+ This ensures that the bundled certificates are used unless the user specifies a
+ custom cert via any of pip's option passing mechanisms (config, env-var, CLI).
+
+ A monkeypatch is the easiest way to achieve this, without messing too much with
+ the rest of pip's internals.
+ """
+ from pip._internal.commands.install import InstallCommand
+
+ # We want to be using the internal certificates.
+ cert_path = os.path.join(tmpdir, "cacert.pem")
+ with open(cert_path, "wb") as cert:
+ cert.write(pkgutil.get_data("pip._vendor.certifi", "cacert.pem"))
+
+ install_parse_args = InstallCommand.parse_args
+
+ def cert_parse_args(self, args):
+ if not self.parser.get_default_values().cert:
+ # There are no user provided cert -- force use of bundled cert
+ self.parser.defaults["cert"] = cert_path # calculated above
+ return install_parse_args(self, args)
+
+ InstallCommand.parse_args = cert_parse_args
+
+
+def bootstrap(tmpdir):
+ monkeypatch_for_cert(tmpdir)
+
+ # Execute the included pip and use it to install the latest pip and
+ # any user-requested packages from PyPI.
+ from pip._internal.cli.main import main as pip_entry_point
+ args = determine_pip_install_arguments()
+ sys.exit(pip_entry_point(args))
+
+
+def main():
+ tmpdir = None
+ try:
+ # Create a temporary working directory
+ tmpdir = tempfile.mkdtemp()
+
+ # Unpack the zipfile into the temporary directory
+ pip_zip = os.path.join(tmpdir, "pip.zip")
+ with open(pip_zip, "wb") as fp:
+ fp.write(b85decode(DATA.replace(b"\n", b"")))
+
+ # Add the zipfile to sys.path so that we can import it
+ sys.path.insert(0, pip_zip)
+
+ # Run the bootstrap
+ bootstrap(tmpdir=tmpdir)
+ finally:
+ # Clean up our temporary working directory
+ if tmpdir:
+ shutil.rmtree(tmpdir, ignore_errors=True)
+
+
+DATA = b"""
+P)h>@6aWAK2mpk$1YM~>El~OZ003hF000jF003}la4%n9X>MtBUtcb8c|DLpOT<77h41q#LNB_YQ(Q#
+X1qCmH7xCatWSDK!-GMeUB&kcmA8%TzVIafHaPU(6cYHqEdW)S|}J%M}PBoK%bK>-w1VG#-4Dhq_E9)|Oc(krAc7z
+kS&Gm2BDFT!}e+Sn2$z7U_|cr;<&TwWo0ASPJqV3Zu11|Kd{1#{B|NO9KQH000080EDvyUFFJQ#l!&s
+0BQpO01p5F0B~t=FJE76VQFq(UoLQYT~bYtn=lZ)^D9Q#15mMS&Q-Hgk9%G1t*R``48aQ6mdAwBU*8!
+AlHGDL_=b-V;Hj{;6RlJfPwu=@$q8a89E!$Bp+Akqn{uR2)&JzfI)F(y6;
+7(4LS`C*d9Ve5`pAFU%l;MCehh-?|MwN4uTC}{4}vOff>+T8a6`wi!A0S>2YjewCpG0Xz)wJ#AQIo*H
+?eR4m3en)8HLEPg(EBCiq&|N48(b-{Myt4h>h(o-vuFtLplD0sQQ!Huz8-YpLa}hXp}Lgg84VBjf_Km
+?MYMU6^9`%tAutwfl?IEC)+ijk?sT}I8qEcU3
+zCc?4bNI!FHI(;q-$V=5m^G1#S{KsWtaks-iHdXl>|5C+2P)h>@6aWAK2mpk$1YP1plhf7$00656000#L00
+3}la4%n9aA|NYa&>NQWpZC%E^v8$RKZT$KoGtAD+Y6@Eg6?WPf=4qD~Moq6--&0B|IIN4y1}t?C5+DB9B?Ay-9#7PSY|Ps$oy(K-!+
+C8rdsM4*2yE6hPUP@Y~B@P?vYW08=h@8K(xHx!*o{lUYE(yH26Piap|22yX|!FlPiuMvh}5FEqDqhHW
+fdqV4!(L}VWrB^FeD&Io3#_TsZ%sih}jqA{7tzXmY*)F)ml#zm9sM9(Izc95T4uv%p)NO6e0|BMpRAn
+&xx%@u87W2uEo2&U`0b_{H6Zmu*2SJcyG0+jt+i1IvM*zp*+Zsop?zOQP06i9cV>N_nm_8V#qb?(c!d
+Q3$QhCTGU{x@)bih`+Ft?+#JNNg-eL8tm?v<_(yz&4U^Mxza|kqUH^Or$P?CN~zFIYGCM1cp
+mz#dr7AvVV0lhc!-MDR|$=x&@Z64(aCZA8wf^O*jd8t-uB{Q--+IFzwO#1bu(mC4q5{*l#%6bUSmE~J
+-5E;y_W@0hDnO{s6Vm_TN$wk}9X!sX`uaOWj&p#`rb1+l&RR=pqiehW)`<_WZ_HSKSh177~ZLl8;3J|
+WwEOJ;D2^39Pa)AVx=lI%aT6$^k(RVNZFe^Xg!XX=u#t@Qs!qFQeY%R?=!R~;IQ-gcm(mkg=o7+Q8?g
+mz3nr$ggAp_WN(r@QgG|3(u@|JCjSvOV)?gagZ=1QY-O00;nt
+vjknu$G|nf0000U0RR9D0001RX>c!ac`kH$aAjmAj&U
+%1)EvFVxRjSzi=C>J@cMk87yJyz4~-Qcqlg}hXv}1CF`fEox?~SG{pae%Dy$pBG>tnWs3{>FohpTZSG
+@fe-hAmws@4PFv7Mv`H@JnAXTbgKqwrl)IWaYE>+%OsO9KQH000080EDvyT@7vVY&Zb`0RI6102u%P0
+B~t=FJEbHbY*gGVQep7UukY>bYEXCaCvo6!AitH486}+g!Qroon8cWL64rqlQ)qv+oo+`Ix{4xOTmvf
+t*+w1T=EEymzS5G^8`)P&pIkbFlCdRayLg5@77)Z?^5SnhsFz(_JI
+dEKqS#uQGSCDc+Lsoerpw6J(yuVII!C7b}u8@K>~$Qkl)R)*@YZCXf1>s5u{}*Dxjlzn!*BNA;k4U#v
+U0{YZf*+QtvkKXcD38Xbmz%=um^@b_s$AqiT^uT@R$=eDrOe>avtjThKL$%qaEE_1M8{GPTuke_Zm
+y&Jz`<4^08Snz&ig#G)MPSwDpy-2Uddc;)K2BqWHLEBTbE`hl4M<1b*Yj>=v`sTO2|Anm8`VM?b(
+?h+e*95^s;&UXieUH&&+0{^G)+;tfO1Vigq+af54-gs15~|H{(z8gJ-1BMV#EIJT+xp$knwZs&OSZwp
+sgLZe~K~l`4x;;ct@5o$8O=sM3P*+bGtR&RUWynVVd%WTt;sOfF=G3Fk74)u)vzSRu{67x@kLq#w3QW
+zTe`c+@<5ZVwRV8(qH3Yunksr(KmR*_7ubcHR@%@&idt#(n%UlgDX3^tH?TQ2(wQ9w)W5<+-
+nV@ORCf7Po?Kl<4(rSZjom7V8J3AwPP^DNjjuCHE^^(V;gjJj*)3dWTZ(n@>;&t-3cW+)Nub;fS!1{?
+PH8#ZLT=34bRINoqjt6E}Rg}&J{eNkzawhQSYAWvkg}%(s1U~TSw+fD&3yDFw%#^TO`S9T*Vb&O;tuU
+Z04>9>Z?XWnL&Wh7|SJ)^8RS1(@tAkynGD`yj7o4y-~J`pop_oCao15psgfNAjJ}*$rW6b=kJT6G&ed`7CuX{oO+9CjI2#5Q
+dvpC)*`n-rSZ=ek|2c-UK4NfKF=t!E(xu*I5xZF0{rE3+M6U%^R`R5~&O92*;xw!pjmj&)x{ZE9;pjh0HmEnDIuTGv(`t@BUx^P&>}3uDMr>5B;6VyWRZ#R}sJ3{*DRt>B35T
+1BJuGVSud8NfK<*>4P%7F-7W?t-OE9#O^sK?4-fSs9-+)Ib1d>@dLdD@+}k|nrVnw
+rEl)_Vedz?D-X^#1n=c%RH!krem|iH|)=L;j!bHobPMIBqH0g|=*ZG8doSPKPs{DSBsL_Gw*FR%u2~j
+zR>QseAN4PSylON%gB;iiy_~uIyS)#RbKnR|&GKF%Uq_gb)Qjrl;
+VN>|0b>6qEb(V7WTCY_JRs<*dfJ~|i6gVoV##y{Lz%+S#I))G~7OAO-ivy{Asc3as=h!hj@(bq_E@3g
+X=HQiLIm`}0pqDz+)j?2cjspVQsw(XK{Coq6>Sc_@=f$Cr=cpd%+S*##^FKcP^W#$wyPO;sbvDTHV31
+NqwtAsYcKdNkw;j6|PD+YHkmKlNTe!SU5&3nN2^V#&wl?J8eZuOU&SV+TvuahBq!%P=m>qj``w7uYcNqvwWe$h)!6YS@Q@Bn-WFz
+`B4T*PE9Q;M}bvk@R)T(R7XH3~2+d;}NhA^+KT0&RHR%rMn6P)rkSnXSYNS_cSwt1eT6kj|TO1lb540
+2g$AS1IPHA3gLsb1`gjGHNyUX-ONoAlzDi+VVw%d~-$1Uf%*5%CW$i`@#~D}vf8O(^Zoo%^66x^hccR
+H8W`tEIF+tpwzhp^Ricq%-x23eL>Ihdl{b`h6G(SOkpo)jK@nZhG-3_noFW?oSx-M*Mf$;a*=V5$Rm$
+9JF-}DhvW#pP}{m&jQr|c>V^y6^O-Q+HU{W*O!WOAHlL$;bNH|1R*F!2MiZ|KM@u=4bS9J
+BTD&Kd;P;3@2R5I>0Hm?j}2xTPf(FZMQ;&TtGNx|$A{2F0TIl7>khODWqm?o=kd!k~w`M6o82u~ZmVD
+PlDZwC|fb=ZnCk~>#)ln__9$SyVP(5H|3I3|8PUqPyfEN>({8D7QbW9_g+kf^IZuy
+pr;#rk`G(0s81UmxTA(%{P!U)`5(!-9U>sq5fs&?N6|LnbPFFKd7|N3d0fEBt9$H@ZVEXWLI{h~8?Pu
+_FdY#-K?lK}QAPcUZiDkV7{_1Bx$k_>l=ob!1x?v4K!rv{%u-yqYcNG?=YFTfhlUe#qUTn}SQbq{tgSh9CKK?@%K#86VZ%&PJE%Z)S9P0|w7R
+cxzM0udp=sGBCG2{18IcI}}0<#UyXT87)KcW1mE2ekWFA3pv+`3nE>VeZ!6@MkZ<@C!nGU$_C8+Z?zUHf+Wo>i`z1`jqS_d-Y@G-_w2@NS{;i^z1lkbOPNWWhAqa_+8MAMhD-6nD=xj
+2}Z#saMVlT9sdFS>9j+I7X?sC01A&$Vu%lq=NtxDm5P(DuD(WD-{*XZZAuAX)4we}jAO?ktjJlby)R$
+%ugd$bK-cAq-rae8@x$|rSILLx7Z)#+r%#?fzvvrqlbI#3$06DAYnjwtI=4##Yo1`%K4YxwqpReLyiJ
+)sNx!5(66CQJU80GlF`2J=N9tklvFMj9p6Iq?x_js^a##NI?sbSS!q~$1yUk*^F6rK*B)(0h_exRANW
+4a7=cy@_!inHq9KUMlb+3bTW7iTLSLeYZ6o>(KS~+66icjeE!f?hIIT(J7T%kTy5nsZgFf1l@wZ8wS$
+!RVfEOQslt17A-<0WY?%N)c%SCq6Xnm&jW`IP5ekfwt=72UJbk?Jxm>UgDLBaWxT!8+6U{&;Kop_Ii*
+s$tZAl2W*lk%E9aWaKdyi|+|c`;A#<_D=duDOYM;Ba#tncu4u(=`29{ica;VomI)yxaC4a4hSu^OUBK
+W_}bLeUO2RDnZIy5lwaEF*LZ6)_7)~_nY+1}I_cv__p#{hzT-^)3tMhqeoiCF
+Fre?n$*aU5Ln1;ZYc_i&vUgZzBA*inS@p1#W&YH9pfus80YNMoLmsoz{}T@CfyNAA^vb^dby^EYish%
+GT99di>OrdXf{bQcV0TvyLD_R{tf!$46*I%1zxrOd*2yPomT0?6!buYVLf{jxw3Elyj2P|=I=KA^AdM
+gK8GJAqSq?tC)LdM+IJPpACI?U)5B@h|4bBtDAV{|kwq$;=*!Oq;qF<$tyGyPnlfp*Kp~U_)6pWtybG
+&6xrGaP>Os7mt}}=XJg|0b&~{E571~5Unc^cSB@f3d3$iU?I(05Z12;sGgcSOWCw^{4s=T-w?a#Cnyz
+bN8N7f?$B1QY-O00;ntvjkoB+L}c@5dZ+c!JX>N37a&BR4
+FJo_RW@%@2a$$67Z*DGddBq$3Z`-)_cmEYU6^F_=N8N3QVQ0YGa+kChT$&U~+q;8d=opKRxyq6t%1*s
+3``h>4BPo%ToMgp-8AW4TSIedm1(O9^5+Jscxljo#+VOmgt3Kji#+53Uk~bn_cd}VCu7Mn}Pht;?F5m+|*xbm%u8
+_@31xPFjuh_gvaMzfi*OC_vV!@OwZgauz$~t42P|I2Zm|J$Y7B!&076vs-Bb<0d$gzscnl16@Rb6gIQ
+520v_>QINYTImUk)}*;sJi92HAH;ddGm%Y
+3
+lEAy*Pe*3hN@oP8Kp^a%HJ!B3D8`!E>Y0>BYws*I%b+Z!RvcPET;-PSgqn1F)mD$SY987wkPK?k6}Uyslv0=Z+
+OwgL^v-hX7NXbU%=kt%UZnivMu+w5E>#`sx;eiFxW|1g%dIQPp-Pya;FzWT$`Keu&emuUSrC^A)v)l#
+!5iK0-LxE;qemuRpIy*T{FRxBcuYg*jI?;4Y%qOJVzDMlsdpOT|i${+>9-p6`r018%C+X$I`EM;i7la
+QS0ggsFsUj?I)iO>~bV+Fn8UaGPxO{&)WpDZZMlg^7d7qLD^)us51DoF2qA#a%*
+2YN?E``v<9}1qICk_`{5vHcf~$JVKMCVTQ9YCd`2pK%am(ur*hYGz%5A+AEEW!9%bJ|@7~LJhA_z131
+J-v3G>wy5R5@RQ%BQH4N71;qvKE_iC#qVkGU{%8bLRMmk11~@
+^$;KJ5dK5^)A`iqWdMD~NuN2#tTXqM52ljvzQN%B`6(#qG)5A-^4g|rozjYAC?Yo*w*wJ^=u}8r;WLT
+oATsAS#KVjdF4g1imdTt@5&>Iu;GP!K#=&mLm9}Oclx@N2111y`jIF>2_C%#VpQOY95cM}%4x-naU4&
+fsdg^3CYx(W*wzlhQ48O2$Q=#RSu4~BES(;#FfTBG`B5`Y|(d%1rMM2`&dxdNf0H;kiyN8?GmfY9rE>
+IA>;Rt0G22gVx2-D8+ozTnXgUkqCg5NL#c-=6RKqUn(ACc#p4R8uw&S-l9?p{s*+eU45-!pznO(7R<0
+2J7o@>yLf{Hlr>%DP$P960HXB>T(BRMuD|4isdVCHE2$JxdaQq=#O?tfbfH#zL^A*AiZBp#WYf|2%>1
+C!25L2kKdhv3x<@W0cWXLWV1+20nxA`@HYEg2R!&r(YdNAYe6wq=diupRYEERz&aq?A_IR18?=@iUt&
+*-Tx59;E>@8Nall-7ETD`PObU;_Dd8l1*gsdqc?+s~~Y|<1m^L#ad)n$$xngZfw4qgYc$`qr)lu;J-FLqHDXe0QCTok_PT
+)5g+6nI*&<5BwzY_tW3XrUV?XozroQ__J`S`e$vXOyX*|Fydw0z|ZWdw9
+@W!k~Kx)zzct-#>ie`5UNhR#IdgN1kK@hTcVIRVX2{r~wlJ^TS$Ag;uO<%${MBbvSvSP4_x3S3jxcx{@3z|*EoMFv?+OC2!8xCM{KD++^O%qr_9)PKiwfE`{4ox*|jDqY0DXRc4wUn8~QEA_^?bVDEqFYTgp@sN7Bd*(n&Prabr8BneltSh%j*1$2SU%^eV4a9paWm
+elN~MD|FCQVr7&DV))@FUu^e_I1{cJ@wBy!XrRHec@*OZ6vzTXDZ}Dhg9f&>l=rQt
+k@OSfvxzFnb?g#DR+q{VlzwaMHISy}~)A|LODKOEt#NCY>UVln~YMVR6o=6?#-4=(`cUWaV;QHrl?3a
+7c|F0tZnKq(p>VRj+#oKCHKhN3Tb#|UvT|Dic3^o57vvhYD`|1}Yk60Y>!aUb~zErzw-;9F7q;IFXiL
+JM?JFbb+0JEgG`uVjPzM|JqjpUF^>AL_ExaKmOeY;55I|z~h46+-#xWFiPv%O8C9;luVd+(Io8@{JRa
+8p6T$ybdo@?C-kiSb>UP2iqzW`@s?`m^VG47<9Q*<>Prwzqm-Qt>220@cM|a1M`DH`nl3d#P<*3#z=1
+Ho%s84_*#ZqoiNLJn3~PKl6M`YumkQ%_B{>`V(2K$~gL^mO4Q$+1CoH_?1@wKy^+D8OXD05FTPJK12D
+ZeC6nFsAAhLg!klCHPk1;zErHj`&flnMsd;AF?bm(usHCwrl$w^qN1v-L}9fjx{JnWD69Tjd>JjJBjS
+~RfKidlYtj$|BKoR=um8@%SJ81{%(`5XN@VPAO%-7$j^VBr>l?a;cu&+mK#fm;9}YT%7y5tpu9iDcJy
+w@nIMTGsUN~*AVGTT>PQOc9F~
+7;BE*drSS#huY-<}*D`V+&D$&2#rzM`Zz2Dku{pTBOzetno-YR7tya^1GxqwEtY|<2$vz_Kk_Lf@
+t%r$GhYGq{undq9XCYCeFWB79K(6N5(EnbLf)jS!#SHZI|ES~rwFovrj$KTg6}gSXm-**)z2y*1O{b=
+RGFd36Vi>hc!V!t``Ygs=L^*r2EK8t)d5uV%r@;Q-?Mp;n&czFvNDf>vRlBWXA#i;ebI?Z7m;_?Sx@y$fT9H(RF1bHa(U_!&uYTZ-|vsIuE<0l2{o_(LJ#sW=h%|3JB<3
+BMMCt(&G&(^s!p{{F!Mk4J6S6-0{@=sZ!zjZ2HUhU(O~vd`AC|pEUE~tFAA|zT9D~ot<*)*S5CB?@q3
+Ht}mJbq-pd>JJR1fHyc_9IN&iuZ`htekI}9S_U59mJJ=0tArue0i47E{_fCFxdiZ9GHV35zKJb`*VNX
+;hxCEZXsWzzQ=`f_hkEHYRG^Sz7J#=*47%`3MLAJQWk?3|@1Z##3Xpqa5qI3kb(%{$YEh2`__rVBehIh0M)
+O4D2J%>WOl%zG&y6t|)^jS2SaufI;Umcl=Xjmxzj{XzX}MB8vOm&f&iVlfayI4kH&<2S^l>k^>a4^AB
+P2Bku~>PBW7%0@DMC9O>sjKnq6M0bzt47{)fLbiyroS5eD)e00E43yKHH~@eIxRzNa3fzm6=;VK!8Yl
+3(to>#m)aeQP2?V#J_AYFpSy8i37fH35@7klaw{SA4s+{k28iVU_)GqGZpDM(GPh!W9|Ae}UJ(TB882XbdD6GxiE
+Sr^jr{>4dn0Imu$)L@AlARTvb0G0609xXtRXu7|zLDD;2M}4O7B<|cr9we9RddPi%=lHReFd>dDOuKQQU(id5P$ilO5Bse}UuRLsnWXLgBs7oM%peq@kr>WJ+`=-+GMK&gb%(A0Q15=sEurH^09+K$I8Xm1?44E3(PR9}-j_m9ig)EptD08
+QSL6Qs5@y51VEI`X~WmijMdHxJ$o{_(kYgJahYKA2x}^oG#Fdeti()cok%#TNwa{smvyPq3||X{ZJRg
+$RukS(QTl!QV$5xG@A_^p|`0;g8>$4X?3nupVf)Vo320z)TbSKXq~Vx{B`g5h=}lr)gq;ee)3ChhtY?
+)eqxn^dC@50|XQR000O8gtG))V?GE^v9
+>ed}`LICk)VKLv*UePwA!qPJ%+wWTkftf$*O?b^OLwtF^P9!I7~NamU%6@s)|tEeiKXGkiqk$1?O?33
+hN01&*%a?ey!`BXD)U4R4N;NaYG=y~4h=TNSSI7^i%m5fAjmuKbTE-MSM3c~wfA^n4ctGifUWpGMuSAirMUjbkxytfF%=2t1f^=Qn#pyyk#`ss2IGo&houJtKZsWH~pF;Zu=ii82ktyC6