From 6211e86d48fab0fef1db17d71b865110d26494ba Mon Sep 17 00:00:00 2001 From: Daniel Ebrahimian Date: Fri, 15 Aug 2025 15:40:50 +1000 Subject: [PATCH 1/2] Add manage.py location detection --- neotest_python/django_unittest.py | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/neotest_python/django_unittest.py b/neotest_python/django_unittest.py index be9568d..74014d9 100644 --- a/neotest_python/django_unittest.py +++ b/neotest_python/django_unittest.py @@ -33,14 +33,29 @@ def case_id(self, case: "TestCase | TestSuite") -> str: 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]: """Converts a neotest ID into test specifier for unittest""" path, *child_ids = case_id.split("::") if not 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_dotted = relative_stem.replace(os.sep, ".") + print(relative_file, relative_stem, relative_dotted) return [*args, ".".join([relative_dotted, *child_ids])] def run(self, args: List[str], _) -> Dict: @@ -117,10 +132,16 @@ def suite_result(self, suite, suite_results, **kwargs): + len(suite_results.unexpectedSuccesses) ) - # Make sure we can import relative to current path - sys.path.insert(0, os.getcwd()) + # Add the location of the django project to system path + # 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 - argv = ["neotest-python"] + self.convert_args(args[-1], args[:-1]) + argv = ["neotest-python"] + self.convert_args(case_id, args[:-1]) # parse args parser = ArgumentParser() DjangoUnittestRunner.add_arguments(parser) From 89a6fe553432dbef93aebc925bda6bf52539fa4e Mon Sep 17 00:00:00 2001 From: Daniel Ebrahimian Date: Fri, 15 Aug 2025 15:43:43 +1000 Subject: [PATCH 2/2] cleanup --- neotest_python/django_unittest.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/neotest_python/django_unittest.py b/neotest_python/django_unittest.py index 74014d9..63847c4 100644 --- a/neotest_python/django_unittest.py +++ b/neotest_python/django_unittest.py @@ -1,9 +1,7 @@ import inspect import os -import subprocess import sys import traceback -import unittest from argparse import ArgumentParser from pathlib import Path from types import TracebackType @@ -55,7 +53,6 @@ def convert_args(self, case_id: str, args: List[str]) -> List[str]: relative_file = os.path.relpath(path, django_root) relative_stem = os.path.splitext(relative_file)[0] relative_dotted = relative_stem.replace(os.sep, ".") - print(relative_file, relative_stem, relative_dotted) return [*args, ".".join([relative_dotted, *child_ids])] def run(self, args: List[str], _) -> Dict: