I see this message from sonarlint and trying to figure out how to reduce the Cognitive Complexity of this function. Any assistance is appreciated in advance.
import os
import json
import click
import hcl
cfn = [".json", ".template", ".yaml", ".yml"]
tf = ["tf"]
def file_handler(dir):
for root, dirs, files in os.walk(dir):
for file in files:
if file.endswith(tuple(cfn)):
with open(os.path.join(root, file), 'r') as fin:
try:
file = fin.read()
if "AWSTemplateFormatVersion" in file:
data = json.dumps(file)
print(data)
except ValueError as e:
raise SystemExit(e)
elif file.endswith(tuple(tf)):
with open(os.path.join(root, file), 'r') as file:
try:
obj = hcl.load(file)
data = json.dumps(obj)
print(data)
except ValueError as e:
raise SystemExit(e)
return data
Extract function to yield file paths:
def _file_paths(directory):
for root, dirs, filenames in os.walk(directory):
for filename in filenames:
file_path = os.path.join(root, filename)
if os.path.isfile(file_path):
yield file_path
Unify exception handling:
from contextlib import contextmanager
@contextmanager
def _translate_error(from_error, to_error):
try:
yield
except from_error as error:
raise to_error(error)
Extract functions to handle file types:
def _handle_cfn(file_object):
file_contents = file_object.read()
if "AWSTemplateFormatVersion" in file_contents:
data = json.dumps(file_contents)
print(data)
def _handle_tf(file_object):
obj = hcl.load(file_oject)
data = json.dumps(obj)
print(data)
Create a null handler for when the file extension doesn't match:
def _null_handler(file_object):
pass
Map file extensions to handlers:
_extension_handlers = {'.json': _handle_cfn,
'.template': _handle_cfn,
'.yaml': _handle_cfn,
'.yml': _handle_cfn,
'.tf': _handle_tf}
Putting it together:
import os
import json
import click
import hcl
def file_handler(dir):
for file_path in _file_paths(dir):
base, extension = os.path.splitext(file_path)
handler = _extension_handlers.get(extension, _null_handler)
with open(file_path) as file_object:
with _translate_error(ValueError, SystemExit):
handler(file_object)
You can go further by extracting out a function for handling each file:
def _handle_file(file_path):
base, extension = os.path.splitext(file_path)
handler = _extension_handlers.get(extension, _null_handler)
with open(file_path) as file_object:
with _translate_error(ValueError, SystemExit):
handler(file_object)
Then your main function is:
def file_handler(dir):
for file_path in _file_paths(dir):
_handle_file(file_path)