feat: improve Django unit test execution pathing (#103)

This commit is contained in:
Daniel Ebrahimian
2025-09-27 20:36:59 +10:00
committed by GitHub
parent 1b1b1abf92
commit 7cab6e2ecc

View File

@@ -1,9 +1,7 @@
import inspect import inspect
import os import os
import subprocess
import sys import sys
import traceback import traceback
import unittest
from argparse import ArgumentParser from argparse import ArgumentParser
from pathlib import Path from pathlib import Path
from types import TracebackType from types import TracebackType
@@ -33,12 +31,26 @@ class CaseUtilsMixin:
class DjangoNeotestAdapter(CaseUtilsMixin, NeotestAdapter): class DjangoNeotestAdapter(CaseUtilsMixin, NeotestAdapter):
def get_django_root(self, path: str) -> Path:
"""
Traverse the file system to locate the nearest manage.py parent
from the location of a given path.
This is the location of the django project
"""
test_file_path = Path(path).resolve()
for parent in [test_file_path] + list(test_file_path.parents):
if (parent / "manage.py").exists():
return parent
raise FileNotFoundError("manage.py not found")
def convert_args(self, case_id: str, args: List[str]) -> List[str]: def convert_args(self, case_id: str, args: List[str]) -> List[str]:
"""Converts a neotest ID into test specifier for unittest""" """Converts a neotest ID into test specifier for unittest"""
path, *child_ids = case_id.split("::") path, *child_ids = case_id.split("::")
if not child_ids: if not child_ids:
child_ids = [] child_ids = []
relative_file = os.path.relpath(path, os.getcwd()) django_root = self.get_django_root(path)
relative_file = os.path.relpath(path, django_root)
relative_stem = os.path.splitext(relative_file)[0] relative_stem = os.path.splitext(relative_file)[0]
relative_dotted = relative_stem.replace(os.sep, ".") relative_dotted = relative_stem.replace(os.sep, ".")
return [*args, ".".join([relative_dotted, *child_ids])] return [*args, ".".join([relative_dotted, *child_ids])]
@@ -117,10 +129,16 @@ class DjangoNeotestAdapter(CaseUtilsMixin, NeotestAdapter):
+ len(suite_results.unexpectedSuccesses) + len(suite_results.unexpectedSuccesses)
) )
# Make sure we can import relative to current path # Add the location of the django project to system path
sys.path.insert(0, os.getcwd()) # to ensure we have the same import paths as if the tests were ran
# by manage.py
case_id = args[-1]
path, *_ = case_id.split("::")
manage_py_location = self.get_django_root(path)
sys.path.insert(0, str(manage_py_location))
# Prepend an executable name which is just used in output # Prepend an executable name which is just used in output
argv = ["neotest-python"] + self.convert_args(args[-1], args[:-1]) argv = ["neotest-python"] + self.convert_args(case_id, args[:-1])
# parse args # parse args
parser = ArgumentParser() parser = ArgumentParser()
DjangoUnittestRunner.add_arguments(parser) DjangoUnittestRunner.add_arguments(parser)