pyfixit-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyfixit/__init__.py +0 -0
- pyfixit/cleaner.py +62 -0
- pyfixit/cli.py +265 -0
- pyfixit/dependencies.py +32 -0
- pyfixit/diagnostics.py +294 -0
- pyfixit/environment.py +21 -0
- pyfixit/imports.py +95 -0
- pyfixit/module_classifier.py +62 -0
- pyfixit/package_mapping.py +17 -0
- pyfixit/package_names.py +26 -0
- pyfixit/requirements_parser.py +62 -0
- pyfixit_cli-0.1.0.dist-info/METADATA +507 -0
- pyfixit_cli-0.1.0.dist-info/RECORD +17 -0
- pyfixit_cli-0.1.0.dist-info/WHEEL +5 -0
- pyfixit_cli-0.1.0.dist-info/entry_points.txt +2 -0
- pyfixit_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- pyfixit_cli-0.1.0.dist-info/top_level.txt +1 -0
pyfixit/__init__.py
ADDED
|
File without changes
|
pyfixit/cleaner.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from pyfixit.requirements_parser import parse_requirement
|
|
4
|
+
from pyfixit.package_names import get_import_name
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def clean_requirements(project_directory=".", apply=False):
|
|
8
|
+
project_directory = Path(project_directory)
|
|
9
|
+
|
|
10
|
+
requirements_file = project_directory / "requirements.txt"
|
|
11
|
+
|
|
12
|
+
if not requirements_file.exists():
|
|
13
|
+
return []
|
|
14
|
+
|
|
15
|
+
lines = requirements_file.read_text(
|
|
16
|
+
encoding="utf-8"
|
|
17
|
+
).splitlines()
|
|
18
|
+
|
|
19
|
+
from pyfixit.imports import get_project_imports
|
|
20
|
+
|
|
21
|
+
imports = get_project_imports(project_directory)
|
|
22
|
+
|
|
23
|
+
kept = []
|
|
24
|
+
removed = []
|
|
25
|
+
|
|
26
|
+
for line in lines:
|
|
27
|
+
|
|
28
|
+
original_line = line
|
|
29
|
+
line = line.strip()
|
|
30
|
+
|
|
31
|
+
if not line:
|
|
32
|
+
kept.append(original_line)
|
|
33
|
+
continue
|
|
34
|
+
|
|
35
|
+
if line.startswith("#"):
|
|
36
|
+
kept.append(original_line)
|
|
37
|
+
continue
|
|
38
|
+
|
|
39
|
+
parsed = parse_requirement(line)
|
|
40
|
+
|
|
41
|
+
if parsed is None:
|
|
42
|
+
kept.append(original_line)
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
package_name = parsed["package"]
|
|
46
|
+
|
|
47
|
+
import_name = get_import_name(package_name)
|
|
48
|
+
|
|
49
|
+
if import_name not in imports:
|
|
50
|
+
removed.append(original_line)
|
|
51
|
+
else:
|
|
52
|
+
kept.append(original_line)
|
|
53
|
+
|
|
54
|
+
# Only modify requirements.txt when --apply is used
|
|
55
|
+
if apply and removed:
|
|
56
|
+
|
|
57
|
+
requirements_file.write_text(
|
|
58
|
+
"\n".join(kept) + "\n",
|
|
59
|
+
encoding="utf-8"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return removed
|
pyfixit/cli.py
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import json
|
|
3
|
+
from pyfixit.diagnostics import diagnose_project, get_fix_suggestion
|
|
4
|
+
from pyfixit.cleaner import clean_requirements
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main():
|
|
8
|
+
|
|
9
|
+
parser = argparse.ArgumentParser(
|
|
10
|
+
description="Diagnose common Python import and dependency problems."
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
parser.add_argument(
|
|
14
|
+
"command",
|
|
15
|
+
nargs="?",
|
|
16
|
+
default="diagnose",
|
|
17
|
+
help="Command to run"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
parser.add_argument(
|
|
21
|
+
"project_directory",
|
|
22
|
+
nargs="?",
|
|
23
|
+
default=".",
|
|
24
|
+
help="Python project directory"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
parser.add_argument(
|
|
28
|
+
"--apply",
|
|
29
|
+
action="store_true",
|
|
30
|
+
help="Apply cleanup changes"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"--json",
|
|
35
|
+
action="store_true",
|
|
36
|
+
help="Output diagnosis as JSON"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"--version",
|
|
41
|
+
action="version",
|
|
42
|
+
version="PyFixIt 0.1.0"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
args = parser.parse_args()
|
|
46
|
+
|
|
47
|
+
# ------------------------------------------------
|
|
48
|
+
# Support: pyfixit .
|
|
49
|
+
# ------------------------------------------------
|
|
50
|
+
|
|
51
|
+
if args.command not in ["diagnose", "clean", "check"]:
|
|
52
|
+
args.project_directory = args.command
|
|
53
|
+
args.command = "diagnose"
|
|
54
|
+
|
|
55
|
+
# ------------------------------------------------
|
|
56
|
+
# CLEAN
|
|
57
|
+
# ------------------------------------------------
|
|
58
|
+
|
|
59
|
+
if args.command == "clean":
|
|
60
|
+
|
|
61
|
+
print("PyFixIt v0.1.0")
|
|
62
|
+
print("Python Project Troubleshooter")
|
|
63
|
+
print()
|
|
64
|
+
|
|
65
|
+
removed = clean_requirements(
|
|
66
|
+
args.project_directory,
|
|
67
|
+
apply=args.apply
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
print("Cleaning requirements.txt")
|
|
71
|
+
print("------------------------------")
|
|
72
|
+
|
|
73
|
+
if len(removed) == 0:
|
|
74
|
+
print("Nothing to remove.")
|
|
75
|
+
|
|
76
|
+
elif args.apply:
|
|
77
|
+
|
|
78
|
+
for dependency in removed:
|
|
79
|
+
print(f"[REMOVED] {dependency}")
|
|
80
|
+
|
|
81
|
+
print()
|
|
82
|
+
print(f"{len(removed)} dependencies removed.")
|
|
83
|
+
|
|
84
|
+
else:
|
|
85
|
+
|
|
86
|
+
for dependency in removed:
|
|
87
|
+
print(f"[REMOVE] {dependency}")
|
|
88
|
+
|
|
89
|
+
print()
|
|
90
|
+
print(
|
|
91
|
+
f"{len(removed)} unused dependencies found."
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
print(
|
|
95
|
+
"Run 'pyfixit clean --apply' to remove them."
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# ------------------------------------------------
|
|
103
|
+
# CHECK
|
|
104
|
+
# ------------------------------------------------
|
|
105
|
+
|
|
106
|
+
if args.command == "check":
|
|
107
|
+
|
|
108
|
+
print("PyFixIt v0.1.0")
|
|
109
|
+
print("Python Project Troubleshooter")
|
|
110
|
+
print()
|
|
111
|
+
|
|
112
|
+
result = diagnose_project(
|
|
113
|
+
args.project_directory
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
dependency_problems = 0
|
|
117
|
+
|
|
118
|
+
for item in result["dependencies"]:
|
|
119
|
+
|
|
120
|
+
if item["status"] != "ok":
|
|
121
|
+
dependency_problems += 1
|
|
122
|
+
|
|
123
|
+
unused_count = len(
|
|
124
|
+
result["unused_dependencies"]
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
print("Checking project...")
|
|
128
|
+
print()
|
|
129
|
+
|
|
130
|
+
if dependency_problems == 0:
|
|
131
|
+
print("[OK] No dependency problems found")
|
|
132
|
+
else:
|
|
133
|
+
print(
|
|
134
|
+
f"[FAIL] {dependency_problems} "
|
|
135
|
+
f"dependency problems found"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
if unused_count == 0:
|
|
139
|
+
print("[OK] No unused dependencies found")
|
|
140
|
+
else:
|
|
141
|
+
print(
|
|
142
|
+
f"[FAIL] {unused_count} "
|
|
143
|
+
f"unused dependencies found"
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
print()
|
|
147
|
+
|
|
148
|
+
if dependency_problems > 0 or unused_count > 0:
|
|
149
|
+
raise SystemExit(1)
|
|
150
|
+
|
|
151
|
+
raise SystemExit(0)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# ------------------------------------------------
|
|
156
|
+
# DIAGNOSE
|
|
157
|
+
# ------------------------------------------------
|
|
158
|
+
|
|
159
|
+
result = diagnose_project(
|
|
160
|
+
args.project_directory
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if args.json:
|
|
164
|
+
print(json.dumps(result, indent=2))
|
|
165
|
+
|
|
166
|
+
has_problems = any(
|
|
167
|
+
item["status"] != "ok"
|
|
168
|
+
for item in result["dependencies"]
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if len(result["unused_dependencies"]) > 0:
|
|
172
|
+
has_problems = True
|
|
173
|
+
|
|
174
|
+
if has_problems:
|
|
175
|
+
raise SystemExit(1)
|
|
176
|
+
|
|
177
|
+
raise SystemExit(0)
|
|
178
|
+
|
|
179
|
+
print("PyFixIt v0.1.0")
|
|
180
|
+
print("Python Project Troubleshooter")
|
|
181
|
+
print()
|
|
182
|
+
|
|
183
|
+
print("Dependencies")
|
|
184
|
+
print("------------------------------")
|
|
185
|
+
|
|
186
|
+
has_problems = False
|
|
187
|
+
|
|
188
|
+
for item in result["dependencies"]:
|
|
189
|
+
|
|
190
|
+
status = item["status"]
|
|
191
|
+
|
|
192
|
+
if status == "ok":
|
|
193
|
+
print(f"[OK] {item['module']}")
|
|
194
|
+
continue
|
|
195
|
+
|
|
196
|
+
has_problems = True
|
|
197
|
+
|
|
198
|
+
if status == "version_conflict":
|
|
199
|
+
|
|
200
|
+
print(
|
|
201
|
+
f"[VERSION CONFLICT] {item['module']}"
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
print(
|
|
205
|
+
f" Required: "
|
|
206
|
+
f"{item['operator']}{item['required_version']}"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
print(
|
|
210
|
+
f" Installed: "
|
|
211
|
+
f"{item['installed_version']}"
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
print(
|
|
215
|
+
f" Fix: "
|
|
216
|
+
f"{get_fix_suggestion(item)}"
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
print()
|
|
220
|
+
|
|
221
|
+
continue
|
|
222
|
+
|
|
223
|
+
print(f"[PROBLEM] {item['module']}")
|
|
224
|
+
print(f" Status: {status}")
|
|
225
|
+
print(
|
|
226
|
+
f" Fix: "
|
|
227
|
+
f"{get_fix_suggestion(item)}"
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
print()
|
|
231
|
+
|
|
232
|
+
print("Unused dependencies")
|
|
233
|
+
print("------------------------------")
|
|
234
|
+
|
|
235
|
+
unused = result["unused_dependencies"]
|
|
236
|
+
|
|
237
|
+
if len(unused) == 0:
|
|
238
|
+
|
|
239
|
+
print("None")
|
|
240
|
+
|
|
241
|
+
else:
|
|
242
|
+
|
|
243
|
+
has_problems = True
|
|
244
|
+
|
|
245
|
+
for dependency in unused:
|
|
246
|
+
|
|
247
|
+
print(f"[UNUSED] {dependency}")
|
|
248
|
+
|
|
249
|
+
print(
|
|
250
|
+
f" Fix: Remove "
|
|
251
|
+
f"'{dependency}' from requirements.txt"
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# ------------------------------------------------
|
|
255
|
+
# EXIT CODE
|
|
256
|
+
# ------------------------------------------------
|
|
257
|
+
|
|
258
|
+
if has_problems:
|
|
259
|
+
raise SystemExit(1)
|
|
260
|
+
|
|
261
|
+
raise SystemExit(0)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
if __name__ == "__main__":
|
|
265
|
+
main()
|
pyfixit/dependencies.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def find_requirements_file():
|
|
6
|
+
requirements_file = Path("requirements.txt")
|
|
7
|
+
|
|
8
|
+
if requirements_file.exists():
|
|
9
|
+
return requirements_file
|
|
10
|
+
|
|
11
|
+
return None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def read_requirements(requirements_file):
|
|
15
|
+
dependencies = []
|
|
16
|
+
|
|
17
|
+
with open(requirements_file, "r", encoding="utf-8") as file:
|
|
18
|
+
for line in file:
|
|
19
|
+
line = line.strip()
|
|
20
|
+
|
|
21
|
+
if line and not line.startswith("#"):
|
|
22
|
+
dependencies.append(line)
|
|
23
|
+
|
|
24
|
+
return dependencies
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def is_package_installed(package_name):
|
|
28
|
+
try:
|
|
29
|
+
version(package_name)
|
|
30
|
+
return True
|
|
31
|
+
except PackageNotFoundError:
|
|
32
|
+
return False
|
pyfixit/diagnostics.py
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from pyfixit.package_names import get_import_name, get_package_name
|
|
6
|
+
from pyfixit.requirements_parser import parse_requirement, check_version
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def check_dependency_declared(package_name, dependencies):
|
|
10
|
+
for dependency in dependencies:
|
|
11
|
+
|
|
12
|
+
parsed = parse_requirement(dependency)
|
|
13
|
+
|
|
14
|
+
if parsed is None:
|
|
15
|
+
continue
|
|
16
|
+
|
|
17
|
+
if parsed["package"].lower() == package_name.lower():
|
|
18
|
+
return True
|
|
19
|
+
|
|
20
|
+
return False
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def check_dependency_installed(module_name):
|
|
24
|
+
try:
|
|
25
|
+
spec = importlib.util.find_spec(module_name)
|
|
26
|
+
|
|
27
|
+
if spec is None:
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
return True
|
|
31
|
+
|
|
32
|
+
except ModuleNotFoundError:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_installed_version(package_name):
|
|
37
|
+
try:
|
|
38
|
+
return version(package_name)
|
|
39
|
+
|
|
40
|
+
except PackageNotFoundError:
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def diagnose_dependency(module_name, dependencies):
|
|
45
|
+
|
|
46
|
+
import_name = module_name
|
|
47
|
+
package_name = get_package_name(module_name)
|
|
48
|
+
|
|
49
|
+
declared = False
|
|
50
|
+
required_version = None
|
|
51
|
+
operator = None
|
|
52
|
+
|
|
53
|
+
for dependency in dependencies:
|
|
54
|
+
|
|
55
|
+
parsed = parse_requirement(dependency)
|
|
56
|
+
|
|
57
|
+
if parsed is None:
|
|
58
|
+
continue
|
|
59
|
+
|
|
60
|
+
declared_package = parsed["package"]
|
|
61
|
+
|
|
62
|
+
if declared_package.lower() == package_name.lower():
|
|
63
|
+
|
|
64
|
+
declared = True
|
|
65
|
+
required_version = parsed["version"]
|
|
66
|
+
operator = parsed["operator"]
|
|
67
|
+
|
|
68
|
+
break
|
|
69
|
+
|
|
70
|
+
installed = check_dependency_installed(
|
|
71
|
+
import_name
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
installed_version = None
|
|
75
|
+
|
|
76
|
+
if installed:
|
|
77
|
+
installed_version = get_installed_version(
|
|
78
|
+
package_name
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if not declared and not installed:
|
|
82
|
+
|
|
83
|
+
status = "missing_declaration_and_installation"
|
|
84
|
+
|
|
85
|
+
elif declared and not installed:
|
|
86
|
+
|
|
87
|
+
status = "missing_installation"
|
|
88
|
+
|
|
89
|
+
elif not declared and installed:
|
|
90
|
+
|
|
91
|
+
status = "missing_declaration"
|
|
92
|
+
|
|
93
|
+
elif required_version is not None:
|
|
94
|
+
|
|
95
|
+
if check_version(
|
|
96
|
+
installed_version,
|
|
97
|
+
operator,
|
|
98
|
+
required_version
|
|
99
|
+
):
|
|
100
|
+
|
|
101
|
+
status = "ok"
|
|
102
|
+
|
|
103
|
+
else:
|
|
104
|
+
|
|
105
|
+
status = "version_conflict"
|
|
106
|
+
|
|
107
|
+
else:
|
|
108
|
+
|
|
109
|
+
status = "ok"
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
"module": module_name,
|
|
113
|
+
"package_name": package_name,
|
|
114
|
+
"import_name": import_name,
|
|
115
|
+
"declared": declared,
|
|
116
|
+
"installed": installed,
|
|
117
|
+
"installed_version": installed_version,
|
|
118
|
+
"required_version": required_version,
|
|
119
|
+
"operator": operator,
|
|
120
|
+
"status": status
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def diagnose_dependencies(modules, dependencies):
|
|
125
|
+
|
|
126
|
+
results = []
|
|
127
|
+
|
|
128
|
+
for module in modules:
|
|
129
|
+
|
|
130
|
+
result = diagnose_dependency(
|
|
131
|
+
module,
|
|
132
|
+
dependencies
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
results.append(result)
|
|
136
|
+
|
|
137
|
+
return results
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def read_requirements(project_directory="."):
|
|
141
|
+
|
|
142
|
+
requirements_file = Path(
|
|
143
|
+
project_directory
|
|
144
|
+
) / "requirements.txt"
|
|
145
|
+
|
|
146
|
+
if not requirements_file.exists():
|
|
147
|
+
return []
|
|
148
|
+
|
|
149
|
+
dependencies = []
|
|
150
|
+
|
|
151
|
+
with open(
|
|
152
|
+
requirements_file,
|
|
153
|
+
"r",
|
|
154
|
+
encoding="utf-8"
|
|
155
|
+
) as file:
|
|
156
|
+
|
|
157
|
+
for line in file:
|
|
158
|
+
|
|
159
|
+
line = line.strip()
|
|
160
|
+
|
|
161
|
+
if not line:
|
|
162
|
+
continue
|
|
163
|
+
|
|
164
|
+
if line.startswith("#"):
|
|
165
|
+
continue
|
|
166
|
+
|
|
167
|
+
dependencies.append(line)
|
|
168
|
+
|
|
169
|
+
return dependencies
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def find_unused_dependencies(imports, dependencies):
|
|
173
|
+
|
|
174
|
+
unused = []
|
|
175
|
+
|
|
176
|
+
for dependency in dependencies:
|
|
177
|
+
|
|
178
|
+
parsed = parse_requirement(dependency)
|
|
179
|
+
|
|
180
|
+
if parsed is None:
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
package_name = parsed["package"]
|
|
184
|
+
|
|
185
|
+
import_name = get_import_name(
|
|
186
|
+
package_name
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if import_name not in imports:
|
|
190
|
+
|
|
191
|
+
unused.append(dependency)
|
|
192
|
+
|
|
193
|
+
return unused
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def diagnose_project(project_directory="."):
|
|
197
|
+
|
|
198
|
+
from pyfixit.imports import get_project_imports
|
|
199
|
+
from pyfixit.module_classifier import classify_modules
|
|
200
|
+
|
|
201
|
+
imports = get_project_imports(
|
|
202
|
+
project_directory
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
classified = classify_modules(
|
|
206
|
+
imports,
|
|
207
|
+
project_directory
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
declared_dependencies = read_requirements(
|
|
211
|
+
project_directory
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
third_party_modules = classified[
|
|
215
|
+
"third_party"
|
|
216
|
+
]
|
|
217
|
+
|
|
218
|
+
results = diagnose_dependencies(
|
|
219
|
+
third_party_modules,
|
|
220
|
+
declared_dependencies
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
unused_dependencies = find_unused_dependencies(
|
|
224
|
+
imports,
|
|
225
|
+
declared_dependencies
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
"dependencies": results,
|
|
230
|
+
"unused_dependencies": unused_dependencies
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def get_fix_suggestion(result):
|
|
235
|
+
|
|
236
|
+
status = result["status"]
|
|
237
|
+
|
|
238
|
+
module = result["module"]
|
|
239
|
+
|
|
240
|
+
package_name = result.get(
|
|
241
|
+
"package_name",
|
|
242
|
+
module
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
if status == "missing_installation":
|
|
246
|
+
|
|
247
|
+
return f"pip install {package_name}"
|
|
248
|
+
|
|
249
|
+
if status == "missing_declaration_and_installation":
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
f"Install it with: pip install {package_name}\n"
|
|
253
|
+
f"Then add '{package_name}' to requirements.txt"
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
if status == "missing_declaration":
|
|
257
|
+
|
|
258
|
+
return (
|
|
259
|
+
f"Add '{package_name}' to requirements.txt"
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
if status == "version_conflict":
|
|
263
|
+
|
|
264
|
+
required_version = result["required_version"]
|
|
265
|
+
operator = result["operator"]
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
f"pip install "
|
|
269
|
+
f"{package_name}{operator}{required_version}"
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
if status == "ok":
|
|
273
|
+
|
|
274
|
+
return "No action needed"
|
|
275
|
+
|
|
276
|
+
return "No fix available"
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def get_diagnosis_summary(diagnosis):
|
|
281
|
+
dependencies = diagnosis["dependencies"]
|
|
282
|
+
unused_dependencies = diagnosis["unused_dependencies"]
|
|
283
|
+
|
|
284
|
+
problems = 0
|
|
285
|
+
|
|
286
|
+
for dependency in dependencies:
|
|
287
|
+
if dependency["status"] != "ok":
|
|
288
|
+
problems += 1
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
"total_dependencies": len(dependencies),
|
|
292
|
+
"problems": problems,
|
|
293
|
+
"unused_dependencies": len(unused_dependencies)
|
|
294
|
+
}
|
pyfixit/environment.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_python_version():
|
|
5
|
+
return f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_python_executable():
|
|
9
|
+
return sys.executable
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def is_virtual_environment():
|
|
13
|
+
return sys.prefix != sys.base_prefix
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_environment_info():
|
|
17
|
+
return {
|
|
18
|
+
"python_version": get_python_version(),
|
|
19
|
+
"python_executable": get_python_executable(),
|
|
20
|
+
"virtual_environment": is_virtual_environment()
|
|
21
|
+
}
|