Skip to content

Commit 88382e0

Browse files
authored
Merge branch 'main' into nervous-monkey
2 parents 980c4f6 + 520f396 commit 88382e0

File tree

20 files changed

+482
-388
lines changed

20 files changed

+482
-388
lines changed

noxfile.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def install_python_libs(session: nox.Session):
5353
)
5454

5555
session.install("packaging")
56+
session.install("debugpy")
5657

5758
# Download get-pip script
5859
session.run(

python_files/testing_tools/socket_manager.py

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,39 +20,24 @@ def __exit__(self, *_):
2020
self.close()
2121

2222
def connect(self):
23-
if sys.platform == "win32":
24-
self._writer = open(self.name, "w", encoding="utf-8") # noqa: SIM115, PTH123
25-
# reader created in read method
26-
else:
27-
self._socket = _SOCKET(socket.AF_UNIX, socket.SOCK_STREAM)
28-
self._socket.connect(self.name)
23+
self._writer = open(self.name, "w", encoding="utf-8") # noqa: SIM115, PTH123
24+
# reader created in read method
2925
return self
3026

3127
def close(self):
32-
if sys.platform == "win32":
33-
self._writer.close()
34-
else:
35-
# add exception catch
36-
self._socket.close()
28+
self._writer.close()
29+
if hasattr(self, "_reader"):
30+
self._reader.close()
3731

3832
def write(self, data: str):
39-
if sys.platform == "win32":
40-
try:
41-
# for windows, is should only use \n\n
42-
request = (
43-
f"""content-length: {len(data)}\ncontent-type: application/json\n\n{data}"""
44-
)
45-
self._writer.write(request)
46-
self._writer.flush()
47-
except Exception as e:
48-
print("error attempting to write to pipe", e)
49-
raise (e)
50-
else:
51-
# must include the carriage-return defined (as \r\n) for unix systems
52-
request = (
53-
f"""content-length: {len(data)}\r\ncontent-type: application/json\r\n\r\n{data}"""
54-
)
55-
self._socket.send(request.encode("utf-8"))
33+
try:
34+
# for windows, is should only use \n\n
35+
request = f"""content-length: {len(data)}\ncontent-type: application/json\n\n{data}"""
36+
self._writer.write(request)
37+
self._writer.flush()
38+
except Exception as e:
39+
print("error attempting to write to pipe", e)
40+
raise (e)
5641

5742
def read(self, bufsize=1024) -> str:
5843
"""Read data from the socket.
@@ -63,17 +48,10 @@ def read(self, bufsize=1024) -> str:
6348
Returns:
6449
data (str): Data received from the socket.
6550
"""
66-
if sys.platform == "win32":
67-
# returns a string automatically from read
68-
if not hasattr(self, "_reader"):
69-
self._reader = open(self.name, encoding="utf-8") # noqa: SIM115, PTH123
70-
return self._reader.read(bufsize)
71-
else:
72-
# receive bytes and convert to string
73-
while True:
74-
part: bytes = self._socket.recv(bufsize)
75-
data: str = part.decode("utf-8")
76-
return data
51+
# returns a string automatically from read
52+
if not hasattr(self, "_reader"):
53+
self._reader = open(self.name, encoding="utf-8") # noqa: SIM115, PTH123
54+
return self._reader.read(bufsize)
7755

7856

7957
class SocketManager:

python_files/tests/pytestadapter/helpers.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,22 @@ def parse_rpc_message(data: str) -> Tuple[Dict[str, str], str]:
128128
print("json decode error")
129129

130130

131+
def _listen_on_fifo(pipe_name: str, result: List[str], completed: threading.Event):
132+
# Open the FIFO for reading
133+
fifo_path = pathlib.Path(pipe_name)
134+
with fifo_path.open() as fifo:
135+
print("Waiting for data...")
136+
while True:
137+
if completed.is_set():
138+
break # Exit loop if completed event is set
139+
data = fifo.read() # This will block until data is available
140+
if len(data) == 0:
141+
# If data is empty, assume EOF
142+
break
143+
print(f"Received: {data}")
144+
result.append(data)
145+
146+
131147
def _listen_on_pipe_new(listener, result: List[str], completed: threading.Event):
132148
"""Listen on the named pipe or Unix domain socket for JSON data from the server.
133149
@@ -307,14 +323,19 @@ def runner_with_cwd_env(
307323
# if additional environment variables are passed, add them to the environment
308324
if env_add:
309325
env.update(env_add)
310-
server = UnixPipeServer(pipe_name)
311-
server.start()
326+
# server = UnixPipeServer(pipe_name)
327+
# server.start()
328+
#################
329+
# Create the FIFO (named pipe) if it doesn't exist
330+
# if not pathlib.Path.exists(pipe_name):
331+
os.mkfifo(pipe_name)
332+
#################
312333

313334
completed = threading.Event()
314335

315336
result = [] # result is a string array to store the data during threading
316337
t1: threading.Thread = threading.Thread(
317-
target=_listen_on_pipe_new, args=(server, result, completed)
338+
target=_listen_on_fifo, args=(pipe_name, result, completed)
318339
)
319340
t1.start()
320341

@@ -364,14 +385,14 @@ def generate_random_pipe_name(prefix=""):
364385

365386
# For Windows, named pipes have a specific naming convention.
366387
if sys.platform == "win32":
367-
return f"\\\\.\\pipe\\{prefix}-{random_suffix}-sock"
388+
return f"\\\\.\\pipe\\{prefix}-{random_suffix}"
368389

369390
# For Unix-like systems, use either the XDG_RUNTIME_DIR or a temporary directory.
370391
xdg_runtime_dir = os.getenv("XDG_RUNTIME_DIR")
371392
if xdg_runtime_dir:
372-
return os.path.join(xdg_runtime_dir, f"{prefix}-{random_suffix}.sock") # noqa: PTH118
393+
return os.path.join(xdg_runtime_dir, f"{prefix}-{random_suffix}") # noqa: PTH118
373394
else:
374-
return os.path.join(tempfile.gettempdir(), f"{prefix}-{random_suffix}.sock") # noqa: PTH118
395+
return os.path.join(tempfile.gettempdir(), f"{prefix}-{random_suffix}") # noqa: PTH118
375396

376397

377398
class UnixPipeServer:

python_files/unittestadapter/pvsc_utils.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919
from typing_extensions import NotRequired # noqa: E402
2020

21-
from testing_tools import socket_manager # noqa: E402
22-
2321
# Types
2422

2523

@@ -331,10 +329,10 @@ def send_post_request(
331329

332330
if __writer is None:
333331
try:
334-
__writer = socket_manager.PipeManager(test_run_pipe)
335-
__writer.connect()
332+
__writer = open(test_run_pipe, "wb") # noqa: SIM115, PTH123
336333
except Exception as error:
337334
error_msg = f"Error attempting to connect to extension named pipe {test_run_pipe}[vscode-unittest]: {error}"
335+
print(error_msg, file=sys.stderr)
338336
__writer = None
339337
raise VSCodeUnittestError(error_msg) from error
340338

@@ -343,10 +341,19 @@ def send_post_request(
343341
"params": payload,
344342
}
345343
data = json.dumps(rpc)
346-
347344
try:
348345
if __writer:
349-
__writer.write(data)
346+
request = (
347+
f"""content-length: {len(data)}\r\ncontent-type: application/json\r\n\r\n{data}"""
348+
)
349+
size = 4096
350+
encoded = request.encode("utf-8")
351+
bytes_written = 0
352+
while bytes_written < len(encoded):
353+
print("writing more bytes!")
354+
segment = encoded[bytes_written : bytes_written + size]
355+
bytes_written += __writer.write(segment)
356+
__writer.flush()
350357
else:
351358
print(
352359
f"Connection error[vscode-unittest], writer is None \n[vscode-unittest] data: \n{data} \n",

python_files/vscode_pytest/__init__.py

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@
1414

1515
import pytest
1616

17-
script_dir = pathlib.Path(__file__).parent.parent
18-
sys.path.append(os.fspath(script_dir))
19-
sys.path.append(os.fspath(script_dir / "lib" / "python"))
20-
from testing_tools import socket_manager # noqa: E402
21-
2217
if TYPE_CHECKING:
2318
from pluggy import Result
2419

@@ -164,7 +159,7 @@ def pytest_exception_interact(node, call, report):
164159
collected_test = TestRunResultDict()
165160
collected_test[node_id] = item_result
166161
cwd = pathlib.Path.cwd()
167-
execution_post(
162+
send_execution_message(
168163
os.fsdecode(cwd),
169164
"success",
170165
collected_test if collected_test else None,
@@ -288,7 +283,7 @@ def pytest_report_teststatus(report, config): # noqa: ARG001
288283
)
289284
collected_test = TestRunResultDict()
290285
collected_test[absolute_node_id] = item_result
291-
execution_post(
286+
send_execution_message(
292287
os.fsdecode(cwd),
293288
"success",
294289
collected_test if collected_test else None,
@@ -322,7 +317,7 @@ def pytest_runtest_protocol(item, nextitem): # noqa: ARG001
322317
)
323318
collected_test = TestRunResultDict()
324319
collected_test[absolute_node_id] = item_result
325-
execution_post(
320+
send_execution_message(
326321
os.fsdecode(cwd),
327322
"success",
328323
collected_test if collected_test else None,
@@ -398,15 +393,15 @@ def pytest_sessionfinish(session, exitstatus):
398393
"children": [],
399394
"id_": "",
400395
}
401-
post_response(os.fsdecode(cwd), error_node)
396+
send_discovery_message(os.fsdecode(cwd), error_node)
402397
try:
403398
session_node: TestNode | None = build_test_tree(session)
404399
if not session_node:
405400
raise VSCodePytestError(
406401
"Something went wrong following pytest finish, \
407402
no session node was created"
408403
)
409-
post_response(os.fsdecode(cwd), session_node)
404+
send_discovery_message(os.fsdecode(cwd), session_node)
410405
except Exception as e:
411406
ERRORS.append(
412407
f"Error Occurred, traceback: {(traceback.format_exc() if e.__traceback__ else '')}"
@@ -418,7 +413,7 @@ def pytest_sessionfinish(session, exitstatus):
418413
"children": [],
419414
"id_": "",
420415
}
421-
post_response(os.fsdecode(cwd), error_node)
416+
send_discovery_message(os.fsdecode(cwd), error_node)
422417
else:
423418
if exitstatus == 0 or exitstatus == 1:
424419
exitstatus_bool = "success"
@@ -428,7 +423,7 @@ def pytest_sessionfinish(session, exitstatus):
428423
)
429424
exitstatus_bool = "error"
430425

431-
execution_post(
426+
send_execution_message(
432427
os.fsdecode(cwd),
433428
exitstatus_bool,
434429
None,
@@ -482,7 +477,7 @@ def pytest_sessionfinish(session, exitstatus):
482477
result=file_coverage_map,
483478
error=None,
484479
)
485-
send_post_request(payload)
480+
send_message(payload)
486481

487482

488483
def build_test_tree(session: pytest.Session) -> TestNode:
@@ -591,19 +586,8 @@ def build_test_tree(session: pytest.Session) -> TestNode:
591586
if test_class_node is not None and test_class_node not in test_file_node["children"]:
592587
test_file_node["children"].append(test_class_node)
593588
elif not hasattr(test_case, "callspec"):
589+
# This includes test cases that are pytest functions or a doctests.
594590
parent_path = get_node_path(test_case.parent)
595-
# # This includes test cases that are pytest functions or a doctests. got here with ruff test
596-
# is_ruff = False
597-
# # 'script_a.py::ruff'
598-
# for mark in test_case.own_markers:
599-
# if mark.name == "ruff":
600-
# # This is a ruff test, we do not want to include this in the tree.
601-
# print("[vscode-pytest]: Skipping ruff test: ", test_case.nodeid)
602-
# is_ruff = True
603-
# if is_ruff:
604-
# # cast RuffFile type to pytest.File
605-
# print("is_ruff true")
606-
# # parent_case = pytest.Module.from_parent(test_case.parent)
607591
try:
608592
parent_test_case = file_nodes_dict[os.fspath(parent_path)]
609593
except KeyError:
@@ -879,8 +863,10 @@ def get_node_path(node: Any) -> pathlib.Path:
879863
atexit.register(lambda: __writer.close() if __writer else None)
880864

881865

882-
def execution_post(cwd: str, status: Literal["success", "error"], tests: TestRunResultDict | None):
883-
"""Sends a POST request with execution payload details.
866+
def send_execution_message(
867+
cwd: str, status: Literal["success", "error"], tests: TestRunResultDict | None
868+
):
869+
"""Sends message execution payload details.
884870
885871
Args:
886872
cwd (str): Current working directory.
@@ -892,10 +878,10 @@ def execution_post(cwd: str, status: Literal["success", "error"], tests: TestRun
892878
)
893879
if ERRORS:
894880
payload["error"] = ERRORS
895-
send_post_request(payload)
881+
send_message(payload)
896882

897883

898-
def post_response(cwd: str, session_node: TestNode) -> None:
884+
def send_discovery_message(cwd: str, session_node: TestNode) -> None:
899885
"""
900886
Sends a POST request with test session details in payload.
901887
@@ -911,7 +897,7 @@ def post_response(cwd: str, session_node: TestNode) -> None:
911897
}
912898
if ERRORS is not None:
913899
payload["error"] = ERRORS
914-
send_post_request(payload, cls_encoder=PathEncoder)
900+
send_message(payload, cls_encoder=PathEncoder)
915901

