Skip to content

Commit c181d08

Browse files
authored
Use Python 3.8 in AzDo pipelines (#10276)
* Use Python 3.8 in AzDo pipelines * Add python 3.8 condition * Fail fast (single workspace) * Try downgrading pytest * Upgrade pytest, update pytest args * Uncomment other PR validation stages * Windis fail fast pytest 3.6.3 python 3.8 * Commenting everything out didn't work out * Re-upgrade pytest to 4.6.9 * Use pathlib2 for py27 compatibility * Save path as string * Fix paths in the parent function (for all tests) * Use Path.resolve() for projroot too * Use pathlib in test_util too * Uncomment accidental comment * Add comments
1 parent 15e4a5e commit c181d08

File tree

7 files changed

+76
-44
lines changed

7 files changed

+76
-44
lines changed

build/ci/templates/globals.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
variables:
2-
PythonVersion: '3.7' # Always use latest version.
2+
PythonVersion: '3.8' # Always use latest version.
33
NodeVersion: '12.4.0' # Check version of node used in VS Code.
44
NpmVersion: '6.13.4'
55
MOCHA_FILE: '$(Build.ArtifactStagingDirectory)/test-junit.xml' # All test files will write their JUnit xml output to this file, clobbering the last time it was written.

build/test-requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ pycodestyle
1010
prospector
1111
pydocstyle
1212
nose
13-
pytest==3.6.3
13+
pytest==4.6.9 # Last version of pytest with Python 2.7 support
1414
rope
1515
flask
1616
django
1717
isort
18-
packaging==19.2
18+
pathlib2>=2.2.0 ; python_version<'3.6' # Python 2.7 compatibility (pytest)

news/3 Code Health/8298.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use Python 3.8 in tests run on Azure DevOps.

pythonFiles/tests/testing_tools/adapter/pytest/test_discovery.py

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
from testing_tools.adapter.pytest import _pytest_item as pytest_item
2121
from testing_tools.adapter.pytest._discovery import discover, TestCollector
2222

23+
# In Python 3.8 __len__ is called twice, which impacts some of the test assertions we do below.
24+
PYTHON_38_OR_LATER = sys.version_info[0] >= 3 and sys.version_info[1] >= 8
25+
2326

2427
class StubPyTest(StubProxy):
2528
def __init__(self, stub=None):
@@ -255,20 +258,22 @@ def test_basic(self):
255258
plugin = StubPlugin(stub)
256259
expected = []
257260
plugin.discovered = expected
261+
calls = [
262+
("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
263+
("discovered.parents", None, None),
264+
("discovered.__len__", None, None),
265+
("discovered.__getitem__", (0,), None),
266+
]
267+
268+
# In Python 3.8 __len__ is called twice.
269+
if PYTHON_38_OR_LATER:
270+
calls.insert(3, ("discovered.__len__", None, None))
258271

259272
parents, tests = discover([], _pytest_main=stubpytest.main, _plugin=plugin)
260273

261274
self.assertEqual(parents, [])
262275
self.assertEqual(tests, expected)
263-
self.assertEqual(
264-
stub.calls,
265-
[
266-
("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
267-
("discovered.parents", None, None),
268-
("discovered.__len__", None, None),
269-
("discovered.__getitem__", (0,), None),
270-
],
271-
)
276+
self.assertEqual(stub.calls, calls)
272277

273278
def test_failure(self):
274279
stub = Stub()
@@ -291,20 +296,22 @@ def test_no_tests_found(self):
291296
plugin = StubPlugin(stub)
292297
expected = []
293298
plugin.discovered = expected
299+
calls = [
300+
("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
301+
("discovered.parents", None, None),
302+
("discovered.__len__", None, None),
303+
("discovered.__getitem__", (0,), None),
304+
]
305+
306+
# In Python 3.8 __len__ is called twice.
307+
if PYTHON_38_OR_LATER:
308+
calls.insert(3, ("discovered.__len__", None, None))
294309

295310
parents, tests = discover([], _pytest_main=pytest.main, _plugin=plugin)
296311

297312
self.assertEqual(parents, [])
298313
self.assertEqual(tests, expected)
299-
self.assertEqual(
300-
stub.calls,
301-
[
302-
("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
303-
("discovered.parents", None, None),
304-
("discovered.__len__", None, None),
305-
("discovered.__getitem__", (0,), None),
306-
],
307-
)
314+
self.assertEqual(stub.calls, calls)
308315

309316
def test_stdio_hidden(self):
310317
pytest_stdout = "spamspamspamspamspamspamspammityspam"
@@ -317,6 +324,17 @@ def fake_pytest_main(args, plugins):
317324

318325
plugin = StubPlugin(stub)
319326
plugin.discovered = []
327+
calls = [
328+
("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
329+
("discovered.parents", None, None),
330+
("discovered.__len__", None, None),
331+
("discovered.__getitem__", (0,), None),
332+
]
333+
334+
# In Python 3.8 __len__ is called twice.
335+
if PYTHON_38_OR_LATER:
336+
calls.insert(3, ("discovered.__len__", None, None))
337+
320338
buf = StringIO()
321339

322340
sys.stdout = buf
@@ -327,15 +345,7 @@ def fake_pytest_main(args, plugins):
327345
captured = buf.getvalue()
328346

329347
self.assertEqual(captured, "")
330-
self.assertEqual(
331-
stub.calls,
332-
[
333-
("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
334-
("discovered.parents", None, None),
335-
("discovered.__len__", None, None),
336-
("discovered.__getitem__", (0,), None),
337-
],
338-
)
348+
self.assertEqual(stub.calls, calls)
339349

340350
def test_stdio_not_hidden(self):
341351
pytest_stdout = "spamspamspamspamspamspamspammityspam"
@@ -348,6 +358,17 @@ def fake_pytest_main(args, plugins):
348358

349359
plugin = StubPlugin(stub)
350360
plugin.discovered = []
361+
calls = [
362+
("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
363+
("discovered.parents", None, None),
364+
("discovered.__len__", None, None),
365+
("discovered.__getitem__", (0,), None),
366+
]
367+
368+
# In Python 3.8 __len__ is called twice.
369+
if PYTHON_38_OR_LATER:
370+
calls.insert(3, ("discovered.__len__", None, None))
371+
351372
buf = StringIO()
352373

353374
sys.stdout = buf
@@ -358,15 +379,7 @@ def fake_pytest_main(args, plugins):
358379
captured = buf.getvalue()
359380

360381
self.assertEqual(captured, pytest_stdout)
361-
self.assertEqual(
362-
stub.calls,
363-
[
364-
("pytest.main", None, {"args": self.DEFAULT_ARGS, "plugins": [plugin]}),
365-
("discovered.parents", None, None),
366-
("discovered.__len__", None, None),
367-
("discovered.__getitem__", (0,), None),
368-
],
369-
)
382+
self.assertEqual(stub.calls, calls)
370383

371384

372385
class CollectorTests(unittest.TestCase):

pythonFiles/tests/testing_tools/adapter/test_functional.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
from ...__main__ import TESTING_TOOLS_ROOT
1616
from testing_tools.adapter.util import fix_path, PATH_SEP
1717

18+
# Pytest 3.7 and later uses pathlib/pathlib2 for path resolution.
19+
try:
20+
from pathlib import Path
21+
except ImportError:
22+
from pathlib2 import Path
23+
1824

1925
CWD = os.getcwd()
2026
DATA_DIR = os.path.join(os.path.dirname(__file__), ".data")
@@ -23,7 +29,8 @@
2329

2430
def resolve_testroot(name):
2531
projroot = os.path.join(DATA_DIR, name)
26-
return projroot, os.path.join(projroot, "tests")
32+
testroot = os.path.join(projroot, "tests")
33+
return str(Path(projroot).resolve()), str(Path(testroot).resolve())
2734

2835

2936
def run_adapter(cmd, tool, *cliargs):

pythonFiles/tests/testing_tools/adapter/test_util.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313

1414
import pytest
1515

16+
# Pytest 3.7 and later uses pathlib/pathlib2 for path resolution.
17+
try:
18+
from pathlib import Path
19+
except ImportError:
20+
from pathlib2 import Path
21+
1622
from testing_tools.adapter.util import (
1723
fix_path,
1824
fix_relpath,
@@ -30,9 +36,9 @@ def test_isolated_imports(self):
3036
from . import test_functional
3137

3238
ignored = {
33-
os.path.abspath(__file__),
34-
os.path.abspath(util.__file__),
35-
os.path.abspath(test_functional.__file__),
39+
str(Path(os.path.abspath(__file__)).resolve()),
40+
str(Path(os.path.abspath(util.__file__)).resolve()),
41+
str(Path(os.path.abspath(test_functional.__file__)).resolve()),
3642
}
3743
adapter = os.path.abspath(os.path.dirname(testing_tools.adapter.__file__))
3844
tests = os.path.join(

src/client/testing/pytest/services/argsService.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const OptionsWithArguments = [
1818
'-n', // -n is a pytest-xdist option
1919
'--assert',
2020
'--basetemp',
21+
'--cache-show',
2122
'--capture',
2223
'--color',
2324
'--confcutdir',
@@ -31,6 +32,7 @@ const OptionsWithArguments = [
3132
'--doctest-report',
3233
'--durations',
3334
'--ignore',
35+
'--ignore-glob',
3436
'--import-mode',
3537
'--junit-prefix',
3638
'--junit-xml',
@@ -65,7 +67,6 @@ const OptionsWithArguments = [
6567

6668
const OptionsWithoutArguments = [
6769
'--cache-clear',
68-
'--cache-show',
6970
'--collect-in-virtualenv',
7071
'--collect-only',
7172
'--continue-on-collection-errors',
@@ -106,7 +107,11 @@ const OptionsWithoutArguments = [
106107
'--setup-plan',
107108
'--setup-show',
108109
'--showlocals',
110+
'--stepwise',
111+
'--sw',
112+
'--stepwise-skip',
109113
'--strict',
114+
'--strict-markers',
110115
'--trace-config',
111116
'--verbose',
112117
'--version',

0 commit comments

Comments
 (0)