GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Split up pytest.py. (#5638) · hypostulate/vscode-python@498279f

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • pythonFiles
    • testing_tools/adapter
      • pytest.py
      • pytest
        • __init__.py
        • _cli.py
        • _discovery.py
        • _pytest_item.py
      • util.py
    • tests/testing_tools/adapter
      • pytest
        • __init__.py
        • test_cli.py
        • test_discovery.py
      • test_functional.py
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎pythonFiles/testing_tools/adapter/pytest.py‎

Copy file name to clipboardExpand all lines: pythonFiles/testing_tools/adapter/pytest.py
-462Lines changed: 0 additions & 462 deletions
This file was deleted.
Collapse file

‎pythonFiles/testing_tools/adapter/pytest/__init__.py‎

Copy file name to clipboard
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from __future__ import absolute_import
5+
6+
from ._cli import add_subparser as add_cli_subparser
7+
from ._discovery import discover
Collapse file

‎pythonFiles/testing_tools/adapter/pytest/_cli.py‎

Copy file name to clipboard
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from __future__ import absolute_import
5+
6+
from ..errors import UnsupportedCommandError
7+
8+
9+
def add_subparser(cmd, name, parent):
10+
"""Add a new subparser to the given parent and add args to it."""
11+
parser = parent.add_parser(name)
12+
if cmd == 'discover':
13+
# For now we don't have any tool-specific CLI options to add.
14+
pass
15+
else:
16+
raise UnsupportedCommandError(cmd)
17+
return parser
Collapse file

‎pythonFiles/testing_tools/adapter/pytest/_discovery.py‎

Copy file name to clipboard
+198Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from __future__ import absolute_import, print_function
5+
6+
import os.path
7+
import sys
8+
9+
import pytest
10+
11+
from .. import util
12+
from ..info import ParentInfo
13+
from ._pytest_item import parse_item
14+
15+
16+
def discover(pytestargs=None, hidestdio=False,
17+
_pytest_main=pytest.main, _plugin=None, **_ignored):
18+
"""Return the results of test discovery."""
19+
if _plugin is None:
20+
_plugin = TestCollector()
21+
22+
pytestargs = _adjust_pytest_args(pytestargs)
23+
# We use this helper rather than "-pno:terminal" due to possible
24+
# platform-dependent issues.
25+
with (util.hide_stdio() if hidestdio else util.noop_cm()) as stdio:
26+
ec = _pytest_main(pytestargs, [_plugin])
27+
# See: https://docs.pytest.org/en/latest/usage.html#possible-exit-codes
28+
if ec == 5:
29+
# No tests were discovered.
30+
pass
31+
elif ec != 0:
32+
if hidestdio:
33+
print(stdio.getvalue(), file=sys.stderr)
34+
sys.stdout.flush()
35+
raise Exception('pytest discovery failed (exit code {})'.format(ec))
36+
if not _plugin._started:
37+
if hidestdio:
38+
print(stdio.getvalue(), file=sys.stderr)
39+
sys.stdout.flush()
40+
raise Exception('pytest discovery did not start')
41+
return (
42+
_plugin._tests.parents,
43+
list(_plugin._tests),
44+
)
45+
46+
47+
def _adjust_pytest_args(pytestargs):
48+
"""Return a corrected copy of the given pytest CLI args."""
49+
pytestargs = list(pytestargs) if pytestargs else []
50+
# Duplicate entries should be okay.
51+
pytestargs.insert(0, '--collect-only')
52+
# TODO: pull in code from:
53+
# src/client/testing/pytest/services/discoveryService.ts
54+
# src/client/testing/pytest/services/argsService.ts
55+
return pytestargs
56+
57+
58+
class TestCollector(object):
59+
"""This is a pytest plugin that collects the discovered tests."""
60+
61+
NORMCASE = staticmethod(os.path.normcase)
62+
PATHSEP = os.path.sep
63+
64+
def __init__(self, tests=None):
65+
if tests is None:
66+
tests = DiscoveredTests()
67+
self._tests = tests
68+
self._started = False
69+
70+
# Relevant plugin hooks:
71+
# https://docs.pytest.org/en/latest/reference.html#collection-hooks
72+
73+
def pytest_collection_modifyitems(self, session, config, items):
74+
self._started = True
75+
self._tests.reset()
76+
for item in items:
77+
test, suiteids = parse_item(item, self.NORMCASE, self.PATHSEP)
78+
self._tests.add_test(test, suiteids)
79+
80+
# This hook is not specified in the docs, so we also provide
81+
# the "modifyitems" hook just in case.
82+
def pytest_collection_finish(self, session):
83+
self._started = True
84+
try:
85+
items = session.items
86+
except AttributeError:
87+
# TODO: Is there an alternative?
88+
return
89+
self._tests.reset()
90+
for item in items:
91+
test, suiteids = parse_item(item, self.NORMCASE, self.PATHSEP)
92+
self._tests.add_test(test, suiteids)
93+
94+
95+
class DiscoveredTests(object):
96+
"""A container for the discovered tests and their parents."""
97+
98+
def __init__(self):
99+
self.reset()
100+
101+
def __len__(self):
102+
return len(self._tests)
103+
104+
def __getitem__(self, index):
105+
return self._tests[index]
106+
107+
@property
108+
def parents(self):
109+
return sorted(self._parents.values(), key=lambda v: (v.root or v.name, v.id))
110+
111+
def reset(self):
112+
"""Clear out any previously discovered tests."""
113+
self._parents = {}
114+
self._tests = []
115+
116+
def add_test(self, test, suiteids):
117+
"""Add the given test and its parents."""
118+
parentid = self._ensure_parent(test.path, test.parentid, suiteids)
119+
test = test._replace(parentid=parentid)
120+
if not test.id.startswith('.' + os.path.sep):
121+
test = test._replace(id=os.path.join('.', test.id))
122+
self._tests.append(test)
123+
124+
def _ensure_parent(self, path, parentid, suiteids):
125+
if not parentid.startswith('.' + os.path.sep):
126+
parentid = os.path.join('.', parentid)
127+
fileid = self._ensure_file(path.root, path.relfile)
128+
rootdir = path.root
129+
130+
if not path.func:
131+
return parentid
132+
133+
fullsuite, _, funcname = path.func.rpartition('.')
134+
suiteid = self._ensure_suites(fullsuite, rootdir, fileid, suiteids)
135+
parent = suiteid if suiteid else fileid
136+
137+
if path.sub:
138+
if (rootdir, parentid) not in self._parents:
139+
funcinfo = ParentInfo(parentid, 'function', funcname,
140+
rootdir, parent)
141+
self._parents[(rootdir, parentid)] = funcinfo
142+
elif parent != parentid:
143+
print(parent, parentid)
144+
# TODO: What to do?
145+
raise NotImplementedError
146+
return parentid
147+
148+
def _ensure_file(self, rootdir, relfile):
149+
if (rootdir, '.') not in self._parents:
150+
self._parents[(rootdir, '.')] = ParentInfo('.', 'folder', rootdir)
151+
if relfile.startswith('.' + os.path.sep):
152+
fileid = relfile
153+
else:
154+
fileid = relfile = os.path.join('.', relfile)
155+
156+
if (rootdir, fileid) not in self._parents:
157+
folderid, filebase = os.path.split(fileid)
158+
fileinfo = ParentInfo(fileid, 'file', filebase, rootdir, folderid)
159+
self._parents[(rootdir, fileid)] = fileinfo
160+
161+
while folderid != '.' and (rootdir, folderid) not in self._parents:
162+
parentid, name = os.path.split(folderid)
163+
folderinfo = ParentInfo(folderid, 'folder', name, rootdir, parentid)
164+
self._parents[(rootdir, folderid)] = folderinfo
165+
folderid = parentid
166+
return relfile
167+
168+
def _ensure_suites(self, fullsuite, rootdir, fileid, suiteids):
169+
if not fullsuite:
170+
if suiteids:
171+
print(suiteids)
172+
# TODO: What to do?
173+
raise NotImplementedError
174+
return None
175+
if len(suiteids) != fullsuite.count('.') + 1:
176+
print(suiteids)
177+
# TODO: What to do?
178+
raise NotImplementedError
179+
180+
suiteid = suiteids.pop()
181+
if not suiteid.startswith('.' + os.path.sep):
182+
suiteid = os.path.join('.', suiteid)
183+
final = suiteid
184+
while '.' in fullsuite and (rootdir, suiteid) not in self._parents:
185+
parentid = suiteids.pop()
186+
if not parentid.startswith('.' + os.path.sep):
187+
parentid = os.path.join('.', parentid)
188+
fullsuite, _, name = fullsuite.rpartition('.')
189+
suiteinfo = ParentInfo(suiteid, 'suite', name, rootdir, parentid)
190+
self._parents[(rootdir, suiteid)] = suiteinfo
191+
192+
suiteid = parentid
193+
else:
194+
name = fullsuite
195+
suiteinfo = ParentInfo(suiteid, 'suite', name, rootdir, fileid)
196+
if (rootdir, suiteid) not in self._parents:
197+
self._parents[(rootdir, suiteid)] = suiteinfo
198+
return final

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.