Coverage for circular_deps/resolvers/python.py: 54%

1 from __future__ import annotations

2

3 import os

4

5 from circular_deps.resolvers.base import PathResolver

6

7

8 class PythonPathResolver(PathResolver):

9 def resolve(self, module, current_file, root_dir):

10 if module.startswith("."):

11 return self._resolve_relative(module, current_file, root_dir)

12 else:

13 return self._resolve_absolute(module, current_file, root_dir)

14

15 def _resolve_relative(self, module, current_file, root_dir):

16 current_dir = os.path.dirname(current_file)

17

18 if module.startswith(".."):

19 parts = []

20 i = 0

21 while i < len(module) and module[i] == ".":

22 parts.append("..")

23 i += 1

24 if parts:

25 module_suffix = module[len(parts) :].strip(".")

26 target_dir = os.path.abspath(os.path.join(current_dir, *parts))

27 if module_suffix:

28 target_path = os.path.join(

29 target_dir, module_suffix.replace(".", os.sep)

30 )

31 else:

32 target_path = target_dir

33 else:

34 target_path = os.path.abspath(

35 os.path.join(current_dir, module.lstrip("."))

36 )

37 else:

38 module_name = module.lstrip(".").strip(".")

39 if module_name:

40 target_path = os.path.abspath(

41 os.path.join(current_dir, module_name.replace(".", os.sep))

42 )

43 else:

44 return None

45

46 return self._find_py_file(target_path, root_dir)

47

48 def _resolve_absolute(self, module, current_file, root_dir):

49 module_path = module.replace(".", os.sep)

50 current_dir = os.path.dirname(current_file)

51

52 for search_path in [current_dir, root_dir]:

53 target_path = os.path.join(search_path, module_path)

54 resolved = self._find_py_file(target_path, root_dir)

55 if resolved:

56 return resolved

57

58 return None

59

60 def _find_py_file(self, target_path, root_dir):

61 if os.path.isfile(target_path) and target_path.endswith(".py"):

62 return self._check_under_root(target_path, root_dir)

63

64 if os.path.isdir(target_path):

65 init_py = os.path.join(target_path, "__init__.py")

66 if os.path.isfile(init_py):

67 return self._check_under_root(init_py, root_dir)

68

69 py_file = target_path + ".py"

70 if os.path.isfile(py_file):

71 return self._check_under_root(py_file, root_dir)

72

73 return None

74

75 def _check_under_root(self, path, root_dir):

76 abs_path = os.path.abspath(path)

77 abs_root = os.path.abspath(root_dir)

78 if abs_path.startswith(abs_root):

79 return abs_path

80 return None