Skip to content

Commit b1c7ac7

Browse files
committed
Simple refactor to PEP8
1 parent 72e7cd7 commit b1c7ac7

File tree

1 file changed

+102
-97
lines changed

1 file changed

+102
-97
lines changed

src/sasctl/pzmm/write_json_files.py

Lines changed: 102 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,7 @@ def convertDataRole(self, dataRole):
985985
return conversion
986986

987987
@classmethod
988-
def createRequirementsJSON(cls, jPath=Path.cwd()):
988+
def create_requirements_json(cls, json_path=Path.cwd()):
989989
"""
990990
Searches the model directory for Python scripts and pickle files and determines
991991
their Python package dependencies. Found dependencies are then matched to the package
@@ -999,51 +999,50 @@ def createRequirementsJSON(cls, jPath=Path.cwd()):
999999
10001000
This function works best when run in the model development environment and is likely to
10011001
throw errors if run in another environment (and/or produce incorrect package versions).
1002-
In the case of using this function outside of the model development environment, it is
1002+
In the case of using this function outside the model development environment, it is
10031003
recommended to the user that they adjust the requirements.json file's package versions
10041004
to match the model development environment.
10051005
10061006
Parameters
10071007
----------
1008-
jPath : str, optional
1009-
The path to a Python project, by default Path.cwd().
1010-
1008+
json_path : str, optional
1009+
The path to a Python project, by default the current working directory.
10111010
Yields
10121011
------
10131012
requirements.json : file
10141013
JSON file used to create a specific Python environment in a SAS Model Manager published
10151014
container.
10161015
"""
10171016

1018-
picklePackages = []
1019-
pickleFiles = cls.getPickleFile(jPath)
1020-
for pickleFile in pickleFiles:
1021-
picklePackages.append(cls.getDependenciesFromPickleFile(cls, pickleFile))
1017+
pickle_packages = []
1018+
pickle_files = cls.get_pickle_file(json_path)
1019+
for pickle_file in pickle_files:
1020+
pickle_packages.append(cls.get_pickle_dependencies(pickle_file))
10221021

1023-
codeDependencies = cls.getCodeDependencies(cls, jPath)
1022+
code_dependencies = cls.get_code_dependencies(json_path)
10241023

1025-
packageList = list(picklePackages) + codeDependencies
1026-
packageList = list(set(list(flatten(packageList))))
1027-
packageList = cls.removeStdlibPackages(packageList)
1028-
packageAndVersion = cls.getLocalPackageVersion(packageList)
1024+
package_list = list(pickle_packages) + code_dependencies
1025+
package_list = list(set(list(flatten(package_list))))
1026+
package_list = cls.remove_standard_library_packages(package_list)
1027+
package_and_version = cls.get_local_package_version(package_list)
10291028
# Identify packages with missing versions
1030-
missingPackageVersions = [item[0] for item in packageAndVersion if not item[1]]
1029+
missing_package_versions = [item[0] for item in package_and_version if not item[1]]
10311030

