summaryrefslogtreecommitdiffstats
path: root/library/python/pytest/module_utils.py
blob: 4775ba374482c782155867275742e8c7609f2cea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import os

import yatest.common
import __res


def is_relative_to(path, parent):
    """
    A polyfill for pathlib.Path.is_relative_to (string-based implementation).
    Does NOT involve filesystem operations.
    """
    path = os.path.normpath(path)
    parent = os.path.normpath(parent)

    if path == parent:
        return True

    if not parent.endswith(os.sep):
        parent += os.sep

    return path.startswith(parent)


def relative_to(path, parent):
    """
    A polyfill for pathlib.Path.relative_to (string-based implementation).
    Does NOT involve filesystem operations.
    """
    path = os.path.normpath(path)
    parent = os.path.normpath(parent)

    if path == parent:
        return ''

    if not parent.endswith(os.sep):
        parent += os.sep

    # Check if path starts with parent
    if not path.startswith(parent):
        raise ValueError('Path {} is not relative to {}', path, parent)

    return path[len(parent) :]


def get_module_file_path(module_name):
    """
    Get the file path for a module without importing it.
    For synthesized empty __init__.py modules, returns module_name as a fake file path.
    """
    return __res.importer.get_filename(module_name)


_BASE_PATHS = None


def get_proper_module_path(module_name):
    """
    Get the file path for a test module relative to the repository root.
    For synthesized empty __init__.py modules, returns None.
    """
    global _BASE_PATHS
    if _BASE_PATHS is None:
        _BASE_PATHS = (
            str(yatest.common.source_path()),
            str(yatest.common.work_path()),
            str(yatest.common.build_path()),
        )

    path = get_module_file_path(module_name)

    if not os.path.isabs(path):
        if path == module_name:
            # Synthesized __init__.py module.
            return None
        return path

    for base_path in _BASE_PATHS:
        if is_relative_to(path, base_path):
            return relative_to(path, base_path)

    raise ValueError(
        'Failed to resolve module "{}" with path="{}" against known base paths'.format(module_name, path),
    )