Skip to content

Commit 93852c1

Browse files
authored
Use python debug adapter when in experiment (microsoft#8119)
* Use DebugAdapterServer for attaches * Add mock to test DebugAdapterServer * Custom debugger packaging and path fixes * Minor cleanups * Fix DebugAdapterDescriptorFactory tests * Fix ptvsd install path * Linter fixes * Fix install ptvsd test * Address comments * Remove python packages that are no longer needed * Cleanup distribution.toml
1 parent a30c616 commit 93852c1

14 files changed

Lines changed: 416 additions & 1130 deletions

File tree

ThirdPartyNotices-Distribution.txt

Lines changed: 250 additions & 277 deletions
Large diffs are not rendered by default.

pythonFiles/install_ptvsd.py

Lines changed: 39 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,57 @@
1-
from io import BytesIO
2-
from os import path
3-
from zipfile import ZipFile
1+
import io
42
import json
5-
import urllib.request
6-
import sys
3+
import os
4+
import urllib.request as url_lib
5+
import zipfile
76

8-
ROOT = path.dirname(path.dirname(path.abspath(__file__)))
9-
REQUIREMENTS = path.join(ROOT, "requirements.txt")
10-
PYTHONFILES = path.join(ROOT, "pythonFiles", "lib", "python")
11-
PYPI_PTVSD_URL = "https://pypi.org/pypi/ptvsd/json"
127

8+
EXTENSION_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
9+
DEBUGGER_DEST = os.path.join(EXTENSION_ROOT, "pythonFiles", "lib", "python")
10+
DEBUGGER_PACKAGE = "ptvsd"
11+
DEBUGGER_VERSION = "5.0.0a5"
12+
DEBUGGER_PYTHON_VERSIONS = ("cp37",)
1313

14-
def install_ptvsd():
15-
sys.path.insert(0, PYTHONFILES)
16-
from packaging.requirements import Requirement
1714

18-
with open(REQUIREMENTS, "r", encoding="utf-8") as reqsfile:
19-
for line in reqsfile:
20-
pkgreq = Requirement(line)
21-
if pkgreq.name == "ptvsd":
22-
specs = pkgreq.specifier
23-
version = next(iter(specs)).version
24-
break
15+
def _contains(s, parts=()):
16+
return any(p for p in parts if p in s)
2517

26-
try:
27-
version
28-
except NameError:
29-
raise Exception("ptvsd requirement not found.")
3018

19+
def _get_debugger_wheel_urls():
20+
json_uri = "https://pypi.org/pypi/{0}/json".format(DEBUGGER_PACKAGE)
3121
# Response format: https://warehouse.readthedocs.io/api-reference/json/#project
32-
with urllib.request.urlopen(PYPI_PTVSD_URL) as response:
22+
# Release metadata format: https://github.com/pypa/interoperability-peps/blob/master/pep-0426-core-metadata.rst
23+
with url_lib.urlopen(json_uri) as response:
3324
json_response = json.loads(response.read())
34-
releases = json_response["releases"]
25+
return list(
26+
r["url"]
27+
for r in json_response["releases"][DEBUGGER_VERSION]
28+
if _contains(r["url"], DEBUGGER_PYTHON_VERSIONS)
29+
)
3530

36-
# Release metadata format: https://github.com/pypa/interoperability-peps/blob/master/pep-0426-core-metadata.rst
37-
for wheel_info in releases[version]:
38-
# Download only if it's a 3.7 wheel.
39-
if not wheel_info["python_version"].endswith(("37", "3.7")):
40-
continue
41-
42-
# Trim the file extension and remove the ptvsd version from the folder name.
43-
filename = wheel_info["filename"].rpartition(".")[0]
44-
filename = filename.replace(f"{version}-", "")
45-
ptvsd_path = path.join(PYTHONFILES, filename)
46-
47-
with urllib.request.urlopen(wheel_info["url"]) as wheel_response:
48-
wheel_file = BytesIO(wheel_response.read())
31+
32+
def _download_and_extract(root, url):
33+
root = os.getcwd() if root is None or root == "." else root
34+
prefix = os.path.join("ptvsd-{0}.data".format(DEBUGGER_VERSION), "purelib")
35+
with url_lib.urlopen(url) as response:
4936
# Extract only the contents of the purelib subfolder (parent folder of ptvsd),
5037
# since ptvsd files rely on the presence of a 'ptvsd' folder.
51-
prefix = path.join(f"ptvsd-{version}.data", "purelib")
52-
53-
with ZipFile(wheel_file, "r") as wheel:
38+
with zipfile.ZipFile(io.BytesIO(response.read()), "r") as wheel:
5439
for zip_info in wheel.infolist():
55-
# Normalize path for Windows, the wheel folder structure uses forward slashes.
56-
normalized = path.normpath(zip_info.filename)
40+
# Ignore dist info since we are merging multiple wheels
41+
if ".dist-info" in zip_info.filename:
42+
continue
43+
# Normalize path for Windows, the wheel folder structure
44+
# uses forward slashes.
45+
normalized = os.path.normpath(zip_info.filename)
5746
# Flatten the folder structure.
5847
zip_info.filename = normalized.split(prefix)[-1]
59-
wheel.extract(zip_info, ptvsd_path)
48+
wheel.extract(zip_info, root)
49+
50+
51+
def main(root):
52+
for url in _get_debugger_wheel_urls():
53+
_download_and_extract(root, url)
6054

6155

6256
if __name__ == "__main__":
63-
install_ptvsd()
57+
main(DEBUGGER_DEST)

pythonFiles/ptvsd_folder_name.py

Lines changed: 0 additions & 37 deletions
This file was deleted.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import os
2+
import pytest
3+
import subprocess
4+
import sys
5+
6+
7+
def _check_binaries(dir_path):
8+
expected_endswith = (
9+
"win_amd64.pyd",
10+
"win32.pyd",
11+
"darwin.so",
12+
"i386-linux-gnu.so",
13+
"x86_64-linux-gnu.so",
14+
)
15+
16+
binaries = list(p for p in os.listdir(dir_path) if p.endswith(expected_endswith))
17+
18+
assert len(binaries) == len(expected_endswith)
19+
20+
@pytest.mark.skipif(
21+
sys.version_info[:2] != (3, 7),
22+
reason="PTVSD wheels shipped for Python 3.7 only",
23+
)
24+
def test_install_ptvsd(tmpdir):
25+
import install_ptvsd
26+
install_ptvsd.main(str(tmpdir))
27+
dir_path = os.path.join(
28+
str(tmpdir), "ptvsd", "_vendored", "pydevd", "_pydevd_bundle"
29+
)
30+
_check_binaries(dir_path)
31+
32+
dir_path = os.path.join(
33+
str(tmpdir), "ptvsd", "_vendored", "pydevd", "_pydevd_frame_eval"
34+
)
35+
_check_binaries(dir_path)

pythonFiles/tests/debug_adapter/test_ptvsd_folder_name.py

Lines changed: 0 additions & 53 deletions
This file was deleted.

pythonFiles/tests/debug_adapter/test_ptvsd_folder_name_functional.py

Lines changed: 0 additions & 52 deletions
This file was deleted.

requirements.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
jedi==0.15.1
22
parso==0.5.1
33
isort==4.3.21
4-
ptvsd==5.0.0a5
54
pyparsing==2.4.0
6-
six==1.12.0
7-
packaging==19.2

src/client/api.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ export function buildApi(ready: Promise<any>, experimentsManager: IExperimentsMa
4949
const useNewDAPtvsd = experimentsManager.inExperiment(DebugAdapterExperiment.experiment) && (await debugFactory.useNewPtvsd(pythonSettings.pythonPath));
5050

5151
if (!useNewDAPtvsd) {
52-
return new RemoteDebuggerExternalLauncherScriptProvider().getLauncherArgs({ host, port, waitUntilDebuggerAttaches });
53-
}
52+
return new RemoteDebuggerExternalLauncherScriptProvider().getLauncherArgs({ host, port, waitUntilDebuggerAttaches });
53+
}
5454

5555
// Same logic as in RemoteDebuggerExternalLauncherScriptProvider, but eventually launcherProvider.ts will be deleted.
5656
const args = debugFactory.getRemotePtvsdArgs({ host, port, waitUntilDebuggerAttaches });
57-
return [await debugFactory.getPtvsdPath(pythonSettings.pythonPath), ...args];
58-
}
57+
return [debugFactory.getPtvsdPath(), ...args];
58+
}
5959
}
6060
};
6161
}

0 commit comments

Comments
 (0)