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/imports.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
EXCLUDED_DIRECTORIES = {
|
|
6
|
+
".venv",
|
|
7
|
+
"venv",
|
|
8
|
+
"env",
|
|
9
|
+
"test_env",
|
|
10
|
+
"__pycache__",
|
|
11
|
+
".git",
|
|
12
|
+
"site-packages",
|
|
13
|
+
"build",
|
|
14
|
+
"dist",
|
|
15
|
+
".pytest_cache",
|
|
16
|
+
"tests",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def find_python_files(project_directory):
|
|
21
|
+
project_path = Path(project_directory).resolve()
|
|
22
|
+
|
|
23
|
+
python_files = []
|
|
24
|
+
|
|
25
|
+
for path in project_path.rglob("*.py"):
|
|
26
|
+
path = path.resolve()
|
|
27
|
+
|
|
28
|
+
if any(part in EXCLUDED_DIRECTORIES for part in path.parts):
|
|
29
|
+
continue
|
|
30
|
+
|
|
31
|
+
# Don't analyze PyFixIt's own source code
|
|
32
|
+
if "src" in path.parts and "pyfixit" in path.parts:
|
|
33
|
+
continue
|
|
34
|
+
|
|
35
|
+
python_files.append(path)
|
|
36
|
+
|
|
37
|
+
return python_files
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_imports_from_file(file_path):
|
|
41
|
+
imports = []
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
source = Path(file_path).read_text(
|
|
45
|
+
encoding="utf-8"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
tree = ast.parse(source)
|
|
49
|
+
|
|
50
|
+
except (SyntaxError, UnicodeDecodeError):
|
|
51
|
+
return imports
|
|
52
|
+
|
|
53
|
+
for node in ast.walk(tree):
|
|
54
|
+
|
|
55
|
+
if isinstance(node, ast.Import):
|
|
56
|
+
|
|
57
|
+
for alias in node.names:
|
|
58
|
+
|
|
59
|
+
module = alias.name.split(".")[0]
|
|
60
|
+
|
|
61
|
+
if module not in imports:
|
|
62
|
+
imports.append(module)
|
|
63
|
+
|
|
64
|
+
elif isinstance(node, ast.ImportFrom):
|
|
65
|
+
|
|
66
|
+
if node.module is not None:
|
|
67
|
+
|
|
68
|
+
module = node.module.split(".")[0]
|
|
69
|
+
|
|
70
|
+
if module not in imports:
|
|
71
|
+
imports.append(module)
|
|
72
|
+
|
|
73
|
+
return imports
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_project_imports(project_directory="."):
|
|
77
|
+
|
|
78
|
+
python_files = find_python_files(
|
|
79
|
+
project_directory
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
all_imports = []
|
|
83
|
+
|
|
84
|
+
for file_path in python_files:
|
|
85
|
+
|
|
86
|
+
imports = get_imports_from_file(
|
|
87
|
+
file_path
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
for module in imports:
|
|
91
|
+
|
|
92
|
+
if module not in all_imports:
|
|
93
|
+
all_imports.append(module)
|
|
94
|
+
|
|
95
|
+
return all_imports
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def is_standard_library(module_name):
|
|
6
|
+
if module_name in sys.stdlib_module_names:
|
|
7
|
+
return True
|
|
8
|
+
|
|
9
|
+
return False
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def is_local_module(module_name, project_directory="."):
|
|
13
|
+
project_directory = Path(project_directory)
|
|
14
|
+
|
|
15
|
+
possible_locations = [
|
|
16
|
+
project_directory,
|
|
17
|
+
project_directory / "src"
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
for location in possible_locations:
|
|
21
|
+
|
|
22
|
+
module_file = location / f"{module_name}.py"
|
|
23
|
+
module_directory = location / module_name
|
|
24
|
+
|
|
25
|
+
if module_file.exists():
|
|
26
|
+
return True
|
|
27
|
+
|
|
28
|
+
if module_directory.is_dir():
|
|
29
|
+
init_file = module_directory / "__init__.py"
|
|
30
|
+
|
|
31
|
+
if init_file.exists():
|
|
32
|
+
return True
|
|
33
|
+
|
|
34
|
+
return False
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def classify_module(module_name, project_directory="."):
|
|
38
|
+
if is_standard_library(module_name):
|
|
39
|
+
return "standard_library"
|
|
40
|
+
|
|
41
|
+
if is_local_module(module_name, project_directory):
|
|
42
|
+
return "local"
|
|
43
|
+
|
|
44
|
+
return "third_party"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def classify_modules(modules, project_directory="."):
|
|
48
|
+
classified = {
|
|
49
|
+
"standard_library": [],
|
|
50
|
+
"local": [],
|
|
51
|
+
"third_party": []
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
for module in modules:
|
|
55
|
+
category = classify_module(module, project_directory)
|
|
56
|
+
|
|
57
|
+
if module not in classified[category]:
|
|
58
|
+
classified[category].append(module)
|
|
59
|
+
|
|
60
|
+
return classified
|
|
61
|
+
|
|
62
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
PACKAGE_IMPORT_MAP = {
|
|
2
|
+
"scikit-learn": "sklearn",
|
|
3
|
+
"beautifulsoup4": "bs4",
|
|
4
|
+
"python-dotenv": "dotenv",
|
|
5
|
+
"pillow": "PIL",
|
|
6
|
+
"opencv-python": "cv2",
|
|
7
|
+
"pyyaml": "yaml"
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_import_name(package_name):
|
|
12
|
+
package_name = package_name.lower()
|
|
13
|
+
|
|
14
|
+
if package_name in PACKAGE_IMPORT_MAP:
|
|
15
|
+
return PACKAGE_IMPORT_MAP[package_name]
|
|
16
|
+
|
|
17
|
+
return package_name
|
pyfixit/package_names.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
PACKAGE_IMPORT_NAMES = {
|
|
2
|
+
"scikit-learn": "sklearn",
|
|
3
|
+
"beautifulsoup4": "bs4",
|
|
4
|
+
"pillow": "PIL",
|
|
5
|
+
"python-dateutil": "dateutil",
|
|
6
|
+
"opencv-python": "cv2"
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_import_name(package_name):
|
|
11
|
+
package_name = package_name.lower()
|
|
12
|
+
|
|
13
|
+
if package_name in PACKAGE_IMPORT_NAMES:
|
|
14
|
+
return PACKAGE_IMPORT_NAMES[package_name]
|
|
15
|
+
|
|
16
|
+
return package_name
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_package_name(import_name):
|
|
20
|
+
import_name = import_name.lower()
|
|
21
|
+
|
|
22
|
+
for package_name, mapped_import_name in PACKAGE_IMPORT_NAMES.items():
|
|
23
|
+
if mapped_import_name.lower() == import_name:
|
|
24
|
+
return package_name
|
|
25
|
+
|
|
26
|
+
return import_name
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from packaging.version import Version
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def parse_requirement(requirement):
|
|
5
|
+
requirement = requirement.strip()
|
|
6
|
+
|
|
7
|
+
if not requirement:
|
|
8
|
+
return None
|
|
9
|
+
|
|
10
|
+
operators = ["==", ">=", "<=", "!=", ">", "<"]
|
|
11
|
+
|
|
12
|
+
for operator in operators:
|
|
13
|
+
if operator in requirement:
|
|
14
|
+
parts = requirement.split(operator, 1)
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
"package": parts[0].strip(),
|
|
18
|
+
"operator": operator,
|
|
19
|
+
"version": parts[1].strip()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
"package": requirement,
|
|
24
|
+
"operator": None,
|
|
25
|
+
"version": None
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def check_version(installed_version, operator, required_version):
|
|
33
|
+
if installed_version is None:
|
|
34
|
+
return False
|
|
35
|
+
|
|
36
|
+
if operator is None or required_version is None:
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
installed = Version(installed_version)
|
|
40
|
+
required = Version(required_version)
|
|
41
|
+
|
|
42
|
+
if operator == "==":
|
|
43
|
+
return installed == required
|
|
44
|
+
|
|
45
|
+
if operator == ">=":
|
|
46
|
+
return installed >= required
|
|
47
|
+
|
|
48
|
+
if operator == "<=":
|
|
49
|
+
return installed <= required
|
|
50
|
+
|
|
51
|
+
if operator == ">":
|
|
52
|
+
return installed > required
|
|
53
|
+
|
|
54
|
+
if operator == "<":
|
|
55
|
+
return installed < required
|
|
56
|
+
|
|
57
|
+
if operator == "!=":
|
|
58
|
+
return installed != required
|
|
59
|
+
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
|