|
8 | 8 | import json
|
9 | 9 | import pandas as pd
|
10 | 10 | import math
|
| 11 | +import numpy as np |
| 12 | +from scipy.stats import kendalltau, gamma |
| 13 | +import types |
| 14 | +import pickle |
| 15 | +import pickletools |
| 16 | +from pipreqs import pipreqs |
11 | 17 |
|
12 | 18 |
|
13 | 19 | class JSONFiles:
|
@@ -950,3 +956,178 @@ def convertDataRole(self, dataRole):
|
950 | 956 | conversion = 1
|
951 | 957 |
|
952 | 958 | return conversion
|
| 959 | + |
| 960 | + def get_imports(self): |
| 961 | + """[summary] |
| 962 | +
|
| 963 | + Yields |
| 964 | + ------- |
| 965 | + [type] |
| 966 | + [description] |
| 967 | + """ |
| 968 | + |
| 969 | + for name, val in globals().items(): |
| 970 | + if isinstance(val, types.ModuleType): |
| 971 | + # Split ensures you get root package, not just imported function |
| 972 | + name = val.__name__.split(".")[0] |
| 973 | + yield name |
| 974 | + elif isinstance(val, type): |
| 975 | + name = val.__module__.split(".")[0] |
| 976 | + yield name |
| 977 | + |
| 978 | + def get_pickle_file(self, pPath): |
| 979 | + """[summary] |
| 980 | +
|
| 981 | + Parameters |
| 982 | + ---------- |
| 983 | + pPath : [type] |
| 984 | + [description] |
| 985 | + """ |
| 986 | + fileNames = [] |
| 987 | + fileNames.extend(sorted(Path(pPath).glob("*.pickle"))) |
| 988 | + |
| 989 | + def get_modules_from_pickle_file(self, pickle_file): |
| 990 | + """[summary] |
| 991 | +
|
| 992 | + Parameters |
| 993 | + ---------- |
| 994 | + pickle_file : [type] |
| 995 | + [description] |
| 996 | +
|
| 997 | + Returns |
| 998 | + ------- |
| 999 | + [type] |
| 1000 | + [description] |
| 1001 | + """ |
| 1002 | + with (open(pickle_file, "rb")) as openfile: |
| 1003 | + obj = pickle.load(openfile) |
| 1004 | + dumps = pickle.dumps(obj) |
| 1005 | + |
| 1006 | + modules = {mod.split(".")[0] for mod, _ in self.get_names(dumps)} |
| 1007 | + return modules |
| 1008 | + |
| 1009 | + def createRequirementsJSON(self, jPath=Path.cwd()): |
| 1010 | + """[summary] |
| 1011 | +
|
| 1012 | + Parameters |
| 1013 | + ---------- |
| 1014 | + jPath : [type], optional |
| 1015 | + [description], by default Path.cwd() |
| 1016 | + """ |
| 1017 | + |
| 1018 | + imports = list(set(self.get_imports())) |
| 1019 | + |
| 1020 | + with open("./imports.py", "w") as file: |
| 1021 | + for item in imports: |
| 1022 | + file.write("import %s\n" % item) |
| 1023 | + |
| 1024 | + pipreqs.init( |
| 1025 | + { |
| 1026 | + "<path>": jPath, |
| 1027 | + "--savepath": None, |
| 1028 | + "--print": False, |
| 1029 | + "--use-local": None, |
| 1030 | + "--force": True, |
| 1031 | + "--proxy": None, |
| 1032 | + "--pypi-server": None, |
| 1033 | + "--diff": None, |
| 1034 | + "--clean": None, |
| 1035 | + } |
| 1036 | + ) |
| 1037 | + |
| 1038 | + module_version_map = {} |
| 1039 | + pickle_file = self.get_pickle_file(jPath) |
| 1040 | + filename = "./requirements.txt" |
| 1041 | + with open(filename, "r") as f: |
| 1042 | + modules_requirements_txt = set() |
| 1043 | + modules_pickle = self.get_modules_from_pickle_file(pickle_file) |
| 1044 | + for line in f: |
| 1045 | + module_parts = line.rstrip().split("==") |
| 1046 | + module = module_parts[0] |
| 1047 | + version = module_parts[1] |
| 1048 | + module_version_map[module] = version |
| 1049 | + modules_requirements_txt.add(module) |
| 1050 | + pip_name_list = list(modules_requirements_txt.union(modules_pickle)) |
| 1051 | + |
| 1052 | + for item in pip_name_list: |
| 1053 | + if item in module_version_map: |
| 1054 | + if module_version_map[item] == "0.0.0": |
| 1055 | + print( |
| 1056 | + "Warning: No pip install name found for package: " |
| 1057 | + + item.split("==")[0] |
| 1058 | + ) |
| 1059 | + pip_name_list.remove(item) |
| 1060 | + |
| 1061 | + j = json.dumps( |
| 1062 | + [ |
| 1063 | + { |
| 1064 | + "step": "install " + i, |
| 1065 | + "command": "pip install " + i + "==" + module_version_map[i], |
| 1066 | + } |
| 1067 | + if i in module_version_map |
| 1068 | + else {"step": "install " + i, "command": "pip install " + i} |
| 1069 | + for i in pip_name_list |
| 1070 | + ], |
| 1071 | + indent=4, |
| 1072 | + ) |
| 1073 | + with open("./requirements.json", "w") as file: |
| 1074 | + print(j, file=file) |
| 1075 | + |
| 1076 | + def get_names(self, stream): |
| 1077 | + """Generates (module, qualname) tuples from a pickle stream |
| 1078 | +
|
| 1079 | + Credit: https://stackoverflow.com/questions/64850179/inspecting-a-pickle-dump-for-dependencies |
| 1080 | +
|
| 1081 | + Parameters |
| 1082 | + ---------- |
| 1083 | + stream : [type] |
| 1084 | + [description] |
| 1085 | +
|
| 1086 | + Yields |
| 1087 | + ------- |
| 1088 | + [type] |
| 1089 | + [description] |
| 1090 | + """ |
| 1091 | + |
| 1092 | + stack, markstack, memo = [], [], [] |
| 1093 | + mo = pickletools.markobject |
| 1094 | + |
| 1095 | + for op, arg, pos in pickletools.genops(stream): |
| 1096 | + # simulate the pickle stack and marking scheme, insofar |
| 1097 | + # necessary to allow us to retrieve the names used by STACK_GLOBAL |
| 1098 | + |
| 1099 | + before, after = op.stack_before, op.stack_after |
| 1100 | + numtopop = len(before) |
| 1101 | + |
| 1102 | + if op.name == "GLOBAL": |
| 1103 | + yield tuple(arg.split(1, None)) |
| 1104 | + elif op.name == "STACK_GLOBAL": |
| 1105 | + yield (stack[-2], stack[-1]) |
| 1106 | + |
| 1107 | + elif mo in before or (op.name == "POP" and stack and stack[-1] is mo): |
| 1108 | + markpos = markstack.pop() |
| 1109 | + while stack[-1] is not mo: |
| 1110 | + stack.pop() |
| 1111 | + stack.pop() |
| 1112 | + try: |
| 1113 | + numtopop = before.index(mo) |
| 1114 | + except ValueError: |
| 1115 | + numtopop = 0 |
| 1116 | + elif op.name in {"PUT", "BINPUT", "LONG_BINPUT", "MEMOIZE"}: |
| 1117 | + if op.name == "MEMOIZE": |
| 1118 | + memo.append(stack[-1]) |
| 1119 | + else: |
| 1120 | + memo[arg] = stack[-1] |
| 1121 | + numtopop, after = 0, [] # memoize and put do not pop the stack |
| 1122 | + elif op.name in {"GET", "BINGET", "LONG_BINGET"}: |
| 1123 | + arg = memo[arg] |
| 1124 | + |
| 1125 | + if numtopop: |
| 1126 | + del stack[-numtopop:] |
| 1127 | + if mo in after: |
| 1128 | + markstack.append(pos) |
| 1129 | + |
| 1130 | + if len(after) == 1 and op.arg is not None: |
| 1131 | + stack.append(arg) |
| 1132 | + else: |
| 1133 | + stack.extend(after) |
0 commit comments