From eec4450532a2979a60dbbd8a276305de7ca0b41f Mon Sep 17 00:00:00 2001 From: Eleanor Boyd Date: Wed, 24 Aug 2022 10:39:57 -0700 Subject: [PATCH 01/26] setup file structure --- pythonFiles/{unittestadapter => pytest_adapter}/__init__.py | 0 pythonFiles/pytest_adapter/pytest_discovery.py | 0 pythonFiles/pytest_adapter/pytest_execution.py | 0 pythonFiles/unittest_adapter/__init__.py | 2 ++ .../discovery.py => unittest_adapter/unittest_discovery.py} | 0 .../execution.py => unittest_adapter/unittest_execution.py} | 0 pythonFiles/{unittestadapter => unittest_adapter}/utils.py | 0 .../testing/testController/pytest/pytestDiscoveryAdapter.ts | 0 .../testing/testController/pytest/pytestExecutionAdapter.ts | 0 .../{testDiscoveryAdapter.ts => unittestDiscoveryAdapter.ts} | 0 .../{testExecutionAdapter.ts => unittestExecutionAdapter.ts} | 0 11 files changed, 2 insertions(+) rename pythonFiles/{unittestadapter => pytest_adapter}/__init__.py (100%) create mode 100644 pythonFiles/pytest_adapter/pytest_discovery.py create mode 100644 pythonFiles/pytest_adapter/pytest_execution.py create mode 100644 pythonFiles/unittest_adapter/__init__.py rename pythonFiles/{unittestadapter/discovery.py => unittest_adapter/unittest_discovery.py} (100%) rename pythonFiles/{unittestadapter/execution.py => unittest_adapter/unittest_execution.py} (100%) rename pythonFiles/{unittestadapter => unittest_adapter}/utils.py (100%) create mode 100644 src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts create mode 100644 src/client/testing/testController/pytest/pytestExecutionAdapter.ts rename src/client/testing/testController/unittest/{testDiscoveryAdapter.ts => unittestDiscoveryAdapter.ts} (100%) rename src/client/testing/testController/unittest/{testExecutionAdapter.ts => unittestExecutionAdapter.ts} (100%) diff --git a/pythonFiles/unittestadapter/__init__.py b/pythonFiles/pytest_adapter/__init__.py similarity index 100% rename from pythonFiles/unittestadapter/__init__.py rename to pythonFiles/pytest_adapter/__init__.py diff --git a/pythonFiles/pytest_adapter/pytest_discovery.py b/pythonFiles/pytest_adapter/pytest_discovery.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/pythonFiles/pytest_adapter/pytest_execution.py b/pythonFiles/pytest_adapter/pytest_execution.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/pythonFiles/unittest_adapter/__init__.py b/pythonFiles/unittest_adapter/__init__.py new file mode 100644 index 000000000000..5b7f7a925cc0 --- /dev/null +++ b/pythonFiles/unittest_adapter/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. diff --git a/pythonFiles/unittestadapter/discovery.py b/pythonFiles/unittest_adapter/unittest_discovery.py similarity index 100% rename from pythonFiles/unittestadapter/discovery.py rename to pythonFiles/unittest_adapter/unittest_discovery.py diff --git a/pythonFiles/unittestadapter/execution.py b/pythonFiles/unittest_adapter/unittest_execution.py similarity index 100% rename from pythonFiles/unittestadapter/execution.py rename to pythonFiles/unittest_adapter/unittest_execution.py diff --git a/pythonFiles/unittestadapter/utils.py b/pythonFiles/unittest_adapter/utils.py similarity index 100% rename from pythonFiles/unittestadapter/utils.py rename to pythonFiles/unittest_adapter/utils.py diff --git a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/client/testing/testController/unittest/testDiscoveryAdapter.ts b/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts similarity index 100% rename from src/client/testing/testController/unittest/testDiscoveryAdapter.ts rename to src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts diff --git a/src/client/testing/testController/unittest/testExecutionAdapter.ts b/src/client/testing/testController/unittest/unittestExecutionAdapter.ts similarity index 100% rename from src/client/testing/testController/unittest/testExecutionAdapter.ts rename to src/client/testing/testController/unittest/unittestExecutionAdapter.ts From 72d5ef0b40cf8ceedf41914e1c500bbb9396ae70 Mon Sep 17 00:00:00 2001 From: Eleanor Boyd Date: Wed, 24 Aug 2022 13:49:50 -0700 Subject: [PATCH 02/26] reverse dummy commit --- pythonFiles/unittest_adapter/unittest_discovery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pythonFiles/unittest_adapter/unittest_discovery.py b/pythonFiles/unittest_adapter/unittest_discovery.py index 0be09e986ca8..5f22a4cc4b92 100644 --- a/pythonFiles/unittest_adapter/unittest_discovery.py +++ b/pythonFiles/unittest_adapter/unittest_discovery.py @@ -17,7 +17,7 @@ from testing_tools import socket_manager # If I use from utils then there will be an import error in test_discovery.py. -from unittestadapter.utils import TestNode, build_test_tree, parse_unittest_args +from unittest_adapter.utils import TestNode, build_test_tree, parse_unittest_args # Add the lib path to sys.path to find the typing_extensions module. sys.path.insert(0, os.path.join(PYTHON_FILES, "lib", "python")) From 470e0be2bcb47f879603d059e715d85f87e681f8 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 25 Aug 2022 11:03:38 -0700 Subject: [PATCH 03/26] stash to isolate error --- .../unittest_adapter/unittest_execution.py | 2 +- .../testing/testController/controller.ts | 55 +++++++++----- .../pytest/pytestDiscoveryAdapter.ts | 71 ++++++++++++++++++ .../pytest/pytestExecutionAdapter.ts | 73 +++++++++++++++++++ .../unittest/unittestDiscoveryAdapter.ts | 2 +- .../testDiscoveryAdapter.unit.test.ts | 2 +- .../workspaceTestAdapter.unit.test.ts | 4 +- 7 files changed, 184 insertions(+), 25 deletions(-) diff --git a/pythonFiles/unittest_adapter/unittest_execution.py b/pythonFiles/unittest_adapter/unittest_execution.py index a016ff1af9ec..935e7fbeae57 100644 --- a/pythonFiles/unittest_adapter/unittest_execution.py +++ b/pythonFiles/unittest_adapter/unittest_execution.py @@ -18,7 +18,7 @@ sys.path.insert(0, os.path.join(PYTHON_FILES, "lib", "python")) from testing_tools import socket_manager from typing_extensions import NotRequired -from unittestadapter.utils import parse_unittest_args +from unittest_adapter.utils import parse_unittest_args DEFAULT_PORT = "45454" diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index fafdd3fafe7e..3d9a8fa03fd1 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -38,9 +38,12 @@ import { TestRefreshOptions, ITestExecutionAdapter, } from './common/types'; -import { UnittestTestDiscoveryAdapter } from './unittest/testDiscoveryAdapter'; +// TODO: create pytest and add to import +import { UnittestTestDiscoveryAdapter } from './unittest/unittestDiscoveryAdapter'; +import { UnittestTestExecutionAdapter } from './unittest/unittestExecutionAdapter'; +import { PytestTestDiscoveryAdapter } from './pytest/pytestDiscoveryAdapter'; +import { PytestTestExecutionAdapter } from './pytest/pytestExecutionAdapter'; import { WorkspaceTestAdapter } from './workspaceTestAdapter'; -import { UnittestTestExecutionAdapter } from './unittest/testExecutionAdapter'; import { ITestDebugLauncher } from '../common/types'; // Types gymnastics to make sure that sendTriggerTelemetry only accepts the correct types. @@ -156,14 +159,19 @@ export class PythonTestController implements ITestController, IExtensionSingleAc let discoveryAdapter: ITestDiscoveryAdapter; let executionAdapter: ITestExecutionAdapter; let testProvider: TestProvider; - if (settings.testing.unittestEnabled) { + if (settings.testing.pytestEnabled) { + console.log('settings.testing.pytestEnabled = true'); + discoveryAdapter = new PytestTestDiscoveryAdapter(this.pythonTestServer, { ...this.configSettings }); // what is the ... for + executionAdapter = new PytestTestExecutionAdapter(this.pythonTestServer, this.configSettings); + testProvider = PYTEST_PROVIDER; + } else if (settings.testing.unittestEnabled) { + console.log('settings.testing.unittestEnabled = true'); discoveryAdapter = new UnittestTestDiscoveryAdapter(this.pythonTestServer, this.configSettings); executionAdapter = new UnittestTestExecutionAdapter(this.pythonTestServer, this.configSettings); testProvider = UNITTEST_PROVIDER; } else { - // TODO: PYTEST DISCOVERY ADAPTER - // this is a placeholder for now - discoveryAdapter = new UnittestTestDiscoveryAdapter(this.pythonTestServer, { ...this.configSettings }); + // this would be an error because neither is enabled? + discoveryAdapter = new UnittestTestDiscoveryAdapter(this.pythonTestServer, this.configSettings); executionAdapter = new UnittestTestExecutionAdapter(this.pythonTestServer, this.configSettings); testProvider = PYTEST_PROVIDER; } @@ -227,27 +235,29 @@ export class PythonTestController implements ITestController, IExtensionSingleAc if (settings.testing.pytestEnabled) { traceVerbose(`Testing: Refreshing test data for ${uri.fsPath}`); + // pytest needs to be added in the new design + // Ensure we send test telemetry if it gets disabled again this.sendTestDisabledTelemetry = true; await this.pytest.refreshTestData(this.testController, uri, this.refreshCancellation.token); } else if (settings.testing.unittestEnabled) { // TODO: Use new test discovery mechanism - // traceVerbose(`Testing: Refreshing test data for ${uri.fsPath}`); - // const workspace = this.workspaceService.getWorkspaceFolder(uri); - // console.warn(`Discover tests for workspace name: ${workspace?.name} - uri: ${uri.fsPath}`); - // const testAdapter = - // this.testAdapters.get(uri) || (this.testAdapters.values().next().value as WorkspaceTestAdapter); - // testAdapter.discoverTests( - // this.testController, - // this.refreshCancellation.token, - // this.testAdapters.size > 1, - // this.workspaceService.workspaceFile?.fsPath, - // ); - // // Ensure we send test telemetry if it gets disabled again - // this.sendTestDisabledTelemetry = true; + traceVerbose(`Testing: Refreshing test data for ${uri.fsPath}`); + const workspace = this.workspaceService.getWorkspaceFolder(uri); + console.warn(`Discover tests for workspace name: ${workspace?.name} - uri: ${uri.fsPath}`); + const testAdapter = + this.testAdapters.get(uri) || (this.testAdapters.values().next().value as WorkspaceTestAdapter); + testAdapter.discoverTests( + this.testController, + this.refreshCancellation.token, + this.testAdapters.size > 1, + this.workspaceService.workspaceFile?.fsPath, + ); + // Ensure we send test telemetry if it gets disabled again + this.sendTestDisabledTelemetry = true; // comment below 229 to run the new way and uncomment above 212 ~ 227 - await this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); + // await this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); } else { if (this.sendTestDisabledTelemetry) { this.sendTestDisabledTelemetry = false; @@ -293,6 +303,7 @@ export class PythonTestController implements ITestController, IExtensionSingleAc const settings = this.configSettings.getSettings(item.uri); if (settings.testing.pytestEnabled) { return this.pytest.resolveChildren(this.testController, item, this.refreshCancellation.token); + // ** check resolve children functionality } if (settings.testing.unittestEnabled) { return this.unittest.resolveChildren(this.testController, item, this.refreshCancellation.token); @@ -360,9 +371,11 @@ export class PythonTestController implements ITestController, IExtensionSingleAc if (testItems.length > 0) { if (settings.testing.pytestEnabled) { sendTelemetryEvent(EventName.UNITTEST_RUN, undefined, { + // seems like this telemetry is named incorrectly? tool: 'pytest', debugging: request.profile?.kind === TestRunProfileKind.Debug, }); + // ** update this to reflect the nwe execution style before return this.pytest.runTests( { includes: testItems, @@ -492,6 +505,8 @@ export class PythonTestController implements ITestController, IExtensionSingleAc ); } + // ** not sure about the telemetry + /** * Send UNITTEST_DISCOVERY_TRIGGER telemetry event only once per trigger type. * diff --git a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts index e69de29bb2d1..3a3f8fb9a51b 100644 --- a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts +++ b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import * as path from 'path'; +import { Uri } from 'vscode'; +import { IConfigurationService } from '../../../common/types'; +import { createDeferred, Deferred } from '../../../common/utils/async'; +import { EXTENSION_ROOT_DIR } from '../../../constants'; +import { + DataReceivedEvent, + DiscoveredTestPayload, + ITestDiscoveryAdapter, + ITestServer, + TestCommandOptions, + TestDiscoveryCommand, +} from '../common/types'; + +/** + */ +export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { + private deferred: Deferred | undefined; + + private cwd: string | undefined; + + constructor(public testServer: ITestServer, public configSettings: IConfigurationService) { + testServer.onDataReceived(this.onDataReceivedHandler, this); + } + + public onDataReceivedHandler({ cwd, data }: DataReceivedEvent): void { + if (this.deferred && cwd === this.cwd) { + const testData: DiscoveredTestPayload = JSON.parse(data); + + this.deferred.resolve(testData); + this.deferred = undefined; + } + } + + public async discoverTests(uri: Uri): Promise { + if (!this.deferred) { + const settings = this.configSettings.getSettings(uri); + const { unittestArgs } = settings.testing; + + const command = buildDiscoveryCommand(unittestArgs); + + this.cwd = uri.fsPath; + + const options: TestCommandOptions = { + workspaceFolder: uri, + command, + cwd: this.cwd, + }; + + this.deferred = createDeferred(); + + // Send the test command to the server. + // The server will fire an onDataReceived event once it gets a response. + this.testServer.sendCommand(options); + } + + return this.deferred.promise; + } +} + +function buildDiscoveryCommand(args: string[]): TestDiscoveryCommand { + const discoveryScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'discovery.py'); + + return { + script: discoveryScript, + args: ['--udiscovery', ...args], + }; +} diff --git a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts index e69de29bb2d1..35d62c50e774 100644 --- a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts +++ b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import * as path from 'path'; +import { Uri } from 'vscode'; +import { IConfigurationService } from '../../../common/types'; +import { createDeferred, Deferred } from '../../../common/utils/async'; +import { EXTENSION_ROOT_DIR } from '../../../constants'; +import { + DataReceivedEvent, + ExecutionTestPayload, + ITestExecutionAdapter, + ITestServer, + TestCommandOptions, + TestExecutionCommand, +} from '../common/types'; + +/** + * Wrapper Class for unittest test execution. This is where we call `runTestCommand`? + */ + +export class PytestTestExecutionAdapter implements ITestExecutionAdapter { + private deferred: Deferred | undefined; + + private cwd: string | undefined; + + constructor(public testServer: ITestServer, public configSettings: IConfigurationService) { + testServer.onDataReceived(this.onDataReceivedHandler, this); + } + + public onDataReceivedHandler({ cwd, data }: DataReceivedEvent): void { + if (this.deferred && cwd === this.cwd) { + const testData: ExecutionTestPayload = JSON.parse(data); + + this.deferred.resolve(testData); + this.deferred = undefined; + } + } + + public async runTests(uri: Uri, testIds: string[], debugBool?: boolean): Promise { + if (!this.deferred) { + const settings = this.configSettings.getSettings(uri); + const { unittestArgs } = settings.testing; + + const command = buildExecutionCommand(unittestArgs); + this.cwd = uri.fsPath; + + const options: TestCommandOptions = { + workspaceFolder: uri, + command, + cwd: this.cwd, + debugBool, + testIds, + }; + + this.deferred = createDeferred(); + + // send test command to server + // server fire onDataReceived event once it gets response + this.testServer.sendCommand(options); + } + return this.deferred.promise; + } +} + +function buildExecutionCommand(args: string[]): TestExecutionCommand { + const executionScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'execution.py'); + + return { + script: executionScript, + args: ['--udiscovery', ...args], + }; +} diff --git a/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts b/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts index f0a5a957807c..13ded842a8b6 100644 --- a/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts +++ b/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts @@ -16,7 +16,7 @@ import { } from '../common/types'; /** - * Wrapper class for unittest test discovery. This is where we call `runTestCommand`. + * Wrapper class for unittest test discovery. This is where we call `runTestCommand`. #this seems incorrectly copied */ export class UnittestTestDiscoveryAdapter implements ITestDiscoveryAdapter { private deferred: Deferred | undefined; diff --git a/src/test/testing/testController/unittest/testDiscoveryAdapter.unit.test.ts b/src/test/testing/testController/unittest/testDiscoveryAdapter.unit.test.ts index cee4353db09a..9f8dbeabb4b3 100644 --- a/src/test/testing/testController/unittest/testDiscoveryAdapter.unit.test.ts +++ b/src/test/testing/testController/unittest/testDiscoveryAdapter.unit.test.ts @@ -7,7 +7,7 @@ import { Uri } from 'vscode'; import { IConfigurationService } from '../../../../client/common/types'; import { EXTENSION_ROOT_DIR } from '../../../../client/constants'; import { ITestServer, TestCommandOptions } from '../../../../client/testing/testController/common/types'; -import { UnittestTestDiscoveryAdapter } from '../../../../client/testing/testController/unittest/testDiscoveryAdapter'; +import { UnittestTestDiscoveryAdapter } from '../../../../client/testing/testController/unittest/unittestDiscoveryAdapter'; suite('Unittest test discovery adapter', () => { let stubConfigSettings: IConfigurationService; diff --git a/src/test/testing/testController/workspaceTestAdapter.unit.test.ts b/src/test/testing/testController/workspaceTestAdapter.unit.test.ts index b6be8d6081de..8d875ef60f6c 100644 --- a/src/test/testing/testController/workspaceTestAdapter.unit.test.ts +++ b/src/test/testing/testController/workspaceTestAdapter.unit.test.ts @@ -6,8 +6,8 @@ import * as sinon from 'sinon'; import { TestController, TestItem, Uri } from 'vscode'; import { IConfigurationService } from '../../../client/common/types'; -import { UnittestTestDiscoveryAdapter } from '../../../client/testing/testController/unittest/testDiscoveryAdapter'; -import { UnittestTestExecutionAdapter } from '../../../client/testing/testController/unittest/testExecutionAdapter'; // 7/7 +import { UnittestTestDiscoveryAdapter } from '../../../client/testing/testController/unittest/unittestDiscoveryAdapter'; +import { UnittestTestExecutionAdapter } from '../../../client/testing/testController/unittest/unittestExecutionAdapter'; // 7/7 import { WorkspaceTestAdapter } from '../../../client/testing/testController/workspaceTestAdapter'; import * as Telemetry from '../../../client/telemetry'; import { EventName } from '../../../client/telemetry/constants'; From dba9088dc57659058fb594dd2616a8b2c8a5434f Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Wed, 7 Sep 2022 14:55:10 -0700 Subject: [PATCH 04/26] fixing merge issues --- .vscode/settings.json | 7 +- .../build/lib/pytest_vscode_integration.py | 21 ++ .../PKG-INFO | 104 ++++++++ .../SOURCES.txt | 11 + .../dependency_links.txt | 1 + .../entry_points.txt | 2 + .../requires.txt | 1 + .../top_level.txt | 1 + pythonFiles/pytest_adapter/conftest.py | 27 +++ .../pytest_adapter/pytest_discovery.py | 144 +++++++++++ pythonFiles/pytest_adapter/pytest_utils.py | 228 ++++++++++++++++++ .../unittest_adapter/unittest_discovery.py | 11 + .../testing/testController/common/server.ts | 50 +++- .../testing/testController/controller.ts | 27 ++- .../pytest/pytestDiscoveryAdapter.ts | 6 +- .../unittest/unittestDiscoveryAdapter.ts | 2 +- .../unittest/unittestExecutionAdapter.ts | 2 +- 17 files changed, 633 insertions(+), 12 deletions(-) create mode 100644 pythonFiles/pytest-vscode-integration/build/lib/pytest_vscode_integration.py create mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/PKG-INFO create mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/SOURCES.txt create mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/dependency_links.txt create mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/entry_points.txt create mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/requires.txt create mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/top_level.txt create mode 100644 pythonFiles/pytest_adapter/conftest.py create mode 100644 pythonFiles/pytest_adapter/pytest_utils.py diff --git a/.vscode/settings.json b/.vscode/settings.json index 174a850c901e..b46b2e8e40b6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,5 +65,10 @@ "--max-line-length=88" ], "typescript.preferences.importModuleSpecifier": "relative", - "debug.javascript.usePreview": false + "debug.javascript.usePreview": false, + "python.testing.pytestArgs": [ + "." + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true } diff --git a/pythonFiles/pytest-vscode-integration/build/lib/pytest_vscode_integration.py b/pythonFiles/pytest-vscode-integration/build/lib/pytest_vscode_integration.py new file mode 100644 index 000000000000..692d49fb0258 --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/build/lib/pytest_vscode_integration.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +import pytest + + +def pytest_addoption(parser): + group = parser.getgroup('vscode-integration') + group.addoption( + '--foo', + action='store', + dest='dest_foo', + default='2022', + help='Set the value for the fixture "bar".' + ) + + parser.addini('HELLO', 'Dummy pytest.ini setting') + + +@pytest.fixture +def bar(request): + return request.config.option.dest_foo diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/PKG-INFO b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/PKG-INFO new file mode 100644 index 000000000000..172aed3ab5bb --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/PKG-INFO @@ -0,0 +1,104 @@ +Metadata-Version: 2.1 +Name: pytest-vscode-integration +Version: 0.1.0 +Summary: used to surface pytest functionality to ports for vscode integration +Home-page: https://github.com/eleanorboyd/pytest-vscode-integration +Author: Eleanor Boyd +Author-email: eleanorboyd@microsoft.com +Maintainer: Eleanor Boyd +Maintainer-email: eleanorboyd@microsoft.com +License: MIT +Classifier: Development Status :: 4 - Beta +Classifier: Framework :: Pytest +Classifier: Intended Audience :: Developers +Classifier: Topic :: Software Development :: Testing +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Operating System :: OS Independent +Classifier: License :: OSI Approved :: MIT License +Requires-Python: >=3.5 +License-File: LICENSE + +========================= +pytest-vscode-integration +========================= + +.. image:: https://img.shields.io/pypi/v/pytest-vscode-integration.svg + :target: https://pypi.org/project/pytest-vscode-integration + :alt: PyPI version + +.. image:: https://img.shields.io/pypi/pyversions/pytest-vscode-integration.svg + :target: https://pypi.org/project/pytest-vscode-integration + :alt: Python versions + +.. image:: https://ci.appveyor.com/api/projects/status/github/eleanorboyd/pytest-vscode-integration?branch=master + :target: https://ci.appveyor.com/project/eleanorboyd/pytest-vscode-integration/branch/master + :alt: See Build Status on AppVeyor + +used to surface pytest functionality to ports for vscode integration + +---- + +This `pytest`_ plugin was generated with `Cookiecutter`_ along with `@hackebrot`_'s `cookiecutter-pytest-plugin`_ template. + + +Features +-------- + +* TODO + + +Requirements +------------ + +* TODO + + +Installation +------------ + +You can install "pytest-vscode-integration" via `pip`_ from `PyPI`_:: + + $ pip install pytest-vscode-integration + + +Usage +----- + +* TODO + +Contributing +------------ +Contributions are very welcome. Tests can be run with `tox`_, please ensure +the coverage at least stays the same before you submit a pull request. + +License +------- + +Distributed under the terms of the `MIT`_ license, "pytest-vscode-integration" is free and open source software + + +Issues +------ + +If you encounter any problems, please `file an issue`_ along with a detailed description. + +.. _`Cookiecutter`: https://github.com/audreyr/cookiecutter +.. _`@hackebrot`: https://github.com/hackebrot +.. _`MIT`: http://opensource.org/licenses/MIT +.. _`BSD-3`: http://opensource.org/licenses/BSD-3-Clause +.. _`GNU GPL v3.0`: http://www.gnu.org/licenses/gpl-3.0.txt +.. _`Apache Software License 2.0`: http://www.apache.org/licenses/LICENSE-2.0 +.. _`cookiecutter-pytest-plugin`: https://github.com/pytest-dev/cookiecutter-pytest-plugin +.. _`file an issue`: https://github.com/eleanorboyd/pytest-vscode-integration/issues +.. _`pytest`: https://github.com/pytest-dev/pytest +.. _`tox`: https://tox.readthedocs.io/en/latest/ +.. _`pip`: https://pypi.org/project/pip/ +.. _`PyPI`: https://pypi.org/project diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/SOURCES.txt b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/SOURCES.txt new file mode 100644 index 000000000000..3b06f2a2dcce --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/SOURCES.txt @@ -0,0 +1,11 @@ +LICENSE +MANIFEST.in +README.rst +pytest_vscode_integration.py +setup.py +pytest_vscode_integration.egg-info/PKG-INFO +pytest_vscode_integration.egg-info/SOURCES.txt +pytest_vscode_integration.egg-info/dependency_links.txt +pytest_vscode_integration.egg-info/entry_points.txt +pytest_vscode_integration.egg-info/requires.txt +pytest_vscode_integration.egg-info/top_level.txt \ No newline at end of file diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/dependency_links.txt b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/dependency_links.txt new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/entry_points.txt b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/entry_points.txt new file mode 100644 index 000000000000..7df59de8857f --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/entry_points.txt @@ -0,0 +1,2 @@ +[pytest11] +vscode-integration = pytest_vscode_integration diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/requires.txt b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/requires.txt new file mode 100644 index 000000000000..a1fa3684923e --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/requires.txt @@ -0,0 +1 @@ +pytest>=3.5.0 diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/top_level.txt b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/top_level.txt new file mode 100644 index 000000000000..ea1bb3c56250 --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/top_level.txt @@ -0,0 +1 @@ +pytest_vscode_integration diff --git a/pythonFiles/pytest_adapter/conftest.py b/pythonFiles/pytest_adapter/conftest.py new file mode 100644 index 000000000000..7f9754b50a85 --- /dev/null +++ b/pythonFiles/pytest_adapter/conftest.py @@ -0,0 +1,27 @@ +import sys + +import pytest + +sys.path.append( + "/Users/eleanorboyd/.vscode/extensions/ms-python.python-2022.12.1/pythonFiles/lib/python" +) # +import debugpy + +debugpy.connect(5678) + + +@pytest.hookimpl() +def pytest_sessionstart(session): + print("hello") + + +def pytest_collection_finish(session): + print("end collection") + for item in session.items: + print("**") + parentCur = item.parent + path = str(item.name) + "> " + while parentCur != None: + path += str(parentCur.name) + "> " + parentCur = parentCur.parent + print("P:", path) diff --git a/pythonFiles/pytest_adapter/pytest_discovery.py b/pythonFiles/pytest_adapter/pytest_discovery.py index e69de29bb2d1..34e6a2945cde 100644 --- a/pythonFiles/pytest_adapter/pytest_discovery.py +++ b/pythonFiles/pytest_adapter/pytest_discovery.py @@ -0,0 +1,144 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import argparse +import json +import logging +import os +import pathlib +import sys +import traceback +from typing import List, Literal, Optional, Tuple, TypedDict, Union + +import pytest + +sys.path.append( + "/Users/eleanorboyd/.vscode/extensions/ms-python.python-2022.12.1/pythonFiles/lib/python" +) # +import debugpy + +debugpy.connect(5678) + +# Add the path to pythonFiles to sys.path to find testing_tools.socket_manager. +PYTHON_FILES = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, PYTHON_FILES) + +from pytest_utils import TestNode, parse_unittest_args +from testing_tools import socket_manager + +# Add the lib path to sys.path to find the typing_extensions module. +sys.path.insert(0, os.path.join(PYTHON_FILES, "lib", "python")) + +from typing_extensions import NotRequired + +DEFAULT_PORT = "45454" + + +def parse_discovery_cli_args(args: List[str]) -> Tuple[int, Union[str, None]]: + """Parse command-line arguments that should be processed by the script. + + So far this includes the port number that it needs to connect to, and the uuid passed by the TS side. + The port is passed to the discovery.py script when it is executed, and + defaults to DEFAULT_PORT if it can't be parsed. + The uuid should be passed to the discovery.py script when it is executed, and defaults to None if it can't be parsed. + If the arguments appear several times, the value returned by parse_cli_args will be the value of the last argument. + """ + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument("--port", default=DEFAULT_PORT) + arg_parser.add_argument("--uuid") + arg_parser.add_argument("--udiscovery") + parsed_args, _ = arg_parser.parse_known_args(args) + + return int(parsed_args.port), parsed_args.uuid, parsed_args.udiscovery + + +class PayloadDict(TypedDict): + cwd: str + status: Literal["success", "error"] + tests: NotRequired[TestNode] + errors: NotRequired[List[str]] + + +def discover_tests(start_dir: str) -> PayloadDict: + """Returns a dictionary containing details of the discovered tests. + + The returned dict has the following keys: + + - cwd: Absolute path to the test start directory; + - uuid: UUID sent by the caller of the Python script, that needs to be sent back as an integrity check; + - status: Test discovery status, can be "success" or "error"; + - tests: Discoverered tests if any, not present otherwise. Note that the status can be "error" but the payload can still contain tests; + - errors: Discovery errors if any, not present otherwise. + + Payload format for a successful discovery: + { + "status": "success", + "cwd": , + "tests": + } + + Payload format for a successful discovery with no tests: + { + "status": "success", + "cwd": , + } + + Payload format when there are errors: + { + "cwd": + "errors": [list of errors] + "status": "error", + } + """ + cwd = os.path.abspath(start_dir) + payload: PayloadDict = {"cwd": cwd, "status": "success"} + tests = None + errors: List[str] = [] + + try: + # test loading + tests = "" + retcode = pytest.main(["--collect-only", "-q"]) + print("dine") + + except Exception: + errors.append(traceback.format_exc()) + + if tests is not None: + payload["tests"] = tests + + if len(errors): + payload["status"] = "error" + payload["errors"] = errors + + return payload + + +if __name__ == "__main__": + # Get unittest discovery arguments. + argv = sys.argv[1:] + index = argv.index("--udiscovery") + + # start_dir, pattern, top_level_dir = parse_unittest_args(argv[index + 1 :]) + # logging.debug( + # "start_dir, pattern, top_level_dir", start_dir, pattern, top_level_dir + # ) + # logging.debug("hi") + + # Perform test discovery. + port, uuid, start_dir = parse_discovery_cli_args(argv) + + payload = discover_tests(start_dir) + + # Build the request data (it has to be a POST request or the Node side will not process it), and send it. + addr = ("localhost", port) + with socket_manager.SocketManager(addr) as s: + data = json.dumps(payload) + request = f"""POST / HTTP/1.1 +Host: localhost:{port} +Content-Length: {len(data)} +Content-Type: application/json +Request-uuid: {uuid} + +{data}""" + result = s.socket.sendall(request.encode("utf-8")) # type: ignore diff --git a/pythonFiles/pytest_adapter/pytest_utils.py b/pythonFiles/pytest_adapter/pytest_utils.py new file mode 100644 index 000000000000..568ff30ee92d --- /dev/null +++ b/pythonFiles/pytest_adapter/pytest_utils.py @@ -0,0 +1,228 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import argparse +import enum +import inspect +import os +import pathlib +import unittest +from typing import List, Tuple, TypedDict, Union + +# Types + + +# Inherit from str so it's JSON serializable. +class TestNodeTypeEnum(str, enum.Enum): + class_ = "class" + file = "file" + folder = "folder" + test = "test" + + +class TestData(TypedDict): + name: str + path: str + type_: TestNodeTypeEnum + id_: str + + +class TestItem(TestData): + lineno: str + runID: str + + +class TestNode(TestData): + children: "List[TestNode | TestItem]" + + +# Helper functions for data retrieval. + + +def get_test_case(suite): + """Iterate through a unittest test suite and return all test cases.""" + for test in suite: + if isinstance(test, unittest.TestCase): + yield test + else: + for test_case in get_test_case(test): + yield test_case + + +def get_source_line(obj) -> str: + """Get the line number of a test case start line.""" + try: + sourcelines, lineno = inspect.getsourcelines(obj) + except: + try: + # tornado-specific, see https://github.com/microsoft/vscode-python/issues/17285. + sourcelines, lineno = inspect.getsourcelines(obj.orig_method) + except: + return "*" + + # Return the line number of the first line of the test case definition. + for i, v in enumerate(sourcelines): + if v.strip().startswith(("def", "async def")): + return str(lineno + i) + + return "*" + + +# Helper functions for test tree building. + + +def build_test_node(path: str, name: str, type_: TestNodeTypeEnum) -> TestNode: + """Build a test node with no children. A test node can be a folder, a file or a class.""" + ## figure out if we are folder, file, or class + id_gen = path + if type_ == TestNodeTypeEnum.folder or type_ == TestNodeTypeEnum.file: + id_gen = path + else: + # means we have to build test node for class + id_gen = path + "\\" + name + + return {"path": path, "name": name, "type_": type_, "children": [], "id_": id_gen} + + +def get_child_node( + name: str, path: str, type_: TestNodeTypeEnum, root: TestNode +) -> TestNode: + """Find a child node in a test tree given its name and type. If the node doesn't exist, create it.""" + try: + result = next( + node + for node in root["children"] + if node["name"] == name and node["type_"] == type_ + ) + except StopIteration: + result = build_test_node(path, name, type_) + root["children"].append(result) + + return result # type:ignore + + +def build_test_tree( + suite: unittest.TestSuite, test_directory: str +) -> Tuple[Union[TestNode, None], List[str]]: + """Build a test tree from a unittest test suite. + + This function returns the test tree, and any errors found by unittest. + If no tests were discovered, return `None` and a list of errors (if any). + + Test tree structure: + { + "path": , + "type": "folder", + "name": , + "children": [ + { files and folders } + ... + { + "path": , + "name": filename.py, + "type_": "file", + "children": [ + { + "path": , + "name": , + "type_": "class", + "children": [ + { + "path": , + "name": , + "type_": "test", + "lineno": + "id_": , + } + ], + "id_": + } + ], + "id_": + } + ], + "id_": + } + """ + errors = [] + directory_path = pathlib.PurePath(test_directory) + root = build_test_node(test_directory, directory_path.name, TestNodeTypeEnum.folder) + + for test_case in get_test_case(suite): + test_id = test_case.id() + if test_id.startswith("unittest.loader._FailedTest"): + errors.append(str(test_case._exception)) # type: ignore + else: + # Get the static test path components: filename, class name and function name. + components = test_id.split(".") + *folders, filename, class_name, function_name = components + py_filename = f"{filename}.py" + + current_node = root + + # Find/build nodes for the intermediate folders in the test path. + for folder in folders: + current_node = get_child_node( + folder, + os.fsdecode(pathlib.PurePath(current_node["path"], folder)), + TestNodeTypeEnum.folder, + current_node, + ) + + # Find/build file node. + path_components = [test_directory] + folders + [py_filename] + file_path = os.fsdecode(pathlib.PurePath("/".join(path_components))) + current_node = get_child_node( + py_filename, file_path, TestNodeTypeEnum.file, current_node + ) + + # Find/build class node. + current_node = get_child_node( + class_name, file_path, TestNodeTypeEnum.class_, current_node + ) + + # Get test line number. + test_method = getattr(test_case, test_case._testMethodName) + lineno = get_source_line(test_method) + + # Add test node. + test_node: TestItem = { + "name": function_name, + "path": file_path, + "lineno": lineno, + "type_": TestNodeTypeEnum.test, + "id_": file_path + "\\" + class_name + "\\" + function_name, + "runID": test_id, + } # concatenate class name and function test name + current_node["children"].append(test_node) + + if not root["children"]: + root = None + + return root, errors + + +def parse_unittest_args(args: List[str]) -> Tuple[str, str, Union[str, None]]: + """Parse command-line arguments that should be forwarded to unittest to perform discovery. + + Valid unittest arguments are: -v, -s, -p, -t and their long-form counterparts, + however we only care about the last three. + + The returned tuple contains the following items + - start_directory: The directory where to start discovery, defaults to . + - pattern: The pattern to match test files, defaults to test*.py + - top_level_directory: The top-level directory of the project, defaults to None, and unittest will use start_directory behind the scenes. + """ + + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument("--start-directory", "-s", default=".") + arg_parser.add_argument("--pattern", "-p", default="test*.py") + arg_parser.add_argument("--top-level-directory", "-t", default=None) + + parsed_args, _ = arg_parser.parse_known_args(args) + + return ( + parsed_args.start_directory, + parsed_args.pattern, + parsed_args.top_level_directory, + ) diff --git a/pythonFiles/unittest_adapter/unittest_discovery.py b/pythonFiles/unittest_adapter/unittest_discovery.py index 5f22a4cc4b92..cc09637078ee 100644 --- a/pythonFiles/unittest_adapter/unittest_discovery.py +++ b/pythonFiles/unittest_adapter/unittest_discovery.py @@ -3,6 +3,7 @@ import argparse import json +import logging import os import pathlib import sys @@ -10,6 +11,13 @@ import unittest from typing import List, Literal, Optional, Tuple, TypedDict, Union +sys.path.append( + "/Users/eleanorboyd/.vscode/extensions/ms-python.python-2022.12.1/pythonFiles/lib/python" +) # +import debugpy + +debugpy.connect(5678) + # Add the path to pythonFiles to sys.path to find testing_tools.socket_manager. PYTHON_FILES = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, PYTHON_FILES) @@ -114,6 +122,9 @@ def discover_tests( index = argv.index("--udiscovery") start_dir, pattern, top_level_dir = parse_unittest_args(argv[index + 1 :]) + logging.debug( + "start_dir, pattern, top_level_dir", start_dir, pattern, top_level_dir + ) # Perform test discovery. port, uuid = parse_discovery_cli_args(argv[:index]) diff --git a/src/client/testing/testController/common/server.ts b/src/client/testing/testController/common/server.ts index adf5bba1a33c..df5e2c2e7eae 100644 --- a/src/client/testing/testController/common/server.ts +++ b/src/client/testing/testController/common/server.ts @@ -71,6 +71,12 @@ export class PythonTestServer implements ITestServer, Disposable { return (this.server.address() as net.AddressInfo).port; } + public createUUID(options: TestCommandOptions): string { + const uuid = crypto.randomUUID(); + this.uuids.set(uuid, options.cwd); + return uuid; + } + public dispose(): void { this.server.close(); this._onDataReceived.dispose(); @@ -80,15 +86,53 @@ export class PythonTestServer implements ITestServer, Disposable { return this._onDataReceived.event; } - async sendCommand(options: TestCommandOptions): Promise { - const uuid = crypto.randomUUID(); + async sendCommandPytest(options: TestCommandOptions, args: string[]): Promise { + const uuid = this.createUUID(options); const spawnOptions: SpawnOptions = { token: options.token, cwd: options.cwd, throwOnStdErr: true, }; - this.uuids.set(uuid, options.cwd); + // Create the Python environment in which to execute the command. + const creationOptions: ExecutionFactoryCreateWithEnvironmentOptions = { + allowEnvironmentFetchExceptions: false, + resource: options.workspaceFolder, + }; + const execService = await this.executionFactory.createActivatedEnvironment(creationOptions); + + try { + if (options.debugBool) { + const launchOptions: LaunchOptions = { + cwd: options.cwd, + args, + token: options.token, + testProvider: UNITTEST_PROVIDER, + }; + + await this.debugLauncher!.launchDebugger(launchOptions); + } else { + await execService.exec(args, spawnOptions); + } + } catch (ex) { + this.uuids.delete(uuid); + this._onDataReceived.fire({ + cwd: options.cwd, + data: JSON.stringify({ + status: 'error', + errors: [(ex as Error).message], + }), + }); + } + } + + async sendCommand(options: TestCommandOptions): Promise { + const uuid = this.createUUID(options); + const spawnOptions: SpawnOptions = { + token: options.token, + cwd: options.cwd, + throwOnStdErr: true, + }; // Create the Python environment in which to execute the command. const creationOptions: ExecutionFactoryCreateWithEnvironmentOptions = { diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index 3d9a8fa03fd1..273b89adba48 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -144,7 +144,11 @@ export class PythonTestController implements ITestController, IExtensionSingleAc }); return this.refreshTestData(undefined, { forceRefresh: true }); }; +<<<<<<< HEAD +======= + // this.pythonTestServer = new PythonTestServer(this.pythonExecFactory); // old way where debugLauncher did not have to be passed +>>>>>>> 9cca1d959 (pytest is now running - unable to collect output) this.pythonTestServer = new PythonTestServer(this.pythonExecFactory, this.debugLauncher); } @@ -161,7 +165,7 @@ export class PythonTestController implements ITestController, IExtensionSingleAc let testProvider: TestProvider; if (settings.testing.pytestEnabled) { console.log('settings.testing.pytestEnabled = true'); - discoveryAdapter = new PytestTestDiscoveryAdapter(this.pythonTestServer, { ...this.configSettings }); // what is the ... for + discoveryAdapter = new PytestTestDiscoveryAdapter(this.pythonTestServer, this.configSettings); // what is the ... for executionAdapter = new PytestTestExecutionAdapter(this.pythonTestServer, this.configSettings); testProvider = PYTEST_PROVIDER; } else if (settings.testing.unittestEnabled) { @@ -235,10 +239,21 @@ export class PythonTestController implements ITestController, IExtensionSingleAc if (settings.testing.pytestEnabled) { traceVerbose(`Testing: Refreshing test data for ${uri.fsPath}`); - // pytest needs to be added in the new design - + // can I move these out of the if statement + const workspace = this.workspaceService.getWorkspaceFolder(uri); + console.warn(`Discover tests for workspace name: ${workspace?.name} - uri: ${uri.fsPath}`); + const testAdapter = + this.testAdapters.get(uri) || (this.testAdapters.values().next().value as WorkspaceTestAdapter); + testAdapter.discoverTests( + this.testController, + this.refreshCancellation.token, + this.testAdapters.size > 1, + this.workspaceService.workspaceFile?.fsPath, + ); // Ensure we send test telemetry if it gets disabled again this.sendTestDisabledTelemetry = true; + // comment below 229 to run the new way and uncomment above 212 ~ 227 + // await this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); await this.pytest.refreshTestData(this.testController, uri, this.refreshCancellation.token); } else if (settings.testing.unittestEnabled) { @@ -322,6 +337,11 @@ export class PythonTestController implements ITestController, IExtensionSingleAc }), ); } + console.log('HERE2'); + this.testController.items.forEach((element) => console.log(element)); + + console.log(this.testController.items); + console.log('size', this.testController.items.size); return Promise.resolve(); } @@ -422,6 +442,7 @@ export class PythonTestController implements ITestController, IExtensionSingleAc } if (!settings.testing.pytestEnabled && !settings.testing.unittestEnabled) { + // ** this could be the logic I am looking for unconfiguredWorkspaces.push(workspace); } return Promise.resolve(); diff --git a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts index 3a3f8fb9a51b..4b11b575e635 100644 --- a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts +++ b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts @@ -38,9 +38,9 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { public async discoverTests(uri: Uri): Promise { if (!this.deferred) { const settings = this.configSettings.getSettings(uri); - const { unittestArgs } = settings.testing; + const { pytestArgs } = settings.testing; - const command = buildDiscoveryCommand(unittestArgs); + const command = buildDiscoveryCommand(pytestArgs); this.cwd = uri.fsPath; @@ -62,7 +62,7 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { } function buildDiscoveryCommand(args: string[]): TestDiscoveryCommand { - const discoveryScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'discovery.py'); + const discoveryScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'pytest_adapter', 'pytest_discovery.py'); return { script: discoveryScript, diff --git a/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts b/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts index 13ded842a8b6..d50d0ce3961b 100644 --- a/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts +++ b/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts @@ -63,7 +63,7 @@ export class UnittestTestDiscoveryAdapter implements ITestDiscoveryAdapter { } function buildDiscoveryCommand(args: string[]): TestDiscoveryCommand { - const discoveryScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'discovery.py'); + const discoveryScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittest_adapter', 'unittest_discovery.py'); return { script: discoveryScript, diff --git a/src/client/testing/testController/unittest/unittestExecutionAdapter.ts b/src/client/testing/testController/unittest/unittestExecutionAdapter.ts index d71dea9fea36..2b4e098323a4 100644 --- a/src/client/testing/testController/unittest/unittestExecutionAdapter.ts +++ b/src/client/testing/testController/unittest/unittestExecutionAdapter.ts @@ -64,7 +64,7 @@ export class UnittestTestExecutionAdapter implements ITestExecutionAdapter { } function buildExecutionCommand(args: string[]): TestExecutionCommand { - const executionScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'execution.py'); + const executionScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittest_adapter', 'unittest_execution.py'); return { script: executionScript, From 01cb5e166f3cfe69976fd1b08a5d2c32e82df3e4 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Wed, 7 Sep 2022 14:33:30 -0700 Subject: [PATCH 05/26] pushing changes in order to rebase --- .../pytest-vscode-integration/.gitignore | 74 ++++++++++++++++++ pythonFiles/pytest-vscode-integration/LICENSE | 22 ++++++ .../pytest-vscode-integration/MANIFEST.in | 5 ++ .../pytest-vscode-integration/README.rst | 76 +++++++++++++++++++ .../pytest-vscode-integration/appveyor.yml | 40 ++++++++++ .../pytest-vscode-integration/docs/index.md | 3 + .../pytest-vscode-integration/mkdocs.yml | 10 +++ .../pytest_vscode_integration.py | 26 +++++++ .../pytest-vscode-integration/setup.py | 51 +++++++++++++ .../tests/conftest.py | 1 + .../tests/test_vscode_integration.py | 64 ++++++++++++++++ pythonFiles/pytest-vscode-integration/tox.ini | 12 +++ pythonFiles/pytest_adapter/conftest.py | 1 + .../pytest_adapter/pytest_discovery.py | 19 ++++- pythonFiles/testing_tools/run_adapter.py | 4 +- .../testing/testController/controller.ts | 2 +- .../testController/pytest/arguments.ts | 2 +- .../pytest/pytestDiscoveryAdapter.ts | 50 +++++++++--- 18 files changed, 444 insertions(+), 18 deletions(-) create mode 100644 pythonFiles/pytest-vscode-integration/.gitignore create mode 100644 pythonFiles/pytest-vscode-integration/LICENSE create mode 100644 pythonFiles/pytest-vscode-integration/MANIFEST.in create mode 100644 pythonFiles/pytest-vscode-integration/README.rst create mode 100644 pythonFiles/pytest-vscode-integration/appveyor.yml create mode 100644 pythonFiles/pytest-vscode-integration/docs/index.md create mode 100644 pythonFiles/pytest-vscode-integration/mkdocs.yml create mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.py create mode 100644 pythonFiles/pytest-vscode-integration/setup.py create mode 100644 pythonFiles/pytest-vscode-integration/tests/conftest.py create mode 100644 pythonFiles/pytest-vscode-integration/tests/test_vscode_integration.py create mode 100644 pythonFiles/pytest-vscode-integration/tox.ini diff --git a/pythonFiles/pytest-vscode-integration/.gitignore b/pythonFiles/pytest-vscode-integration/.gitignore new file mode 100644 index 000000000000..6c5886e04363 --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/.gitignore @@ -0,0 +1,74 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ +.pytest_cache + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask instance folder +instance/ + +# Sphinx documentation +docs/_build/ + +# MkDocs documentation +/site/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + diff --git a/pythonFiles/pytest-vscode-integration/LICENSE b/pythonFiles/pytest-vscode-integration/LICENSE new file mode 100644 index 000000000000..544793b47855 --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/LICENSE @@ -0,0 +1,22 @@ + +The MIT License (MIT) + +Copyright (c) 2022 Eleanor Boyd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/pythonFiles/pytest-vscode-integration/MANIFEST.in b/pythonFiles/pytest-vscode-integration/MANIFEST.in new file mode 100644 index 000000000000..1ade348bb74d --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/MANIFEST.in @@ -0,0 +1,5 @@ +include LICENSE +include README.rst + +recursive-exclude * __pycache__ +recursive-exclude * *.py[co] diff --git a/pythonFiles/pytest-vscode-integration/README.rst b/pythonFiles/pytest-vscode-integration/README.rst new file mode 100644 index 000000000000..28a55c3da118 --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/README.rst @@ -0,0 +1,76 @@ +========================= +pytest-vscode-integration +========================= + +.. image:: https://img.shields.io/pypi/v/pytest-vscode-integration.svg + :target: https://pypi.org/project/pytest-vscode-integration + :alt: PyPI version + +.. image:: https://img.shields.io/pypi/pyversions/pytest-vscode-integration.svg + :target: https://pypi.org/project/pytest-vscode-integration + :alt: Python versions + +.. image:: https://ci.appveyor.com/api/projects/status/github/eleanorboyd/pytest-vscode-integration?branch=master + :target: https://ci.appveyor.com/project/eleanorboyd/pytest-vscode-integration/branch/master + :alt: See Build Status on AppVeyor + +used to surface pytest functionality to ports for vscode integration + +---- + +This `pytest`_ plugin was generated with `Cookiecutter`_ along with `@hackebrot`_'s `cookiecutter-pytest-plugin`_ template. + + +Features +-------- + +* TODO + + +Requirements +------------ + +* TODO + + +Installation +------------ + +You can install "pytest-vscode-integration" via `pip`_ from `PyPI`_:: + + $ pip install pytest-vscode-integration + + +Usage +----- + +* TODO + +Contributing +------------ +Contributions are very welcome. Tests can be run with `tox`_, please ensure +the coverage at least stays the same before you submit a pull request. + +License +------- + +Distributed under the terms of the `MIT`_ license, "pytest-vscode-integration" is free and open source software + + +Issues +------ + +If you encounter any problems, please `file an issue`_ along with a detailed description. + +.. _`Cookiecutter`: https://github.com/audreyr/cookiecutter +.. _`@hackebrot`: https://github.com/hackebrot +.. _`MIT`: http://opensource.org/licenses/MIT +.. _`BSD-3`: http://opensource.org/licenses/BSD-3-Clause +.. _`GNU GPL v3.0`: http://www.gnu.org/licenses/gpl-3.0.txt +.. _`Apache Software License 2.0`: http://www.apache.org/licenses/LICENSE-2.0 +.. _`cookiecutter-pytest-plugin`: https://github.com/pytest-dev/cookiecutter-pytest-plugin +.. _`file an issue`: https://github.com/eleanorboyd/pytest-vscode-integration/issues +.. _`pytest`: https://github.com/pytest-dev/pytest +.. _`tox`: https://tox.readthedocs.io/en/latest/ +.. _`pip`: https://pypi.org/project/pip/ +.. _`PyPI`: https://pypi.org/project diff --git a/pythonFiles/pytest-vscode-integration/appveyor.yml b/pythonFiles/pytest-vscode-integration/appveyor.yml new file mode 100644 index 000000000000..61bdd159551a --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/appveyor.yml @@ -0,0 +1,40 @@ +# What Python version is installed where: +# https://www.appveyor.com/docs/build-environment/#python + +environment: + matrix: + - PYTHON: "C:\\Python35" + TOX_ENV: "py35" + + - PYTHON: "C:\\Python36" + TOX_ENV: "py36" + + - PYTHON: "C:\\Python37" + TOX_ENV: "py37" + + - PYTHON: "C:\\Python38" + TOX_ENV: "py38" + +init: + - "%PYTHON%/python -V" + - "%PYTHON%/python -c \"import struct;print( 8 * struct.calcsize(\'P\'))\"" + +install: + - "%PYTHON%/Scripts/easy_install -U pip" + - "%PYTHON%/Scripts/pip install tox" + - "%PYTHON%/Scripts/pip install wheel" + +build: false # Not a C# project, build stuff at the test step instead. + +test_script: + - "%PYTHON%/Scripts/tox -e %TOX_ENV%" + +after_test: + - "%PYTHON%/python setup.py bdist_wheel" + - ps: "ls dist" + +artifacts: + - path: dist\* + +#on_success: +# - TODO: upload the content of dist/*.whl to a public wheelhouse diff --git a/pythonFiles/pytest-vscode-integration/docs/index.md b/pythonFiles/pytest-vscode-integration/docs/index.md new file mode 100644 index 000000000000..6502b106decf --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/docs/index.md @@ -0,0 +1,3 @@ +# Welcome to pytest-vscode-integration + +used to surface pytest functionality to ports for vscode integration diff --git a/pythonFiles/pytest-vscode-integration/mkdocs.yml b/pythonFiles/pytest-vscode-integration/mkdocs.yml new file mode 100644 index 000000000000..e7aeb8d8508d --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/mkdocs.yml @@ -0,0 +1,10 @@ +site_name: pytest-vscode-integration +site_description: used to surface pytest functionality to ports for vscode integration +site_author: Eleanor Boyd + +theme: readthedocs + +repo_url: https://github.com/eleanorboyd/pytest-vscode-integration + +pages: +- Home: index.md diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.py b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.py new file mode 100644 index 000000000000..11cb14fc379b --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +import pytest + + +def pytest_addoption(parser): + group = parser.getgroup("vscode-integration") + group.addoption( + "--foo", + action="store", + dest="dest_foo", + default="2022", + help='Set the value for the fixture "bar".', + ) + + parser.addini("HELLO", "Dummy pytest.ini setting") + + +@pytest.fixture +def bar(request): + return request.config.option.dest_foo + + +def pytest_runtest_setup(item): + # called for running each test in 'a' directory + print("AAAAA: setting up", item) diff --git a/pythonFiles/pytest-vscode-integration/setup.py b/pythonFiles/pytest-vscode-integration/setup.py new file mode 100644 index 000000000000..9a5b79444162 --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/setup.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import codecs +import os + +from setuptools import setup + + +def read(fname): + file_path = os.path.join(os.path.dirname(__file__), fname) + return codecs.open(file_path, encoding='utf-8').read() + + +setup( + name='pytest-vscode-integration', + version='0.1.0', + author='Eleanor Boyd', + author_email='eleanorboyd@microsoft.com', + maintainer='Eleanor Boyd', + maintainer_email='eleanorboyd@microsoft.com', + license='MIT', + url='https://github.com/eleanorboyd/pytest-vscode-integration', + description='used to surface pytest functionality to ports for vscode integration', + long_description=read('README.rst'), + py_modules=['pytest_vscode_integration'], + python_requires='>=3.5', + install_requires=['pytest>=3.5.0'], + classifiers=[ + 'Development Status :: 4 - Beta', + 'Framework :: Pytest', + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Testing', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3 :: Only', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', + 'Operating System :: OS Independent', + 'License :: OSI Approved :: MIT License', + ], + entry_points={ + 'pytest11': [ + 'vscode-integration = pytest_vscode_integration', + ], + }, +) diff --git a/pythonFiles/pytest-vscode-integration/tests/conftest.py b/pythonFiles/pytest-vscode-integration/tests/conftest.py new file mode 100644 index 000000000000..bc711e55fefd --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/tests/conftest.py @@ -0,0 +1 @@ +pytest_plugins = 'pytester' diff --git a/pythonFiles/pytest-vscode-integration/tests/test_vscode_integration.py b/pythonFiles/pytest-vscode-integration/tests/test_vscode_integration.py new file mode 100644 index 000000000000..657faa8e5881 --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/tests/test_vscode_integration.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + + +def test_bar_fixture(testdir): + """Make sure that pytest accepts our fixture.""" + + # create a temporary pytest test module + testdir.makepyfile(""" + def test_sth(bar): + assert bar == "europython2015" + """) + + # run pytest with the following cmd args + result = testdir.runpytest( + '--foo=europython2015', + '-v' + ) + + # fnmatch_lines does an assertion internally + result.stdout.fnmatch_lines([ + '*::test_sth PASSED*', + ]) + + # make sure that that we get a '0' exit code for the testsuite + assert result.ret == 0 + + +def test_help_message(testdir): + result = testdir.runpytest( + '--help', + ) + # fnmatch_lines does an assertion internally + result.stdout.fnmatch_lines([ + 'vscode-integration:', + '*--foo=DEST_FOO*Set the value for the fixture "bar".', + ]) + + +def test_hello_ini_setting(testdir): + testdir.makeini(""" + [pytest] + HELLO = world + """) + + testdir.makepyfile(""" + import pytest + + @pytest.fixture + def hello(request): + return request.config.getini('HELLO') + + def test_hello_world(hello): + assert hello == 'world' + """) + + result = testdir.runpytest('-v') + + # fnmatch_lines does an assertion internally + result.stdout.fnmatch_lines([ + '*::test_hello_world PASSED*', + ]) + + # make sure that that we get a '0' exit code for the testsuite + assert result.ret == 0 diff --git a/pythonFiles/pytest-vscode-integration/tox.ini b/pythonFiles/pytest-vscode-integration/tox.ini new file mode 100644 index 000000000000..9b037d48e319 --- /dev/null +++ b/pythonFiles/pytest-vscode-integration/tox.ini @@ -0,0 +1,12 @@ +# For more information about tox, see https://tox.readthedocs.io/en/latest/ +[tox] +envlist = py35,py36,py37,py38,pypy3,flake8 + +[testenv] +deps = pytest>=3.0 +commands = pytest {posargs:tests} + +[testenv:flake8] +skip_install = true +deps = flake8 +commands = flake8 pytest_vscode_integration.py setup.py tests diff --git a/pythonFiles/pytest_adapter/conftest.py b/pythonFiles/pytest_adapter/conftest.py index 7f9754b50a85..e562b648576e 100644 --- a/pythonFiles/pytest_adapter/conftest.py +++ b/pythonFiles/pytest_adapter/conftest.py @@ -1,3 +1,4 @@ +import os import sys import pytest diff --git a/pythonFiles/pytest_adapter/pytest_discovery.py b/pythonFiles/pytest_adapter/pytest_discovery.py index 34e6a2945cde..e8089944aa73 100644 --- a/pythonFiles/pytest_adapter/pytest_discovery.py +++ b/pythonFiles/pytest_adapter/pytest_discovery.py @@ -11,6 +11,7 @@ from typing import List, Literal, Optional, Tuple, TypedDict, Union import pytest +import pytest_vscode_integration sys.path.append( "/Users/eleanorboyd/.vscode/extensions/ms-python.python-2022.12.1/pythonFiles/lib/python" @@ -23,12 +24,16 @@ PYTHON_FILES = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, PYTHON_FILES) + from pytest_utils import TestNode, parse_unittest_args from testing_tools import socket_manager # Add the lib path to sys.path to find the typing_extensions module. sys.path.insert(0, os.path.join(PYTHON_FILES, "lib", "python")) + +# pytest_plugins = ("myapp.testsupport.myplugin",) + from typing_extensions import NotRequired DEFAULT_PORT = "45454" @@ -98,8 +103,13 @@ def discover_tests(start_dir: str) -> PayloadDict: try: # test loading tests = "" - retcode = pytest.main(["--collect-only", "-q"]) - print("dine") + # retcode = pytest.main(["--collect-only", "-q"]) + # print("dine") + # sys.exit(pytest.main(["-qq"], plugins=[MyPlugin()])) + # python - + os.system("python3 -m pytest --collect-only") + print("HELLO") + os.system("python3 -m pytest --collect-only -p pytest-vscode-integration") except Exception: errors.append(traceback.format_exc()) @@ -114,6 +124,11 @@ def discover_tests(start_dir: str) -> PayloadDict: return payload +class MyPlugin: + def pytest_sessionfinish(self): + print("*** test run reporting finishing") + + if __name__ == "__main__": # Get unittest discovery arguments. argv = sys.argv[1:] diff --git a/pythonFiles/testing_tools/run_adapter.py b/pythonFiles/testing_tools/run_adapter.py index 1eeef194f8f5..b2c6c35608ff 100644 --- a/pythonFiles/testing_tools/run_adapter.py +++ b/pythonFiles/testing_tools/run_adapter.py @@ -14,9 +14,9 @@ ), ) -from testing_tools.adapter.__main__ import parse_args, main - +from testing_tools.adapter.__main__ import main, parse_args if __name__ == "__main__": tool, cmd, subargs, toolargs = parse_args() main(tool, cmd, subargs, toolargs) + print("run adapter hello") diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index 273b89adba48..c96e1f9492f0 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -255,7 +255,7 @@ export class PythonTestController implements ITestController, IExtensionSingleAc // comment below 229 to run the new way and uncomment above 212 ~ 227 // await this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); - await this.pytest.refreshTestData(this.testController, uri, this.refreshCancellation.token); + // await this.pytest.refreshTestData(this.testController, uri, this.refreshCancellation.token); } else if (settings.testing.unittestEnabled) { // TODO: Use new test discovery mechanism traceVerbose(`Testing: Refreshing test data for ${uri.fsPath}`); diff --git a/src/client/testing/testController/pytest/arguments.ts b/src/client/testing/testController/pytest/arguments.ts index 78b451acdd6b..25b2853539e7 100644 --- a/src/client/testing/testController/pytest/arguments.ts +++ b/src/client/testing/testController/pytest/arguments.ts @@ -263,7 +263,7 @@ export function preparePytestArgumentsForDiscovery(options: TestDiscoveryOptions // Remove unwanted arguments (which happen to be test directories & test specific args). const args = pytestFilterArguments(options.args, TestFilter.discovery); if (options.ignoreCache && args.indexOf('--cache-clear') === -1) { - args.splice(0, 0, '--cache-clear'); + args.splice(0, 0, 'bbbbb--cache-clear'); } if (args.indexOf('-s') === -1) { args.splice(0, 0, '-s'); diff --git a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts index 4b11b575e635..f3b5c1ab2b2c 100644 --- a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts +++ b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. - import * as path from 'path'; import { Uri } from 'vscode'; import { IConfigurationService } from '../../../common/types'; import { createDeferred, Deferred } from '../../../common/utils/async'; import { EXTENSION_ROOT_DIR } from '../../../constants'; + import { DataReceivedEvent, DiscoveredTestPayload, @@ -16,6 +16,7 @@ import { } from '../common/types'; /** + * Wrapper class for unittest test discovery. This is where we call `runTestCommand`. #this seems incorrectly copied */ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { private deferred: Deferred | undefined; @@ -39,33 +40,58 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { if (!this.deferred) { const settings = this.configSettings.getSettings(uri); const { pytestArgs } = settings.testing; + console.debug(pytestArgs); + // const command2 = buildDiscoveryCommand('-m pytest', ['--collect-only', ...pytestArgs]); + // const command = buildDiscoveryCommand('import pytest', []); - const command = buildDiscoveryCommand(pytestArgs); + this.cwd = uri.fsPath; // this.cwd normally = '/Users/eleanorboyd/Documents/testing - tester files/inc_dec_example' + // const discoveryScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittest_adapter', 'unittest_discovery.py'); - this.cwd = uri.fsPath; - - const options: TestCommandOptions = { + const relativePathToPytest = 'pythonFiles/pytest-vscode-integration'; + const fpath = path.join(EXTENSION_ROOT_DIR, relativePathToPytest); + // console.debug('1.2: ', fpath); + const cc = 'sys.path.append('.concat(fpath.toString(), ')'); // 1.2: /Users/eleanorboyd/vscode-python/pythonFiles/pytest-vscode-integration + // console.debug('1.3: ', cc); + let command: TestDiscoveryCommand = buildDiscoveryCommand(cc, []); + const options3: TestCommandOptions = { workspaceFolder: uri, command, - cwd: this.cwd, + cwd: fpath, }; + this.testServer.sendCommand(options3); + + // const options2: TestCommandOptions = { + // workspaceFolder: uri, + // command3, + // cwd: this.cwd, + // }; this.deferred = createDeferred(); + const prom = this.deferred.promise; + const a = await prom; + console.debug('AAAA', a); - // Send the test command to the server. - // The server will fire an onDataReceived event once it gets a response. - this.testServer.sendCommand(options); + // // Send the test command to the server. + // // The server will fire an onDataReceived event once it gets a response. + // this.testServer.sendCommand(options2); + command = buildDiscoveryCommand('import pytest', []); + const options4: TestCommandOptions = { + workspaceFolder: uri, + command, + cwd: fpath, + }; + this.testServer.sendCommand(options4); } return this.deferred.promise; } } -function buildDiscoveryCommand(args: string[]): TestDiscoveryCommand { - const discoveryScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'pytest_adapter', 'pytest_discovery.py'); +function buildDiscoveryCommand(script: string, args: string[]): TestDiscoveryCommand { + const discoveryScript = script; return { script: discoveryScript, - args: ['--udiscovery', ...args], + args: [...args], }; } From 494b7778a43b7c735d714bdd259dc9d81de1530a Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 10 Nov 2022 11:30:42 -0800 Subject: [PATCH 06/26] rmv python file --- .../pytest_vscode_integration.py | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.py b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.py index 11cb14fc379b..e69de29bb2d1 100644 --- a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.py +++ b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.py @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- - -import pytest - - -def pytest_addoption(parser): - group = parser.getgroup("vscode-integration") - group.addoption( - "--foo", - action="store", - dest="dest_foo", - default="2022", - help='Set the value for the fixture "bar".', - ) - - parser.addini("HELLO", "Dummy pytest.ini setting") - - -@pytest.fixture -def bar(request): - return request.config.option.dest_foo - - -def pytest_runtest_setup(item): - # called for running each test in 'a' directory - print("AAAAA: setting up", item) From f4df6f5e33066fd2970dc8c25be8a69acef70865 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 10 Nov 2022 14:05:01 -0800 Subject: [PATCH 07/26] delete pytest plugin --- .../pytest-vscode-integration/.gitignore | 74 ------------- pythonFiles/pytest-vscode-integration/LICENSE | 22 ---- .../pytest-vscode-integration/MANIFEST.in | 5 - .../pytest-vscode-integration/README.rst | 76 ------------- .../pytest-vscode-integration/appveyor.yml | 40 ------- .../build/lib/pytest_vscode_integration.py | 21 ---- .../pytest-vscode-integration/docs/index.md | 3 - .../pytest-vscode-integration/mkdocs.yml | 10 -- .../PKG-INFO | 104 ------------------ .../SOURCES.txt | 11 -- .../dependency_links.txt | 1 - .../entry_points.txt | 2 - .../requires.txt | 1 - .../top_level.txt | 1 - .../pytest_vscode_integration.py | 0 .../pytest-vscode-integration/setup.py | 51 --------- .../tests/conftest.py | 1 - .../tests/test_vscode_integration.py | 64 ----------- pythonFiles/pytest-vscode-integration/tox.ini | 12 -- 19 files changed, 499 deletions(-) delete mode 100644 pythonFiles/pytest-vscode-integration/.gitignore delete mode 100644 pythonFiles/pytest-vscode-integration/LICENSE delete mode 100644 pythonFiles/pytest-vscode-integration/MANIFEST.in delete mode 100644 pythonFiles/pytest-vscode-integration/README.rst delete mode 100644 pythonFiles/pytest-vscode-integration/appveyor.yml delete mode 100644 pythonFiles/pytest-vscode-integration/build/lib/pytest_vscode_integration.py delete mode 100644 pythonFiles/pytest-vscode-integration/docs/index.md delete mode 100644 pythonFiles/pytest-vscode-integration/mkdocs.yml delete mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/PKG-INFO delete mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/SOURCES.txt delete mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/dependency_links.txt delete mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/entry_points.txt delete mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/requires.txt delete mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/top_level.txt delete mode 100644 pythonFiles/pytest-vscode-integration/pytest_vscode_integration.py delete mode 100644 pythonFiles/pytest-vscode-integration/setup.py delete mode 100644 pythonFiles/pytest-vscode-integration/tests/conftest.py delete mode 100644 pythonFiles/pytest-vscode-integration/tests/test_vscode_integration.py delete mode 100644 pythonFiles/pytest-vscode-integration/tox.ini diff --git a/pythonFiles/pytest-vscode-integration/.gitignore b/pythonFiles/pytest-vscode-integration/.gitignore deleted file mode 100644 index 6c5886e04363..000000000000 --- a/pythonFiles/pytest-vscode-integration/.gitignore +++ /dev/null @@ -1,74 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover -.hypothesis/ -.pytest_cache - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py - -# Flask instance folder -instance/ - -# Sphinx documentation -docs/_build/ - -# MkDocs documentation -/site/ - -# PyBuilder -target/ - -# IPython Notebook -.ipynb_checkpoints - -# pyenv -.python-version - diff --git a/pythonFiles/pytest-vscode-integration/LICENSE b/pythonFiles/pytest-vscode-integration/LICENSE deleted file mode 100644 index 544793b47855..000000000000 --- a/pythonFiles/pytest-vscode-integration/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ - -The MIT License (MIT) - -Copyright (c) 2022 Eleanor Boyd - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/pythonFiles/pytest-vscode-integration/MANIFEST.in b/pythonFiles/pytest-vscode-integration/MANIFEST.in deleted file mode 100644 index 1ade348bb74d..000000000000 --- a/pythonFiles/pytest-vscode-integration/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include LICENSE -include README.rst - -recursive-exclude * __pycache__ -recursive-exclude * *.py[co] diff --git a/pythonFiles/pytest-vscode-integration/README.rst b/pythonFiles/pytest-vscode-integration/README.rst deleted file mode 100644 index 28a55c3da118..000000000000 --- a/pythonFiles/pytest-vscode-integration/README.rst +++ /dev/null @@ -1,76 +0,0 @@ -========================= -pytest-vscode-integration -========================= - -.. image:: https://img.shields.io/pypi/v/pytest-vscode-integration.svg - :target: https://pypi.org/project/pytest-vscode-integration - :alt: PyPI version - -.. image:: https://img.shields.io/pypi/pyversions/pytest-vscode-integration.svg - :target: https://pypi.org/project/pytest-vscode-integration - :alt: Python versions - -.. image:: https://ci.appveyor.com/api/projects/status/github/eleanorboyd/pytest-vscode-integration?branch=master - :target: https://ci.appveyor.com/project/eleanorboyd/pytest-vscode-integration/branch/master - :alt: See Build Status on AppVeyor - -used to surface pytest functionality to ports for vscode integration - ----- - -This `pytest`_ plugin was generated with `Cookiecutter`_ along with `@hackebrot`_'s `cookiecutter-pytest-plugin`_ template. - - -Features --------- - -* TODO - - -Requirements ------------- - -* TODO - - -Installation ------------- - -You can install "pytest-vscode-integration" via `pip`_ from `PyPI`_:: - - $ pip install pytest-vscode-integration - - -Usage ------ - -* TODO - -Contributing ------------- -Contributions are very welcome. Tests can be run with `tox`_, please ensure -the coverage at least stays the same before you submit a pull request. - -License -------- - -Distributed under the terms of the `MIT`_ license, "pytest-vscode-integration" is free and open source software - - -Issues ------- - -If you encounter any problems, please `file an issue`_ along with a detailed description. - -.. _`Cookiecutter`: https://github.com/audreyr/cookiecutter -.. _`@hackebrot`: https://github.com/hackebrot -.. _`MIT`: http://opensource.org/licenses/MIT -.. _`BSD-3`: http://opensource.org/licenses/BSD-3-Clause -.. _`GNU GPL v3.0`: http://www.gnu.org/licenses/gpl-3.0.txt -.. _`Apache Software License 2.0`: http://www.apache.org/licenses/LICENSE-2.0 -.. _`cookiecutter-pytest-plugin`: https://github.com/pytest-dev/cookiecutter-pytest-plugin -.. _`file an issue`: https://github.com/eleanorboyd/pytest-vscode-integration/issues -.. _`pytest`: https://github.com/pytest-dev/pytest -.. _`tox`: https://tox.readthedocs.io/en/latest/ -.. _`pip`: https://pypi.org/project/pip/ -.. _`PyPI`: https://pypi.org/project diff --git a/pythonFiles/pytest-vscode-integration/appveyor.yml b/pythonFiles/pytest-vscode-integration/appveyor.yml deleted file mode 100644 index 61bdd159551a..000000000000 --- a/pythonFiles/pytest-vscode-integration/appveyor.yml +++ /dev/null @@ -1,40 +0,0 @@ -# What Python version is installed where: -# https://www.appveyor.com/docs/build-environment/#python - -environment: - matrix: - - PYTHON: "C:\\Python35" - TOX_ENV: "py35" - - - PYTHON: "C:\\Python36" - TOX_ENV: "py36" - - - PYTHON: "C:\\Python37" - TOX_ENV: "py37" - - - PYTHON: "C:\\Python38" - TOX_ENV: "py38" - -init: - - "%PYTHON%/python -V" - - "%PYTHON%/python -c \"import struct;print( 8 * struct.calcsize(\'P\'))\"" - -install: - - "%PYTHON%/Scripts/easy_install -U pip" - - "%PYTHON%/Scripts/pip install tox" - - "%PYTHON%/Scripts/pip install wheel" - -build: false # Not a C# project, build stuff at the test step instead. - -test_script: - - "%PYTHON%/Scripts/tox -e %TOX_ENV%" - -after_test: - - "%PYTHON%/python setup.py bdist_wheel" - - ps: "ls dist" - -artifacts: - - path: dist\* - -#on_success: -# - TODO: upload the content of dist/*.whl to a public wheelhouse diff --git a/pythonFiles/pytest-vscode-integration/build/lib/pytest_vscode_integration.py b/pythonFiles/pytest-vscode-integration/build/lib/pytest_vscode_integration.py deleted file mode 100644 index 692d49fb0258..000000000000 --- a/pythonFiles/pytest-vscode-integration/build/lib/pytest_vscode_integration.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -import pytest - - -def pytest_addoption(parser): - group = parser.getgroup('vscode-integration') - group.addoption( - '--foo', - action='store', - dest='dest_foo', - default='2022', - help='Set the value for the fixture "bar".' - ) - - parser.addini('HELLO', 'Dummy pytest.ini setting') - - -@pytest.fixture -def bar(request): - return request.config.option.dest_foo diff --git a/pythonFiles/pytest-vscode-integration/docs/index.md b/pythonFiles/pytest-vscode-integration/docs/index.md deleted file mode 100644 index 6502b106decf..000000000000 --- a/pythonFiles/pytest-vscode-integration/docs/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Welcome to pytest-vscode-integration - -used to surface pytest functionality to ports for vscode integration diff --git a/pythonFiles/pytest-vscode-integration/mkdocs.yml b/pythonFiles/pytest-vscode-integration/mkdocs.yml deleted file mode 100644 index e7aeb8d8508d..000000000000 --- a/pythonFiles/pytest-vscode-integration/mkdocs.yml +++ /dev/null @@ -1,10 +0,0 @@ -site_name: pytest-vscode-integration -site_description: used to surface pytest functionality to ports for vscode integration -site_author: Eleanor Boyd - -theme: readthedocs - -repo_url: https://github.com/eleanorboyd/pytest-vscode-integration - -pages: -- Home: index.md diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/PKG-INFO b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/PKG-INFO deleted file mode 100644 index 172aed3ab5bb..000000000000 --- a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/PKG-INFO +++ /dev/null @@ -1,104 +0,0 @@ -Metadata-Version: 2.1 -Name: pytest-vscode-integration -Version: 0.1.0 -Summary: used to surface pytest functionality to ports for vscode integration -Home-page: https://github.com/eleanorboyd/pytest-vscode-integration -Author: Eleanor Boyd -Author-email: eleanorboyd@microsoft.com -Maintainer: Eleanor Boyd -Maintainer-email: eleanorboyd@microsoft.com -License: MIT -Classifier: Development Status :: 4 - Beta -Classifier: Framework :: Pytest -Classifier: Intended Audience :: Developers -Classifier: Topic :: Software Development :: Testing -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Operating System :: OS Independent -Classifier: License :: OSI Approved :: MIT License -Requires-Python: >=3.5 -License-File: LICENSE - -========================= -pytest-vscode-integration -========================= - -.. image:: https://img.shields.io/pypi/v/pytest-vscode-integration.svg - :target: https://pypi.org/project/pytest-vscode-integration - :alt: PyPI version - -.. image:: https://img.shields.io/pypi/pyversions/pytest-vscode-integration.svg - :target: https://pypi.org/project/pytest-vscode-integration - :alt: Python versions - -.. image:: https://ci.appveyor.com/api/projects/status/github/eleanorboyd/pytest-vscode-integration?branch=master - :target: https://ci.appveyor.com/project/eleanorboyd/pytest-vscode-integration/branch/master - :alt: See Build Status on AppVeyor - -used to surface pytest functionality to ports for vscode integration - ----- - -This `pytest`_ plugin was generated with `Cookiecutter`_ along with `@hackebrot`_'s `cookiecutter-pytest-plugin`_ template. - - -Features --------- - -* TODO - - -Requirements ------------- - -* TODO - - -Installation ------------- - -You can install "pytest-vscode-integration" via `pip`_ from `PyPI`_:: - - $ pip install pytest-vscode-integration - - -Usage ------ - -* TODO - -Contributing ------------- -Contributions are very welcome. Tests can be run with `tox`_, please ensure -the coverage at least stays the same before you submit a pull request. - -License -------- - -Distributed under the terms of the `MIT`_ license, "pytest-vscode-integration" is free and open source software - - -Issues ------- - -If you encounter any problems, please `file an issue`_ along with a detailed description. - -.. _`Cookiecutter`: https://github.com/audreyr/cookiecutter -.. _`@hackebrot`: https://github.com/hackebrot -.. _`MIT`: http://opensource.org/licenses/MIT -.. _`BSD-3`: http://opensource.org/licenses/BSD-3-Clause -.. _`GNU GPL v3.0`: http://www.gnu.org/licenses/gpl-3.0.txt -.. _`Apache Software License 2.0`: http://www.apache.org/licenses/LICENSE-2.0 -.. _`cookiecutter-pytest-plugin`: https://github.com/pytest-dev/cookiecutter-pytest-plugin -.. _`file an issue`: https://github.com/eleanorboyd/pytest-vscode-integration/issues -.. _`pytest`: https://github.com/pytest-dev/pytest -.. _`tox`: https://tox.readthedocs.io/en/latest/ -.. _`pip`: https://pypi.org/project/pip/ -.. _`PyPI`: https://pypi.org/project diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/SOURCES.txt b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/SOURCES.txt deleted file mode 100644 index 3b06f2a2dcce..000000000000 --- a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/SOURCES.txt +++ /dev/null @@ -1,11 +0,0 @@ -LICENSE -MANIFEST.in -README.rst -pytest_vscode_integration.py -setup.py -pytest_vscode_integration.egg-info/PKG-INFO -pytest_vscode_integration.egg-info/SOURCES.txt -pytest_vscode_integration.egg-info/dependency_links.txt -pytest_vscode_integration.egg-info/entry_points.txt -pytest_vscode_integration.egg-info/requires.txt -pytest_vscode_integration.egg-info/top_level.txt \ No newline at end of file diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/dependency_links.txt b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/dependency_links.txt deleted file mode 100644 index 8b137891791f..000000000000 --- a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/entry_points.txt b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/entry_points.txt deleted file mode 100644 index 7df59de8857f..000000000000 --- a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[pytest11] -vscode-integration = pytest_vscode_integration diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/requires.txt b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/requires.txt deleted file mode 100644 index a1fa3684923e..000000000000 --- a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/requires.txt +++ /dev/null @@ -1 +0,0 @@ -pytest>=3.5.0 diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/top_level.txt b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/top_level.txt deleted file mode 100644 index ea1bb3c56250..000000000000 --- a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -pytest_vscode_integration diff --git a/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.py b/pythonFiles/pytest-vscode-integration/pytest_vscode_integration.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/pythonFiles/pytest-vscode-integration/setup.py b/pythonFiles/pytest-vscode-integration/setup.py deleted file mode 100644 index 9a5b79444162..000000000000 --- a/pythonFiles/pytest-vscode-integration/setup.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import codecs -import os - -from setuptools import setup - - -def read(fname): - file_path = os.path.join(os.path.dirname(__file__), fname) - return codecs.open(file_path, encoding='utf-8').read() - - -setup( - name='pytest-vscode-integration', - version='0.1.0', - author='Eleanor Boyd', - author_email='eleanorboyd@microsoft.com', - maintainer='Eleanor Boyd', - maintainer_email='eleanorboyd@microsoft.com', - license='MIT', - url='https://github.com/eleanorboyd/pytest-vscode-integration', - description='used to surface pytest functionality to ports for vscode integration', - long_description=read('README.rst'), - py_modules=['pytest_vscode_integration'], - python_requires='>=3.5', - install_requires=['pytest>=3.5.0'], - classifiers=[ - 'Development Status :: 4 - Beta', - 'Framework :: Pytest', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Testing', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Operating System :: OS Independent', - 'License :: OSI Approved :: MIT License', - ], - entry_points={ - 'pytest11': [ - 'vscode-integration = pytest_vscode_integration', - ], - }, -) diff --git a/pythonFiles/pytest-vscode-integration/tests/conftest.py b/pythonFiles/pytest-vscode-integration/tests/conftest.py deleted file mode 100644 index bc711e55fefd..000000000000 --- a/pythonFiles/pytest-vscode-integration/tests/conftest.py +++ /dev/null @@ -1 +0,0 @@ -pytest_plugins = 'pytester' diff --git a/pythonFiles/pytest-vscode-integration/tests/test_vscode_integration.py b/pythonFiles/pytest-vscode-integration/tests/test_vscode_integration.py deleted file mode 100644 index 657faa8e5881..000000000000 --- a/pythonFiles/pytest-vscode-integration/tests/test_vscode_integration.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- - - -def test_bar_fixture(testdir): - """Make sure that pytest accepts our fixture.""" - - # create a temporary pytest test module - testdir.makepyfile(""" - def test_sth(bar): - assert bar == "europython2015" - """) - - # run pytest with the following cmd args - result = testdir.runpytest( - '--foo=europython2015', - '-v' - ) - - # fnmatch_lines does an assertion internally - result.stdout.fnmatch_lines([ - '*::test_sth PASSED*', - ]) - - # make sure that that we get a '0' exit code for the testsuite - assert result.ret == 0 - - -def test_help_message(testdir): - result = testdir.runpytest( - '--help', - ) - # fnmatch_lines does an assertion internally - result.stdout.fnmatch_lines([ - 'vscode-integration:', - '*--foo=DEST_FOO*Set the value for the fixture "bar".', - ]) - - -def test_hello_ini_setting(testdir): - testdir.makeini(""" - [pytest] - HELLO = world - """) - - testdir.makepyfile(""" - import pytest - - @pytest.fixture - def hello(request): - return request.config.getini('HELLO') - - def test_hello_world(hello): - assert hello == 'world' - """) - - result = testdir.runpytest('-v') - - # fnmatch_lines does an assertion internally - result.stdout.fnmatch_lines([ - '*::test_hello_world PASSED*', - ]) - - # make sure that that we get a '0' exit code for the testsuite - assert result.ret == 0 diff --git a/pythonFiles/pytest-vscode-integration/tox.ini b/pythonFiles/pytest-vscode-integration/tox.ini deleted file mode 100644 index 9b037d48e319..000000000000 --- a/pythonFiles/pytest-vscode-integration/tox.ini +++ /dev/null @@ -1,12 +0,0 @@ -# For more information about tox, see https://tox.readthedocs.io/en/latest/ -[tox] -envlist = py35,py36,py37,py38,pypy3,flake8 - -[testenv] -deps = pytest>=3.0 -commands = pytest {posargs:tests} - -[testenv:flake8] -skip_install = true -deps = flake8 -commands = flake8 pytest_vscode_integration.py setup.py tests From e0a8adcde17d756e1631951b53d3991bb68b6261 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 10 Nov 2022 14:07:31 -0800 Subject: [PATCH 08/26] rename reverse --- pythonFiles/{unittest_adapter => unittestadapter}/__init__.py | 0 .../unittest_discovery.py => unittestadapter/discovery.py} | 0 .../unittest_execution.py => unittestadapter/execution.py} | 0 pythonFiles/{unittest_adapter => unittestadapter}/utils.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename pythonFiles/{unittest_adapter => unittestadapter}/__init__.py (100%) rename pythonFiles/{unittest_adapter/unittest_discovery.py => unittestadapter/discovery.py} (100%) rename pythonFiles/{unittest_adapter/unittest_execution.py => unittestadapter/execution.py} (100%) rename pythonFiles/{unittest_adapter => unittestadapter}/utils.py (100%) diff --git a/pythonFiles/unittest_adapter/__init__.py b/pythonFiles/unittestadapter/__init__.py similarity index 100% rename from pythonFiles/unittest_adapter/__init__.py rename to pythonFiles/unittestadapter/__init__.py diff --git a/pythonFiles/unittest_adapter/unittest_discovery.py b/pythonFiles/unittestadapter/discovery.py similarity index 100% rename from pythonFiles/unittest_adapter/unittest_discovery.py rename to pythonFiles/unittestadapter/discovery.py diff --git a/pythonFiles/unittest_adapter/unittest_execution.py b/pythonFiles/unittestadapter/execution.py similarity index 100% rename from pythonFiles/unittest_adapter/unittest_execution.py rename to pythonFiles/unittestadapter/execution.py diff --git a/pythonFiles/unittest_adapter/utils.py b/pythonFiles/unittestadapter/utils.py similarity index 100% rename from pythonFiles/unittest_adapter/utils.py rename to pythonFiles/unittestadapter/utils.py From 101a60598a7884757ef8dc9477d00b5f6d255900 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 10 Nov 2022 14:09:11 -0800 Subject: [PATCH 09/26] remove files --- .vscode/settings.json | 5 - pythonFiles/pytest_adapter/__init__.py | 2 - pythonFiles/pytest_adapter/conftest.py | 28 --- .../pytest_adapter/pytest_discovery.py | 159 ------------ .../pytest_adapter/pytest_execution.py | 0 pythonFiles/pytest_adapter/pytest_utils.py | 228 ------------------ 6 files changed, 422 deletions(-) delete mode 100644 pythonFiles/pytest_adapter/__init__.py delete mode 100644 pythonFiles/pytest_adapter/conftest.py delete mode 100644 pythonFiles/pytest_adapter/pytest_discovery.py delete mode 100644 pythonFiles/pytest_adapter/pytest_execution.py delete mode 100644 pythonFiles/pytest_adapter/pytest_utils.py diff --git a/.vscode/settings.json b/.vscode/settings.json index b46b2e8e40b6..f54fc284cac9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -66,9 +66,4 @@ ], "typescript.preferences.importModuleSpecifier": "relative", "debug.javascript.usePreview": false, - "python.testing.pytestArgs": [ - "." - ], - "python.testing.unittestEnabled": false, - "python.testing.pytestEnabled": true } diff --git a/pythonFiles/pytest_adapter/__init__.py b/pythonFiles/pytest_adapter/__init__.py deleted file mode 100644 index 5b7f7a925cc0..000000000000 --- a/pythonFiles/pytest_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/pytest_adapter/conftest.py b/pythonFiles/pytest_adapter/conftest.py deleted file mode 100644 index e562b648576e..000000000000 --- a/pythonFiles/pytest_adapter/conftest.py +++ /dev/null @@ -1,28 +0,0 @@ -import os -import sys - -import pytest - -sys.path.append( - "/Users/eleanorboyd/.vscode/extensions/ms-python.python-2022.12.1/pythonFiles/lib/python" -) # -import debugpy - -debugpy.connect(5678) - - -@pytest.hookimpl() -def pytest_sessionstart(session): - print("hello") - - -def pytest_collection_finish(session): - print("end collection") - for item in session.items: - print("**") - parentCur = item.parent - path = str(item.name) + "> " - while parentCur != None: - path += str(parentCur.name) + "> " - parentCur = parentCur.parent - print("P:", path) diff --git a/pythonFiles/pytest_adapter/pytest_discovery.py b/pythonFiles/pytest_adapter/pytest_discovery.py deleted file mode 100644 index e8089944aa73..000000000000 --- a/pythonFiles/pytest_adapter/pytest_discovery.py +++ /dev/null @@ -1,159 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import argparse -import json -import logging -import os -import pathlib -import sys -import traceback -from typing import List, Literal, Optional, Tuple, TypedDict, Union - -import pytest -import pytest_vscode_integration - -sys.path.append( - "/Users/eleanorboyd/.vscode/extensions/ms-python.python-2022.12.1/pythonFiles/lib/python" -) # -import debugpy - -debugpy.connect(5678) - -# Add the path to pythonFiles to sys.path to find testing_tools.socket_manager. -PYTHON_FILES = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -sys.path.insert(0, PYTHON_FILES) - - -from pytest_utils import TestNode, parse_unittest_args -from testing_tools import socket_manager - -# Add the lib path to sys.path to find the typing_extensions module. -sys.path.insert(0, os.path.join(PYTHON_FILES, "lib", "python")) - - -# pytest_plugins = ("myapp.testsupport.myplugin",) - -from typing_extensions import NotRequired - -DEFAULT_PORT = "45454" - - -def parse_discovery_cli_args(args: List[str]) -> Tuple[int, Union[str, None]]: - """Parse command-line arguments that should be processed by the script. - - So far this includes the port number that it needs to connect to, and the uuid passed by the TS side. - The port is passed to the discovery.py script when it is executed, and - defaults to DEFAULT_PORT if it can't be parsed. - The uuid should be passed to the discovery.py script when it is executed, and defaults to None if it can't be parsed. - If the arguments appear several times, the value returned by parse_cli_args will be the value of the last argument. - """ - arg_parser = argparse.ArgumentParser() - arg_parser.add_argument("--port", default=DEFAULT_PORT) - arg_parser.add_argument("--uuid") - arg_parser.add_argument("--udiscovery") - parsed_args, _ = arg_parser.parse_known_args(args) - - return int(parsed_args.port), parsed_args.uuid, parsed_args.udiscovery - - -class PayloadDict(TypedDict): - cwd: str - status: Literal["success", "error"] - tests: NotRequired[TestNode] - errors: NotRequired[List[str]] - - -def discover_tests(start_dir: str) -> PayloadDict: - """Returns a dictionary containing details of the discovered tests. - - The returned dict has the following keys: - - - cwd: Absolute path to the test start directory; - - uuid: UUID sent by the caller of the Python script, that needs to be sent back as an integrity check; - - status: Test discovery status, can be "success" or "error"; - - tests: Discoverered tests if any, not present otherwise. Note that the status can be "error" but the payload can still contain tests; - - errors: Discovery errors if any, not present otherwise. - - Payload format for a successful discovery: - { - "status": "success", - "cwd": , - "tests": - } - - Payload format for a successful discovery with no tests: - { - "status": "success", - "cwd": , - } - - Payload format when there are errors: - { - "cwd": - "errors": [list of errors] - "status": "error", - } - """ - cwd = os.path.abspath(start_dir) - payload: PayloadDict = {"cwd": cwd, "status": "success"} - tests = None - errors: List[str] = [] - - try: - # test loading - tests = "" - # retcode = pytest.main(["--collect-only", "-q"]) - # print("dine") - # sys.exit(pytest.main(["-qq"], plugins=[MyPlugin()])) - # python - - os.system("python3 -m pytest --collect-only") - print("HELLO") - os.system("python3 -m pytest --collect-only -p pytest-vscode-integration") - - except Exception: - errors.append(traceback.format_exc()) - - if tests is not None: - payload["tests"] = tests - - if len(errors): - payload["status"] = "error" - payload["errors"] = errors - - return payload - - -class MyPlugin: - def pytest_sessionfinish(self): - print("*** test run reporting finishing") - - -if __name__ == "__main__": - # Get unittest discovery arguments. - argv = sys.argv[1:] - index = argv.index("--udiscovery") - - # start_dir, pattern, top_level_dir = parse_unittest_args(argv[index + 1 :]) - # logging.debug( - # "start_dir, pattern, top_level_dir", start_dir, pattern, top_level_dir - # ) - # logging.debug("hi") - - # Perform test discovery. - port, uuid, start_dir = parse_discovery_cli_args(argv) - - payload = discover_tests(start_dir) - - # Build the request data (it has to be a POST request or the Node side will not process it), and send it. - addr = ("localhost", port) - with socket_manager.SocketManager(addr) as s: - data = json.dumps(payload) - request = f"""POST / HTTP/1.1 -Host: localhost:{port} -Content-Length: {len(data)} -Content-Type: application/json -Request-uuid: {uuid} - -{data}""" - result = s.socket.sendall(request.encode("utf-8")) # type: ignore diff --git a/pythonFiles/pytest_adapter/pytest_execution.py b/pythonFiles/pytest_adapter/pytest_execution.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/pythonFiles/pytest_adapter/pytest_utils.py b/pythonFiles/pytest_adapter/pytest_utils.py deleted file mode 100644 index 568ff30ee92d..000000000000 --- a/pythonFiles/pytest_adapter/pytest_utils.py +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import argparse -import enum -import inspect -import os -import pathlib -import unittest -from typing import List, Tuple, TypedDict, Union - -# Types - - -# Inherit from str so it's JSON serializable. -class TestNodeTypeEnum(str, enum.Enum): - class_ = "class" - file = "file" - folder = "folder" - test = "test" - - -class TestData(TypedDict): - name: str - path: str - type_: TestNodeTypeEnum - id_: str - - -class TestItem(TestData): - lineno: str - runID: str - - -class TestNode(TestData): - children: "List[TestNode | TestItem]" - - -# Helper functions for data retrieval. - - -def get_test_case(suite): - """Iterate through a unittest test suite and return all test cases.""" - for test in suite: - if isinstance(test, unittest.TestCase): - yield test - else: - for test_case in get_test_case(test): - yield test_case - - -def get_source_line(obj) -> str: - """Get the line number of a test case start line.""" - try: - sourcelines, lineno = inspect.getsourcelines(obj) - except: - try: - # tornado-specific, see https://github.com/microsoft/vscode-python/issues/17285. - sourcelines, lineno = inspect.getsourcelines(obj.orig_method) - except: - return "*" - - # Return the line number of the first line of the test case definition. - for i, v in enumerate(sourcelines): - if v.strip().startswith(("def", "async def")): - return str(lineno + i) - - return "*" - - -# Helper functions for test tree building. - - -def build_test_node(path: str, name: str, type_: TestNodeTypeEnum) -> TestNode: - """Build a test node with no children. A test node can be a folder, a file or a class.""" - ## figure out if we are folder, file, or class - id_gen = path - if type_ == TestNodeTypeEnum.folder or type_ == TestNodeTypeEnum.file: - id_gen = path - else: - # means we have to build test node for class - id_gen = path + "\\" + name - - return {"path": path, "name": name, "type_": type_, "children": [], "id_": id_gen} - - -def get_child_node( - name: str, path: str, type_: TestNodeTypeEnum, root: TestNode -) -> TestNode: - """Find a child node in a test tree given its name and type. If the node doesn't exist, create it.""" - try: - result = next( - node - for node in root["children"] - if node["name"] == name and node["type_"] == type_ - ) - except StopIteration: - result = build_test_node(path, name, type_) - root["children"].append(result) - - return result # type:ignore - - -def build_test_tree( - suite: unittest.TestSuite, test_directory: str -) -> Tuple[Union[TestNode, None], List[str]]: - """Build a test tree from a unittest test suite. - - This function returns the test tree, and any errors found by unittest. - If no tests were discovered, return `None` and a list of errors (if any). - - Test tree structure: - { - "path": , - "type": "folder", - "name": , - "children": [ - { files and folders } - ... - { - "path": , - "name": filename.py, - "type_": "file", - "children": [ - { - "path": , - "name": , - "type_": "class", - "children": [ - { - "path": , - "name": , - "type_": "test", - "lineno": - "id_": , - } - ], - "id_": - } - ], - "id_": - } - ], - "id_": - } - """ - errors = [] - directory_path = pathlib.PurePath(test_directory) - root = build_test_node(test_directory, directory_path.name, TestNodeTypeEnum.folder) - - for test_case in get_test_case(suite): - test_id = test_case.id() - if test_id.startswith("unittest.loader._FailedTest"): - errors.append(str(test_case._exception)) # type: ignore - else: - # Get the static test path components: filename, class name and function name. - components = test_id.split(".") - *folders, filename, class_name, function_name = components - py_filename = f"{filename}.py" - - current_node = root - - # Find/build nodes for the intermediate folders in the test path. - for folder in folders: - current_node = get_child_node( - folder, - os.fsdecode(pathlib.PurePath(current_node["path"], folder)), - TestNodeTypeEnum.folder, - current_node, - ) - - # Find/build file node. - path_components = [test_directory] + folders + [py_filename] - file_path = os.fsdecode(pathlib.PurePath("/".join(path_components))) - current_node = get_child_node( - py_filename, file_path, TestNodeTypeEnum.file, current_node - ) - - # Find/build class node. - current_node = get_child_node( - class_name, file_path, TestNodeTypeEnum.class_, current_node - ) - - # Get test line number. - test_method = getattr(test_case, test_case._testMethodName) - lineno = get_source_line(test_method) - - # Add test node. - test_node: TestItem = { - "name": function_name, - "path": file_path, - "lineno": lineno, - "type_": TestNodeTypeEnum.test, - "id_": file_path + "\\" + class_name + "\\" + function_name, - "runID": test_id, - } # concatenate class name and function test name - current_node["children"].append(test_node) - - if not root["children"]: - root = None - - return root, errors - - -def parse_unittest_args(args: List[str]) -> Tuple[str, str, Union[str, None]]: - """Parse command-line arguments that should be forwarded to unittest to perform discovery. - - Valid unittest arguments are: -v, -s, -p, -t and their long-form counterparts, - however we only care about the last three. - - The returned tuple contains the following items - - start_directory: The directory where to start discovery, defaults to . - - pattern: The pattern to match test files, defaults to test*.py - - top_level_directory: The top-level directory of the project, defaults to None, and unittest will use start_directory behind the scenes. - """ - - arg_parser = argparse.ArgumentParser() - arg_parser.add_argument("--start-directory", "-s", default=".") - arg_parser.add_argument("--pattern", "-p", default="test*.py") - arg_parser.add_argument("--top-level-directory", "-t", default=None) - - parsed_args, _ = arg_parser.parse_known_args(args) - - return ( - parsed_args.start_directory, - parsed_args.pattern, - parsed_args.top_level_directory, - ) From d14d4fbbd678e5a9474b6bf083274366d49c5765 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 10 Nov 2022 14:38:40 -0800 Subject: [PATCH 10/26] reverse uneeded edits --- .vscode/settings.json | 2 +- pythonFiles/testing_tools/run_adapter.py | 1 - pythonFiles/unittestadapter/discovery.py | 13 +------------ pythonFiles/unittestadapter/execution.py | 2 +- src/client/testing/testController/controller.ts | 3 --- .../unittest/unittestDiscoveryAdapter.ts | 4 ++-- .../unittest/unittestExecutionAdapter.ts | 2 +- 7 files changed, 6 insertions(+), 21 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f54fc284cac9..174a850c901e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,5 +65,5 @@ "--max-line-length=88" ], "typescript.preferences.importModuleSpecifier": "relative", - "debug.javascript.usePreview": false, + "debug.javascript.usePreview": false } diff --git a/pythonFiles/testing_tools/run_adapter.py b/pythonFiles/testing_tools/run_adapter.py index b2c6c35608ff..4d888ffb60b0 100644 --- a/pythonFiles/testing_tools/run_adapter.py +++ b/pythonFiles/testing_tools/run_adapter.py @@ -19,4 +19,3 @@ if __name__ == "__main__": tool, cmd, subargs, toolargs = parse_args() main(tool, cmd, subargs, toolargs) - print("run adapter hello") diff --git a/pythonFiles/unittestadapter/discovery.py b/pythonFiles/unittestadapter/discovery.py index cc09637078ee..0be09e986ca8 100644 --- a/pythonFiles/unittestadapter/discovery.py +++ b/pythonFiles/unittestadapter/discovery.py @@ -3,7 +3,6 @@ import argparse import json -import logging import os import pathlib import sys @@ -11,13 +10,6 @@ import unittest from typing import List, Literal, Optional, Tuple, TypedDict, Union -sys.path.append( - "/Users/eleanorboyd/.vscode/extensions/ms-python.python-2022.12.1/pythonFiles/lib/python" -) # -import debugpy - -debugpy.connect(5678) - # Add the path to pythonFiles to sys.path to find testing_tools.socket_manager. PYTHON_FILES = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, PYTHON_FILES) @@ -25,7 +17,7 @@ from testing_tools import socket_manager # If I use from utils then there will be an import error in test_discovery.py. -from unittest_adapter.utils import TestNode, build_test_tree, parse_unittest_args +from unittestadapter.utils import TestNode, build_test_tree, parse_unittest_args # Add the lib path to sys.path to find the typing_extensions module. sys.path.insert(0, os.path.join(PYTHON_FILES, "lib", "python")) @@ -122,9 +114,6 @@ def discover_tests( index = argv.index("--udiscovery") start_dir, pattern, top_level_dir = parse_unittest_args(argv[index + 1 :]) - logging.debug( - "start_dir, pattern, top_level_dir", start_dir, pattern, top_level_dir - ) # Perform test discovery. port, uuid = parse_discovery_cli_args(argv[:index]) diff --git a/pythonFiles/unittestadapter/execution.py b/pythonFiles/unittestadapter/execution.py index 935e7fbeae57..a016ff1af9ec 100644 --- a/pythonFiles/unittestadapter/execution.py +++ b/pythonFiles/unittestadapter/execution.py @@ -18,7 +18,7 @@ sys.path.insert(0, os.path.join(PYTHON_FILES, "lib", "python")) from testing_tools import socket_manager from typing_extensions import NotRequired -from unittest_adapter.utils import parse_unittest_args +from unittestadapter.utils import parse_unittest_args DEFAULT_PORT = "45454" diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index c96e1f9492f0..e590101c5e04 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -144,11 +144,8 @@ export class PythonTestController implements ITestController, IExtensionSingleAc }); return this.refreshTestData(undefined, { forceRefresh: true }); }; -<<<<<<< HEAD -======= // this.pythonTestServer = new PythonTestServer(this.pythonExecFactory); // old way where debugLauncher did not have to be passed ->>>>>>> 9cca1d959 (pytest is now running - unable to collect output) this.pythonTestServer = new PythonTestServer(this.pythonExecFactory, this.debugLauncher); } diff --git a/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts b/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts index d50d0ce3961b..f0a5a957807c 100644 --- a/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts +++ b/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts @@ -16,7 +16,7 @@ import { } from '../common/types'; /** - * Wrapper class for unittest test discovery. This is where we call `runTestCommand`. #this seems incorrectly copied + * Wrapper class for unittest test discovery. This is where we call `runTestCommand`. */ export class UnittestTestDiscoveryAdapter implements ITestDiscoveryAdapter { private deferred: Deferred | undefined; @@ -63,7 +63,7 @@ export class UnittestTestDiscoveryAdapter implements ITestDiscoveryAdapter { } function buildDiscoveryCommand(args: string[]): TestDiscoveryCommand { - const discoveryScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittest_adapter', 'unittest_discovery.py'); + const discoveryScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'discovery.py'); return { script: discoveryScript, diff --git a/src/client/testing/testController/unittest/unittestExecutionAdapter.ts b/src/client/testing/testController/unittest/unittestExecutionAdapter.ts index 2b4e098323a4..d71dea9fea36 100644 --- a/src/client/testing/testController/unittest/unittestExecutionAdapter.ts +++ b/src/client/testing/testController/unittest/unittestExecutionAdapter.ts @@ -64,7 +64,7 @@ export class UnittestTestExecutionAdapter implements ITestExecutionAdapter { } function buildExecutionCommand(args: string[]): TestExecutionCommand { - const executionScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittest_adapter', 'unittest_execution.py'); + const executionScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'execution.py'); return { script: executionScript, From a670f14eec44dcd3657493382c5fa043dbb7166e Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 10 Nov 2022 14:41:27 -0800 Subject: [PATCH 11/26] change file naming --- .../{unittestDiscoveryAdapter.ts => testDiscoveryAdapter.ts} | 0 .../{unittestExecutionAdapter.ts => testExecutionAdapter.ts} | 0 .../testController/unittest/testDiscoveryAdapter.unit.test.ts | 2 +- .../testing/testController/workspaceTestAdapter.unit.test.ts | 4 ++-- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/client/testing/testController/unittest/{unittestDiscoveryAdapter.ts => testDiscoveryAdapter.ts} (100%) rename src/client/testing/testController/unittest/{unittestExecutionAdapter.ts => testExecutionAdapter.ts} (100%) diff --git a/src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts b/src/client/testing/testController/unittest/testDiscoveryAdapter.ts similarity index 100% rename from src/client/testing/testController/unittest/unittestDiscoveryAdapter.ts rename to src/client/testing/testController/unittest/testDiscoveryAdapter.ts diff --git a/src/client/testing/testController/unittest/unittestExecutionAdapter.ts b/src/client/testing/testController/unittest/testExecutionAdapter.ts similarity index 100% rename from src/client/testing/testController/unittest/unittestExecutionAdapter.ts rename to src/client/testing/testController/unittest/testExecutionAdapter.ts diff --git a/src/test/testing/testController/unittest/testDiscoveryAdapter.unit.test.ts b/src/test/testing/testController/unittest/testDiscoveryAdapter.unit.test.ts index 9f8dbeabb4b3..cee4353db09a 100644 --- a/src/test/testing/testController/unittest/testDiscoveryAdapter.unit.test.ts +++ b/src/test/testing/testController/unittest/testDiscoveryAdapter.unit.test.ts @@ -7,7 +7,7 @@ import { Uri } from 'vscode'; import { IConfigurationService } from '../../../../client/common/types'; import { EXTENSION_ROOT_DIR } from '../../../../client/constants'; import { ITestServer, TestCommandOptions } from '../../../../client/testing/testController/common/types'; -import { UnittestTestDiscoveryAdapter } from '../../../../client/testing/testController/unittest/unittestDiscoveryAdapter'; +import { UnittestTestDiscoveryAdapter } from '../../../../client/testing/testController/unittest/testDiscoveryAdapter'; suite('Unittest test discovery adapter', () => { let stubConfigSettings: IConfigurationService; diff --git a/src/test/testing/testController/workspaceTestAdapter.unit.test.ts b/src/test/testing/testController/workspaceTestAdapter.unit.test.ts index 8d875ef60f6c..b6be8d6081de 100644 --- a/src/test/testing/testController/workspaceTestAdapter.unit.test.ts +++ b/src/test/testing/testController/workspaceTestAdapter.unit.test.ts @@ -6,8 +6,8 @@ import * as sinon from 'sinon'; import { TestController, TestItem, Uri } from 'vscode'; import { IConfigurationService } from '../../../client/common/types'; -import { UnittestTestDiscoveryAdapter } from '../../../client/testing/testController/unittest/unittestDiscoveryAdapter'; -import { UnittestTestExecutionAdapter } from '../../../client/testing/testController/unittest/unittestExecutionAdapter'; // 7/7 +import { UnittestTestDiscoveryAdapter } from '../../../client/testing/testController/unittest/testDiscoveryAdapter'; +import { UnittestTestExecutionAdapter } from '../../../client/testing/testController/unittest/testExecutionAdapter'; // 7/7 import { WorkspaceTestAdapter } from '../../../client/testing/testController/workspaceTestAdapter'; import * as Telemetry from '../../../client/telemetry'; import { EventName } from '../../../client/telemetry/constants'; From 8eb76122f25679afe6b6d0d500d524a228dec589 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 10 Nov 2022 14:42:38 -0800 Subject: [PATCH 12/26] controler changes --- src/client/testing/testController/controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index e590101c5e04..0a2b999b6a9e 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -39,8 +39,8 @@ import { ITestExecutionAdapter, } from './common/types'; // TODO: create pytest and add to import -import { UnittestTestDiscoveryAdapter } from './unittest/unittestDiscoveryAdapter'; -import { UnittestTestExecutionAdapter } from './unittest/unittestExecutionAdapter'; +import { UnittestTestDiscoveryAdapter } from './unittest/testDiscoveryAdapter'; +import { UnittestTestExecutionAdapter } from './unittest/testExecutionAdapter'; import { PytestTestDiscoveryAdapter } from './pytest/pytestDiscoveryAdapter'; import { PytestTestExecutionAdapter } from './pytest/pytestExecutionAdapter'; import { WorkspaceTestAdapter } from './workspaceTestAdapter'; From 6d45f0654296fde09665e5d5c0005fbcfabd305f Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 10 Nov 2022 14:44:32 -0800 Subject: [PATCH 13/26] remove testing logic --- src/client/testing/testController/pytest/arguments.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/testing/testController/pytest/arguments.ts b/src/client/testing/testController/pytest/arguments.ts index 25b2853539e7..78b451acdd6b 100644 --- a/src/client/testing/testController/pytest/arguments.ts +++ b/src/client/testing/testController/pytest/arguments.ts @@ -263,7 +263,7 @@ export function preparePytestArgumentsForDiscovery(options: TestDiscoveryOptions // Remove unwanted arguments (which happen to be test directories & test specific args). const args = pytestFilterArguments(options.args, TestFilter.discovery); if (options.ignoreCache && args.indexOf('--cache-clear') === -1) { - args.splice(0, 0, 'bbbbb--cache-clear'); + args.splice(0, 0, '--cache-clear'); } if (args.indexOf('-s') === -1) { args.splice(0, 0, '-s'); From b30adfdf5204fa2194ab35c2395ee059fa54cd19 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 10 Nov 2022 15:03:31 -0800 Subject: [PATCH 14/26] remove comments and logs --- src/client/testing/testController/common/server.ts | 11 +++++++++++ src/client/testing/testController/controller.ts | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/client/testing/testController/common/server.ts b/src/client/testing/testController/common/server.ts index df5e2c2e7eae..ee49e13d6d21 100644 --- a/src/client/testing/testController/common/server.ts +++ b/src/client/testing/testController/common/server.ts @@ -71,6 +71,11 @@ export class PythonTestServer implements ITestServer, Disposable { return (this.server.address() as net.AddressInfo).port; } + /** + * TODO: not actually sure if this is necessary! + * @param options + * @returns + */ public createUUID(options: TestCommandOptions): string { const uuid = crypto.randomUUID(); this.uuids.set(uuid, options.cwd); @@ -86,6 +91,12 @@ export class PythonTestServer implements ITestServer, Disposable { return this._onDataReceived.event; } + /** + * Sends the pytest command to the server with the passed in args + * @param options configuration options + * @param args arguments to be passed to pytest + * @returns Promise + */ async sendCommandPytest(options: TestCommandOptions, args: string[]): Promise { const uuid = this.createUUID(options); const spawnOptions: SpawnOptions = { diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index 0a2b999b6a9e..2e414e30b508 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -315,7 +315,6 @@ export class PythonTestController implements ITestController, IExtensionSingleAc const settings = this.configSettings.getSettings(item.uri); if (settings.testing.pytestEnabled) { return this.pytest.resolveChildren(this.testController, item, this.refreshCancellation.token); - // ** check resolve children functionality } if (settings.testing.unittestEnabled) { return this.unittest.resolveChildren(this.testController, item, this.refreshCancellation.token); @@ -334,11 +333,6 @@ export class PythonTestController implements ITestController, IExtensionSingleAc }), ); } - console.log('HERE2'); - this.testController.items.forEach((element) => console.log(element)); - - console.log(this.testController.items); - console.log('size', this.testController.items.size); return Promise.resolve(); } @@ -388,11 +382,9 @@ export class PythonTestController implements ITestController, IExtensionSingleAc if (testItems.length > 0) { if (settings.testing.pytestEnabled) { sendTelemetryEvent(EventName.UNITTEST_RUN, undefined, { - // seems like this telemetry is named incorrectly? tool: 'pytest', debugging: request.profile?.kind === TestRunProfileKind.Debug, }); - // ** update this to reflect the nwe execution style before return this.pytest.runTests( { includes: testItems, @@ -439,7 +431,6 @@ export class PythonTestController implements ITestController, IExtensionSingleAc } if (!settings.testing.pytestEnabled && !settings.testing.unittestEnabled) { - // ** this could be the logic I am looking for unconfiguredWorkspaces.push(workspace); } return Promise.resolve(); @@ -523,8 +514,6 @@ export class PythonTestController implements ITestController, IExtensionSingleAc ); } - // ** not sure about the telemetry - /** * Send UNITTEST_DISCOVERY_TRIGGER telemetry event only once per trigger type. * From 8d3b7b369e2dc2e353edc9a8f3aa5ee6e8dee2ec Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 10 Nov 2022 15:13:10 -0800 Subject: [PATCH 15/26] comment out new code --- .../testing/testController/controller.ts | 64 +++++++------------ 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index 2e414e30b508..ddfa582e5318 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -38,7 +38,6 @@ import { TestRefreshOptions, ITestExecutionAdapter, } from './common/types'; -// TODO: create pytest and add to import import { UnittestTestDiscoveryAdapter } from './unittest/testDiscoveryAdapter'; import { UnittestTestExecutionAdapter } from './unittest/testExecutionAdapter'; import { PytestTestDiscoveryAdapter } from './pytest/pytestDiscoveryAdapter'; @@ -160,22 +159,16 @@ export class PythonTestController implements ITestController, IExtensionSingleAc let discoveryAdapter: ITestDiscoveryAdapter; let executionAdapter: ITestExecutionAdapter; let testProvider: TestProvider; - if (settings.testing.pytestEnabled) { - console.log('settings.testing.pytestEnabled = true'); - discoveryAdapter = new PytestTestDiscoveryAdapter(this.pythonTestServer, this.configSettings); // what is the ... for - executionAdapter = new PytestTestExecutionAdapter(this.pythonTestServer, this.configSettings); - testProvider = PYTEST_PROVIDER; - } else if (settings.testing.unittestEnabled) { - console.log('settings.testing.unittestEnabled = true'); + if (settings.testing.unittestEnabled) { discoveryAdapter = new UnittestTestDiscoveryAdapter(this.pythonTestServer, this.configSettings); executionAdapter = new UnittestTestExecutionAdapter(this.pythonTestServer, this.configSettings); testProvider = UNITTEST_PROVIDER; } else { - // this would be an error because neither is enabled? - discoveryAdapter = new UnittestTestDiscoveryAdapter(this.pythonTestServer, this.configSettings); + discoveryAdapter = new UnittestTestDiscoveryAdapter(this.pythonTestServer, { ...this.configSettings }); executionAdapter = new UnittestTestExecutionAdapter(this.pythonTestServer, this.configSettings); testProvider = PYTEST_PROVIDER; } + // why is the default unit tests? Also shouldn't it test for pytest first because if both are enabled that comes first? const workspaceTestAdapter = new WorkspaceTestAdapter( testProvider, @@ -233,43 +226,35 @@ export class PythonTestController implements ITestController, IExtensionSingleAc this.refreshingStartedEvent.fire(); if (uri) { const settings = this.configSettings.getSettings(uri); + traceVerbose(`Testing: Refreshing test data for ${uri.fsPath}`); + const workspace = this.workspaceService.getWorkspaceFolder(uri); + console.warn(`Discover tests for workspace name: ${workspace?.name} - uri: ${uri.fsPath}`); if (settings.testing.pytestEnabled) { - traceVerbose(`Testing: Refreshing test data for ${uri.fsPath}`); - - // can I move these out of the if statement - const workspace = this.workspaceService.getWorkspaceFolder(uri); - console.warn(`Discover tests for workspace name: ${workspace?.name} - uri: ${uri.fsPath}`); - const testAdapter = - this.testAdapters.get(uri) || (this.testAdapters.values().next().value as WorkspaceTestAdapter); - testAdapter.discoverTests( - this.testController, - this.refreshCancellation.token, - this.testAdapters.size > 1, - this.workspaceService.workspaceFile?.fsPath, - ); + // const testAdapter = + // this.testAdapters.get(uri) || (this.testAdapters.values().next().value as WorkspaceTestAdapter); + // testAdapter.discoverTests( + // this.testController, + // this.refreshCancellation.token, + // this.testAdapters.size > 1, + // this.workspaceService.workspaceFile?.fsPath, + // ); // Ensure we send test telemetry if it gets disabled again this.sendTestDisabledTelemetry = true; // comment below 229 to run the new way and uncomment above 212 ~ 227 - // await this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); - - // await this.pytest.refreshTestData(this.testController, uri, this.refreshCancellation.token); + await this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); } else if (settings.testing.unittestEnabled) { - // TODO: Use new test discovery mechanism - traceVerbose(`Testing: Refreshing test data for ${uri.fsPath}`); - const workspace = this.workspaceService.getWorkspaceFolder(uri); - console.warn(`Discover tests for workspace name: ${workspace?.name} - uri: ${uri.fsPath}`); - const testAdapter = - this.testAdapters.get(uri) || (this.testAdapters.values().next().value as WorkspaceTestAdapter); - testAdapter.discoverTests( - this.testController, - this.refreshCancellation.token, - this.testAdapters.size > 1, - this.workspaceService.workspaceFile?.fsPath, - ); + // const testAdapter = + // this.testAdapters.get(uri) || (this.testAdapters.values().next().value as WorkspaceTestAdapter); + // testAdapter.discoverTests( + // this.testController, + // this.refreshCancellation.token, + // this.testAdapters.size > 1, + // this.workspaceService.workspaceFile?.fsPath, + // ); // Ensure we send test telemetry if it gets disabled again this.sendTestDisabledTelemetry = true; // comment below 229 to run the new way and uncomment above 212 ~ 227 - // await this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); + await this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); } else { if (this.sendTestDisabledTelemetry) { this.sendTestDisabledTelemetry = false; @@ -278,7 +263,6 @@ export class PythonTestController implements ITestController, IExtensionSingleAc // If we are here we may have to remove an existing node from the tree // This handles the case where user removes test settings. Which should remove the // tests for that particular case from the tree view - const workspace = this.workspaceService.getWorkspaceFolder(uri); if (workspace) { const toDelete: string[] = []; this.testController.items.forEach((i: TestItem) => { From e76ddf06ad69ef115589438fe1c337514bf9e787 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 10 Nov 2022 15:22:58 -0800 Subject: [PATCH 16/26] need to confirm it works after vscode isort fix --- src/client/testing/testController/controller.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index ddfa582e5318..2611ccd67bf9 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -143,8 +143,6 @@ export class PythonTestController implements ITestController, IExtensionSingleAc }); return this.refreshTestData(undefined, { forceRefresh: true }); }; - - // this.pythonTestServer = new PythonTestServer(this.pythonExecFactory); // old way where debugLauncher did not have to be passed this.pythonTestServer = new PythonTestServer(this.pythonExecFactory, this.debugLauncher); } @@ -164,8 +162,8 @@ export class PythonTestController implements ITestController, IExtensionSingleAc executionAdapter = new UnittestTestExecutionAdapter(this.pythonTestServer, this.configSettings); testProvider = UNITTEST_PROVIDER; } else { - discoveryAdapter = new UnittestTestDiscoveryAdapter(this.pythonTestServer, { ...this.configSettings }); - executionAdapter = new UnittestTestExecutionAdapter(this.pythonTestServer, this.configSettings); + discoveryAdapter = new PytestTestDiscoveryAdapter(this.pythonTestServer, { ...this.configSettings }); + executionAdapter = new PytestTestExecutionAdapter(this.pythonTestServer, this.configSettings); testProvider = PYTEST_PROVIDER; } // why is the default unit tests? Also shouldn't it test for pytest first because if both are enabled that comes first? @@ -241,7 +239,7 @@ export class PythonTestController implements ITestController, IExtensionSingleAc // Ensure we send test telemetry if it gets disabled again this.sendTestDisabledTelemetry = true; // comment below 229 to run the new way and uncomment above 212 ~ 227 - await this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); + await this.pytest.refreshTestData(this.testController, uri, this.refreshCancellation.token); } else if (settings.testing.unittestEnabled) { // const testAdapter = // this.testAdapters.get(uri) || (this.testAdapters.values().next().value as WorkspaceTestAdapter); From aece46ddf0ef0b5852527ce5d4913a037c3e9672 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Fri, 11 Nov 2022 11:39:57 -0800 Subject: [PATCH 17/26] requested Changes --- .../testing/testController/controller.ts | 2 -- .../pytest/pytestDiscoveryAdapter.ts | 20 +++---------------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index 2611ccd67bf9..a8c49126cacc 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -166,8 +166,6 @@ export class PythonTestController implements ITestController, IExtensionSingleAc executionAdapter = new PytestTestExecutionAdapter(this.pythonTestServer, this.configSettings); testProvider = PYTEST_PROVIDER; } - // why is the default unit tests? Also shouldn't it test for pytest first because if both are enabled that comes first? - const workspaceTestAdapter = new WorkspaceTestAdapter( testProvider, discoveryAdapter, diff --git a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts index f3b5c1ab2b2c..f89a63857730 100644 --- a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts +++ b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts @@ -16,7 +16,7 @@ import { } from '../common/types'; /** - * Wrapper class for unittest test discovery. This is where we call `runTestCommand`. #this seems incorrectly copied + * Wrapper class for pytest test discovery. This is where we call `discovery`. */ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { private deferred: Deferred | undefined; @@ -41,17 +41,10 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { const settings = this.configSettings.getSettings(uri); const { pytestArgs } = settings.testing; console.debug(pytestArgs); - // const command2 = buildDiscoveryCommand('-m pytest', ['--collect-only', ...pytestArgs]); - // const command = buildDiscoveryCommand('import pytest', []); - - this.cwd = uri.fsPath; // this.cwd normally = '/Users/eleanorboyd/Documents/testing - tester files/inc_dec_example' - // const discoveryScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittest_adapter', 'unittest_discovery.py'); - + this.cwd = uri.fsPath; const relativePathToPytest = 'pythonFiles/pytest-vscode-integration'; const fpath = path.join(EXTENSION_ROOT_DIR, relativePathToPytest); - // console.debug('1.2: ', fpath); - const cc = 'sys.path.append('.concat(fpath.toString(), ')'); // 1.2: /Users/eleanorboyd/vscode-python/pythonFiles/pytest-vscode-integration - // console.debug('1.3: ', cc); + const cc = 'sys.path.append('.concat(fpath.toString(), ')'); let command: TestDiscoveryCommand = buildDiscoveryCommand(cc, []); const options3: TestCommandOptions = { workspaceFolder: uri, @@ -60,12 +53,6 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { }; this.testServer.sendCommand(options3); - // const options2: TestCommandOptions = { - // workspaceFolder: uri, - // command3, - // cwd: this.cwd, - // }; - this.deferred = createDeferred(); const prom = this.deferred.promise; const a = await prom; @@ -73,7 +60,6 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { // // Send the test command to the server. // // The server will fire an onDataReceived event once it gets a response. - // this.testServer.sendCommand(options2); command = buildDiscoveryCommand('import pytest', []); const options4: TestCommandOptions = { workspaceFolder: uri, From b035b452074d0317e2cd75b52e5e0914d5d531fb Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Fri, 11 Nov 2022 11:41:15 -0800 Subject: [PATCH 18/26] fix comment --- .../testing/testController/unittest/testExecutionAdapter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/testing/testController/unittest/testExecutionAdapter.ts b/src/client/testing/testController/unittest/testExecutionAdapter.ts index d71dea9fea36..dcaceeb63f00 100644 --- a/src/client/testing/testController/unittest/testExecutionAdapter.ts +++ b/src/client/testing/testController/unittest/testExecutionAdapter.ts @@ -16,7 +16,7 @@ import { } from '../common/types'; /** - * Wrapper Class for unittest test execution. This is where we call `runTestCommand`? + * Wrapper Class for pytest test execution. This is where we call `runTestCommand`? */ export class UnittestTestExecutionAdapter implements ITestExecutionAdapter { From 0dee36f99c4567e9d29ef862a3bc1d5165133821 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Fri, 11 Nov 2022 11:42:07 -0800 Subject: [PATCH 19/26] reverse error --- .../testing/testController/pytest/pytestExecutionAdapter.ts | 2 +- .../testing/testController/unittest/testExecutionAdapter.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts index 35d62c50e774..8a36a7dc2cae 100644 --- a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts +++ b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts @@ -16,7 +16,7 @@ import { } from '../common/types'; /** - * Wrapper Class for unittest test execution. This is where we call `runTestCommand`? + * Wrapper Class for pytest test execution. This is where we call `runTestCommand`? */ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { diff --git a/src/client/testing/testController/unittest/testExecutionAdapter.ts b/src/client/testing/testController/unittest/testExecutionAdapter.ts index dcaceeb63f00..d71dea9fea36 100644 --- a/src/client/testing/testController/unittest/testExecutionAdapter.ts +++ b/src/client/testing/testController/unittest/testExecutionAdapter.ts @@ -16,7 +16,7 @@ import { } from '../common/types'; /** - * Wrapper Class for pytest test execution. This is where we call `runTestCommand`? + * Wrapper Class for unittest test execution. This is where we call `runTestCommand`? */ export class UnittestTestExecutionAdapter implements ITestExecutionAdapter { From 51d54a0a538389469f6e9f6654c0c7adb35f7812 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Fri, 11 Nov 2022 13:26:29 -0800 Subject: [PATCH 20/26] remove unneeded code --- .../testing/testController/common/server.ts | 46 ------------------- 1 file changed, 46 deletions(-) diff --git a/src/client/testing/testController/common/server.ts b/src/client/testing/testController/common/server.ts index ee49e13d6d21..a21ca260915c 100644 --- a/src/client/testing/testController/common/server.ts +++ b/src/client/testing/testController/common/server.ts @@ -91,52 +91,6 @@ export class PythonTestServer implements ITestServer, Disposable { return this._onDataReceived.event; } - /** - * Sends the pytest command to the server with the passed in args - * @param options configuration options - * @param args arguments to be passed to pytest - * @returns Promise - */ - async sendCommandPytest(options: TestCommandOptions, args: string[]): Promise { - const uuid = this.createUUID(options); - const spawnOptions: SpawnOptions = { - token: options.token, - cwd: options.cwd, - throwOnStdErr: true, - }; - - // Create the Python environment in which to execute the command. - const creationOptions: ExecutionFactoryCreateWithEnvironmentOptions = { - allowEnvironmentFetchExceptions: false, - resource: options.workspaceFolder, - }; - const execService = await this.executionFactory.createActivatedEnvironment(creationOptions); - - try { - if (options.debugBool) { - const launchOptions: LaunchOptions = { - cwd: options.cwd, - args, - token: options.token, - testProvider: UNITTEST_PROVIDER, - }; - - await this.debugLauncher!.launchDebugger(launchOptions); - } else { - await execService.exec(args, spawnOptions); - } - } catch (ex) { - this.uuids.delete(uuid); - this._onDataReceived.fire({ - cwd: options.cwd, - data: JSON.stringify({ - status: 'error', - errors: [(ex as Error).message], - }), - }); - } - } - async sendCommand(options: TestCommandOptions): Promise { const uuid = this.createUUID(options); const spawnOptions: SpawnOptions = { From 0692878c5ceb5ed8073c7a610db80581f1169910 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Wed, 18 Jan 2023 14:04:22 -0800 Subject: [PATCH 21/26] kartik review --- .../testing/testController/common/server.ts | 6 ++--- .../pytest/pytestDiscoveryAdapter.ts | 27 +++++++------------ .../pytest/pytestExecutionAdapter.ts | 8 +++--- 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/client/testing/testController/common/server.ts b/src/client/testing/testController/common/server.ts index a21ca260915c..7b53ad301c13 100644 --- a/src/client/testing/testController/common/server.ts +++ b/src/client/testing/testController/common/server.ts @@ -72,9 +72,9 @@ export class PythonTestServer implements ITestServer, Disposable { } /** - * TODO: not actually sure if this is necessary! - * @param options - * @returns + * creates a UUID using crypto library given test command options + * @param options test command options + * @returns a UUID as a string */ public createUUID(options: TestCommandOptions): string { const uuid = crypto.randomUUID(); diff --git a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts index f89a63857730..571a108cdf71 100644 --- a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts +++ b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts @@ -38,35 +38,26 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { public async discoverTests(uri: Uri): Promise { if (!this.deferred) { - const settings = this.configSettings.getSettings(uri); - const { pytestArgs } = settings.testing; - console.debug(pytestArgs); this.cwd = uri.fsPath; const relativePathToPytest = 'pythonFiles/pytest-vscode-integration'; const fpath = path.join(EXTENSION_ROOT_DIR, relativePathToPytest); - const cc = 'sys.path.append('.concat(fpath.toString(), ')'); - let command: TestDiscoveryCommand = buildDiscoveryCommand(cc, []); - const options3: TestCommandOptions = { + + // send path for pytest plugin + const pytestPluginPath = 'sys.path.append('.concat(fpath.toString(), ')'); + let command: TestDiscoveryCommand = buildDiscoveryCommand(pytestPluginPath, []); + const options: TestCommandOptions = { workspaceFolder: uri, command, cwd: fpath, }; - this.testServer.sendCommand(options3); + this.testServer.sendCommand(options); this.deferred = createDeferred(); - const prom = this.deferred.promise; - const a = await prom; - console.debug('AAAA', a); - // // Send the test command to the server. - // // The server will fire an onDataReceived event once it gets a response. + // importing pytest command = buildDiscoveryCommand('import pytest', []); - const options4: TestCommandOptions = { - workspaceFolder: uri, - command, - cwd: fpath, - }; - this.testServer.sendCommand(options4); + + this.testServer.sendCommand(options); } return this.deferred.promise; diff --git a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts index 8a36a7dc2cae..566b7670b256 100644 --- a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts +++ b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts @@ -1,11 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import * as path from 'path'; import { Uri } from 'vscode'; import { IConfigurationService } from '../../../common/types'; import { createDeferred, Deferred } from '../../../common/utils/async'; -import { EXTENSION_ROOT_DIR } from '../../../constants'; import { DataReceivedEvent, ExecutionTestPayload, @@ -40,9 +38,9 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { public async runTests(uri: Uri, testIds: string[], debugBool?: boolean): Promise { if (!this.deferred) { const settings = this.configSettings.getSettings(uri); - const { unittestArgs } = settings.testing; + const { pytestArgs } = settings.testing; - const command = buildExecutionCommand(unittestArgs); + const command = buildExecutionCommand(pytestArgs); this.cwd = uri.fsPath; const options: TestCommandOptions = { @@ -64,7 +62,7 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { } function buildExecutionCommand(args: string[]): TestExecutionCommand { - const executionScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'unittestadapter', 'execution.py'); + const executionScript = ''; return { script: executionScript, From 0c358f2081c55376180a8d85bf31d602dd95d927 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Wed, 18 Jan 2023 14:31:58 -0800 Subject: [PATCH 22/26] update discovery adapter file --- .../testing/testController/common/server.ts | 6 +- .../testing/testController/common/types.ts | 16 +++- .../pytest/pytestDiscoveryAdapter.ts | 78 ++++++++++--------- 3 files changed, 60 insertions(+), 40 deletions(-) diff --git a/src/client/testing/testController/common/server.ts b/src/client/testing/testController/common/server.ts index 7b53ad301c13..6a2622da3944 100644 --- a/src/client/testing/testController/common/server.ts +++ b/src/client/testing/testController/common/server.ts @@ -76,9 +76,9 @@ export class PythonTestServer implements ITestServer, Disposable { * @param options test command options * @returns a UUID as a string */ - public createUUID(options: TestCommandOptions): string { + public createUUID(cwd: string): string { const uuid = crypto.randomUUID(); - this.uuids.set(uuid, options.cwd); + this.uuids.set(uuid, cwd); return uuid; } @@ -92,7 +92,7 @@ export class PythonTestServer implements ITestServer, Disposable { } async sendCommand(options: TestCommandOptions): Promise { - const uuid = this.createUUID(options); + const uuid = this.createUUID(options.cwd); const spawnOptions: SpawnOptions = { token: options.token, cwd: options.cwd, diff --git a/src/client/testing/testController/common/types.ts b/src/client/testing/testController/common/types.ts index 064307ca8d9a..b61fad1c9167 100644 --- a/src/client/testing/testController/common/types.ts +++ b/src/client/testing/testController/common/types.ts @@ -12,6 +12,7 @@ import { Uri, WorkspaceFolder, } from 'vscode'; +import { IPythonExecutionFactory } from '../../../common/process/types'; import { TestDiscoveryOptions } from '../../common/types'; export type TestRunInstanceOptions = TestRunOptions & { @@ -151,6 +152,17 @@ export type TestCommandOptions = { testIds?: string[]; }; +export type TestCommandOptionsPytest = { + workspaceFolder: Uri; + cwd: string; + commandStr: string; + token?: CancellationToken; + outChannel?: OutputChannel; + debugBool?: boolean; + testIds?: string[]; + env: { [key: string]: string | undefined }; +}; + /** * Interface describing the server that will send test commands to the Python side, and process responses. * @@ -161,10 +173,12 @@ export interface ITestServer { readonly onDataReceived: Event; sendCommand(options: TestCommandOptions): Promise; serverReady(): Promise; + getPort(): number; + createUUID(cwd: string): string; } export interface ITestDiscoveryAdapter { - discoverTests(uri: Uri): Promise; + discoverTests(uri: Uri, executionFactory: IPythonExecutionFactory): Promise; } // interface for execution/runner adapter diff --git a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts index 571a108cdf71..8cdd96def619 100644 --- a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts +++ b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts @@ -2,21 +2,18 @@ // Licensed under the MIT License. import * as path from 'path'; import { Uri } from 'vscode'; +import { + ExecutionFactoryCreateWithEnvironmentOptions, + IPythonExecutionFactory, + SpawnOptions, +} from '../../../common/process/types'; import { IConfigurationService } from '../../../common/types'; import { createDeferred, Deferred } from '../../../common/utils/async'; import { EXTENSION_ROOT_DIR } from '../../../constants'; - -import { - DataReceivedEvent, - DiscoveredTestPayload, - ITestDiscoveryAdapter, - ITestServer, - TestCommandOptions, - TestDiscoveryCommand, -} from '../common/types'; +import { DataReceivedEvent, DiscoveredTestPayload, ITestDiscoveryAdapter, ITestServer } from '../common/types'; /** - * Wrapper class for pytest test discovery. This is where we call `discovery`. + * Wrapper class for unittest test discovery. This is where we call `runTestCommand`. #this seems incorrectly copied */ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { private deferred: Deferred | undefined; @@ -36,39 +33,48 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { } } - public async discoverTests(uri: Uri): Promise { + public async discoverTests(uri: Uri, executionFactory: IPythonExecutionFactory): Promise { + const settings = this.configSettings.getSettings(uri); + const { pytestArgs } = settings.testing; + console.debug(pytestArgs); // do we use pytestArgs anywhere? + + this.cwd = uri.fsPath; + return this.runPytestDiscovery(uri, executionFactory); + } + + async runPytestDiscovery(uri: Uri, executionFactory: IPythonExecutionFactory): Promise { if (!this.deferred) { - this.cwd = uri.fsPath; + this.deferred = createDeferred(); const relativePathToPytest = 'pythonFiles/pytest-vscode-integration'; - const fpath = path.join(EXTENSION_ROOT_DIR, relativePathToPytest); + const fullPluginPath = path.join(EXTENSION_ROOT_DIR, relativePathToPytest); + const uuid = this.testServer.createUUID(uri.fsPath); + const settings = this.configSettings.getSettings(uri); + const { pytestArgs } = settings.testing; + const pythonPathCommand = `${fullPluginPath}${path.delimiter}`.concat(process.env.PYTHONPATH ?? ''); - // send path for pytest plugin - const pytestPluginPath = 'sys.path.append('.concat(fpath.toString(), ')'); - let command: TestDiscoveryCommand = buildDiscoveryCommand(pytestPluginPath, []); - const options: TestCommandOptions = { - workspaceFolder: uri, - command, - cwd: fpath, + const spawnOptions: SpawnOptions = { + cwd: uri.fsPath, + throwOnStdErr: true, + extraVariables: { + PYTHONPATH: pythonPathCommand, + TEST_UUID: uuid.toString(), + TEST_PORT: this.testServer.getPort().toString(), + }, }; - this.testServer.sendCommand(options); - this.deferred = createDeferred(); - - // importing pytest - command = buildDiscoveryCommand('import pytest', []); + // Create the Python environment in which to execute the command. + const creationOptions: ExecutionFactoryCreateWithEnvironmentOptions = { + allowEnvironmentFetchExceptions: false, + resource: uri, + }; + const execService = await executionFactory.createActivatedEnvironment(creationOptions); - this.testServer.sendCommand(options); + try { + execService.exec(['-m', 'pytest', '--collect-only'].concat(pytestArgs), spawnOptions); + } catch (ex) { + console.error(ex); + } } - return this.deferred.promise; } } - -function buildDiscoveryCommand(script: string, args: string[]): TestDiscoveryCommand { - const discoveryScript = script; - - return { - script: discoveryScript, - args: [...args], - }; -} From 815652fccbc93813ebec727a577f7862c0a94771 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Wed, 18 Jan 2023 15:16:32 -0800 Subject: [PATCH 23/26] updated to handle new discovery code --- .../testing/testController/common/types.ts | 4 ++-- .../pytest/pytestDiscoveryAdapter.ts | 20 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/client/testing/testController/common/types.ts b/src/client/testing/testController/common/types.ts index b61fad1c9167..291772397b55 100644 --- a/src/client/testing/testController/common/types.ts +++ b/src/client/testing/testController/common/types.ts @@ -12,7 +12,6 @@ import { Uri, WorkspaceFolder, } from 'vscode'; -import { IPythonExecutionFactory } from '../../../common/process/types'; import { TestDiscoveryOptions } from '../../common/types'; export type TestRunInstanceOptions = TestRunOptions & { @@ -178,7 +177,8 @@ export interface ITestServer { } export interface ITestDiscoveryAdapter { - discoverTests(uri: Uri, executionFactory: IPythonExecutionFactory): Promise; + discoverTests(uri: Uri): Promise; + // discoverTests(uri: Uri, executionFactory: IPythonExecutionFactory): Promise; testing rewrite } // interface for execution/runner adapter diff --git a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts index 8cdd96def619..de79ec2d884a 100644 --- a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts +++ b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts @@ -24,6 +24,12 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { testServer.onDataReceived(this.onDataReceivedHandler, this); } + discoverTests(uri: Uri): Promise { + console.log(uri); + this.deferred = createDeferred(); + return this.deferred.promise; + } + public onDataReceivedHandler({ cwd, data }: DataReceivedEvent): void { if (this.deferred && cwd === this.cwd) { const testData: DiscoveredTestPayload = JSON.parse(data); @@ -33,14 +39,14 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { } } - public async discoverTests(uri: Uri, executionFactory: IPythonExecutionFactory): Promise { - const settings = this.configSettings.getSettings(uri); - const { pytestArgs } = settings.testing; - console.debug(pytestArgs); // do we use pytestArgs anywhere? + // public async discoverTests(uri: Uri, executionFactory: IPythonExecutionFactory): Promise { + // const settings = this.configSettings.getSettings(uri); + // const { pytestArgs } = settings.testing; + // console.debug(pytestArgs); // do we use pytestArgs anywhere? - this.cwd = uri.fsPath; - return this.runPytestDiscovery(uri, executionFactory); - } + // this.cwd = uri.fsPath; + // return this.runPytestDiscovery(uri, executionFactory); + // } async runPytestDiscovery(uri: Uri, executionFactory: IPythonExecutionFactory): Promise { if (!this.deferred) { From feeeb4682e7ea98730b44dc2a467c6df61eaf1ac Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Tue, 24 Jan 2023 14:45:01 -0800 Subject: [PATCH 24/26] fix line numbers in comment --- src/client/testing/testController/controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index a8c49126cacc..7b3f179b7f4a 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -236,7 +236,7 @@ export class PythonTestController implements ITestController, IExtensionSingleAc // ); // Ensure we send test telemetry if it gets disabled again this.sendTestDisabledTelemetry = true; - // comment below 229 to run the new way and uncomment above 212 ~ 227 + // comment the line 240 and uncomment the lines 229-236 to run the new way await this.pytest.refreshTestData(this.testController, uri, this.refreshCancellation.token); } else if (settings.testing.unittestEnabled) { // const testAdapter = From 6d8c29f6b1172a6252757b58ad5991aee75a6b91 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Tue, 31 Jan 2023 08:37:50 -0800 Subject: [PATCH 25/26] remove console log --- .../testing/testController/pytest/pytestDiscoveryAdapter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts index de79ec2d884a..7f65c4c5c2a5 100644 --- a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts +++ b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts @@ -25,7 +25,7 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { } discoverTests(uri: Uri): Promise { - console.log(uri); + console.debug(uri); this.deferred = createDeferred(); return this.deferred.promise; } From b7b990ab8739ab4cd5349e0c6d66336cecef8345 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Tue, 31 Jan 2023 09:45:08 -0800 Subject: [PATCH 26/26] switch to trace verbose --- .../testing/testController/pytest/pytestDiscoveryAdapter.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts index 7f65c4c5c2a5..97cece32a948 100644 --- a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts +++ b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts @@ -10,6 +10,7 @@ import { import { IConfigurationService } from '../../../common/types'; import { createDeferred, Deferred } from '../../../common/utils/async'; import { EXTENSION_ROOT_DIR } from '../../../constants'; +import { traceVerbose } from '../../../logging'; import { DataReceivedEvent, DiscoveredTestPayload, ITestDiscoveryAdapter, ITestServer } from '../common/types'; /** @@ -25,7 +26,7 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { } discoverTests(uri: Uri): Promise { - console.debug(uri); + traceVerbose(uri); this.deferred = createDeferred(); return this.deferred.promise; } @@ -42,7 +43,7 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { // public async discoverTests(uri: Uri, executionFactory: IPythonExecutionFactory): Promise { // const settings = this.configSettings.getSettings(uri); // const { pytestArgs } = settings.testing; - // console.debug(pytestArgs); // do we use pytestArgs anywhere? + // traceVerbose(pytestArgs); // do we use pytestArgs anywhere? // this.cwd = uri.fsPath; // return this.runPytestDiscovery(uri, executionFactory);