2017-12-27 950 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?