1032-
with open(Path(jPath) / "requirements.json", "w") as file:
1033-
if missingPackageVersions:
1034-
jsonStep = json.dumps(
1031+
with open(Path(json_path) / "requirements.json", "w") as file:
1032+
if missing_package_versions:
1033+
json_step = json.dumps(
10351034
[
10361035
{
10371036
"Warning": "The versions for the following packages could not be determined:",
1038-
"Packages": ", ".join(missingPackageVersions)
1037+
"Packages": ", ".join(missing_package_versions)
10391038
}
10401039
],
10411040
indent=4,
10421041
)
1043-
file.write(jsonStep)
1044-
for package, version in packageAndVersion:
1042+
file.write(json_step)
1043+
for package, version in package_and_version:
10451044
if version:
1046-
jsonStep = json.dumps(
1045+
json_step = json.dumps(
10471046
[
10481047
{
10491048
"step": "install " + package,
@@ -1053,7 +1052,7 @@ def createRequirementsJSON(cls, jPath=Path.cwd()):
10531052
indent=4,
10541053
)
10551054
else:
1056-
jsonStep = json.dumps(
1055+
json_step = json.dumps(
10571056
[
10581057
{
10591058
"step": "install " + package,
@@ -1062,96 +1061,101 @@ def createRequirementsJSON(cls, jPath=Path.cwd()):
10621061
],
10631062
indent=4,
10641063
)
1065-
file.write(jsonStep)
1064+
file.write(json_step)
10661065

1067-
def getLocalPackageVersion(packageList):
1068-
'''Get package versions from the local environment. If the package
1066+
@classmethod
1067+
def get_local_package_version(cls, package_list):
1068+
"""
1069+
Get package_name versions from the local environment. If the package_name
10691070
does not contain an attribute of "__version__", "version", or
1070-
"VERSION", no package version will be found.
1071+
"VERSION", no package_name version will be found.
10711072
10721073
Parameters
10731074
----------
1074-
packageList : list
1075+
package_list : list
10751076
List of Python packages.
10761077
10771078
Returns
10781079
-------
10791080
list
1080-
Nested list of Python package names and found versions.
1081-
'''
1082-
def packageNotFoundOutput(package, packageAndVersion):
1083-
print("Warning: Package {} was not found in the local environment, so a version could not be determined.".format(package))
1084-
print("The pip installation command will not include a version number for {}.".format(package))
1085-
packageAndVersion.append([package, None])
1086-
return packageAndVersion
1087-
1088-
packageAndVersion = []
1081+
Nested list of Python package_name names and found versions.
1082+
"""
1083+
def package_not_found_output(package_name, package_versions):
1084+
print(f"Warning: Package {package_name} was not found in the local environment, so a version could not be "
1085+
"determined.")
1086+
print(f"The pip installation command will not include a version number for {package_name}.")
1087+
package_versions.append([package_name, None])
1088+
return package_versions
1089+
1090+
package_and_version = []
10891091
import importlib
1090-
for package in packageList:
1092+
for package in package_list:
10911093
try:
10921094
name = importlib.import_module(package)
10931095
try:
1094-
packageAndVersion.append([package, name.__version__])
1096+
package_and_version.append([package, name.__version__])
10951097
except AttributeError:
1096-
pass
10971098
try:
1098-
packageAndVersion.append([package, name.version])
1099+
package_and_version.append([package, name.version])
10991100
except AttributeError:
11001101
try:
1101-
packageAndVersion.append([package, name.VERSION])
1102+
package_and_version.append([package, name.VERSION])
11021103
except AttributeError:
1103-
packageAndVersion = packageNotFoundOutput(package, packageAndVersion)
1104+
package_and_version = package_not_found_output(package, package_and_version)
11041105
except ModuleNotFoundError:
1105-
packageAndVersion = packageNotFoundOutput(package, packageAndVersion)
1106+
package_and_version = package_not_found_output(package, package_and_version)
11061107

1107-
return packageAndVersion
1108+
return package_and_version
11081109

1109-
def getCodeDependencies(cls, jPath=Path.cwd()):
1110-
'''Get the package dependencies for all Python scripts in the
1110+
@classmethod
1111+
def get_code_dependencies(cls, json_path=Path.cwd()):
1112+
"""
1113+
Get the package dependencies for all Python scripts in the
11111114
provided directory path. Note that currently this functionality
11121115
only works for .py files.
11131116
11141117
Parameters
11151118
----------
1116-
jPath : string, optional
1119+
json_path : string, optional
11171120
File location for the output JSON file. Default is the current
11181121
working directory.
11191122
11201123
Returns
11211124
-------
11221125
list
11231126
List of found package dependencies.
1124-
'''
1125-
fileNames = []
1126-
fileNames.extend(sorted(Path(jPath).glob("*.py")))
1127-
1128-
importInfo = []
1129-
for file in fileNames:
1130-
importInfo.append(cls.findImports(file))
1131-
importInfo = list(set(flatten(importInfo)))
1132-
return importInfo
1133-
1134-
def findImports(fPath):
1135-
'''Find import calls in provided Python code path. Ignores
1127+
"""
1128+
file_names = []
1129+
file_names.extend(sorted(Path(json_path).glob("*.py")))
1130+
1131+
import_info = []
1132+
for file in file_names:
1133+
import_info.append(cls.find_imports(file))
1134+
import_info = list(set(flatten(import_info)))
1135+
return import_info
1136+
1137+
@classmethod
1138+
def find_imports(cls, file_path):
1139+
"""
1140+
Find import calls in provided Python code path. Ignores
11361141
built in Python modules.
11371142
11381143
Credit: modified from https://stackoverflow.com/questions/44988487/regex-to-parse-import-statements-in-python
11391144
11401145
Parameters
11411146
----------
1142-
fPath : string
1147+
file_path : string or Path
11431148
File location for the Python file to be parsed.
1144-
11451149
Returns
11461150
-------
11471151
list
11481152
List of found package dependencies.
1149-
'''
1153+
"""
11501154
import ast
11511155

1152-
fileText = open(fPath).read()
1156+
file_text = open(file_path).read()
11531157
# Parse the file to get the abstract syntax tree representation
1154-
tree = ast.parse(fileText)
1158+
tree = ast.parse(file_text)
11551159
modules = []
11561160

11571161
# Walk through each node in the ast to find import calls
@@ -1174,27 +1178,27 @@ def findImports(fPath):
11741178
except ValueError:
11751179
return modules
11761180

1177-
def getPickleFile(pPath=Path.cwd()):
1181+
@classmethod
1182+
def get_pickle_file(cls, pickle_folder=Path.cwd()):
11781183
"""
11791184
Given a file path, retrieve the pickle file(s).
11801185
11811186
Parameters
11821187
----------
1183-
pPath : str
1184-
File location for the input pickle file. Default is the current
1185-
working directory.
1186-
1188+
pickle_folder : str
1189+
File location for the input pickle file. Default is the current working directory.
11871190
Returns
11881191
-------
11891192
list
11901193
A list of pickle files.
11911194
"""
11921195

1193-
fileNames = []
1194-
fileNames.extend(sorted(Path(pPath).glob("*.pickle")))
1195-
return fileNames
1196+
file_names = []
1197+
file_names.extend(sorted(Path(pickle_folder).glob("*.pickle")))
1198+
return file_names
11961199

1197-
def getDependenciesFromPickleFile(cls, pickleFile):
1200+
@classmethod
1201+
def get_pickle_dependencies(cls, pickle_file):
11981202
"""
11991203
Reads the pickled byte stream from a file object, serializes the pickled byte
12001204
stream as a bytes object, and inspects the bytes object for all Python modules
@@ -1212,15 +1216,16 @@ def getDependenciesFromPickleFile(cls, pickleFile):
12121216
Python built-in modules are removed.
12131217
"""
12141218

1215-
with (open(pickleFile, "rb")) as openfile:
1216-
obj = pickle.load(openfile)
1219+
with (open(pickle_file, "rb")) as open_file:
1220+
obj = pickle.load(open_file)
12171221
dumps = pickle.dumps(obj)
12181222

1219-
modules = {mod.split(".")[0] for mod, _ in cls.getPackageNames(dumps)}
1223+
modules = {mod.split(".")[0] for mod, _ in cls.get_package_names(dumps)}
12201224
modules.discard("builtins")
12211225
return list(modules)
12221226

1223-
def getPackageNames(stream):
1227+
@classmethod
1228+
def get_package_names(cls, stream):
12241229
"""
12251230
Generates (module, class_name) tuples from a pickle stream. Extracts all class names referenced
12261231
by GLOBAL and STACK_GLOBAL opcodes.
@@ -1239,62 +1244,62 @@ def getPackageNames(stream):
12391244
Generated (module, class_name) tuples.
12401245
"""
12411246

1242-
stack, markstack, memo = [], [], []
1247+
stack, mark_stack, memo = [], [], []
12431248
mark = pickletools.markobject
12441249

12451250
# Step through the pickle stack and retrieve names used by STACK_GLOBAL
12461251
for opcode, arg, pos in pickletools.genops(stream):
12471252

12481253
before, after = opcode.stack_before, opcode.stack_after
1249-
numtopop = len(before)
1254+
number_to_pop = len(before)
12501255

12511256
if opcode.name == "GLOBAL":
12521257
yield tuple(arg.split(1, None))
12531258
elif opcode.name == "STACK_GLOBAL":
1254-
yield (stack[-2], stack[-1])
1259+
yield stack[-2], stack[-1]
12551260
elif mark in before or (opcode.name == "POP" and stack and stack[-1] is mark):
1256-
markpos = markstack.pop()
1261+
mark_stack.pop()
12571262
while stack[-1] is not mark:
12581263
stack.pop()
12591264
stack.pop()
12601265
try:
1261-
numtopop = before.index(mark)
1266+
number_to_pop = before.index(mark)
12621267
except ValueError:
1263-
numtopop = 0
1268+
number_to_pop = 0
12641269
elif opcode.name in {"PUT", "BINPUT", "LONG_BINPUT", "MEMOIZE"}:
12651270
if opcode.name == "MEMOIZE":
12661271
memo.append(stack[-1])
12671272
else:
12681273
memo[arg] = stack[-1]
1269-
numtopop, after = 0, [] # memoize and put; do not pop the stack
1274+
number_to_pop, after = 0, [] # memoize and put; do not pop the stack
12701275
elif opcode.name in {"GET", "BINGET", "LONG_BINGET"}:
12711276
arg = memo[arg]
12721277

1273-
if numtopop:
1274-
del stack[-numtopop:]
1278+
if number_to_pop:
1279+
del stack[-number_to_pop:]
12751280
if mark in after:
1276-
markstack.append(pos)
1281+
mark_stack.append(pos)
12771282

12781283
if len(after) == 1 and opcode.arg is not None:
12791284
stack.append(arg)
12801285
else:
12811286
stack.extend(after)
12821287

1283-
def removeStdlibPackages(packageList):
1284-
'''Remove any packages from the required list of installed packages that are part of the Python
1285-
Standard Library.
1288+
@classmethod
1289+
def remove_standard_library_packages(cls, package_list):
1290+
"""
1291+
Remove any packages from the required list of installed packages that are part of the Python Standard Library.
12861292
12871293
Parameters
12881294
----------
1289-
packageList : list
1295+
package_list : list
12901296
List of all packages found that are not Python built-in packages.
12911297
12921298
Returns
12931299
-------
12941300
list
1295-
List of all packages found that are not Python built-in packages or part of the Python
1296-
Standard Library.
1297-
'''
1301+
List of all packages found that are not Python built-in packages or part of the Python Standard Library.
1302+
"""
12981303
py10stdlib = ['_aix_support', '_heapq', 'lzma', 'gc', 'mailcap', 'winsound', 'sre_constants', 'netrc', 'audioop',
12991304
'xdrlib', 'code', '_pyio', '_gdbm', 'unicodedata', 'pwd', 'xml', '_symtable', 'pkgutil', '_decimal',
13001305
'_compat_pickle', '_frozen_importlib_external', '_signal', 'fcntl', 'wsgiref', 'uu', 'textwrap',
@@ -1330,5 +1335,5 @@ def removeStdlibPackages(packageList):
13301335
'_curses_panel', 'wave', 'mmap', 'warnings', 'functools', 'ipaddress', 'nturl2path', 'optparse', '_queue',
13311336
'turtle', 'spwd', 'stat', 'configparser', '_warnings', 'bdb', '_osx_support', 'typing', 'zipfile', 'glob',
13321337
'random', 'smtplib', 'plistlib', 'hashlib', '_struct']
1333-
packageList = [package for package in packageList if package not in py10stdlib]
1334-
return packageList
1338+
package_list = [package for package in package_list if package not in py10stdlib]
1339+
return package_list

0 commit comments

Comments
 (0)