diff --git a/neotest_python/params_getter.py b/neotest_python/params_getter.py index ed75931..c3ee78e 100644 --- a/neotest_python/params_getter.py +++ b/neotest_python/params_getter.py @@ -1,3 +1,5 @@ +import logging +from logging.handlers import WatchedFileHandler import asyncio import atexit from collections import deque @@ -17,9 +19,16 @@ import argparse import inspect from pathlib import Path from typing import Any, Callable, Generator, Self, cast - SOCKET_ROOT_DIR = Path("/tmp/neotest-python") +python_socket_path = ( + SOCKET_ROOT_DIR / hashlib.sha1(sys.executable.encode()).digest().hex() +) + +logger = logging.getLogger('neotest-python') +logger.addHandler(WatchedFileHandler(filename=python_socket_path.with_suffix('.log'))) + +logger.setLevel(logging.DEBUG) class LineReceiver: def __init__(self, s: socket.socket) -> None: @@ -56,6 +65,7 @@ class LineReceiver: def get_tests(paths: Iterable[str]) -> Generator[str, None, None]: + logger.info("loading tests from %s", paths) root = Path(os.curdir).absolute() if Path(os.curdir).absolute().as_posix() not in sys.path: sys.path.insert(0, Path(os.curdir).absolute().as_posix()) @@ -68,16 +78,17 @@ def get_tests(paths: Iterable[str]) -> Generator[str, None, None]: mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) - tests: Iterable[tuple[str, Callable[..., Any]]] = inspect.getmembers( + tests: Iterable[tuple[str, Callable[..., Any]]] = list(inspect.getmembers( mod, predicate=lambda member: inspect.isfunction(member) and member.__name__.startswith("test_"), - ) + )) for _, test in tests: if not (marks := getattr(test, "pytestmark", None)): yield (f"{path.relative_to(root).as_posix()}::{test.__name__}") continue + logger.debug("path: %s - found parametrized test function %s", path, test.__name__) for mark in cast(Iterable[pytest.Mark], marks): if mark.name == "parametrize": ids = mark.kwargs.get("ids") @@ -105,15 +116,25 @@ def get_tests(paths: Iterable[str]) -> Generator[str, None, None]: test.__name__, # pyright: ignore[reportArgumentType] ) - id_maker = IdMaker( - argnames, - parametersets, - idfn, - ids_, - None, - nodeid=None, - func_name=test.__name__, - ) + try: + id_maker = IdMaker( + argnames, + parametersets, + idfn, + ids_, + None, + nodeid=None, + ) + except Exception: + id_maker = IdMaker( + argnames, + parametersets, + idfn, + ids_, + None, + nodeid=None, + func_name=test.__name__, + ) yield from ( f"{path.relative_to(root).as_posix()}::{test.__name__}[{id_}]" for id_ in id_maker.make_unique_parameterset_ids() @@ -127,12 +148,10 @@ def _close_socket(path: Path) -> None: async def serve_socket(): + global python_socket_path if not SOCKET_ROOT_DIR.exists(): SOCKET_ROOT_DIR.mkdir() - python_socket_path = ( - SOCKET_ROOT_DIR / hashlib.sha1(sys.executable.encode()).digest().hex() - ) if python_socket_path.exists(): print(python_socket_path) @@ -145,9 +164,14 @@ async def serve_socket(): async def handle_client(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): path = await reader.readline() - tests = "\n".join( - [test for test in get_tests([cast(bytes, path).decode().strip()])] # pyright: ignore[reportUnnecessaryCast] - ) + try: + tests = "\n".join( + [test for test in get_tests([path.decode().strip()]) if test] + ) + for test in tests.split('\n'): + logger.debug("found test: %s", test) + except Exception: + logger.exception("Failed to get tests for path: %s", path) writer.write(f"{tests}\n".encode()) writer.close() @@ -190,11 +214,14 @@ if __name__ == "__main__": ) args = parser.parse_args() paths: list[str] = args.paths - main( - paths=paths, - quiet=args.quiet, - collect_only=args.collect_only, - verbosity=args.verbosity, - socket_mode=args.socket_mode, - no_fork=args.no_fork, - ) + try: + main( + paths=paths, + quiet=args.quiet, + collect_only=args.collect_only, + verbosity=args.verbosity, + socket_mode=args.socket_mode, + no_fork=args.no_fork, + ) + except BaseException: + logger.exception("failed to run neotest-python pytest parser")