916902

917903
class PathEncoder(json.JSONEncoder):
@@ -923,7 +909,7 @@ def default(self, o):
923909
return super().default(o)
924910

925911

926-
def send_post_request(
912+
def send_message(
927913
payload: ExecutionPayloadDict | DiscoveryPayloadDict | CoveragePayloadDict,
928914
cls_encoder=None,
929915
):
@@ -948,8 +934,7 @@ def send_post_request(
948934

949935
if __writer is None:
950936
try:
951-
__writer = socket_manager.PipeManager(TEST_RUN_PIPE)
952-
__writer.connect()
937+
__writer = open(TEST_RUN_PIPE, "wb") # noqa: SIM115, PTH123
953938
except Exception as error:
954939
error_msg = f"Error attempting to connect to extension named pipe {TEST_RUN_PIPE}[vscode-pytest]: {error}"
955940
print(error_msg, file=sys.stderr)
@@ -967,10 +952,18 @@ def send_post_request(
967952
"params": payload,
968953
}
969954
data = json.dumps(rpc, cls=cls_encoder)
970-
971955
try:
972956
if __writer:
973-
__writer.write(data)
957+
request = (
958+
f"""content-length: {len(data)}\r\ncontent-type: application/json\r\n\r\n{data}"""
959+
)
960+
size = 4096
961+
encoded = request.encode("utf-8")
962+
bytes_written = 0
963+
while bytes_written < len(encoded):
964+
segment = encoded[bytes_written : bytes_written + size]
965+
bytes_written += __writer.write(segment)
966+
__writer.flush()
974967
else:
975968
print(
976969
f"Plugin error connection error[vscode-pytest], writer is None \n[vscode-pytest] data: \n{data} \n",
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# def send_post_request():
2+
# return

0 commit comments

Comments
 (0)