File size: 6,119 Bytes
447ebeb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
"""
Prevent usage of 'requests' library in the codebase.
"""

import os
import ast
import sys
from typing import List, Tuple


def find_requests_usage(directory: str) -> List[Tuple[str, int, str]]:
    """
    Recursively search for Python files in the given directory
    and find usages of the 'requests' library.

    Args:
        directory (str): The root directory to search for Python files

    Returns:
        List of tuples containing (file_path, line_number, usage_type)
    """
    requests_usages = []

    def is_likely_requests_usage(node):
        """
        More precise check to avoid false positives
        """
        try:
            # Convert node to string representation
            node_str = ast.unparse(node)

            # Specific checks to ensure it's the requests library
            requests_identifiers = [
                # HTTP methods
                "requests.get",
                "requests.post",
                "requests.put",
                "requests.delete",
                "requests.head",
                "requests.patch",
                "requests.options",
                "requests.request",
                "requests.session",
                # Types and exceptions
                "requests.Response",
                "requests.Request",
                "requests.Session",
                "requests.ConnectionError",
                "requests.HTTPError",
                "requests.Timeout",
                "requests.TooManyRedirects",
                "requests.RequestException",
                # Additional modules and attributes
                "requests.api",
                "requests.exceptions",
                "requests.models",
                "requests.auth",
                "requests.cookies",
                "requests.structures",
            ]

            # Check for specific requests library identifiers
            return any(identifier in node_str for identifier in requests_identifiers)
        except:
            return False

    def scan_file(file_path: str):
        """
        Scan a single Python file for requests library usage
        """
        try:
            # Use utf-8-sig to handle files with BOM, ignore errors
            with open(file_path, "r", encoding="utf-8-sig", errors="ignore") as file:
                tree = ast.parse(file.read())

            for node in ast.walk(tree):
                # Check import statements
                if isinstance(node, ast.Import):
                    for alias in node.names:
                        if alias.name == "requests":
                            requests_usages.append(
                                (file_path, node.lineno, f"Import: {alias.name}")
                            )

                # Check import from statements
                elif isinstance(node, ast.ImportFrom):
                    if node.module == "requests":
                        requests_usages.append(
                            (file_path, node.lineno, f"Import from: {node.module}")
                        )

                # Check method calls
                elif isinstance(node, ast.Call):
                    # More precise check for requests usage
                    try:
                        if is_likely_requests_usage(node.func):
                            requests_usages.append(
                                (
                                    file_path,
                                    node.lineno,
                                    f"Method Call: {ast.unparse(node.func)}",
                                )
                            )
                    except:
                        pass

                # Check attribute access
                elif isinstance(node, ast.Attribute):
                    try:
                        # More precise check
                        if is_likely_requests_usage(node):
                            requests_usages.append(
                                (
                                    file_path,
                                    node.lineno,
                                    f"Attribute Access: {ast.unparse(node)}",
                                )
                            )
                    except:
                        pass

        except SyntaxError as e:
            print(f"Syntax error in {file_path}: {e}", file=sys.stderr)
        except Exception as e:
            print(f"Error processing {file_path}: {e}", file=sys.stderr)

    # Recursively walk through directory
    for root, dirs, files in os.walk(directory):
        # Remove virtual environment and cache directories from search
        dirs[:] = [
            d
            for d in dirs
            if not any(
                venv in d
                for venv in [
                    "venv",
                    "env",
                    "myenv",
                    ".venv",
                    "__pycache__",
                    ".pytest_cache",
                ]
            )
        ]

        for file in files:
            if file.endswith(".py"):
                full_path = os.path.join(root, file)
                # Skip files in virtual environment or cache directories
                if not any(
                    venv in full_path
                    for venv in [
                        "venv",
                        "env",
                        "myenv",
                        ".venv",
                        "__pycache__",
                        ".pytest_cache",
                    ]
                ):
                    scan_file(full_path)

    return requests_usages


def main():
    # Get directory from command line argument or use current directory
    directory = "../../litellm"

    # Find requests library usages
    results = find_requests_usage(directory)

    # Print results
    if results:
        print("Requests Library Usages Found:")
        for file_path, line_num, usage_type in results:
            print(f"{file_path}:{line_num} - {usage_type}")
    else:
        print("No requests library usages found.")


if __name__ == "__main__":
    main()