diff --git a/build/conda-functional-requirements.txt b/build/conda-functional-requirements.txt index a00a7672678..715e6923a5e 100644 --- a/build/conda-functional-requirements.txt +++ b/build/conda-functional-requirements.txt @@ -14,7 +14,6 @@ pytest==4.6.9 # Last version of pytest with Python 2.7 support rope flask django -isort pathlib2>=2.2.0 ; python_version<'3.6' # Python 2.7 compatibility (pytest) pythreejs ipysheet @@ -23,4 +22,4 @@ beakerx py4j bqplot K3D -debugpy \ No newline at end of file +debugpy diff --git a/build/test-requirements.txt b/build/test-requirements.txt index 90239895741..b4253bb0c5d 100644 --- a/build/test-requirements.txt +++ b/build/test-requirements.txt @@ -14,7 +14,6 @@ pytest < 6.0.0; python_version > '2.7' # Tests do not support pytest 6 yet. rope flask django -isort # Python 2.7 compatibility (pytest) pytest==4.6.9; python_version == '2.7' pathlib2>=2.2.0; python_version == '2.7' diff --git a/languages/pip-requirements.json b/languages/pip-requirements.json deleted file mode 100644 index 746aa3ac3e2..00000000000 --- a/languages/pip-requirements.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "comments": { - "lineComment": "#" - } -} diff --git a/news/1 Enhancements/12932.md b/news/1 Enhancements/12932.md deleted file mode 100644 index 5075b7151f7..00000000000 --- a/news/1 Enhancements/12932.md +++ /dev/null @@ -1 +0,0 @@ -Upgraded isort to `5.3.2`. diff --git a/news/1 Enhancements/13061.md b/news/1 Enhancements/13061.md deleted file mode 100644 index 6b65b12e624..00000000000 --- a/news/1 Enhancements/13061.md +++ /dev/null @@ -1,2 +0,0 @@ -Remove default "--no-reload" from debug configurations. -(thanks [ian910297](https://github.com/ian910297)) diff --git a/news/1 Enhancements/13306.md b/news/1 Enhancements/13306.md deleted file mode 100644 index ba792cdea38..00000000000 --- a/news/1 Enhancements/13306.md +++ /dev/null @@ -1 +0,0 @@ -Update API to expose events for cell excecution and kernel restart. diff --git a/news/1 Enhancements/13716.md b/news/1 Enhancements/13716.md deleted file mode 100644 index 9289e62b8c4..00000000000 --- a/news/1 Enhancements/13716.md +++ /dev/null @@ -1 +0,0 @@ -Show a general warning prompt pointing to the upgrade guide when users attempt to run isort5 using deprecated settings. diff --git a/news/1 Enhancements/13831.md b/news/1 Enhancements/13831.md deleted file mode 100644 index a5d0ac448b9..00000000000 --- a/news/1 Enhancements/13831.md +++ /dev/null @@ -1 +0,0 @@ -Upgrade isort to `5.5.2`. diff --git a/news/1 Enhancements/5578.md b/news/1 Enhancements/5578.md deleted file mode 100644 index 7fc44ac6386..00000000000 --- a/news/1 Enhancements/5578.md +++ /dev/null @@ -1 +0,0 @@ -Docstrings are added to `class` and `def` snippets (thanks [alannt777](https://github.com/alannt777/)) \ No newline at end of file diff --git a/news/2 Fixes/10270.md b/news/2 Fixes/10270.md deleted file mode 100644 index b90f01f1e94..00000000000 --- a/news/2 Fixes/10270.md +++ /dev/null @@ -1 +0,0 @@ -Fixed the output being trimmed. Tables that start with empty space will now display correctly. diff --git a/news/2 Fixes/11729.md b/news/2 Fixes/11729.md deleted file mode 100644 index 912cb3af7ab..00000000000 --- a/news/2 Fixes/11729.md +++ /dev/null @@ -1,3 +0,0 @@ -#11729 -Prevent test discovery from picking up stdout from low level file descriptors -(thanks [Ryo Miyajima](https://github.com/sergeant-wizard)) diff --git a/news/2 Fixes/12245.md b/news/2 Fixes/12245.md deleted file mode 100644 index e493d890bb5..00000000000 --- a/news/2 Fixes/12245.md +++ /dev/null @@ -1 +0,0 @@ -Fix opening new blank notebooks when using the VS code custom editor API. \ No newline at end of file diff --git a/news/2 Fixes/12760.md b/news/2 Fixes/12760.md deleted file mode 100644 index f47a84a5c3f..00000000000 --- a/news/2 Fixes/12760.md +++ /dev/null @@ -1 +0,0 @@ -Support starting kernels with the same directory as the notebook. \ No newline at end of file diff --git a/news/2 Fixes/12949.md b/news/2 Fixes/12949.md deleted file mode 100644 index 0e16948f227..00000000000 --- a/news/2 Fixes/12949.md +++ /dev/null @@ -1 +0,0 @@ -Fixed `Sort imports` command with setuptools version `49.2`. diff --git a/news/2 Fixes/12962.md b/news/2 Fixes/12962.md deleted file mode 100644 index c94aeff6e07..00000000000 --- a/news/2 Fixes/12962.md +++ /dev/null @@ -1 +0,0 @@ -Do not fail interpreter discovery if accessing Windows registry fails. diff --git a/news/2 Fixes/13229.md b/news/2 Fixes/13229.md deleted file mode 100644 index 2ab8d5a2b62..00000000000 --- a/news/2 Fixes/13229.md +++ /dev/null @@ -1 +0,0 @@ -Show error output from nbconvert when exporting a notebook fails. \ No newline at end of file diff --git a/news/2 Fixes/13258.md b/news/2 Fixes/13258.md deleted file mode 100644 index f0dafc1af18..00000000000 --- a/news/2 Fixes/13258.md +++ /dev/null @@ -1 +0,0 @@ -Prevent daemon from trying to prewarm an execution service. \ No newline at end of file diff --git a/news/2 Fixes/13338.md b/news/2 Fixes/13338.md deleted file mode 100644 index 052f45ac03a..00000000000 --- a/news/2 Fixes/13338.md +++ /dev/null @@ -1 +0,0 @@ -Respect stop on error setting for executing cells in native notebook. \ No newline at end of file diff --git a/news/2 Fixes/13409.md b/news/2 Fixes/13409.md deleted file mode 100644 index fc7d478c9e4..00000000000 --- a/news/2 Fixes/13409.md +++ /dev/null @@ -1 +0,0 @@ -Native notebook launch doesn't hang if the kernel does not start, and notifies the user of the failure. Also does not show the first cell as executing until the kernel is actually started and connected. \ No newline at end of file diff --git a/news/2 Fixes/13493.md b/news/2 Fixes/13493.md deleted file mode 100644 index c7c567cfed4..00000000000 --- a/news/2 Fixes/13493.md +++ /dev/null @@ -1 +0,0 @@ -Fix path to isolated script on Windows shell_exec. diff --git a/news/2 Fixes/13509.md b/news/2 Fixes/13509.md deleted file mode 100644 index 62188ee43db..00000000000 --- a/news/2 Fixes/13509.md +++ /dev/null @@ -1 +0,0 @@ -Updating other cells with display.update does not work in native notebooks. \ No newline at end of file diff --git a/news/2 Fixes/13520.md b/news/2 Fixes/13520.md deleted file mode 100644 index 6ee5043c318..00000000000 --- a/news/2 Fixes/13520.md +++ /dev/null @@ -1 +0,0 @@ -Fix for notebook using the first kernel every time. It will now use the language in the notebook to determine the most appropriate kernel. \ No newline at end of file diff --git a/news/2 Fixes/13553.md b/news/2 Fixes/13553.md deleted file mode 100644 index 05434a9f1c1..00000000000 --- a/news/2 Fixes/13553.md +++ /dev/null @@ -1 +0,0 @@ -Shift+enter should execute current cell and select the next cell. diff --git a/news/2 Fixes/13612.md b/news/2 Fixes/13612.md deleted file mode 100644 index c74758c7375..00000000000 --- a/news/2 Fixes/13612.md +++ /dev/null @@ -1,2 +0,0 @@ -Fixes typo in export command registration. -(thanks [Anton Kosyakov](https://github.com/akosyakov/)) diff --git a/news/2 Fixes/13706.md b/news/2 Fixes/13706.md deleted file mode 100644 index fb3074fa782..00000000000 --- a/news/2 Fixes/13706.md +++ /dev/null @@ -1 +0,0 @@ -Fix the behavior of the 'python.showStartPage' setting. diff --git a/news/3 Code Health/13103.md b/news/3 Code Health/13103.md deleted file mode 100644 index a22bfbd98e3..00000000000 --- a/news/3 Code Health/13103.md +++ /dev/null @@ -1 +0,0 @@ -Fix bandit issues in vscode_datascience_helpers. \ No newline at end of file diff --git a/news/3 Code Health/13411.md b/news/3 Code Health/13411.md deleted file mode 100644 index 5cce0297131..00000000000 --- a/news/3 Code Health/13411.md +++ /dev/null @@ -1 +0,0 @@ -Cast type to `any` to get around issues with `ts-node` (`ts-node` is used by `nyc` for code coverage). diff --git a/news/3 Code Health/13459.md b/news/3 Code Health/13459.md deleted file mode 100644 index b1a4e4d8d88..00000000000 --- a/news/3 Code Health/13459.md +++ /dev/null @@ -1 +0,0 @@ -Drop support for Python 3.5 (it reaches end-of-life on September 13, 2020 and isort 5 does not support it). diff --git a/news/3 Code Health/13501.md b/news/3 Code Health/13501.md deleted file mode 100644 index 440c4d45789..00000000000 --- a/news/3 Code Health/13501.md +++ /dev/null @@ -1 +0,0 @@ -Fix nightly flake test issue with timeout waiting for kernel. \ No newline at end of file diff --git a/news/3 Code Health/13542.md b/news/3 Code Health/13542.md deleted file mode 100644 index 33b462f5b54..00000000000 --- a/news/3 Code Health/13542.md +++ /dev/null @@ -1 +0,0 @@ -Disable sorting tests for Python 2.7 as isort5 is not compatible with Python 2.7. diff --git a/news/3 Code Health/13605.md b/news/3 Code Health/13605.md deleted file mode 100644 index 248a8f7d61f..00000000000 --- a/news/3 Code Health/13605.md +++ /dev/null @@ -1 +0,0 @@ -Fix nightly flake test current directory failing test. \ No newline at end of file diff --git a/news/3 Code Health/13645.md b/news/3 Code Health/13645.md deleted file mode 100644 index c7c4adb9a66..00000000000 --- a/news/3 Code Health/13645.md +++ /dev/null @@ -1 +0,0 @@ -Rename the `master` branch to `main`. diff --git a/news/3 Code Health/13647.md b/news/3 Code Health/13647.md deleted file mode 100644 index 9b86400b03c..00000000000 --- a/news/3 Code Health/13647.md +++ /dev/null @@ -1 +0,0 @@ -Remove usage of the terms "blacklist" and "whitelist". diff --git a/news/3 Code Health/13726.md b/news/3 Code Health/13726.md deleted file mode 100644 index f7180bab124..00000000000 --- a/news/3 Code Health/13726.md +++ /dev/null @@ -1 +0,0 @@ -Fix a test failure and warning when running test adapter tests under pytest 5 diff --git a/news/3 Code Health/13729.md b/news/3 Code Health/13729.md deleted file mode 100644 index a27cd06e378..00000000000 --- a/news/3 Code Health/13729.md +++ /dev/null @@ -1 +0,0 @@ -Remove unused imports from data science ipython test files. \ No newline at end of file diff --git a/news/3 Code Health/13734.md b/news/3 Code Health/13734.md deleted file mode 100644 index 40e0edd43fe..00000000000 --- a/news/3 Code Health/13734.md +++ /dev/null @@ -1 +0,0 @@ -Fix nighly failure with beakerx. \ No newline at end of file diff --git a/package.json b/package.json index e3ab4c8429a..201541d0883 100644 --- a/package.json +++ b/package.json @@ -1618,62 +1618,6 @@ } }, "languages": [ - { - "id": "pip-requirements", - "aliases": [ - "pip requirements", - "requirements.txt" - ], - "filenames": [ - "requirements.txt", - "constraints.txt", - "requirements.in" - ], - "filenamePatterns": [ - "*-requirements.txt", - "requirements-*.txt", - "constraints-*.txt", - "*-constraints.txt", - "*-requirements.in", - "requirements-*.in" - ], - "configuration": "./languages/pip-requirements.json" - }, - { - "id": "yaml", - "filenames": [ - ".condarc" - ] - }, - { - "id": "toml", - "filenames": [ - "poetry.lock", - "Pipfile" - ] - }, - { - "id": "json", - "filenames": [ - "Pipfile.lock" - ] - }, - { - "id": "ini", - "filenames": [ - ".flake8" - ] - }, - { - "id": "jinja", - "extensions": [ - ".jinja2", - ".j2" - ], - "aliases": [ - "Jinja" - ] - }, { "id": "jupyter", "aliases": [ @@ -1685,41 +1629,6 @@ ] } ], - "grammars": [ - { - "language": "pip-requirements", - "scopeName": "source.pip-requirements", - "path": "./syntaxes/pip-requirements.tmLanguage.json" - } - ], - "jsonValidation": [ - { - "fileMatch": ".condarc", - "url": "./schemas/condarc.json" - }, - { - "fileMatch": "environment.yml", - "url": "./schemas/conda-environment.json" - }, - { - "fileMatch": "meta.yaml", - "url": "./schemas/conda-meta.json" - } - ], - "yamlValidation": [ - { - "fileMatch": ".condarc", - "url": "./schemas/condarc.json" - }, - { - "fileMatch": "environment.yml", - "url": "./schemas/conda-environment.json" - }, - { - "fileMatch": "meta.yaml", - "url": "./schemas/conda-meta.json" - } - ], "notebookOutputRenderer": [ { "id": "jupyter-notebook-renderer", diff --git a/pythonFiles/refactor.py b/pythonFiles/refactor.py deleted file mode 100644 index 9e578906b3c..00000000000 --- 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/sortImports.py b/pythonFiles/sortImports.py deleted file mode 100644 index 070f7883fd6..00000000000 --- 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/testing_tools/__init__.py b/pythonFiles/testing_tools/__init__.py deleted file mode 100644 index 5b7f7a925cc..00000000000 --- a/pythonFiles/testing_tools/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. diff --git a/pythonFiles/testing_tools/adapter/__init__.py b/pythonFiles/testing_tools/adapter/__init__.py deleted file mode 100644 index 5b7f7a925cc..00000000000 --- a/pythonFiles/testing_tools/adapter/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. diff --git a/pythonFiles/testing_tools/adapter/__main__.py b/pythonFiles/testing_tools/adapter/__main__.py deleted file mode 100644 index 5857c63db04..00000000000 --- 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 798aea1e93f..00000000000 --- 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 3e6ae5189cb..00000000000 --- 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 f99ce0b6f9a..00000000000 --- 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 e894f7bcdb8..00000000000 --- 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 3d3eec09a19..00000000000 --- 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 51c94527302..00000000000 --- 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 f9ed1fe0f28..00000000000 --- 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 bacdef7b9a0..00000000000 --- 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 77778c5b612..00000000000 --- 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 1eeef194f8f..00000000000 --- 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/tests/debug_adapter/__init__.py b/pythonFiles/tests/debug_adapter/__init__.py deleted file mode 100644 index 5b7f7a925cc..00000000000 --- a/pythonFiles/tests/debug_adapter/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. 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 19565c19675..00000000000 --- 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/testing_tools/__init__.py b/pythonFiles/tests/testing_tools/__init__.py deleted file mode 100644 index 5b7f7a925cc..00000000000 --- a/pythonFiles/tests/testing_tools/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. diff --git a/pythonFiles/tests/testing_tools/adapter/.data/NormCase/tests/A/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/NormCase/tests/A/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/pythonFiles/tests/testing_tools/adapter/.data/NormCase/tests/A/b/C/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/NormCase/tests/A/b/C/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 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 3501b9e118e..00000000000 --- 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/NormCase/tests/A/b/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/NormCase/tests/A/b/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/pythonFiles/tests/testing_tools/adapter/.data/NormCase/tests/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/NormCase/tests/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 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 e30e96142d0..00000000000 --- 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 b8c49550389..00000000000 --- 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/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 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 4c4134d7558..00000000000 --- 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 4c4134d7558..00000000000 --- 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 4c4134d7558..00000000000 --- 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 27cccbdb77c..00000000000 --- 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 4b51fde5667..00000000000 --- 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 e752106f503..00000000000 --- 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 e9c675647f1..00000000000 --- 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 39d3ece9c0b..00000000000 --- 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 bd22d89f42b..00000000000 --- 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 dd3e8253573..00000000000 --- 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 7ec91c783e2..00000000000 --- 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/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/v/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 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 18c92c09306..00000000000 --- 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 f3e7d951763..00000000000 --- 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 6b6a01f87ec..00000000000 --- 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 18cf56f9053..00000000000 --- 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 6a0b60d1d5b..00000000000 --- 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 6a0b60d1d5b..00000000000 --- 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/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/a/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/a/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 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 bdb7e4fec3a..00000000000 --- 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/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/complex/tests/x/y/z/b/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 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 4923c556c29..00000000000 --- 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 4c4134d7558..00000000000 --- 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/notests/tests/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/notests/tests/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/pythonFiles/tests/testing_tools/adapter/.data/simple/tests/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/simple/tests/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 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 4c4134d7558..00000000000 --- 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/__init__.py b/pythonFiles/tests/testing_tools/adapter/.data/syntax-error/tests/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 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 54d6400a346..00000000000 --- 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/__init__.py b/pythonFiles/tests/testing_tools/adapter/__init__.py deleted file mode 100644 index 5b7f7a925cc..00000000000 --- a/pythonFiles/tests/testing_tools/adapter/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. diff --git a/pythonFiles/tests/testing_tools/adapter/pytest/__init__.py b/pythonFiles/tests/testing_tools/adapter/pytest/__init__.py deleted file mode 100644 index 5b7f7a925cc..00000000000 --- a/pythonFiles/tests/testing_tools/adapter/pytest/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. 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 6f590a31fa5..00000000000 --- 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 98b18567253..00000000000 --- a/pythonFiles/tests/testing_tools/adapter/pytest/test_discovery.py +++ /dev/null @@ -1,1540 +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 warnings - -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", []) - - 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): - 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): - # StubFunctionItem should not be calling __init__(), but instead from_parent(). - # Unfortunately the detangling is massive due to the complexity of the test - # harness, so we are punting in hopes that we rewrite test discovery before - # pytest removes this functionality. - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - return StubFunctionItem(*args, **kwargs) - - -class StubDoctestItem(StubSubtypedItem, _pytest.doctest.DoctestItem): - pass - - -def create_stub_doctest_item(*args, **kwargs): - # StubDoctestItem should not be calling __init__(), but instead from_parent(). - # Unfortunately the detangling is massive due to the complexity of the test - # harness, so we are punting in hopes that we rewrite test discovery before - # pytest removes this functionality. - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - return StubDoctestItem(*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( - _normcase=normcase, - _pathsep=pathsep, - ) - ) - - def _normalize_test_id(*args): - return pytest_item._normalize_test_id( - *args, - **dict( - _fix_fileid=_fix_fileid, - _pathsep=pathsep, - ) - ) - - def _iter_nodes(*args): - return pytest_item._iter_nodes( - *args, - **dict( - _normalize_test_id=_normalize_test_id, - _normcase=normcase, - _pathsep=pathsep, - ) - ) - - def _parse_node_id(*args): - return pytest_item._parse_node_id( - *args, - **dict( - _iter_nodes=_iter_nodes, - ) - ) - - ########## - def _split_fspath(*args): - return pytest_item._split_fspath( - *args, - **dict( - _normcase=normcase, - ) - ) - - ########## - def _matches_relfile(*args): - return pytest_item._matches_relfile( - *args, - **dict( - _normcase=normcase, - _pathsep=pathsep, - ) - ) - - def _is_legacy_wrapper(*args): - return pytest_item._is_legacy_wrapper( - *args, - **dict( - _pathsep=pathsep, - ) - ) - - def _get_location(*args): - return pytest_item._get_location( - *args, - **dict( - _matches_relfile=_matches_relfile, - _is_legacy_wrapper=_is_legacy_wrapper, - _pathsep=pathsep, - ) - ) - - ########## - def _parse_item(item): - return pytest_item.parse_item( - item, - **dict( - _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, - [ - ("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 53500a2f4af..00000000000 --- 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 ec3d198b010..00000000000 --- 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 bd6c6b20031..00000000000 --- a/pythonFiles/tests/testing_tools/adapter/test_functional.py +++ /dev/null @@ -1,1528 +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 - -import pytest - -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)) - - -# 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(result, 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(result, 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 bb68c8a65e7..00000000000 --- 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 822ba2ed1b2..00000000000 --- 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/requirements.in b/requirements.in index 9dcf250e60d..bcf468fe750 100644 --- a/requirements.in +++ b/requirements.in @@ -1,13 +1,11 @@ -# This file is used to generate requirements.txt. +# This file is used to generate requirements.txt. # To update requirements.txt, run the following commands. # 1) pip install pip-tools # 2) pip-compile requirements.in # IntelliSense. This is a specific commit id of our fork of the pappasam jedi-language-server -# If you make fixes to the fork, update the commit id here. -# Note: This pulls in Jedi too but the pypi version. +# If you make fixes to the fork, update the commit id here. +# Note: This pulls in Jedi too but the pypi version. git+git://github.com/vscode-python/jedi-language-server@42823a2598d4b6369e9273c5ad237a48c5d67553 -# Sort Imports -isort==5.5.2; python_version >= '3.6' # DS Python daemon python-jsonrpc-server==0.2.0 diff --git a/requirements.txt b/requirements.txt index a2fb26ae0af..eee48fb74a0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,6 @@ # click==7.1.2 # via jedi-language-server future==0.18.2 # via python-jsonrpc-server -isort==5.5.2 ; python_version >= "3.6" # via -r requirements.in git+git://github.com/vscode-python/jedi-language-server@42823a2598d4b6369e9273c5ad237a48c5d67553 # via -r requirements.in jedi==0.17.2 # via jedi-language-server parso==0.7.0 # via jedi diff --git a/schemas/conda-environment.json b/schemas/conda-environment.json deleted file mode 100644 index 458676942a4..00000000000 --- a/schemas/conda-environment.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "title": "conda environment file", - "description": "Support for conda's enviroment.yml files (e.g. `conda env export > environment.yml`)", - "id": "https://raw.githubusercontent.com/Microsoft/vscode-python/main/schemas/conda-environment.json", - "$schema": "http://json-schema.org/draft-04/schema#", - "definitions": { - "channel": { - "type": "string" - }, - "package": { - "type": "string" - }, - "path": { - "type": "string" - } - }, - "properties": { - "name": { - "type": "string" - }, - "channels": { - "type": "array", - "items": { - "$ref": "#/definitions/channel" - } - }, - "dependencies": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/package" - }, - { - "type": "object", - "properties": { - "pip": { - "type": "array", - "items": { - "$ref": "#/definitions/package" - } - } - }, - "required": ["pip"] - } - ] - } - }, - "prefix": { - "$ref": "#/definitions/path" - } - } -} diff --git a/schemas/conda-meta.json b/schemas/conda-meta.json deleted file mode 100644 index ca2ea03ab24..00000000000 --- a/schemas/conda-meta.json +++ /dev/null @@ -1,405 +0,0 @@ -{ - "title": "conda metadata build recipe", - "description": "conda's meta.yaml file; https://conda.io/docs/user-guide/tasks/build-packages/define-metadata.html", - "id": "https://raw.githubusercontent.com/Microsoft/vscode-python/master/schemas/conda-meta.json", - "$schema": "http://json-schema.org/draft-04/schema#", - "definitions": { - "boolean": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "string" - } - ] - }, - "integer": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "string" - } - ] - }, - "feature": { - "type": "string" - }, - "package": { - "type": "string" - }, - "path": { - "type": "string" - }, - "uri": { - "type": "string" - }, - "requirement": { - "type": "object", - "properties": { - "build": { - "type": "array", - "items": { - "$ref": "#/definitions/package" - } - }, - "host": { - "type": "array", - "items": { - "$ref": "#/definitions/package" - } - }, - "run": { - "type": "array", - "items": { - "$ref": "#/definitions/package" - } - } - } - }, - "source": { - "type": "object", - "properties": { - "url": { - "$ref": "#/definitions/uri" - }, - "md5": { - "type": "string", - "pattern": "^[0-9A-Fa-f]{32}$" - }, - "sha1": { - "type": "string", - "pattern": "^[0-9A-Fa-f]{40}$" - }, - "sha256": { - "type": "string", - "pattern": "^[0-9A-Fa-f]{64}$" - }, - "git_url": { - "$ref": "#/definitions/uri" - }, - "git_rev": { - "type": "string" - }, - "hg_url": { - "$ref": "#/definitions/uri" - }, - "hg_tag": { - "type": "string" - }, - "svn_url": { - "$ref": "#/definitions/uri" - }, - "svn_rev": { - "type": "string" - }, - "svn_ignore_externals": { - "$ref": "#/definitions/boolean" - }, - "path": { - "$ref": "#/definitions/path" - }, - "patches": { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - }, - "folder": { - "$ref": "#/definitions/path" - }, - "fn": { - "type": "string" - } - } - }, - "test": { - "type": "object", - "properties": { - "files": { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - }, - "source_files": { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - }, - "requires": { - "type": "array", - "items": { - "$ref": "#/definitions/package" - } - }, - "commands": { - "type": "array", - "items": { - "type": "string" - } - }, - "imports": { - "type": "array", - "items": { - "$ref": "#/definitions/package" - } - }, - "script": { - "type": "string" - } - } - } - }, - "properties": { - "package": { - "type": "object", - "properties": { - "name": { - "$ref": "#/definitions/package" - }, - "version": { - "type": "string" - } - } - }, - "source": { - "oneOf": [ - { - "$ref": "#/definitions/source" - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/source" - } - } - ] - }, - "build": { - "type": "object", - "properties": { - "number": { - "$ref": "#/definitions/integer" - }, - "string": { - "type": "string" - }, - "entry_points": { - "type": "array", - "items": { - "type": "string" - } - }, - "osx_is_app": { - "$ref": "#/definitions/boolean" - }, - "features": { - "type": "array", - "items": { - "$ref": "#/definitions/feature" - } - }, - "track_features": { - "type": "array", - "items": { - "$ref": "#/definitions/feature" - } - }, - "preserve_egg_dir": { - "$ref": "#/definitions/boolean" - }, - "skip_compile_pyc": { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - }, - "no_link": { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - }, - "script": { - "type": "string" - }, - "rpaths": { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - }, - "always_include_files": { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - }, - "binary_relocation": { - "$ref": "#/definitions/boolean" - }, - "detect_binary_files_with_prefix": { - "$ref": "#/definitions/boolean" - }, - "binary_has_prefix_files": { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - }, - "has_prefix_files": { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - }, - "ignore_prefix_files": { - "oneOf": [ - { - "$ref": "#/definitions/boolean" - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - } - ] - }, - "skip": { - "$ref": "#/definitions/boolean" - }, - "noarch": { - "type": "string" - }, - "noarch_python": { - "$ref": "#/definitions/boolean" - }, - "include_recipe": { - "$ref": "#/definitions/boolean" - }, - "script_env": { - "type": "array", - "items": { - "type": "string" - } - }, - "run_exports": { - "type": "array", - "items": { - "type": "string" - } - }, - "ignore_run_exports": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "requirements": { - "$ref": "#/definitions/requirement" - }, - "test": { - "anyOf": [ - { - "type": "string" - }, - { - "$ref": "#/definitions/test" - } - ] - }, - "outputs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "version": { - "type": "string" - }, - "files": { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - }, - "script": { - "$ref": "#/definitions/path" - }, - "script_interpreter": { - "type": "string" - }, - "requirements": { - "oneOf": [ - { - "$ref": "#/definitions/requirement" - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/package" - } - } - ] - }, - "run_exports": { - "type": "array", - "items": { - "type": "string" - } - }, - "test": { - "$ref": "#/definitions/test" - }, - "type": { - "type": "string" - } - } - } - }, - "about": { - "type": "object", - "properties": { - "home": { - "$ref": "#/definitions/uri" - }, - "license": { - "type": "string" - }, - "license_file": { - "$ref": "#/definitions/path" - }, - "summary": { - "type": "string" - } - } - }, - "app": { - "type": "object", - "properties": { - "entry": { - "type": "string" - }, - "icon": { - "$ref": "#/definitions/path" - }, - "summary": { - "type": "string" - }, - "own_environment": { - "$ref": "#/definitions/boolean" - } - } - }, - "extra": {} - } -} diff --git a/schemas/condarc.json b/schemas/condarc.json deleted file mode 100644 index 396236238c1..00000000000 --- a/schemas/condarc.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "title": ".condarc", - "description": "The conda configuration file; https://conda.io/docs/user-guide/configuration/use-condarc.html", - "id": "https://raw.githubusercontent.com/Microsoft/vscode-python/main/schemas/condarc.json", - "$schema": "http://json-schema.org/draft-04/schema#", - "definitions": { - "channel": { - "type": "string" - }, - "feature": { - "type": "string" - }, - "package": { - "type": "string" - }, - "path": { - "type": "string" - } - }, - "properties": { - "channels": { - "type": "array", - "items": { - "$ref": "#/definitions/channel" - } - }, - "allow_other_channels": { - "type": "boolean" - }, - "default_channels": { - "type": "array", - "items": { - "$ref": "#/definitions/channel" - } - }, - "auto_update_conda": { - "type": "boolean" - }, - "always_yes": { - "type": "boolean" - }, - "show_channel_urls": { - "type": "boolean" - }, - "changeps1": { - "type": "boolean" - }, - "add_pip_as_python_dependency": { - "type": "boolean" - }, - "use_pip": { - "type": "boolean" - }, - "proxy_servers": { - "type": "object", - "additionalProperties": { - "type": "string", - "format": "hostname" - } - }, - "ssl_verify": { - "type": "boolean" - }, - "offline": { - "type": "boolean" - }, - "allow_softlinks": { - "type": "boolean" - }, - "channel_alias": { - "type": "string", - "format": "uri" - }, - "create_default_packages": { - "type": "array", - "items": { - "$ref": "#/definitions/package" - } - }, - "track_features": { - "type": "array", - "items": { - "$ref": "#/definitions/feature" - } - }, - "update_dependencies": { - "type": "boolean" - }, - "disallow": { - "type": "array", - "items": { - "$ref": "#/definitions/package" - } - }, - "add_anaconda_token": { - "type": "boolean" - }, - "envs_dirs": { - "type": "array", - "items": { - "$ref": "#/definitions/path" - } - }, - "anaconda_upload": { - "type": "boolean" - }, - "conda-build": { - "type": "object", - "properties": { - "root-dir": { - "$ref": "#/definitions/path" - }, - "quiet": { - "type": "boolean" - }, - "filename_hashing": { - "type": "boolean" - }, - "no_verify": { - "type": "boolean" - }, - "set_build_id": { - "type": "boolean" - }, - "skip_existing": { - "type": "boolean" - }, - "include_recipe": { - "type": "boolean" - }, - "activate": { - "type": "boolean" - }, - "pypirc": { - "$ref": "#/definitions/path" - }, - "pypi_repository": { - "type": "string" - } - } - } - } -} diff --git a/snippets/python.json b/snippets/python.json index 59dde0bc62d..870c9180228 100644 --- a/snippets/python.json +++ b/snippets/python.json @@ -1,167 +1,4 @@ { - "if": { - "prefix": "if", - "body": ["if ${1:expression}:", "\t${2:pass}"], - "description": "Code snippet for an if statement" - }, - "if/else": { - "prefix": "if/else", - "body": ["if ${1:condition}:", "\t${2:pass}", "else:", "\t${3:pass}"], - "description": "Code snippet for an if statement with else" - }, - "elif": { - "prefix": "elif", - "body": ["elif ${1:expression}:", "\t${2:pass}"], - "description": "Code snippet for an elif" - }, - "else": { - "prefix": "else", - "body": ["else:", "\t${1:pass}"], - "description": "Code snippet for an else" - }, - "while": { - "prefix": "while", - "body": ["while ${1:expression}:", "\t${2:pass}"], - "description": "Code snippet for a while loop" - }, - "while/else": { - "prefix": "while/else", - "body": ["while ${1:expression}:", "\t${2:pass}", "else:", "\t${3:pass}"], - "description": "Code snippet for a while loop with else" - }, - "for": { - "prefix": "for", - "body": ["for ${1:target_list} in ${2:expression_list}:", "\t${3:pass}"], - "description": "Code snippet for a for loop" - }, - "for/else": { - "prefix": "for/else", - "body": ["for ${1:target_list} in ${2:expression_list}:", "\t${3:pass}", "else:", "\t${4:pass}"], - "description": "Code snippet for a for loop with else" - }, - "try/except": { - "prefix": "try/except", - "body": ["try:", "\t${1:pass}", "except ${2:expression} as ${3:identifier}:", "\t${4:pass}"], - "description": "Code snippet for a try/except statement" - }, - "try/finally": { - "prefix": "try/finally", - "body": ["try:", "\t${1:pass}", "finally:", "\t${2:pass}"], - "description": "Code snippet for a try/finally statement" - }, - "try/except/else": { - "prefix": "try/except/else", - "body": [ - "try:", - "\t${1:pass}", - "except ${2:expression} as ${3:identifier}:", - "\t${4:pass}", - "else:", - "\t${5:pass}" - ], - "description": "Code snippet for a try/except/else statement" - }, - "try/except/finally": { - "prefix": "try/except/finally", - "body": [ - "try:", - "\t${1:pass}", - "except ${2:expression} as ${3:identifier}:", - "\t${4:pass}", - "finally:", - "\t${5:pass}" - ], - "description": "Code snippet for a try/except/finally statement" - }, - "try/except/else/finally": { - "prefix": "try/except/else/finally", - "body": [ - "try:", - "\t${1:pass}", - "except ${2:expression} as ${3:identifier}:", - "\t${4:pass}", - "else:", - "\t${5:pass}", - "finally:", - "\t${6:pass}" - ], - "description": "Code snippet for a try/except/else/finally statement" - }, - "with": { - "prefix": "with", - "body": ["with ${1:expression} as ${2:target}:", "\t${3:pass}"], - "description": "Code snippet for a with statement" - }, - "def": { - "prefix": "def", - "body": ["def ${1:funcname}(${2:parameter_list}):", "\t\"\"\"", "\t${3:docstring}", "\t\"\"\"","\t${4:pass}"], - "description": "Code snippet for a function definition" - }, - "def(class method)": { - "prefix": "def(class method)", - "body": ["def ${1:funcname}(self, ${2:parameter_list}):", "\t\"\"\"", "\t${3:docstring}", "\t\"\"\"", "\t${4:pass}"], - "description": "Code snippet for a class method" - }, - "def(static class method)": { - "prefix": "def(static class method)", - "body": ["@staticmethod", "def ${1:funcname}(${2:parameter_list}):", "\t\"\"\"", "\t${3:docstring}", "\t\"\"\"", "\t${4:pass}"], - "description": "Code snippet for a static class method" - }, - "def(abstract class method)": { - "prefix": "def(abstract class method)", - "body": ["def ${1:funcname}(self, ${2:parameter_list}):", "\t\"\"\"", "\t${3:docstring}", "\t\"\"\"", "\traise NotImplementedError"], - "description": "Code snippet for an abstract class method" - }, - "class": { - "prefix": "class", - "body": ["class ${1:classname}(${2:object}):", "\t\"\"\"", "\t${3:docstring}", "\t\"\"\"", "\t${4:pass}"], - "description": "Code snippet for a class definition" - }, - "lambda": { - "prefix": "lambda", - "body": ["lambda ${1:parameter_list}: ${2:expression}"], - "description": "Code snippet for a lambda statement" - }, - "if(main)": { - "prefix": "__main__", - "body": ["if __name__ == \"__main__\":", " ${1:pass}"], - "description": "Code snippet for a `if __name__ == \"__main__\": ...` block" - }, - "async/def": { - "prefix": "async/def", - "body": ["async def ${1:funcname}(${2:parameter_list}):", "\t${3:pass}"], - "description": "Code snippet for an async statement" - }, - "async/for": { - "prefix": "async/for", - "body": ["async for ${1:target} in ${2:iter}:", "\t${3:block}"], - "description": "Code snippet for an async for statement" - }, - "async/for/else": { - "prefix": "async/for/else", - "body": ["async for ${1:target} in ${2:iter}:", "\t${3:block}", "else:", "\t${4:block}"], - "description": "Code snippet for an async for statement with else" - }, - "async/with": { - "prefix": "async/with", - "body": ["async with ${1:expr} as ${2:var}:", "\t${3:block}"], - "description": "Code snippet for an async with statement" - }, - "ipdb": { - "prefix": "ipdb", - "body": "import ipdb; ipdb.set_trace()", - "description": "Code snippet for ipdb debug" - }, - "pdb": { - "prefix": "pdb", - "body": "import pdb; pdb.set_trace()", - "description": "Code snippet for pdb debug" - }, - "pudb": { - "prefix": "pudb", - "body": "import pudb; pudb.set_trace()", - "description": "Code snippet for pudb debug" - }, "add/new/cell": { "prefix": "add/new/cell", "body": "# %%", diff --git a/src/client/common/constants.ts b/src/client/common/constants.ts index 6a582623222..f17bc8788e8 100644 --- a/src/client/common/constants.ts +++ b/src/client/common/constants.ts @@ -22,16 +22,10 @@ export namespace Commands { export const SwitchToInsidersWeekly = 'jupyter.switchToWeeklyChannel'; } export namespace Octicons { - export const Test_Pass = '$(check)'; - export const Test_Fail = '$(alert)'; - export const Test_Error = '$(x)'; - export const Test_Skip = '$(circle-slash)'; export const Downloading = '$(cloud-download)'; export const Installing = '$(desktop-download)'; } -export const Button_Text_Tests_View_Output = 'View Output'; - export namespace Text { export const CodeLensRunUnitTest = 'Run Test'; export const CodeLensDebugUnitTest = 'Debug Test'; diff --git a/src/client/common/helpers.ts b/src/client/common/helpers.ts index 2fd69900bd3..faf67e12dba 100644 --- a/src/client/common/helpers.ts +++ b/src/client/common/helpers.ts @@ -3,7 +3,6 @@ 'use strict'; -import { isTestExecution } from './constants'; import { ModuleNotInstalledError } from './errors/moduleNotInstalledError'; export function isNotInstalledError(error: Error): boolean { @@ -20,20 +19,3 @@ export function isNotInstalledError(error: Error): boolean { const isModuleNoInstalledError = error.message.indexOf('No module named') >= 0; return errorObj.code === 'ENOENT' || errorObj.code === 127 || isModuleNoInstalledError; } - -export function skipIfTest(isAsyncFunction: boolean) { - // tslint:disable-next-line:no-function-expression no-any - return function (_: Object, __: string, descriptor: TypedPropertyDescriptor) { - const originalMethod = descriptor.value; - // tslint:disable-next-line:no-function-expression no-any - descriptor.value = function (...args: any[]) { - if (isTestExecution()) { - return isAsyncFunction ? Promise.resolve() : undefined; - } - // tslint:disable-next-line:no-invalid-this no-use-before-declare no-unsafe-any - return originalMethod.apply(this, args); - }; - - return descriptor; - }; -} diff --git a/src/client/common/installer/productInstaller.ts b/src/client/common/installer/productInstaller.ts index 8919ed27379..3db012cdf4d 100644 --- a/src/client/common/installer/productInstaller.ts +++ b/src/client/common/installer/productInstaller.ts @@ -25,7 +25,7 @@ import { import { isResource } from '../utils/misc'; import { StopWatch } from '../utils/stopWatch'; import { ProductNames } from './productNames'; -import { InterpreterUri, IProductPathService, IProductService } from './types'; +import { InterpreterUri, IProductPathService } from './types'; export { Product } from '../types'; @@ -37,13 +37,11 @@ export abstract class BaseInstaller { protected readonly appShell: IApplicationShell; protected readonly configService: IConfigurationService; private readonly workspaceService: IWorkspaceService; - private readonly productService: IProductService; constructor(protected serviceContainer: IServiceContainer, protected outputChannel: OutputChannel) { this.appShell = serviceContainer.get(IApplicationShell); this.configService = serviceContainer.get(IConfigurationService); this.workspaceService = serviceContainer.get(IWorkspaceService); - this.productService = serviceContainer.get(IProductService); } public promptToInstall( @@ -77,9 +75,6 @@ export abstract class BaseInstaller { } public async isInstalled(product: Product, resource?: InterpreterUri): Promise { - if (product === Product.unittest) { - return true; - } // User may have customized the module name or provided the fully qualified path. const interpreter = isResource(resource) ? undefined : resource; const uri = isResource(resource) ? resource : undefined; @@ -106,13 +101,11 @@ export abstract class BaseInstaller { cancel?: CancellationToken ): Promise; protected getExecutableNameFromSettings(product: Product, resource?: Uri): string { - const productType = this.productService.getProductType(product); - const productPathService = this.serviceContainer.get(IProductPathService, productType); + const productPathService = this.serviceContainer.get(IProductPathService); return productPathService.getExecutableNameFromSettings(product, resource); } protected isExecutableAModule(product: Product, resource?: Uri): Boolean { - const productType = this.productService.getProductType(product); - const productPathService = this.serviceContainer.get(IProductPathService, productType); + const productPathService = this.serviceContainer.get(IProductPathService); return productPathService.isExecutableAModule(product, resource); } } diff --git a/src/client/common/installer/productNames.ts b/src/client/common/installer/productNames.ts index 54d478f81d8..31482f57b23 100644 --- a/src/client/common/installer/productNames.ts +++ b/src/client/common/installer/productNames.ts @@ -5,20 +5,6 @@ import { Product } from '../types'; // tslint:disable-next-line:variable-name export const ProductNames = new Map(); -ProductNames.set(Product.autopep8, 'autopep8'); -ProductNames.set(Product.bandit, 'bandit'); -ProductNames.set(Product.black, 'black'); -ProductNames.set(Product.flake8, 'flake8'); -ProductNames.set(Product.mypy, 'mypy'); -ProductNames.set(Product.nosetest, 'nosetest'); -ProductNames.set(Product.pycodestyle, 'pycodestyle'); -ProductNames.set(Product.pylama, 'pylama'); -ProductNames.set(Product.prospector, 'prospector'); -ProductNames.set(Product.pydocstyle, 'pydocstyle'); -ProductNames.set(Product.pylint, 'pylint'); -ProductNames.set(Product.pytest, 'pytest'); -ProductNames.set(Product.yapf, 'yapf'); -ProductNames.set(Product.rope, 'rope'); ProductNames.set(Product.jupyter, 'jupyter'); ProductNames.set(Product.notebook, 'notebook'); ProductNames.set(Product.ipykernel, 'ipykernel'); diff --git a/src/client/common/installer/productService.ts b/src/client/common/installer/productService.ts deleted file mode 100644 index 9687529670a..00000000000 --- a/src/client/common/installer/productService.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { injectable } from 'inversify'; -import { Product, ProductType } from '../types'; -import { IProductService } from './types'; - -@injectable() -export class ProductService implements IProductService { - private ProductTypes = new Map(); - - constructor() { - this.ProductTypes.set(Product.bandit, ProductType.Linter); - this.ProductTypes.set(Product.flake8, ProductType.Linter); - this.ProductTypes.set(Product.mypy, ProductType.Linter); - this.ProductTypes.set(Product.pycodestyle, ProductType.Linter); - this.ProductTypes.set(Product.prospector, ProductType.Linter); - this.ProductTypes.set(Product.pydocstyle, ProductType.Linter); - this.ProductTypes.set(Product.pylama, ProductType.Linter); - this.ProductTypes.set(Product.pylint, ProductType.Linter); - this.ProductTypes.set(Product.ctags, ProductType.WorkspaceSymbols); - this.ProductTypes.set(Product.nosetest, ProductType.TestFramework); - this.ProductTypes.set(Product.pytest, ProductType.TestFramework); - this.ProductTypes.set(Product.unittest, ProductType.TestFramework); - this.ProductTypes.set(Product.autopep8, ProductType.Formatter); - this.ProductTypes.set(Product.black, ProductType.Formatter); - this.ProductTypes.set(Product.yapf, ProductType.Formatter); - this.ProductTypes.set(Product.rope, ProductType.RefactoringLibrary); - this.ProductTypes.set(Product.jupyter, ProductType.DataScience); - this.ProductTypes.set(Product.notebook, ProductType.DataScience); - this.ProductTypes.set(Product.ipykernel, ProductType.DataScience); - this.ProductTypes.set(Product.nbconvert, ProductType.DataScience); - this.ProductTypes.set(Product.kernelspec, ProductType.DataScience); - this.ProductTypes.set(Product.pandas, ProductType.DataScience); - } - public getProductType(product: Product): ProductType { - return this.ProductTypes.get(product)!; - } -} diff --git a/src/client/common/installer/serviceRegistry.ts b/src/client/common/installer/serviceRegistry.ts index ffa4c39bc38..3d305ea76bb 100644 --- a/src/client/common/installer/serviceRegistry.ts +++ b/src/client/common/installer/serviceRegistry.ts @@ -5,17 +5,9 @@ import { IServiceManager } from '../../ioc/types'; import { IWebviewPanelProvider } from '../application/types'; import { WebviewPanelProvider } from '../application/webviewPanels/webviewPanelProvider'; -import { ProductType } from '../types'; import { InsidersBuildInstaller, StableBuildInstaller } from './extensionBuildInstaller'; import { DataScienceProductPathService } from './productPath'; -import { ProductService } from './productService'; -import { - IExtensionBuildInstaller, - INSIDERS_INSTALLER, - IProductPathService, - IProductService, - STABLE_INSTALLER -} from './types'; +import { IExtensionBuildInstaller, INSIDERS_INSTALLER, IProductPathService, STABLE_INSTALLER } from './types'; export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton( @@ -29,11 +21,6 @@ export function registerTypes(serviceManager: IServiceManager) { INSIDERS_INSTALLER ); - serviceManager.addSingleton(IProductService, ProductService); - serviceManager.addSingleton( - IProductPathService, - DataScienceProductPathService, - ProductType.DataScience - ); + serviceManager.addSingleton(IProductPathService, DataScienceProductPathService); serviceManager.addSingleton(IWebviewPanelProvider, WebviewPanelProvider); } diff --git a/src/client/common/installer/types.ts b/src/client/common/installer/types.ts index 6a390d7dd8b..399695cbc34 100644 --- a/src/client/common/installer/types.ts +++ b/src/client/common/installer/types.ts @@ -3,14 +3,9 @@ import { Uri } from 'vscode'; import { PythonEnvironment } from '../../pythonEnvironments/info'; -import { Product, ProductType, Resource } from '../types'; +import { Product, Resource } from '../types'; export type InterpreterUri = Resource | PythonEnvironment; - -export const IProductService = Symbol('IProductService'); -export interface IProductService { - getProductType(product: Product): ProductType; -} export const IProductPathService = Symbol('IProductPathService'); export interface IProductPathService { getExecutableNameFromSettings(product: Product, resource?: Uri): string; diff --git a/src/client/common/markdown/restTextConverter.ts b/src/client/common/markdown/restTextConverter.ts deleted file mode 100644 index 0881b37f3cf..00000000000 --- a/src/client/common/markdown/restTextConverter.ts +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { EOL } from 'os'; -// tslint:disable-next-line:import-name -import Char from 'typescript-char'; -import { isDecimal, isWhiteSpace } from '../../language/characters'; - -enum State { - Default, - Preformatted, - Code -} - -export class RestTextConverter { - private state: State = State.Default; - private md: string[] = []; - - // tslint:disable-next-line:cyclomatic-complexity - public toMarkdown(docstring: string): string { - // Translates reStructruredText (Python doc syntax) to markdown. - // It only translates as much as needed to display tooltips - // and documentation in the completion list. - // See https://en.wikipedia.org/wiki/ReStructuredText - - const result = this.transformLines(docstring); - this.state = State.Default; - this.md = []; - - return result; - } - - public escapeMarkdown(text: string): string { - // Not complete escape list so it does not interfere - // with subsequent code highlighting (see above). - return text.replace(/\#/g, '\\#').replace(/\*/g, '\\*').replace(/\ _/g, ' \\_').replace(/^_/, '\\_'); - } - - private transformLines(docstring: string): string { - const lines = docstring.split(/\r?\n/); - for (let i = 0; i < lines.length; i += 1) { - const line = lines[i]; - // Avoid leading empty lines - if (this.md.length === 0 && line.length === 0) { - continue; - } - - switch (this.state) { - case State.Default: - i += this.inDefaultState(lines, i); - break; - case State.Preformatted: - i += this.inPreformattedState(lines, i); - break; - case State.Code: - this.inCodeState(line); - break; - default: - break; - } - } - - this.endCodeBlock(); - this.endPreformattedBlock(); - - return this.md.join(EOL).trim(); - } - - private inDefaultState(lines: string[], i: number): number { - let line = lines[i]; - if (line.startsWith('```')) { - this.startCodeBlock(); - return 0; - } - - if (line.startsWith('===') || line.startsWith('---')) { - return 0; // Eat standalone === or --- lines. - } - if (this.handleDoubleColon(line)) { - return 0; - } - if (this.isIgnorable(line)) { - return 0; - } - - if (this.handleSectionHeader(lines, i)) { - return 1; // Eat line with === or --- - } - - const result = this.checkPreContent(lines, i); - if (this.state !== State.Default) { - return result; // Handle line in the new state - } - - line = this.cleanup(line); - line = line.replace(/``/g, '`'); // Convert double backticks to single. - line = this.escapeMarkdown(line); - this.md.push(line); - - return 0; - } - - private inPreformattedState(lines: string[], i: number): number { - let line = lines[i]; - if (this.isIgnorable(line)) { - return 0; - } - // Preformatted block terminates by a line without leading whitespace. - if (line.length > 0 && !isWhiteSpace(line.charCodeAt(0)) && !this.isListItem(line)) { - this.endPreformattedBlock(); - return -1; - } - - const prevLine = this.md.length > 0 ? this.md[this.md.length - 1] : undefined; - if (line.length === 0 && prevLine && (prevLine.length === 0 || prevLine.startsWith('```'))) { - return 0; // Avoid more than one empty line in a row. - } - - // Since we use HTML blocks as preformatted text - // make sure we drop angle brackets since otherwise - // they will render as tags and attributes - line = line.replace(//g, ' '); - line = line.replace(/``/g, '`'); // Convert double backticks to single. - // Keep hard line breaks for the preformatted content - this.md.push(`${line} `); - return 0; - } - - private inCodeState(line: string): void { - const prevLine = this.md.length > 0 ? this.md[this.md.length - 1] : undefined; - if (line.length === 0 && prevLine && (prevLine.length === 0 || prevLine.startsWith('```'))) { - return; // Avoid more than one empty line in a row. - } - - if (line.startsWith('```')) { - this.endCodeBlock(); - } else { - this.md.push(line); - } - } - - private isIgnorable(line: string): boolean { - if (line.indexOf('generated/') >= 0) { - return true; // Drop generated content. - } - const trimmed = line.trim(); - if (trimmed.startsWith('..') && trimmed.indexOf('::') > 0) { - // Ignore lines likes .. sectionauthor:: John Doe. - return true; - } - return false; - } - - private checkPreContent(lines: string[], i: number): number { - const line = lines[i]; - if (i === 0 || line.trim().length === 0) { - return 0; - } - - if (!isWhiteSpace(line.charCodeAt(0)) && !this.isListItem(line)) { - return 0; // regular line, nothing to do here. - } - // Indented content is considered to be preformatted. - this.startPreformattedBlock(); - return -1; - } - - private handleSectionHeader(lines: string[], i: number): boolean { - const line = lines[i]; - if (i < lines.length - 1 && lines[i + 1].startsWith('===')) { - // Section title -> heading level 3. - this.md.push(`### ${this.cleanup(line)}`); - return true; - } - if (i < lines.length - 1 && lines[i + 1].startsWith('---')) { - // Subsection title -> heading level 4. - this.md.push(`#### ${this.cleanup(line)}`); - return true; - } - return false; - } - - private handleDoubleColon(line: string): boolean { - if (!line.endsWith('::')) { - return false; - } - // Literal blocks begin with `::`. Such as sequence like - // '... as shown below::' that is followed by a preformatted text. - if (line.length > 2 && !line.startsWith('..')) { - // Ignore lines likes .. autosummary:: John Doe. - // Trim trailing : so :: turns into :. - this.md.push(line.substring(0, line.length - 1)); - } - - this.startPreformattedBlock(); - return true; - } - - private startPreformattedBlock(): void { - // Remove previous empty line so we avoid double empties. - this.tryRemovePrecedingEmptyLines(); - // Lie about the language since we don't want preformatted text - // to be colorized as Python. HTML is more 'appropriate' as it does - // not colorize -- or + or keywords like 'from'. - this.md.push('```html'); - this.state = State.Preformatted; - } - - private endPreformattedBlock(): void { - if (this.state === State.Preformatted) { - this.tryRemovePrecedingEmptyLines(); - this.md.push('```'); - this.state = State.Default; - } - } - - private startCodeBlock(): void { - // Remove previous empty line so we avoid double empties. - this.tryRemovePrecedingEmptyLines(); - this.md.push('```python'); - this.state = State.Code; - } - - private endCodeBlock(): void { - if (this.state === State.Code) { - this.tryRemovePrecedingEmptyLines(); - this.md.push('```'); - this.state = State.Default; - } - } - - private tryRemovePrecedingEmptyLines(): void { - while (this.md.length > 0 && this.md[this.md.length - 1].trim().length === 0) { - this.md.pop(); - } - } - - private isListItem(line: string): boolean { - const trimmed = line.trim(); - const ch = trimmed.length > 0 ? trimmed.charCodeAt(0) : 0; - return ch === Char.Asterisk || ch === Char.Hyphen || isDecimal(ch); - } - - private cleanup(line: string): string { - return line.replace(/:mod:/g, 'module:'); - } -} diff --git a/src/client/common/open.ts b/src/client/common/open.ts deleted file mode 100644 index 648cfa8029a..00000000000 --- a/src/client/common/open.ts +++ /dev/null @@ -1,85 +0,0 @@ -'use strict'; - -//https://github.com/sindresorhus/opn/blob/master/index.js -//Modified as this uses target as an argument - -import * as childProcess from 'child_process'; - -// tslint:disable:no-any no-function-expression prefer-template -export function open(opts: any): Promise { - // opts = objectAssign({wait: true}, opts); - if (!opts.hasOwnProperty('wait')) { - (opts).wait = true; - } - - let cmd; - let appArgs = []; - let args: string[] = []; - const cpOpts: any = {}; - if (opts.cwd && typeof opts.cwd === 'string' && opts.cwd.length > 0) { - cpOpts.cwd = opts.cwd; - } - if (opts.env && Object.keys(opts.env).length > 0) { - cpOpts.env = opts.env; - } - - if (Array.isArray(opts.app)) { - appArgs = opts.app.slice(1); - opts.app = opts.app[0]; - } - - if (process.platform === 'darwin') { - const sudoPrefix = opts.sudo === true ? 'sudo ' : ''; - cmd = 'osascript'; - args = [ - '-e', - 'tell application "terminal"', - '-e', - 'activate', - '-e', - 'do script "' + sudoPrefix + [opts.app].concat(appArgs).join(' ') + '"', - '-e', - 'end tell' - ]; - } else if (process.platform === 'win32') { - cmd = 'cmd'; - args.push('/c', 'start'); - - if (opts.wait) { - args.push('/wait'); - } - - if (opts.app) { - args.push(opts.app); - } - - if (appArgs.length > 0) { - args = args.concat(appArgs); - } - } else { - cmd = 'gnome-terminal'; - const sudoPrefix = opts.sudo === true ? 'sudo ' : ''; - args = ['-x', 'sh', '-c', `"${sudoPrefix}${opts.app}" ${appArgs.join(' ')}`]; - } - - const cp = childProcess.spawn(cmd, args, cpOpts); - - if (opts.wait) { - return new Promise(function (resolve, reject) { - cp.once('error', reject); - - cp.once('close', function (code) { - if (code > 0) { - reject(new Error(`Exited with code ${code}`)); - return; - } - - resolve(cp); - }); - }); - } - - cp.unref(); - - return Promise.resolve(cp); -} diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 27053b84191..5e2b6142ed7 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -8,7 +8,6 @@ import { CancellationToken, ConfigurationTarget, Disposable, - DocumentSymbolProvider, Event, Extension, ExtensionContext, @@ -23,8 +22,6 @@ import { InterpreterUri } from './installer/types'; import { EnvironmentVariables } from './variables/types'; export const IOutputChannel = Symbol('IOutputChannel'); export interface IOutputChannel extends OutputChannel {} -export const IDocumentSymbolProvider = Symbol('IDocumentSymbolProvider'); -export interface IDocumentSymbolProvider extends DocumentSymbolProvider {} export const IsWindows = Symbol('IS_WINDOWS'); export const IDisposableRegistry = Symbol('IDisposableRegistry'); export type IDisposableRegistry = Disposable[]; @@ -70,33 +67,7 @@ export enum InstallerResponse { Ignore } -export enum ProductType { - Linter = 'Linter', - Formatter = 'Formatter', - TestFramework = 'TestFramework', - RefactoringLibrary = 'RefactoringLibrary', - WorkspaceSymbols = 'WorkspaceSymbols', - DataScience = 'DataScience' -} - export enum Product { - pytest = 1, - nosetest = 2, - pylint = 3, - flake8 = 4, - pycodestyle = 5, - pylama = 6, - prospector = 7, - pydocstyle = 8, - yapf = 9, - autopep8 = 10, - mypy = 11, - unittest = 12, - ctags = 13, - rope = 14, - isort = 15, - black = 16, - bandit = 17, jupyter = 18, ipykernel = 19, notebook = 20, @@ -512,15 +483,3 @@ export type InspectInterpreterSettingType = { workspaceValue?: string; workspaceFolderValue?: string; }; - -/** - * Interface used to access current Interpreter Path - */ -export const IInterpreterPathService = Symbol('IInterpreterPathService'); -export interface IInterpreterPathService { - onDidChange: Event; - get(resource: Resource): string; - inspect(resource: Resource): InspectInterpreterSettingType; - update(resource: Resource, configTarget: ConfigurationTarget, value: string | undefined): Promise; - copyOldInterpreterStorageValuesToNew(resource: Uri | undefined): Promise; -} diff --git a/src/client/common/utils/text.ts b/src/client/common/utils/text.ts index 59359966db4..70316b244df 100644 --- a/src/client/common/utils/text.ts +++ b/src/client/common/utils/text.ts @@ -3,36 +3,9 @@ 'use strict'; -import { Position, Range, TextDocument } from 'vscode'; +import { Position, Range } from 'vscode'; import { isNumber } from './sysTypes'; -export function getWindowsLineEndingCount(document: TextDocument, offset: Number) { - //const eolPattern = new RegExp('\r\n', 'g'); - const eolPattern = /\r\n/g; - const readBlock = 1024; - let count = 0; - let offsetDiff = offset.valueOf(); - - // In order to prevent the one-time loading of large files from taking up too much memory - for (let pos = 0; pos < offset; pos += readBlock) { - const startAt = document.positionAt(pos); - - let endAt: Position; - if (offsetDiff >= readBlock) { - endAt = document.positionAt(pos + readBlock); - offsetDiff = offsetDiff - readBlock; - } else { - endAt = document.positionAt(pos + offsetDiff); - } - - const text = document.getText(new Range(startAt, endAt!)); - const cr = text.match(eolPattern); - - count += cr ? cr.length : 0; - } - return count; -} - /** * Return the range represented by the given string. * diff --git a/src/client/common/utils/workerPool.ts b/src/client/common/utils/workerPool.ts deleted file mode 100644 index 12bc2d32204..00000000000 --- a/src/client/common/utils/workerPool.ts +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { traceError } from '../logger'; -import { createDeferred, Deferred } from './async'; - -interface IWorker { - /** - * Start processing of items. - * @method stop - */ - start(): void; - /** - * Stops any further processing of items. - * @method stop - */ - stop(): void; -} - -type NextFunc = () => Promise; -type WorkFunc = (item: T) => Promise; -type PostResult = (item: T, result?: R, err?: Error) => void; - -interface IWorkItem { - item: T; -} - -export enum QueuePosition { - Back, - Front -} - -export interface IWorkerPool extends IWorker { - /** - * Add items to be processed to a queue. - * @method addToQueue - * @param {T} item: Item to process - * @param {QueuePosition} position: Add items to the front or back of the queue. - * @returns A promise that when resolved gets the result from running the worker function. - */ - addToQueue(item: T, position?: QueuePosition): Promise; -} - -class Worker implements IWorker { - private stopProcessing: boolean = false; - public constructor( - private readonly next: NextFunc, - private readonly workFunc: WorkFunc, - private readonly postResult: PostResult, - private readonly name: string - ) {} - public stop() { - this.stopProcessing = true; - } - - public async start() { - while (!this.stopProcessing) { - try { - const workItem = await this.next(); - try { - const result = await this.workFunc(workItem); - this.postResult(workItem, result); - } catch (ex) { - this.postResult(workItem, undefined, ex); - } - } catch (ex) { - // Next got rejected. Likely worker pool is shutting down. - // continue here and worker will exit if the worker pool is shutting down. - traceError(`Error while running worker[${this.name}].`, ex); - continue; - } - } - } -} - -class WorkQueue { - private readonly items: IWorkItem[] = []; - private readonly results: Map, Deferred> = new Map(); - public add(item: T, position?: QueuePosition): Promise { - // Wrap the user provided item in a wrapper object. This will allow us to track multiple - // submissions of the same item. For example, addToQueue(2), addToQueue(2). If we did not - // wrap this, then from the map both submissions will look the same. Since this is a generic - // worker pool, we do not know if we can resolve both using the same promise. So, a better - // approach is to ensure each gets a unique promise, and let the worker function figure out - // how to handle repeat submissions. - const workItem: IWorkItem = { item }; - if (position === QueuePosition.Front) { - this.items.unshift(workItem); - } else { - this.items.push(workItem); - } - - // This is the promise that will be resolved when the work - // item is complete. We save this in a map to resolve when - // the worker finishes and posts the result. - const deferred = createDeferred(); - this.results.set(workItem, deferred); - - return deferred.promise; - } - - public completed(workItem: IWorkItem, result?: R, error?: Error): void { - const deferred = this.results.get(workItem); - if (deferred !== undefined) { - this.results.delete(workItem); - if (error !== undefined) { - deferred.reject(error); - } - deferred.resolve(result); - } - } - - public next(): IWorkItem | undefined { - return this.items.shift(); - } - - public clear(): void { - this.results.forEach((v: Deferred, k: IWorkItem, map: Map, Deferred>) => { - v.reject(Error('Queue stopped processing')); - map.delete(k); - }); - } -} - -class WorkerPool implements IWorkerPool { - // This collection tracks the full set of workers. - private readonly workers: IWorker[] = []; - - // A collections that holds unblock callback for each worker waiting - // for a work item when the queue is empty - private readonly waitingWorkersUnblockQueue: { unblock(w: IWorkItem): void; stop(): void }[] = []; - - // A collection that manages the work items. - private readonly queue = new WorkQueue(); - - // State of the pool manages via stop(), start() - private stopProcessing = false; - - public constructor( - private readonly workerFunc: WorkFunc, - private readonly numWorkers: number = 2, - private readonly name: string = 'Worker' - ) {} - - public addToQueue(item: T, position?: QueuePosition): Promise { - if (this.stopProcessing) { - throw Error('Queue is stopped'); - } - - // This promise when resolved should return the processed result of the item - // being added to the queue. - const deferred = this.queue.add(item, position); - - const worker = this.waitingWorkersUnblockQueue.shift(); - if (worker) { - const workItem = this.queue.next(); - if (workItem !== undefined) { - // If we are here it means there were no items to process in the queue. - // At least one worker is free and waiting for a work item. Call 'unblock' - // and give the worker the newly added item. - worker.unblock(workItem); - } else { - // Something is wrong, we should not be here. we just added an item to - // the queue. It should not be empty. - traceError('Work queue was empty immediately after adding item.'); - } - } - - return deferred; - } - - public start() { - this.stopProcessing = false; - let num = this.numWorkers; - while (num > 0) { - this.workers.push( - new Worker, R>( - () => this.nextWorkItem(), - (workItem: IWorkItem) => this.workerFunc(workItem.item), - (workItem: IWorkItem, result?: R, error?: Error) => - this.queue.completed(workItem, result, error), - `${this.name} ${num}` - ) - ); - num = num - 1; - } - this.workers.forEach(async (w) => w.start()); - } - - public stop(): void { - this.stopProcessing = true; - - // Signal all registered workers with this worker pool to stop processing. - // Workers should complete the task they are currently doing. - let worker = this.workers.shift(); - while (worker) { - worker.stop(); - worker = this.workers.shift(); - } - - // Remove items from queue. - this.queue.clear(); - - // This is necessary to exit any worker that is waiting for an item. - // If we don't unblock here then the worker just remains blocked - // forever. - let blockedWorker = this.waitingWorkersUnblockQueue.shift(); - while (blockedWorker) { - blockedWorker.stop(); - blockedWorker = this.waitingWorkersUnblockQueue.shift(); - } - } - - public nextWorkItem(): Promise> { - // Note that next() will return `undefined` if the queue is empty. - const nextWorkItem = this.queue.next(); - if (nextWorkItem !== undefined) { - return Promise.resolve(nextWorkItem); - } - - // Queue is Empty, so return a promise that will be resolved when - // new items are added to the queue. - return new Promise>((resolve, reject) => { - this.waitingWorkersUnblockQueue.push({ - unblock: (workItem?: IWorkItem) => { - // This will be called to unblock any worker waiting for items. - if (this.stopProcessing) { - // We should reject here since the processing should be stopped. - reject(); - } - // If we are here, the queue received a new work item. Resolve with that item. - resolve(workItem); - }, - stop: () => { - reject(); - } - }); - }); - } -} - -export function createWorkerPool( - workerFunc: WorkFunc, - numWorkers: number = 2, - name: string = 'Worker' -): IWorkerPool { - const pool = new WorkerPool(workerFunc, numWorkers, name); - pool.start(); - return pool; -} diff --git a/src/client/constants.ts b/src/client/constants.ts index 55e22eb0e4e..4d3d9e31ae3 100644 --- a/src/client/constants.ts +++ b/src/client/constants.ts @@ -12,6 +12,5 @@ export const EXTENSION_ROOT_DIR = folderName === 'client' ? path.join(__dirname, '..', '..') : path.join(__dirname, '..', '..', '..', '..'); export const HiddenFileFormatString = '_HiddenFile_{0}.py'; -export const HiddenFilePrefix = '_HiddenFile_'; export const MillisecondsInADay = 24 * 60 * 60 * 1_000; diff --git a/src/client/language/braceCounter.ts b/src/client/language/braceCounter.ts deleted file mode 100644 index 30d91b53754..00000000000 --- a/src/client/language/braceCounter.ts +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { IToken, TokenType } from './types'; - -class BracePair { - public readonly openBrace: TokenType; - public readonly closeBrace: TokenType; - - constructor(openBrace: TokenType, closeBrace: TokenType) { - this.openBrace = openBrace; - this.closeBrace = closeBrace; - } -} - -class Stack { - private store: IToken[] = []; - public push(val: IToken) { - this.store.push(val); - } - public pop(): IToken | undefined { - return this.store.pop(); - } - public get length(): number { - return this.store.length; - } -} - -export class BraceCounter { - private readonly bracePairs: BracePair[] = [ - new BracePair(TokenType.OpenBrace, TokenType.CloseBrace), - new BracePair(TokenType.OpenBracket, TokenType.CloseBracket), - new BracePair(TokenType.OpenCurly, TokenType.CloseCurly) - ]; - private braceStacks: Stack[] = [new Stack(), new Stack(), new Stack()]; - - public get count(): number { - let c = 0; - for (const s of this.braceStacks) { - c += s.length; - } - return c; - } - - public isOpened(type: TokenType): boolean { - for (let i = 0; i < this.bracePairs.length; i += 1) { - const pair = this.bracePairs[i]; - if (pair.openBrace === type || pair.closeBrace === type) { - return this.braceStacks[i].length > 0; - } - } - return false; - } - - public countBrace(brace: IToken): boolean { - for (let i = 0; i < this.bracePairs.length; i += 1) { - const pair = this.bracePairs[i]; - if (pair.openBrace === brace.type) { - this.braceStacks[i].push(brace); - return true; - } - if (pair.closeBrace === brace.type) { - if (this.braceStacks[i].length > 0) { - this.braceStacks[i].pop(); - } - return true; - } - } - return false; - } -} diff --git a/src/client/language/characterStream.ts b/src/client/language/characterStream.ts deleted file mode 100644 index 09f3bed33f9..00000000000 --- a/src/client/language/characterStream.ts +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -'use strict'; - -// tslint:disable-next-line:import-name -import Char from 'typescript-char'; -import { isLineBreak, isWhiteSpace } from './characters'; -import { TextIterator } from './textIterator'; -import { ICharacterStream, ITextIterator } from './types'; - -export class CharacterStream implements ICharacterStream { - private text: ITextIterator; - private _position: number; - private _currentChar: number; - private _isEndOfStream: boolean; - - constructor(text: string | ITextIterator) { - this.text = typeof text === 'string' ? new TextIterator(text) : text; - this._position = 0; - this._currentChar = text.length > 0 ? text.charCodeAt(0) : 0; - this._isEndOfStream = text.length === 0; - } - - public getText(): string { - return this.text.getText(); - } - - public get position(): number { - return this._position; - } - - public set position(value: number) { - this._position = value; - this.checkBounds(); - } - - public get currentChar(): number { - return this._currentChar; - } - - public get nextChar(): number { - return this.position + 1 < this.text.length ? this.text.charCodeAt(this.position + 1) : 0; - } - - public get prevChar(): number { - return this.position - 1 >= 0 ? this.text.charCodeAt(this.position - 1) : 0; - } - - public isEndOfStream(): boolean { - return this._isEndOfStream; - } - - public lookAhead(offset: number): number { - const pos = this._position + offset; - return pos < 0 || pos >= this.text.length ? 0 : this.text.charCodeAt(pos); - } - - public advance(offset: number) { - this.position += offset; - } - - public moveNext(): boolean { - if (this._position < this.text.length - 1) { - // Most common case, no need to check bounds extensively - this._position += 1; - this._currentChar = this.text.charCodeAt(this._position); - return true; - } - this.advance(1); - return !this.isEndOfStream(); - } - - public isAtWhiteSpace(): boolean { - return isWhiteSpace(this.currentChar); - } - - public isAtLineBreak(): boolean { - return isLineBreak(this.currentChar); - } - - public skipLineBreak(): void { - if (this._currentChar === Char.CarriageReturn) { - this.moveNext(); - if (this.currentChar === Char.LineFeed) { - this.moveNext(); - } - } else if (this._currentChar === Char.LineFeed) { - this.moveNext(); - } - } - - public skipWhitespace(): void { - while (!this.isEndOfStream() && this.isAtWhiteSpace()) { - this.moveNext(); - } - } - - public skipToEol(): void { - while (!this.isEndOfStream() && !this.isAtLineBreak()) { - this.moveNext(); - } - } - - public skipToWhitespace(): void { - while (!this.isEndOfStream() && !this.isAtWhiteSpace()) { - this.moveNext(); - } - } - - public isAtString(): boolean { - return this.currentChar === Char.SingleQuote || this.currentChar === Char.DoubleQuote; - } - - public charCodeAt(index: number): number { - return this.text.charCodeAt(index); - } - - public get length(): number { - return this.text.length; - } - - private checkBounds(): void { - if (this._position < 0) { - this._position = 0; - } - - this._isEndOfStream = this._position >= this.text.length; - if (this._isEndOfStream) { - this._position = this.text.length; - } - - this._currentChar = this._isEndOfStream ? 0 : this.text.charCodeAt(this._position); - } -} diff --git a/src/client/language/characters.ts b/src/client/language/characters.ts deleted file mode 100644 index 50d5f716a03..00000000000 --- a/src/client/language/characters.ts +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// tslint:disable-next-line:import-name -import Char from 'typescript-char'; -import { getUnicodeCategory, UnicodeCategory } from './unicode'; - -export function isIdentifierStartChar(ch: number) { - switch (ch) { - // Underscore is explicitly allowed to start an identifier - case Char.Underscore: - return true; - // Characters with the Other_ID_Start property - case 0x1885: - case 0x1886: - case 0x2118: - case 0x212e: - case 0x309b: - case 0x309c: - return true; - default: - break; - } - - const cat = getUnicodeCategory(ch); - switch (cat) { - // Supported categories for starting an identifier - case UnicodeCategory.UppercaseLetter: - case UnicodeCategory.LowercaseLetter: - case UnicodeCategory.TitlecaseLetter: - case UnicodeCategory.ModifierLetter: - case UnicodeCategory.OtherLetter: - case UnicodeCategory.LetterNumber: - return true; - default: - break; - } - return false; -} - -export function isIdentifierChar(ch: number) { - if (isIdentifierStartChar(ch)) { - return true; - } - - switch (ch) { - // Characters with the Other_ID_Continue property - case 0x00b7: - case 0x0387: - case 0x1369: - case 0x136a: - case 0x136b: - case 0x136c: - case 0x136d: - case 0x136e: - case 0x136f: - case 0x1370: - case 0x1371: - case 0x19da: - return true; - default: - break; - } - - switch (getUnicodeCategory(ch)) { - // Supported categories for continuing an identifier - case UnicodeCategory.NonSpacingMark: - case UnicodeCategory.SpacingCombiningMark: - case UnicodeCategory.DecimalDigitNumber: - case UnicodeCategory.ConnectorPunctuation: - return true; - default: - break; - } - return false; -} - -export function isWhiteSpace(ch: number): boolean { - return ch <= Char.Space || ch === 0x200b; // Unicode whitespace -} - -export function isLineBreak(ch: number): boolean { - return ch === Char.CarriageReturn || ch === Char.LineFeed; -} - -export function isNumber(ch: number): boolean { - return (ch >= Char._0 && ch <= Char._9) || ch === Char.Underscore; -} - -export function isDecimal(ch: number): boolean { - return (ch >= Char._0 && ch <= Char._9) || ch === Char.Underscore; -} - -export function isHex(ch: number): boolean { - return isDecimal(ch) || (ch >= Char.a && ch <= Char.f) || (ch >= Char.A && ch <= Char.F) || ch === Char.Underscore; -} - -export function isOctal(ch: number): boolean { - return (ch >= Char._0 && ch <= Char._7) || ch === Char.Underscore; -} - -export function isBinary(ch: number): boolean { - return ch === Char._0 || ch === Char._1 || ch === Char.Underscore; -} diff --git a/src/client/language/iterableTextRange.ts b/src/client/language/iterableTextRange.ts deleted file mode 100644 index c69c62132e7..00000000000 --- a/src/client/language/iterableTextRange.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { ITextRange, ITextRangeCollection } from './types'; - -export class IterableTextRange implements Iterable { - constructor(private textRangeCollection: ITextRangeCollection) {} - public [Symbol.iterator](): Iterator { - let index = -1; - - return { - next: (): IteratorResult => { - if (index < this.textRangeCollection.count - 1) { - return { - done: false, - value: this.textRangeCollection.getItemAt((index += 1)) - }; - } else { - return { - done: true, - // tslint:disable-next-line:no-any - value: undefined as any - }; - } - } - }; - } -} diff --git a/src/client/language/textBuilder.ts b/src/client/language/textBuilder.ts deleted file mode 100644 index e11f2a1299c..00000000000 --- a/src/client/language/textBuilder.ts +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { isWhiteSpace } from './characters'; - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -export class TextBuilder { - private segments: string[] = []; - - public getText(): string { - if (this.isLastWhiteSpace()) { - this.segments.pop(); - } - return this.segments.join(''); - } - - public softAppendSpace(count: number = 1): void { - if (this.segments.length === 0) { - return; - } - if (this.isLastWhiteSpace()) { - count = count - 1; - } - for (let i = 0; i < count; i += 1) { - this.segments.push(' '); - } - } - - public append(text: string): void { - this.segments.push(text); - } - - private isLastWhiteSpace(): boolean { - return this.segments.length > 0 && this.isWhitespace(this.segments[this.segments.length - 1]); - } - - private isWhitespace(s: string): boolean { - for (let i = 0; i < s.length; i += 1) { - if (!isWhiteSpace(s.charCodeAt(i))) { - return false; - } - } - return true; - } -} diff --git a/src/client/language/textIterator.ts b/src/client/language/textIterator.ts deleted file mode 100644 index 6037cbf67cb..00000000000 --- a/src/client/language/textIterator.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -'use strict'; - -import { Position, Range, TextDocument } from 'vscode'; -import { ITextIterator } from './types'; - -export class TextIterator implements ITextIterator { - private text: string; - - constructor(text: string) { - this.text = text; - } - - public charCodeAt(index: number): number { - if (index >= 0 && index < this.text.length) { - return this.text.charCodeAt(index); - } - return 0; - } - - public get length(): number { - return this.text.length; - } - - public getText(): string { - return this.text; - } -} - -export class DocumentTextIterator implements ITextIterator { - public readonly length: number; - - private document: TextDocument; - - constructor(document: TextDocument) { - this.document = document; - - const lastIndex = this.document.lineCount - 1; - const lastLine = this.document.lineAt(lastIndex); - const end = new Position(lastIndex, lastLine.range.end.character); - this.length = this.document.offsetAt(end); - } - - public charCodeAt(index: number): number { - const position = this.document.positionAt(index); - return this.document.getText(new Range(position, position.translate(0, 1))).charCodeAt(position.character); - } - - public getText(): string { - return this.document.getText(); - } -} diff --git a/src/client/language/textRangeCollection.ts b/src/client/language/textRangeCollection.ts deleted file mode 100644 index 8ce5a744c9a..00000000000 --- a/src/client/language/textRangeCollection.ts +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -'use strict'; - -import { ITextRange, ITextRangeCollection } from './types'; - -export class TextRangeCollection implements ITextRangeCollection { - private items: T[]; - - constructor(items: T[]) { - this.items = items; - } - - public get start(): number { - return this.items.length > 0 ? this.items[0].start : 0; - } - - public get end(): number { - return this.items.length > 0 ? this.items[this.items.length - 1].end : 0; - } - - public get length(): number { - return this.end - this.start; - } - - public get count(): number { - return this.items.length; - } - - public contains(position: number) { - return position >= this.start && position < this.end; - } - - public getItemAt(index: number): T { - if (index < 0 || index >= this.items.length) { - throw new Error('index is out of range'); - } - return this.items[index] as T; - } - - public getItemAtPosition(position: number): number { - if (this.count === 0) { - return -1; - } - if (position < this.start) { - return -1; - } - if (position >= this.end) { - return -1; - } - - let min = 0; - let max = this.count - 1; - - while (min <= max) { - const mid = Math.floor(min + (max - min) / 2); - const item = this.items[mid]; - - if (item.start === position) { - return mid; - } - - if (position < item.start) { - max = mid - 1; - } else { - min = mid + 1; - } - } - return -1; - } - - public getItemContaining(position: number): number { - if (this.count === 0) { - return -1; - } - if (position < this.start) { - return -1; - } - if (position > this.end) { - return -1; - } - - let min = 0; - let max = this.count - 1; - - while (min <= max) { - const mid = Math.floor(min + (max - min) / 2); - const item = this.items[mid]; - - if (item.contains(position)) { - return mid; - } - if (mid < this.count - 1 && item.end <= position && position < this.items[mid + 1].start) { - return -1; - } - - if (position < item.start) { - max = mid - 1; - } else { - min = mid + 1; - } - } - return -1; - } -} diff --git a/src/client/language/tokenizer.ts b/src/client/language/tokenizer.ts deleted file mode 100644 index f51ceaa350c..00000000000 --- a/src/client/language/tokenizer.ts +++ /dev/null @@ -1,514 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -'use strict'; - -// tslint:disable-next-line:import-name -import Char from 'typescript-char'; -import { isBinary, isDecimal, isHex, isIdentifierChar, isIdentifierStartChar, isOctal } from './characters'; -import { CharacterStream } from './characterStream'; -import { TextRangeCollection } from './textRangeCollection'; -import { - ICharacterStream, - ITextRangeCollection, - IToken, - ITokenizer, - TextRange, - TokenizerMode, - TokenType -} from './types'; - -enum QuoteType { - None, - Single, - Double, - TripleSingle, - TripleDouble -} - -class Token extends TextRange implements IToken { - public readonly type: TokenType; - - constructor(type: TokenType, start: number, length: number) { - super(start, length); - this.type = type; - } -} - -export class Tokenizer implements ITokenizer { - private cs: ICharacterStream = new CharacterStream(''); - private tokens: IToken[] = []; - private mode = TokenizerMode.Full; - - public tokenize(text: string): ITextRangeCollection; - public tokenize(text: string, start: number, length: number, mode: TokenizerMode): ITextRangeCollection; - - public tokenize(text: string, start?: number, length?: number, mode?: TokenizerMode): ITextRangeCollection { - if (start === undefined) { - start = 0; - } else if (start < 0 || start >= text.length) { - throw new Error('Invalid range start'); - } - - if (length === undefined) { - length = text.length; - } else if (length < 0 || start + length > text.length) { - throw new Error('Invalid range length'); - } - - this.mode = mode !== undefined ? mode : TokenizerMode.Full; - - this.cs = new CharacterStream(text); - this.cs.position = start; - - const end = start + length; - while (!this.cs.isEndOfStream()) { - this.AddNextToken(); - if (this.cs.position >= end) { - break; - } - } - return new TextRangeCollection(this.tokens); - } - - private AddNextToken(): void { - this.cs.skipWhitespace(); - if (this.cs.isEndOfStream()) { - return; - } - - if (!this.handleCharacter()) { - this.cs.moveNext(); - } - } - - // tslint:disable-next-line:cyclomatic-complexity - private handleCharacter(): boolean { - // f-strings, b-strings, etc - const stringPrefixLength = this.getStringPrefixLength(); - if (stringPrefixLength >= 0) { - // Indeed a string - this.cs.advance(stringPrefixLength); - - const quoteType = this.getQuoteType(); - if (quoteType !== QuoteType.None) { - this.handleString(quoteType, stringPrefixLength); - return true; - } - } - if (this.cs.currentChar === Char.Hash) { - this.handleComment(); - return true; - } - if (this.mode === TokenizerMode.CommentsAndStrings) { - return false; - } - - switch (this.cs.currentChar) { - case Char.OpenParenthesis: - this.tokens.push(new Token(TokenType.OpenBrace, this.cs.position, 1)); - break; - case Char.CloseParenthesis: - this.tokens.push(new Token(TokenType.CloseBrace, this.cs.position, 1)); - break; - case Char.OpenBracket: - this.tokens.push(new Token(TokenType.OpenBracket, this.cs.position, 1)); - break; - case Char.CloseBracket: - this.tokens.push(new Token(TokenType.CloseBracket, this.cs.position, 1)); - break; - case Char.OpenBrace: - this.tokens.push(new Token(TokenType.OpenCurly, this.cs.position, 1)); - break; - case Char.CloseBrace: - this.tokens.push(new Token(TokenType.CloseCurly, this.cs.position, 1)); - break; - case Char.Comma: - this.tokens.push(new Token(TokenType.Comma, this.cs.position, 1)); - break; - case Char.Semicolon: - this.tokens.push(new Token(TokenType.Semicolon, this.cs.position, 1)); - break; - case Char.Colon: - this.tokens.push(new Token(TokenType.Colon, this.cs.position, 1)); - break; - default: - if (this.isPossibleNumber()) { - if (this.tryNumber()) { - return true; - } - } - if (this.cs.currentChar === Char.Period) { - this.tokens.push(new Token(TokenType.Operator, this.cs.position, 1)); - break; - } - if (!this.tryIdentifier()) { - if (!this.tryOperator()) { - this.handleUnknown(); - } - } - return true; - } - return false; - } - - private tryIdentifier(): boolean { - const start = this.cs.position; - if (isIdentifierStartChar(this.cs.currentChar)) { - this.cs.moveNext(); - while (isIdentifierChar(this.cs.currentChar)) { - this.cs.moveNext(); - } - } - if (this.cs.position > start) { - // const text = this.cs.getText().substr(start, this.cs.position - start); - // const type = this.keywords.find((value, index) => value === text) ? TokenType.Keyword : TokenType.Identifier; - this.tokens.push(new Token(TokenType.Identifier, start, this.cs.position - start)); - return true; - } - return false; - } - - // tslint:disable-next-line:cyclomatic-complexity - private isPossibleNumber(): boolean { - if (isDecimal(this.cs.currentChar)) { - return true; - } - - if (this.cs.currentChar === Char.Period && isDecimal(this.cs.nextChar)) { - return true; - } - - const next = this.cs.currentChar === Char.Hyphen || this.cs.currentChar === Char.Plus ? 1 : 0; - // Next character must be decimal or a dot otherwise - // it is not a number. No whitespace is allowed. - if (isDecimal(this.cs.lookAhead(next)) || this.cs.lookAhead(next) === Char.Period) { - // Check what previous token is, if any - if (this.tokens.length === 0) { - // At the start of the file this can only be a number - return true; - } - - const prev = this.tokens[this.tokens.length - 1]; - if ( - prev.type === TokenType.OpenBrace || - prev.type === TokenType.OpenBracket || - prev.type === TokenType.Comma || - prev.type === TokenType.Colon || - prev.type === TokenType.Semicolon || - prev.type === TokenType.Operator - ) { - return true; - } - } - - if (this.cs.lookAhead(next) === Char._0) { - const nextNext = this.cs.lookAhead(next + 1); - if (nextNext === Char.x || nextNext === Char.X) { - return true; - } - if (nextNext === Char.b || nextNext === Char.B) { - return true; - } - if (nextNext === Char.o || nextNext === Char.O) { - return true; - } - } - - return false; - } - - // tslint:disable-next-line:cyclomatic-complexity - private tryNumber(): boolean { - const start = this.cs.position; - let leadingSign = 0; - - if (this.cs.currentChar === Char.Hyphen || this.cs.currentChar === Char.Plus) { - this.cs.moveNext(); // Skip leading +/- - leadingSign = 1; - } - - if (this.cs.currentChar === Char._0) { - let radix = 0; - // Try hex => hexinteger: "0" ("x" | "X") (["_"] hexdigit)+ - if ((this.cs.nextChar === Char.x || this.cs.nextChar === Char.X) && isHex(this.cs.lookAhead(2))) { - this.cs.advance(2); - while (isHex(this.cs.currentChar)) { - this.cs.moveNext(); - } - radix = 16; - } - // Try binary => bininteger: "0" ("b" | "B") (["_"] bindigit)+ - if ((this.cs.nextChar === Char.b || this.cs.nextChar === Char.B) && isBinary(this.cs.lookAhead(2))) { - this.cs.advance(2); - while (isBinary(this.cs.currentChar)) { - this.cs.moveNext(); - } - radix = 2; - } - // Try octal => octinteger: "0" ("o" | "O") (["_"] octdigit)+ - if ((this.cs.nextChar === Char.o || this.cs.nextChar === Char.O) && isOctal(this.cs.lookAhead(2))) { - this.cs.advance(2); - while (isOctal(this.cs.currentChar)) { - this.cs.moveNext(); - } - radix = 8; - } - if (radix > 0) { - const text = this.cs.getText().substr(start + leadingSign, this.cs.position - start - leadingSign); - if (!isNaN(parseInt(text, radix))) { - this.tokens.push(new Token(TokenType.Number, start, text.length + leadingSign)); - return true; - } - } - } - - let decimal = false; - // Try decimal int => - // decinteger: nonzerodigit (["_"] digit)* | "0" (["_"] "0")* - // nonzerodigit: "1"..."9" - // digit: "0"..."9" - if (this.cs.currentChar >= Char._1 && this.cs.currentChar <= Char._9) { - while (isDecimal(this.cs.currentChar)) { - this.cs.moveNext(); - } - decimal = - this.cs.currentChar !== Char.Period && this.cs.currentChar !== Char.e && this.cs.currentChar !== Char.E; - } - - if (this.cs.currentChar === Char._0) { - // "0" (["_"] "0")* - while (this.cs.currentChar === Char._0 || this.cs.currentChar === Char.Underscore) { - this.cs.moveNext(); - } - decimal = - this.cs.currentChar !== Char.Period && this.cs.currentChar !== Char.e && this.cs.currentChar !== Char.E; - } - - if (decimal) { - const text = this.cs.getText().substr(start + leadingSign, this.cs.position - start - leadingSign); - if (!isNaN(parseInt(text, 10))) { - this.tokens.push(new Token(TokenType.Number, start, text.length + leadingSign)); - return true; - } - } - - // Floating point. Sign was already skipped over. - if ( - (this.cs.currentChar >= Char._0 && this.cs.currentChar <= Char._9) || - (this.cs.currentChar === Char.Period && this.cs.nextChar >= Char._0 && this.cs.nextChar <= Char._9) - ) { - if (this.skipFloatingPointCandidate(false)) { - const text = this.cs.getText().substr(start, this.cs.position - start); - if (!isNaN(parseFloat(text))) { - this.tokens.push(new Token(TokenType.Number, start, this.cs.position - start)); - return true; - } - } - } - - this.cs.position = start; - return false; - } - - // tslint:disable-next-line:cyclomatic-complexity - private tryOperator(): boolean { - let length = 0; - const nextChar = this.cs.nextChar; - switch (this.cs.currentChar) { - case Char.Plus: - case Char.Ampersand: - case Char.Bar: - case Char.Caret: - case Char.Equal: - case Char.ExclamationMark: - case Char.Percent: - case Char.Tilde: - length = nextChar === Char.Equal ? 2 : 1; - break; - - case Char.Hyphen: - length = nextChar === Char.Equal || nextChar === Char.Greater ? 2 : 1; - break; - - case Char.Asterisk: - if (nextChar === Char.Asterisk) { - length = this.cs.lookAhead(2) === Char.Equal ? 3 : 2; - } else { - length = nextChar === Char.Equal ? 2 : 1; - } - break; - - case Char.Slash: - if (nextChar === Char.Slash) { - length = this.cs.lookAhead(2) === Char.Equal ? 3 : 2; - } else { - length = nextChar === Char.Equal ? 2 : 1; - } - break; - - case Char.Less: - if (nextChar === Char.Greater) { - length = 2; - } else if (nextChar === Char.Less) { - length = this.cs.lookAhead(2) === Char.Equal ? 3 : 2; - } else { - length = nextChar === Char.Equal ? 2 : 1; - } - break; - - case Char.Greater: - if (nextChar === Char.Greater) { - length = this.cs.lookAhead(2) === Char.Equal ? 3 : 2; - } else { - length = nextChar === Char.Equal ? 2 : 1; - } - break; - - case Char.At: - length = nextChar === Char.Equal ? 2 : 1; - break; - - default: - return false; - } - this.tokens.push(new Token(TokenType.Operator, this.cs.position, length)); - this.cs.advance(length); - return length > 0; - } - - private handleUnknown(): boolean { - const start = this.cs.position; - this.cs.skipToWhitespace(); - const length = this.cs.position - start; - if (length > 0) { - this.tokens.push(new Token(TokenType.Unknown, start, length)); - return true; - } - return false; - } - - private handleComment(): void { - const start = this.cs.position; - this.cs.skipToEol(); - this.tokens.push(new Token(TokenType.Comment, start, this.cs.position - start)); - } - - // tslint:disable-next-line:cyclomatic-complexity - private getStringPrefixLength(): number { - if (this.cs.currentChar === Char.SingleQuote || this.cs.currentChar === Char.DoubleQuote) { - return 0; // Simple string, no prefix - } - - if (this.cs.nextChar === Char.SingleQuote || this.cs.nextChar === Char.DoubleQuote) { - switch (this.cs.currentChar) { - case Char.f: - case Char.F: - case Char.r: - case Char.R: - case Char.b: - case Char.B: - case Char.u: - case Char.U: - return 1; // single-char prefix like u"" or r"" - default: - break; - } - } - - if (this.cs.lookAhead(2) === Char.SingleQuote || this.cs.lookAhead(2) === Char.DoubleQuote) { - const prefix = this.cs.getText().substr(this.cs.position, 2).toLowerCase(); - switch (prefix) { - case 'rf': - case 'ur': - case 'br': - return 2; - default: - break; - } - } - return -1; - } - - private getQuoteType(): QuoteType { - if (this.cs.currentChar === Char.SingleQuote) { - return this.cs.nextChar === Char.SingleQuote && this.cs.lookAhead(2) === Char.SingleQuote - ? QuoteType.TripleSingle - : QuoteType.Single; - } - if (this.cs.currentChar === Char.DoubleQuote) { - return this.cs.nextChar === Char.DoubleQuote && this.cs.lookAhead(2) === Char.DoubleQuote - ? QuoteType.TripleDouble - : QuoteType.Double; - } - return QuoteType.None; - } - - private handleString(quoteType: QuoteType, stringPrefixLength: number): void { - const start = this.cs.position - stringPrefixLength; - if (quoteType === QuoteType.Single || quoteType === QuoteType.Double) { - this.cs.moveNext(); - this.skipToSingleEndQuote(quoteType === QuoteType.Single ? Char.SingleQuote : Char.DoubleQuote); - } else { - this.cs.advance(3); - this.skipToTripleEndQuote(quoteType === QuoteType.TripleSingle ? Char.SingleQuote : Char.DoubleQuote); - } - this.tokens.push(new Token(TokenType.String, start, this.cs.position - start)); - } - - private skipToSingleEndQuote(quote: number): void { - while (!this.cs.isEndOfStream()) { - if (this.cs.currentChar === Char.LineFeed || this.cs.currentChar === Char.CarriageReturn) { - return; // Unterminated single-line string - } - if (this.cs.currentChar === Char.Backslash && this.cs.nextChar === quote) { - this.cs.advance(2); - continue; - } - if (this.cs.currentChar === quote) { - break; - } - this.cs.moveNext(); - } - this.cs.moveNext(); - } - - private skipToTripleEndQuote(quote: number): void { - while ( - !this.cs.isEndOfStream() && - (this.cs.currentChar !== quote || this.cs.nextChar !== quote || this.cs.lookAhead(2) !== quote) - ) { - this.cs.moveNext(); - } - this.cs.advance(3); - } - - private skipFloatingPointCandidate(allowSign: boolean): boolean { - // Determine end of the potential floating point number - const start = this.cs.position; - this.skipFractionalNumber(allowSign); - if (this.cs.position > start) { - if (this.cs.currentChar === Char.e || this.cs.currentChar === Char.E) { - this.cs.moveNext(); // Optional exponent sign - } - this.skipDecimalNumber(true); // skip exponent value - } - return this.cs.position > start; - } - - private skipFractionalNumber(allowSign: boolean): void { - this.skipDecimalNumber(allowSign); - if (this.cs.currentChar === Char.Period) { - this.cs.moveNext(); // Optional period - } - this.skipDecimalNumber(false); - } - - private skipDecimalNumber(allowSign: boolean): void { - if (allowSign && (this.cs.currentChar === Char.Hyphen || this.cs.currentChar === Char.Plus)) { - this.cs.moveNext(); // Optional sign - } - while (isDecimal(this.cs.currentChar)) { - this.cs.moveNext(); // skip integer part - } - } -} diff --git a/src/client/language/types.ts b/src/client/language/types.ts deleted file mode 100644 index 51618039a3d..00000000000 --- a/src/client/language/types.ts +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -'use strict'; - -export interface ITextRange { - readonly start: number; - readonly end: number; - readonly length: number; - contains(position: number): boolean; -} - -export class TextRange implements ITextRange { - public static readonly empty = TextRange.fromBounds(0, 0); - - public readonly start: number; - public readonly length: number; - - constructor(start: number, length: number) { - if (start < 0) { - throw new Error('start must be non-negative'); - } - if (length < 0) { - throw new Error('length must be non-negative'); - } - this.start = start; - this.length = length; - } - - public static fromBounds(start: number, end: number) { - return new TextRange(start, end - start); - } - - public get end(): number { - return this.start + this.length; - } - - public contains(position: number): boolean { - return position >= this.start && position < this.end; - } -} - -export interface ITextRangeCollection extends ITextRange { - count: number; - getItemAt(index: number): T; - getItemAtPosition(position: number): number; - getItemContaining(position: number): number; -} - -export interface ITextIterator { - readonly length: number; - charCodeAt(index: number): number; - getText(): string; -} - -export interface ICharacterStream extends ITextIterator { - position: number; - readonly currentChar: number; - readonly nextChar: number; - readonly prevChar: number; - getText(): string; - isEndOfStream(): boolean; - lookAhead(offset: number): number; - advance(offset: number): void; - moveNext(): boolean; - isAtWhiteSpace(): boolean; - isAtLineBreak(): boolean; - isAtString(): boolean; - skipLineBreak(): void; - skipWhitespace(): void; - skipToEol(): void; - skipToWhitespace(): void; -} - -export enum TokenType { - Unknown, - String, - Comment, - Keyword, - Number, - Identifier, - Operator, - Colon, - Semicolon, - Comma, - OpenBrace, - CloseBrace, - OpenBracket, - CloseBracket, - OpenCurly, - CloseCurly -} - -export interface IToken extends ITextRange { - readonly type: TokenType; -} - -export enum TokenizerMode { - CommentsAndStrings, - Full -} - -export interface ITokenizer { - tokenize(text: string): ITextRangeCollection; - tokenize(text: string, start: number, length: number, mode: TokenizerMode): ITextRangeCollection; -} diff --git a/src/client/language/unicode.ts b/src/client/language/unicode.ts deleted file mode 100644 index 9b3ca0b15b2..00000000000 --- a/src/client/language/unicode.ts +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -'use strict'; - -// tslint:disable:no-require-imports no-var-requires - -export enum UnicodeCategory { - Unknown, - UppercaseLetter, - LowercaseLetter, - TitlecaseLetter, - ModifierLetter, - OtherLetter, - LetterNumber, - NonSpacingMark, - SpacingCombiningMark, - DecimalDigitNumber, - ConnectorPunctuation -} - -export function getUnicodeCategory(ch: number): UnicodeCategory { - const unicodeLu = require('unicode/category/Lu'); - const unicodeLl = require('unicode/category/Ll'); - const unicodeLt = require('unicode/category/Lt'); - const unicodeLo = require('unicode/category/Lo'); - const unicodeLm = require('unicode/category/Lm'); - const unicodeNl = require('unicode/category/Nl'); - const unicodeMn = require('unicode/category/Mn'); - const unicodeMc = require('unicode/category/Mc'); - const unicodeNd = require('unicode/category/Nd'); - const unicodePc = require('unicode/category/Pc'); - - if (unicodeLu[ch]) { - return UnicodeCategory.UppercaseLetter; - } - if (unicodeLl[ch]) { - return UnicodeCategory.LowercaseLetter; - } - if (unicodeLt[ch]) { - return UnicodeCategory.TitlecaseLetter; - } - if (unicodeLo[ch]) { - return UnicodeCategory.OtherLetter; - } - if (unicodeLm[ch]) { - return UnicodeCategory.ModifierLetter; - } - if (unicodeNl[ch]) { - return UnicodeCategory.LetterNumber; - } - if (unicodeMn[ch]) { - return UnicodeCategory.NonSpacingMark; - } - if (unicodeMc[ch]) { - return UnicodeCategory.SpacingCombiningMark; - } - if (unicodeNd[ch]) { - return UnicodeCategory.DecimalDigitNumber; - } - if (unicodePc[ch]) { - return UnicodeCategory.ConnectorPunctuation; - } - return UnicodeCategory.Unknown; -} diff --git a/src/client/refactor/proxy.ts b/src/client/refactor/proxy.ts deleted file mode 100644 index 94bc5cba1b7..00000000000 --- a/src/client/refactor/proxy.ts +++ /dev/null @@ -1,209 +0,0 @@ -// tslint:disable:no-any no-empty member-ordering prefer-const prefer-template no-var-self - -import { ChildProcess } from 'child_process'; -import { Disposable, Position, Range, TextDocument, TextEditorOptions, window } from 'vscode'; -import '../common/extensions'; -import { traceError } from '../common/logger'; -import { IS_WINDOWS } from '../common/platform/constants'; -import * as internalScripts from '../common/process/internal/scripts'; -import { IPythonExecutionService } from '../common/process/types'; -import { createDeferred, Deferred } from '../common/utils/async'; -import { getWindowsLineEndingCount } from '../common/utils/text'; - -export class RefactorProxy extends Disposable { - private _process?: ChildProcess; - private _previousOutData: string = ''; - private _previousStdErrData: string = ''; - private _startedSuccessfully: boolean = false; - private _commandResolve?: (value?: any | PromiseLike) => void; - private _commandReject!: (reason?: any) => void; - private initialized!: Deferred; - constructor( - private workspaceRoot: string, - private getPythonExecutionService: () => Promise - ) { - super(() => {}); - } - - public dispose() { - try { - this._process!.kill(); - } catch (ex) {} - this._process = undefined; - } - private getOffsetAt(document: TextDocument, position: Position): number { - if (!IS_WINDOWS) { - return document.offsetAt(position); - } - - // get line count - // Rope always uses LF, instead of CRLF on windows, funny isn't it - // So for each line, reduce one characer (for CR) - // But Not all Windows users use CRLF - const offset = document.offsetAt(position); - const winEols = getWindowsLineEndingCount(document, offset); - - return offset - winEols; - } - public rename( - document: TextDocument, - name: string, - filePath: string, - range: Range, - options?: TextEditorOptions - ): Promise { - if (!options) { - options = window.activeTextEditor!.options; - } - const command = { - lookup: 'rename', - file: filePath, - start: this.getOffsetAt(document, range.start).toString(), - id: '1', - name: name, - indent_size: options.tabSize - }; - - return this.sendCommand(JSON.stringify(command)); - } - public extractVariable( - document: TextDocument, - name: string, - filePath: string, - range: Range, - options?: TextEditorOptions - ): Promise { - if (!options) { - options = window.activeTextEditor!.options; - } - const command = { - lookup: 'extract_variable', - file: filePath, - start: this.getOffsetAt(document, range.start).toString(), - end: this.getOffsetAt(document, range.end).toString(), - id: '1', - name: name, - indent_size: options.tabSize - }; - return this.sendCommand(JSON.stringify(command)); - } - public extractMethod( - document: TextDocument, - name: string, - filePath: string, - range: Range, - options?: TextEditorOptions - ): Promise { - if (!options) { - options = window.activeTextEditor!.options; - } - // Ensure last line is an empty line - if ( - !document.lineAt(document.lineCount - 1).isEmptyOrWhitespace && - range.start.line === document.lineCount - 1 - ) { - return Promise.reject('Missing blank line at the end of document (PEP8).'); - } - const command = { - lookup: 'extract_method', - file: filePath, - start: this.getOffsetAt(document, range.start).toString(), - end: this.getOffsetAt(document, range.end).toString(), - id: '1', - name: name, - indent_size: options.tabSize - }; - return this.sendCommand(JSON.stringify(command)); - } - private sendCommand(command: string): Promise { - return this.initialize().then(() => { - // tslint:disable-next-line:promise-must-complete - return new Promise((resolve, reject) => { - this._commandResolve = resolve; - this._commandReject = reject; - this._process!.stdin.write(command + '\n'); - }); - }); - } - private async initialize(): Promise { - const pythonProc = await this.getPythonExecutionService(); - this.initialized = createDeferred(); - const [args, parse] = internalScripts.refactor(this.workspaceRoot); - const result = pythonProc.execObservable(args, {}); - this._process = result.proc; - result.out.subscribe( - (output) => { - if (output.source === 'stdout') { - if (!this._startedSuccessfully && output.out.startsWith('STARTED')) { - this._startedSuccessfully = true; - return this.initialized.resolve(); - } - this.onData(output.out, parse); - } else { - this.handleStdError(output.out); - } - }, - (error) => this.handleError(error) - ); - - return this.initialized.promise; - } - private handleStdError(data: string) { - // Possible there was an exception in parsing the data returned - // So append the data then parse it - let dataStr = (this._previousStdErrData = this._previousStdErrData + data + ''); - let errorResponse: { message: string; traceback: string; type: string }[]; - try { - errorResponse = dataStr - .split(/\r?\n/g) - .filter((line) => line.length > 0) - .map((resp) => JSON.parse(resp)); - this._previousStdErrData = ''; - } catch (ex) { - traceError(ex); - // Possible we've only received part of the data, hence don't clear previousData - return; - } - if (typeof errorResponse[0].message !== 'string' || errorResponse[0].message.length === 0) { - errorResponse[0].message = errorResponse[0].traceback.splitLines().pop()!; - } - let errorMessage = errorResponse[0].message + '\n' + errorResponse[0].traceback; - - if (this._startedSuccessfully) { - this._commandReject(`Refactor failed. ${errorMessage}`); - } else { - if (typeof errorResponse[0].type === 'string' && errorResponse[0].type === 'ModuleNotFoundError') { - this.initialized.reject('Not installed'); - return; - } - - this.initialized.reject(`Refactor failed. ${errorMessage}`); - } - } - private handleError(error: Error) { - if (this._startedSuccessfully) { - return this._commandReject(error); - } - this.initialized.reject(error); - } - private onData(data: string, parse: (out: string) => object[]) { - if (!this._commandResolve) { - return; - } - - // Possible there was an exception in parsing the data returned - // So append the data then parse it - let dataStr = (this._previousOutData = this._previousOutData + data + ''); - let response: any; - try { - response = parse(dataStr); - this._previousOutData = ''; - } catch (ex) { - // Possible we've only received part of the data, hence don't clear previousData - return; - } - this.dispose(); - this._commandResolve!(response[0]); - this._commandResolve = undefined; - } -} diff --git a/src/client/telemetry/constants.ts b/src/client/telemetry/constants.ts index 369672263a4..6de1c754322 100644 --- a/src/client/telemetry/constants.ts +++ b/src/client/telemetry/constants.ts @@ -4,77 +4,24 @@ 'use strict'; export enum EventName { - COMPLETION = 'COMPLETION', - COMPLETION_ADD_BRACKETS = 'COMPLETION.ADD_BRACKETS', - DEFINITION = 'DEFINITION', - HOVER_DEFINITION = 'HOVER_DEFINITION', - REFERENCE = 'REFERENCE', - SIGNATURE = 'SIGNATURE', - SYMBOL = 'SYMBOL', - FORMAT_SORT_IMPORTS = 'FORMAT.SORT_IMPORTS', - FORMAT = 'FORMAT.FORMAT', - FORMAT_ON_TYPE = 'FORMAT.FORMAT_ON_TYPE', EDITOR_LOAD = 'EDITOR.LOAD', - LINTING = 'LINTING', - GO_TO_OBJECT_DEFINITION = 'GO_TO_OBJECT_DEFINITION', - REFACTOR_RENAME = 'REFACTOR_RENAME', - REFACTOR_EXTRACT_VAR = 'REFACTOR_EXTRACT_VAR', - REFACTOR_EXTRACT_FUNCTION = 'REFACTOR_EXTRACT_FUNCTION', - REPL = 'REPL', PYTHON_INTERPRETER_ACTIVATION_ENVIRONMENT_VARIABLES = 'PYTHON_INTERPRETER_ACTIVATION_ENVIRONMENT_VARIABLES', INSIDERS_RELOAD_PROMPT = 'INSIDERS_RELOAD_PROMPT', INSIDERS_PROMPT = 'INSIDERS_PROMPT', ENVFILE_VARIABLE_SUBSTITUTION = 'ENVFILE_VARIABLE_SUBSTITUTION', ENVFILE_WORKSPACE = 'ENVFILE_WORKSPACE', - WORKSPACE_SYMBOLS_BUILD = 'WORKSPACE_SYMBOLS.BUILD', - WORKSPACE_SYMBOLS_GO_TO = 'WORKSPACE_SYMBOLS.GO_TO', - EXECUTION_CODE = 'EXECUTION_CODE', - EXECUTION_DJANGO = 'EXECUTION_DJANGO', PYTHON_EXPERIMENTS = 'PYTHON_EXPERIMENTS', PYTHON_EXPERIMENTS_DISABLED = 'PYTHON_EXPERIMENTS_DISABLED', PYTHON_EXPERIMENTS_OPT_IN_OUT = 'PYTHON_EXPERIMENTS_OPT_IN_OUT', PYTHON_EXPERIMENTS_DOWNLOAD_SUCCESS_RATE = 'PYTHON_EXPERIMENTS_DOWNLOAD_SUCCESS_RATE', - PLAY_BUTTON_ICON_DISABLED = 'PLAY_BUTTON_ICON.DISABLED', EXTENSION_SURVEY_PROMPT = 'EXTENSION_SURVEY_PROMPT', - ACTIVATION_TIP_PROMPT = 'ACTIVATION_TIP_PROMPT', - ACTIVATION_SURVEY_PROMPT = 'ACTIVATION_SURVEY_PROMPT', JOIN_MAILING_LIST_PROMPT = 'JOIN_MAILING_LIST_PROMPT', - PYTHON_LANGUAGE_SERVER_CURRENT_SELECTION = 'PYTHON_LANGUAGE_SERVER_CURRENT_SELECTION', - PYTHON_LANGUAGE_SERVER_LIST_BLOB_STORE_PACKAGES = 'PYTHON_LANGUAGE_SERVER.LIST_BLOB_PACKAGES', - PYTHON_LANGUAGE_SERVER_EXTRACTED = 'PYTHON_LANGUAGE_SERVER.EXTRACTED', - PYTHON_LANGUAGE_SERVER_DOWNLOADED = 'PYTHON_LANGUAGE_SERVER.DOWNLOADED', - PYTHON_LANGUAGE_SERVER_ERROR = 'PYTHON_LANGUAGE_SERVER.ERROR', - - PYTHON_LANGUAGE_SERVER_PLATFORM_SUPPORTED = 'PYTHON_LANGUAGE_SERVER.PLATFORM_SUPPORTED', - PYTHON_LANGUAGE_SERVER_ENABLED = 'PYTHON_LANGUAGE_SERVER.ENABLED', - PYTHON_LANGUAGE_SERVER_STARTUP = 'PYTHON_LANGUAGE_SERVER.STARTUP', - PYTHON_LANGUAGE_SERVER_READY = 'PYTHON_LANGUAGE_SERVER.READY', - PYTHON_LANGUAGE_SERVER_TELEMETRY = 'PYTHON_LANGUAGE_SERVER.EVENT', - PYTHON_LANGUAGE_SERVER_REQUEST = 'PYTHON_LANGUAGE_SERVER.REQUEST', - - LANGUAGE_SERVER_ENABLED = 'LANGUAGE_SERVER.ENABLED', - LANGUAGE_SERVER_STARTUP = 'LANGUAGE_SERVER.STARTUP', - LANGUAGE_SERVER_READY = 'LANGUAGE_SERVER.READY', - LANGUAGE_SERVER_TELEMETRY = 'LANGUAGE_SERVER.EVENT', - LANGUAGE_SERVER_REQUEST = 'LANGUAGE_SERVER.REQUEST', - LANGUAGE_SERVER_TRY_PYLANCE = 'LANGUAGE_SERVER.TRY_PYLANCE', - - TERMINAL_CREATE = 'TERMINAL.CREATE', - ACTIVATE_ENV_IN_CURRENT_TERMINAL = 'ACTIVATE_ENV_IN_CURRENT_TERMINAL', - ACTIVATE_ENV_TO_GET_ENV_VARS_FAILED = 'ACTIVATE_ENV_TO_GET_ENV_VARS_FAILED', DIAGNOSTICS_ACTION = 'DIAGNOSTICS.ACTION', DIAGNOSTICS_MESSAGE = 'DIAGNOSTICS.MESSAGE', PLATFORM_INFO = 'PLATFORM.INFO', - - SELECT_LINTER = 'LINTING.SELECT', - - LINTER_NOT_INSTALLED_PROMPT = 'LINTER_NOT_INSTALLED_PROMPT', - CONFIGURE_AVAILABLE_LINTER_PROMPT = 'CONFIGURE_AVAILABLE_LINTER_PROMPT', HASHED_PACKAGE_NAME = 'HASHED_PACKAGE_NAME', - HASHED_PACKAGE_PERF = 'HASHED_PACKAGE_PERF', - - JEDI_MEMORY = 'JEDI_MEMORY' + HASHED_PACKAGE_PERF = 'HASHED_PACKAGE_PERF' } export enum PlatformErrors { diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index b28978df31b..1613c4432a5 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -332,24 +332,6 @@ export interface ISharedPropertyMapping { // Map all events to their properties export interface IEventNamePropertyMapping { - /** - * Telemetry event sent when providing completion items for the given position and document. - */ - [EventName.COMPLETION]: never | undefined; - /** - * Telemetry event sent with details 'python.autoComplete.addBrackets' setting - */ - [EventName.COMPLETION_ADD_BRACKETS]: { - /** - * Carries boolean `true` if 'python.autoComplete.addBrackets' is set to true, `false` otherwise - */ - enabled: boolean; - }; - /** - * Telemetry is sent when providing definitions for python code, particularly when [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition) - * and peek definition features are used. - */ - [EventName.DEFINITION]: never | undefined; /** * Telemetry event sent with details of actions when invoking a diagnostic command */ @@ -407,79 +389,6 @@ export interface IEventNamePropertyMapping { */ hasCustomEnvPath: boolean; }; - /** - * Telemetry Event sent when user sends code to be executed in the terminal. - * - */ - [EventName.EXECUTION_CODE]: { - /** - * Whether the user executed a file in the terminal or just the selected text. - * - * @type {('file' | 'selection')} - */ - scope: 'file' | 'selection'; - /** - * How was the code executed (through the command or by clicking the `Run File` icon). - * - * @type {('command' | 'icon')} - */ - trigger?: 'command' | 'icon'; - }; - /** - * Telemetry Event sent when user executes code against Django Shell. - * Values sent: - * scope - * - */ - [EventName.EXECUTION_DJANGO]: { - /** - * If `file`, then the file was executed in the django shell. - * If `selection`, then the selected text was sent to the django shell. - * - * @type {('file' | 'selection')} - */ - scope: 'file' | 'selection'; - }; - /** - * Telemetry event sent with details when formatting a document - */ - [EventName.FORMAT]: { - /** - * Tool being used to format - */ - tool: 'autopep8' | 'black' | 'yapf'; - /** - * If arguments for formatter is provided in resource settings - */ - hasCustomArgs: boolean; - /** - * Carries `true` when formatting a selection of text, `false` otherwise - */ - formatSelection: boolean; - }; - /** - * Telemetry event sent with the value of setting 'Format on type' - */ - [EventName.FORMAT_ON_TYPE]: { - /** - * Carries `true` if format on type is enabled, `false` otherwise - * - * @type {boolean} - */ - enabled: boolean; - }; - /** - * Telemetry event sent when sorting imports using formatter - */ - [EventName.FORMAT_SORT_IMPORTS]: never | undefined; - /** - * Telemetry event sent when Go to Python object command is executed - */ - [EventName.GO_TO_OBJECT_DEFINITION]: never | undefined; - /** - * Telemetry event sent when providing a hover for the given position and document for interactive window using Jedi. - */ - [EventName.HOVER_DEFINITION]: never | undefined; /** * Telemetry event sent with details when tracking imports */ @@ -532,15 +441,6 @@ export interface IEventNamePropertyMapping { */ osVersion?: string; }; - /** - * Telemetry is sent with details about the play run file icon - */ - [EventName.PLAY_BUTTON_ICON_DISABLED]: { - /** - * Carries `true` if play button icon is not shown (because code runner is installed), `false` otherwise - */ - disabled: boolean; - }; [EventName.PYTHON_INTERPRETER_ACTIVATION_ENVIRONMENT_VARIABLES]: { /** * Carries `true` if environment variables are present, `false` otherwise @@ -593,105 +493,6 @@ export interface IEventNamePropertyMapping { */ selection: 'Reload' | undefined; }; - /** - * Telemetry event sent with details after attempting to download LS - */ - [EventName.PYTHON_LANGUAGE_SERVER_DOWNLOADED]: { - /** - * Whether LS downloading succeeds - */ - success: boolean; - /** - * Version of LS downloaded - */ - lsVersion?: string; - /** - * Whether download uri starts with `https:` or not - */ - usedSSL?: boolean; - - /** - * Name of LS downloaded - */ - lsName?: string; - }; - /** - * Telemetry event sent when LS is started for workspace (workspace folder in case of multi-root) - */ - [EventName.PYTHON_LANGUAGE_SERVER_ENABLED]: { - lsVersion?: string; - }; - /** - * Telemetry event sent with details when downloading or extracting LS fails - */ - [EventName.PYTHON_LANGUAGE_SERVER_ERROR]: { - /** - * The error associated with initializing language server - */ - error: string; - }; - /** - * Telemetry event sent with details after attempting to extract LS - */ - [EventName.PYTHON_LANGUAGE_SERVER_EXTRACTED]: { - /** - * Whether LS extracting succeeds - */ - success: boolean; - /** - * Version of LS extracted - */ - lsVersion?: string; - /** - * Whether download uri starts with `https:` or not - */ - usedSSL?: boolean; - /** - * Package name of LS extracted - */ - lsName?: string; - }; - /** - * Telemetry event sent if azure blob packages are being listed - */ - [EventName.PYTHON_LANGUAGE_SERVER_LIST_BLOB_STORE_PACKAGES]: never | undefined; - /** - * Tracks if LS is supported on platform or not - */ - [EventName.PYTHON_LANGUAGE_SERVER_PLATFORM_SUPPORTED]: { - /** - * Carries `true` if LS is supported, `false` otherwise - * - * @type {boolean} - */ - supported: boolean; - /** - * If checking support for LS failed - * - * @type {'UnknownError'} - */ - failureType?: 'UnknownError'; - }; - /** - * Telemetry event sent when LS is ready to start - */ - [EventName.PYTHON_LANGUAGE_SERVER_READY]: { - lsVersion?: string; - }; - /** - * Telemetry event sent when starting LS - */ - [EventName.PYTHON_LANGUAGE_SERVER_STARTUP]: { - lsVersion?: string; - }; - /** - * Telemetry sent from language server (details of telemetry sent can be provided by LS team) - */ - [EventName.PYTHON_LANGUAGE_SERVER_TELEMETRY]: any; - /** - * Telemetry sent when the client makes a request to the language server - */ - [EventName.PYTHON_LANGUAGE_SERVER_REQUEST]: any; /** * Telemetry event sent with details when inExperiment() API is called */ @@ -734,42 +535,6 @@ export interface IEventNamePropertyMapping { */ error?: string; }; - /** - * Telemetry event sent when LS is started for workspace (workspace folder in case of multi-root) - */ - [EventName.LANGUAGE_SERVER_ENABLED]: { - lsVersion?: string; - }; - /** - * Telemetry event sent when Node.js server is ready to start - */ - [EventName.LANGUAGE_SERVER_READY]: { - lsVersion?: string; - }; - /** - * Telemetry event sent when starting Node.js server - */ - [EventName.LANGUAGE_SERVER_STARTUP]: { - lsVersion?: string; - }; - /** - * Telemetry sent from Node.js server (details of telemetry sent can be provided by LS team) - */ - [EventName.LANGUAGE_SERVER_TELEMETRY]: any; - /** - * Telemetry sent when the client makes a request to the Node.js server - */ - [EventName.LANGUAGE_SERVER_REQUEST]: any; - /** - * Telemetry sent on user response to 'Try Pylance' prompt. - */ - [EventName.LANGUAGE_SERVER_TRY_PYLANCE]: { - /** - * User response to the prompt. - * @type {string} - */ - userAction: string; - }; /** * When user clicks a button in the python extension survey prompt, this telemetry event is sent with details */ @@ -779,14 +544,6 @@ export interface IEventNamePropertyMapping { */ selection: 'Yes' | 'Maybe later' | 'Do not show again' | undefined; }; - /** - * Telemetry event sent when the Python interpreter tip is shown on activation for new users. - */ - [EventName.ACTIVATION_TIP_PROMPT]: never | undefined; - /** - * Telemetry event sent when the feedback survey prompt is shown on activation for new users, and they click on the survey link. - */ - [EventName.ACTIVATION_SURVEY_PROMPT]: never | undefined; /** * Telemetry sent back when join mailing list prompt is shown. */ @@ -796,63 +553,6 @@ export interface IEventNamePropertyMapping { */ selection: 'Yes' | 'No' | undefined; }; - /** - * Telemetry event sent when 'Extract Method' command is invoked - */ - [EventName.REFACTOR_EXTRACT_FUNCTION]: never | undefined; - /** - * Telemetry event sent when 'Extract Variable' command is invoked - */ - [EventName.REFACTOR_EXTRACT_VAR]: never | undefined; - /** - * Telemetry event sent when providing an edit that describes changes to rename a symbol to a different name - */ - [EventName.REFACTOR_RENAME]: never | undefined; - /** - * Telemetry event sent when providing a set of project-wide references for the given position and document - */ - [EventName.REFERENCE]: never | undefined; - /** - * Telemetry event sent when starting REPL - */ - [EventName.REPL]: never | undefined; - /** - * Telemetry event sent when providing help for the signature at the given position and document. - */ - [EventName.SIGNATURE]: never | undefined; - /** - * Telemetry event sent when providing document symbol information for Jedi autocomplete intellisense - */ - [EventName.SYMBOL]: never | undefined; - /** - * Telemetry event sent when the extension is activated, if an active terminal is present and - * the `python.terminal.activateEnvInCurrentTerminal` setting is set to `true`. - */ - [EventName.ACTIVATE_ENV_IN_CURRENT_TERMINAL]: { - /** - * Carries boolean `true` if an active terminal is present (terminal is visible), `false` otherwise - */ - isTerminalVisible?: boolean; - }; - /** - * Telemetry event sent with details when a terminal is created - */ - [EventName.TERMINAL_CREATE]: { - /** - * The default Python interpreter version to be used in terminal, inferred from resource's 'settings.json' - * - * @type {string} - */ - pythonVersion?: string; - }; - /** - * Telemetry sent when building workspace symbols - */ - [EventName.WORKSPACE_SYMBOLS_BUILD]: never | undefined; - /** - * Telemetry sent when providing workspace symbols doing Project-wide search for a symbol matching the given query string - */ - [EventName.WORKSPACE_SYMBOLS_GO_TO]: never | undefined; // Data Science [Telemetry.AddCellBelow]: never | undefined; [Telemetry.CodeLensAverageAcquisitionTime]: never | undefined; @@ -1076,28 +776,6 @@ export interface IEventNamePropertyMapping { [NativeMouseCommandTelemetry.SelectKernel]: never | undefined; [NativeMouseCommandTelemetry.SelectServer]: never | undefined; [NativeMouseCommandTelemetry.ToggleVariableExplorer]: never | undefined; - /* - Telemetry event sent with details of Jedi Memory usage. - mem_use - Memory usage of Process in kb. - limit - Upper bound for memory usage of Jedi process. - isUserDefinedLimit - Whether the user has configfured the upper bound limit. - restart - Whether to restart the Jedi Process (i.e. memory > limit). - */ - [EventName.JEDI_MEMORY]: { mem_use: number; limit: number; isUserDefinedLimit: boolean; restart: boolean }; - /** - * Telemetry event sent when getting environment variables for an activated environment has failed. - * - * @type {(undefined | never)} - * @memberof IEventNamePropertyMapping - */ - [EventName.ACTIVATE_ENV_TO_GET_ENV_VARS_FAILED]: { - /** - * Whether the activation commands contain the name `conda`. - * - * @type {boolean} - */ - isPossiblyCondaEnv: boolean; - }; /** * Telemetry event sent once done searching for kernel spec and interpreter for a local connection. * diff --git a/src/client/telemetry/types.ts b/src/client/telemetry/types.ts index fa7aefc7070..97d601eb5de 100644 --- a/src/client/telemetry/types.ts +++ b/src/client/telemetry/types.ts @@ -6,8 +6,5 @@ import { IEventNamePropertyMapping } from '../telemetry/index'; import { EventName } from './constants'; export type EditorLoadTelemetry = IEventNamePropertyMapping[EventName.EDITOR_LOAD]; -export type ImportNotebook = { - scope: 'command'; -}; export const IImportTracker = Symbol('IImportTracker'); export interface IImportTracker {} diff --git a/src/client/testing/common/constants.ts b/src/client/testing/common/constants.ts index e2b3c0b354a..be4bc56b633 100644 --- a/src/client/testing/common/constants.ts +++ b/src/client/testing/common/constants.ts @@ -1,16 +1,6 @@ -export const CANCELLATION_REASON = 'cancelled_user_request'; export enum CommandSource { auto = 'auto', ui = 'ui', codelens = 'codelens', - commandPalette = 'commandpalette', - testExplorer = 'testExplorer' -} -export const TEST_OUTPUT_CHANNEL = 'TEST_OUTPUT_CHANNEL'; - -export enum Icons { - discovering = 'discovering-tests.svg', - passed = 'status-ok.svg', - failed = 'status-error.svg', - unknown = 'status-unknown.svg' + commandPalette = 'commandpalette' } diff --git a/src/test/common/configuration/service.unit.test.ts b/src/test/common/configuration/service.unit.test.ts index 4dcbeaa1522..e17a1efbcdd 100644 --- a/src/test/common/configuration/service.unit.test.ts +++ b/src/test/common/configuration/service.unit.test.ts @@ -9,13 +9,12 @@ import { ConfigurationTarget, Uri, WorkspaceConfiguration } from 'vscode'; import { IWorkspaceService } from '../../../client/common/application/types'; import { JupyterSettings } from '../../../client/common/configSettings'; import { ConfigurationService } from '../../../client/common/configuration/service'; -import { IExperimentsManager, IInterpreterPathService } from '../../../client/common/types'; +import { IExperimentsManager } from '../../../client/common/types'; import { IServiceContainer } from '../../../client/ioc/types'; suite('Configuration Service', () => { const resource = Uri.parse('a'); let workspaceService: TypeMoq.IMock; - let interpreterPathService: TypeMoq.IMock; let experimentsManager: TypeMoq.IMock; let serviceContainer: TypeMoq.IMock; let configService: ConfigurationService; @@ -28,11 +27,9 @@ suite('Configuration Service', () => { index: 0, name: '0' })); - interpreterPathService = TypeMoq.Mock.ofType(); serviceContainer = TypeMoq.Mock.ofType(); experimentsManager = TypeMoq.Mock.ofType(); serviceContainer.setup((s) => s.get(IWorkspaceService)).returns(() => workspaceService.object); - serviceContainer.setup((s) => s.get(IInterpreterPathService)).returns(() => interpreterPathService.object); serviceContainer.setup((s) => s.get(IExperimentsManager)).returns(() => experimentsManager.object); configService = new ConfigurationService(serviceContainer.object); }); diff --git a/src/test/common/utils/workerPool.functional.test.ts b/src/test/common/utils/workerPool.functional.test.ts deleted file mode 100644 index dfd68d559f5..00000000000 --- a/src/test/common/utils/workerPool.functional.test.ts +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as assert from 'assert'; -import { createWorkerPool, QueuePosition } from '../../../client/common/utils/workerPool'; - -suite('Process Queue', () => { - test('Run two workers to calculate square', async () => { - const workerPool = createWorkerPool(async (i) => Promise.resolve(i * i)); - const promises: Promise[] = []; - const results: number[] = []; - [2, 3, 4, 5, 6, 7, 8, 9].forEach((i) => promises.push(workerPool.addToQueue(i))); - await Promise.all(promises).then((r) => { - results.push(...r); - }); - assert.deepEqual(results, [4, 9, 16, 25, 36, 49, 64, 81]); - }); - - test('Run, wait for result, run again', async () => { - const workerPool = createWorkerPool((i) => Promise.resolve(i * i)); - let promises: Promise[] = []; - let results: number[] = []; - [2, 3, 4].forEach((i) => promises.push(workerPool.addToQueue(i))); - await Promise.all(promises).then((r) => { - results.push(...r); - }); - assert.deepEqual(results, [4, 9, 16]); - - promises = []; - results = []; - [5, 6, 7, 8].forEach((i) => promises.push(workerPool.addToQueue(i))); - await Promise.all(promises).then((r) => { - results.push(...r); - }); - assert.deepEqual(results, [25, 36, 49, 64]); - }); - test('Run two workers and stop in between', async () => { - const workerPool = createWorkerPool(async (i) => { - if (i === 4) { - workerPool.stop(); - } - return Promise.resolve(i * i); - }); - const promises: Promise[] = []; - const results: number[] = []; - const reasons: Error[] = []; - [2, 3, 4, 5, 6].forEach((i) => promises.push(workerPool.addToQueue(i))); - for (const v of promises) { - try { - results.push(await v); - } catch (reason) { - reasons.push(reason); - } - } - assert.deepEqual(results, [4, 9]); - assert.deepEqual(reasons, [ - Error('Queue stopped processing'), - Error('Queue stopped processing'), - Error('Queue stopped processing') - ]); - }); - - test('Add to a stopped queue', async () => { - const workerPool = createWorkerPool((i) => Promise.resolve(i * i)); - workerPool.stop(); - const reasons: Error[] = []; - try { - await workerPool.addToQueue(2); - } catch (reason) { - reasons.push(reason); - } - assert.deepEqual(reasons, [Error('Queue is stopped')]); - }); - - test('Worker function fails', async () => { - const workerPool = createWorkerPool((i) => { - if (i === 4) { - throw Error('Bad input'); - } - return Promise.resolve(i * i); - }); - const promises: Promise[] = []; - const results: number[] = []; - const reasons: string[] = []; - [2, 3, 4, 5, 6].forEach((i) => promises.push(workerPool.addToQueue(i))); - for (const v of promises) { - try { - results.push(await v); - } catch (reason) { - reasons.push(reason); - } - } - assert.deepEqual(reasons, [Error('Bad input')]); - assert.deepEqual(results, [4, 9, 25, 36]); - }); - - test('Add to the front of the queue', async () => { - const processOrder: number[] = []; - const workerPool = createWorkerPool((i) => { - processOrder.push(i); - return Promise.resolve(i * i); - }); - - const promises: Promise[] = []; - const results: number[] = []; - [1, 2, 3, 4, 5, 6].forEach((i) => { - if (i === 4) { - promises.push(workerPool.addToQueue(i, QueuePosition.Front)); - } else { - promises.push(workerPool.addToQueue(i)); - } - }); - await Promise.all(promises).then((r) => { - results.push(...r); - }); - - assert.deepEqual(processOrder, [1, 2, 4, 3, 5, 6]); - assert.deepEqual(results, [1, 4, 9, 16, 25, 36]); - }); -}); diff --git a/src/test/datascience/dataScienceIocContainer.ts b/src/test/datascience/dataScienceIocContainer.ts index 45002dd85ba..9a66977e9ca 100644 --- a/src/test/datascience/dataScienceIocContainer.ts +++ b/src/test/datascience/dataScienceIocContainer.ts @@ -62,8 +62,7 @@ import { ExperimentsManager } from '../../client/common/experiments/manager'; import { ExperimentService } from '../../client/common/experiments/service'; import { ProductInstaller } from '../../client/common/installer/productInstaller'; import { DataScienceProductPathService } from '../../client/common/installer/productPath'; -import { ProductService } from '../../client/common/installer/productService'; -import { IProductPathService, IProductService } from '../../client/common/installer/types'; +import { IProductPathService } from '../../client/common/installer/types'; import { traceError, traceInfo } from '../../client/common/logger'; import { BrowserService } from '../../client/common/net/browser'; import { HttpClient } from '../../client/common/net/httpClient'; @@ -101,7 +100,6 @@ import { IPersistentStateFactory, IsWindows, IWatchableJupyterSettings, - ProductType, Resource, WORKSPACE_MEMENTO } from '../../client/common/types'; @@ -632,15 +630,10 @@ export class DataScienceIocContainer extends UnitTestIocContainer { this.serviceManager.addSingleton(KernelSwitcher, KernelSwitcher); this.serviceManager.addSingleton(IKernelDependencyService, KernelDependencyService); this.serviceManager.addSingleton(INotebookCreationTracker, NotebookCreationTracker); - this.serviceManager.addSingleton(IProductService, ProductService); this.serviceManager.addSingleton(KernelDaemonPool, KernelDaemonPool); this.serviceManager.addSingleton(KernelDaemonPreWarmer, KernelDaemonPreWarmer); this.serviceManager.addSingleton(IVSCodeNotebook, VSCodeNotebook); - this.serviceManager.addSingleton( - IProductPathService, - DataScienceProductPathService, - ProductType.DataScience - ); + this.serviceManager.addSingleton(IProductPathService, DataScienceProductPathService); this.serviceManager.addSingleton(IMultiStepInputFactory, MultiStepInputFactory); // No need of reporting progress. diff --git a/src/test/markdown/restTextConverter.test.ts b/src/test/markdown/restTextConverter.test.ts deleted file mode 100644 index 20cd05e55a9..00000000000 --- a/src/test/markdown/restTextConverter.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as fs from 'fs-extra'; -import * as path from 'path'; -import { RestTextConverter } from '../../client/common/markdown/restTextConverter'; -import { compareFiles } from '../textUtils'; - -const srcPythoFilesPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'markdown'); - -async function testConversion(fileName: string): Promise { - const cvt = new RestTextConverter(); - const file = path.join(srcPythoFilesPath, fileName); - const source = await fs.readFile(`${file}.pydoc`, 'utf8'); - const actual = cvt.toMarkdown(source); - const expected = await fs.readFile(`${file}.md`, 'utf8'); - compareFiles(expected, actual); -} - -// tslint:disable-next-line:max-func-body-length -suite('Hover - RestTextConverter', () => { - test('scipy', async () => testConversion('scipy')); - test('scipy.spatial', async () => testConversion('scipy.spatial')); - test('scipy.spatial.distance', async () => testConversion('scipy.spatial.distance')); - test('anydbm', async () => testConversion('anydbm')); - test('aifc', async () => testConversion('aifc')); - test('astroid', async () => testConversion('astroid')); -}); diff --git a/src/test/serviceRegistry.ts b/src/test/serviceRegistry.ts index 1d0624ce880..738a91f092d 100644 --- a/src/test/serviceRegistry.ts +++ b/src/test/serviceRegistry.ts @@ -41,7 +41,6 @@ import { IEnvironmentActivationService } from '../client/interpreter/activation/ import { ServiceContainer } from '../client/ioc/container'; import { ServiceManager } from '../client/ioc/serviceManager'; import { IServiceContainer, IServiceManager } from '../client/ioc/types'; -import { TEST_OUTPUT_CHANNEL } from '../client/testing/common/constants'; import { MockOutputChannel } from './mockClasses'; import { MockMemento } from './mocks/mementos'; import { MockProcessService } from './mocks/proc'; @@ -176,9 +175,6 @@ export class IocContainer { stdOutputChannel, STANDARD_OUTPUT_CHANNEL ); - const testOutputChannel = new MockOutputChannel('Python Test - UnitTests'); - this.disposables.push(testOutputChannel); - this.serviceManager.addSingletonInstance(IOutputChannel, testOutputChannel, TEST_OUTPUT_CHANNEL); } public async dispose(): Promise { for (const disposable of this.disposables) {