2017-12-27 838 views
0

我从sonarlint看到此消息并试图找出如何减少此功能的认知复杂性。任何援助提前赞赏。Python重构此功能以将其认知复杂度从19降低到15允许

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 
+0

你使用什么metrix工具来获得结果数字? – SteveJ

+0

提取函数,为文件类型创建处理程序查找,统一错误处理,删除重复等,等等。 –

+1

您可能更好地张贴在[codereview.se] –

回答

2

取出功能产生的文件路径:

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 

统一的异常处理:

from contextlib import contextmanager 

@contextmanager 
def _translate_error(from_error, to_error): 
    try: 
     yield 
    except from_error as error: 
     raise to_error(error) 

提取函数来处理文件类型:

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) 

创建时的文件空处理程序扩展名不符:

def _null_handler(file_object): 
    pass 

地图文件扩展名的处理程序:

_extension_handlers = {'.json': _handle_cfn, 
      '.template': _handle_cfn, 
      '.yaml': _handle_cfn, 
      '.yml': _handle_cfn, 
      '.tf': _handle_tf} 

将其组合在一起:

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) 

然后:

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) 

您可以通过处理每个文件中提取出功能走得更远您的主要功能是:

def file_handler(dir): 
    for file_path in _file_paths(dir): 
     _handle_file(file_path) 
+1

我推荐倒数第二个'file_handler'(基于非'map'); 'map'是用于函数式编程的,不应该用于副作用(在Python 2中不必要地创建无用的临时'list's,而不需要额外的更改就可以在Python 3上工作。 – ShadowRanger

+0

@ShadowRanger表示同意,将删除没有解释,因为它超过需要。 –

+0

这工作。 DEF _file_paths(目录): 用于os.walk根,显示目录,文件名(目录): 用于在文件名的文件名: 路径= os.path.join(根,文件名) 如果os.path.isfile(路径): 产量路径 – kilomo

0

您可以通过使用两个发电机表达式通过扩展过滤文件中删除缩进一层:

def file_handler(dir): 
    for root, dirs, files in os.walk(dir): 
     cfn_files = (file for file in files if file.endswith(tuple(cfn))) 
     tf_files = (file for file in files if file.endswith(tuple(tf))) 
     for file in cfn_files: 
      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) 
     for file in tf_files: 
      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 
0

当你知道你应该考虑使用glob递归文件中查找尤其是哪些文件扩展名你是在寻找:

import glob 
import json 
import os 

import click 
import hcl 

def file_handler(dir): 
    for extension in cfn: 
     # eg: /path/to/dir/**/*.json 
     glob_search = os.path.join(dir, "**/*{}".format(extension)) 
     filenames = glob.glob(glob_search, recursive=True) 

     for filename in filenames: 
      with open(filename, 'r') as fin: 
       try: 
        file = fin.read() 
        if "AWSTemplateFormatVersion" in file: 
         data = json.dumps(file) 
         print(data) 

       except ValueError as e: 
        raise SystemExit(e) 

    for extension in tf: 
     # eg: /path/to/dir/**/*tf 
     glob_search = os.path.join(dir, "**/*{}".format(extension)) 
     filenames = glob.glob(glob_search, recursive=True) 

     for filename in filenames: 
      with open(filename, 'r') as file: 
       try: 
        obj = hcl.load(file) 
        data = json.dumps(obj) 
        print(data) 
       except ValueError as e: 
        raise SystemExit(e) 

FYI:关于使用水珠的一个问题(Use a Glob() to find files recursively in Python?