File: test_lazy_imports.py

package info (click to toggle)
python-azure 20251104%2Bgit-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 770,224 kB
  • sloc: python: 6,357,217; ansic: 804; javascript: 287; makefile: 198; sh: 193; xml: 109
file content (135 lines) | stat: -rw-r--r-- 5,118 bytes parent folder | download | duplicates (2)
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""Tests for lazy import behavior of optional dependencies."""

import sys
import unittest
from io import StringIO
import importlib
import pytest

try:
    import semantic_kernel

    has_semantic_kernel = True
except ImportError:
    has_semantic_kernel = False


class TestLazyImports(unittest.TestCase):
    """Test lazy import behavior for optional dependencies."""

    @pytest.mark.unittest
    @pytest.mark.skipif(has_semantic_kernel, reason="semantic-kernel is installed")
    def test_no_messages_during_module_import(self):
        """Test that no messages are printed when importing the main module."""
        # Capture stderr to check for unwanted messages
        captured_stderr = StringIO()
        original_stderr = sys.stderr
        sys.stderr = captured_stderr

        try:
            # Test imports that would normally fail with missing dependencies
            # Since we can't easily control the dependency availability in the test environment,
            # we test the lazy import setup directly

            # This should not print any messages during setup
            _lazy_imports = {}
            _patch_all = []

            def _create_lazy_import(class_name, module_path, dependency_name):
                """Create a lazy import function for optional dependencies."""

                def lazy_import():
                    try:
                        module = __import__(module_path, fromlist=[class_name])
                        cls = getattr(module, class_name)
                        _patch_all.append(class_name)
                        return cls
                    except ImportError:
                        raise ImportError(
                            f"Could not import {class_name}. Please install the dependency with `pip install {dependency_name}`."
                        )

                return lazy_import

            # Setting up lazy imports should not print any messages
            _lazy_imports["SKAgentConverter"] = _create_lazy_import(
                "SKAgentConverter",
                "azure.ai.evaluation._converters._sk_services",
                "semantic-kernel",
            )

            # Check that no messages were printed during setup
            stderr_output = captured_stderr.getvalue()
            self.assertEqual(
                stderr_output,
                "",
                "No messages should be printed during lazy import setup",
            )

        finally:
            sys.stderr = original_stderr

    @pytest.mark.unittest
    @pytest.mark.skipif(has_semantic_kernel, reason="semantic-kernel is installed")
    def test_message_shown_when_accessing_missing_dependency(self):
        """Test that appropriate message is shown when accessing a class with missing dependency."""
        # Test the __getattr__ functionality
        _lazy_imports = {}

        def _create_lazy_import(class_name, module_path, dependency_name):
            """Create a lazy import function for optional dependencies."""

            def lazy_import():
                try:
                    # This should fail in most test environments
                    module = __import__(module_path, fromlist=[class_name])
                    cls = getattr(module, class_name)
                    return cls
                except ImportError:
                    raise ImportError(
                        f"Could not import {class_name}. Please install the dependency with `pip install {dependency_name}`."
                    )

            return lazy_import

        _lazy_imports["SKAgentConverter"] = _create_lazy_import(
            "SKAgentConverter",
            "azure.ai.evaluation._converters._sk_services",
            "semantic-kernel",
        )

        def mock_getattr(name):
            """Mock __getattr__ function like the one in __init__.py"""
            if name in _lazy_imports:
                return _lazy_imports[name]()
            raise AttributeError(f"module has no attribute '{name}'")

        # This should raise ImportError directly
        with self.assertRaises(ImportError) as cm:
            mock_getattr("SKAgentConverter")

        # Check that the ImportError message contains the expected information
        error_message = str(cm.exception)
        self.assertIn("Could not import SKAgentConverter", error_message)
        self.assertIn("pip install semantic-kernel", error_message)

    @pytest.mark.unittest
    def test_getattr_with_non_existent_attribute(self):
        """Test __getattr__ behavior with non-existent attributes."""
        _lazy_imports = {}

        def mock_getattr(name):
            """Mock __getattr__ function like the one in __init__.py"""
            if name in _lazy_imports:
                return _lazy_imports[name]()
            raise AttributeError(f"module has no attribute '{name}'")

        # Test with a non-existent attribute
        with self.assertRaises(AttributeError) as cm:
            mock_getattr("NonExistentClass")

        self.assertIn("has no attribute 'NonExistentClass'", str(cm.exception))


if __name__ == "__main__":
    unittest.main()