2013-07-31 43 views
1

我正在使用Python来测试REST API。我得到一个响应消息为json并且想要检查每个字段。我创建了一个check_json函数,并根据检查字典进行检查。检查器字典中有一个字符串键,它是json中键的名称,其值是一个带有第一个bool参数的元组(一对),是否为必需项,第二个参数是要做直接比较的对象还是添加更多的函数检查功能。如何删除这些检查功能的全局需要

我做检查是这样的:

r= check_json(myjson, checker) 

其中r是结果格式:“田”:真或假 - 取决于检查是否通过或失败

的代码是一个小messay具有许多全球功能。一个想法是在check_json中包含检查函数。我被告知我也可以使用闭包。但是如何?

这里是我的代码:

# check nested json 
import json 
import collections 
import functools 
import datetime 

#this is json from GET session 
myjson = { 
    "accessed": "Wed, 31 Jul 2013 13:03:38 GMT", 
    "created": "Wed, 31 Jul 2013 13:03:38 GMT", 
    "dnUrls": [ 
     "http://135.86.180.69:8580/ucc/api/v1/session/dns/50000" 
    ], 
    "expires": "Wed, 31 Jul 2013 13:03:48 GMT", 
    "modified": "Wed, 31 Jul 2013 13:03:38 GMT", 
    "name": "KW50000", 
    "person": { 
     "employeeId": "KW50000", 
     "firstName": "KW50000", 
     "lastName": "Dev5" 
    }, 
    "previewRedirect": { 
     "destination": "", 
     "enabled": False, 
     "setupEnabled": False 
    } 
} 

def isDate(s): 
    try: 
     testdate = datetime.datetime.strptime(s, '%a, %d %b %Y %H:%M:%S GMT') 
     return True 
    except Exception: 
     print "conversion to date failed" 
     return False 

def isURL(l): 
    count = 0 
    for item in l: 
     count += 1 if item.startswith("http://") else (-1) 

    return count > 0 

def isAlnum(s): 
    return s.isalnum() 

def isBool(s): 
    return type(s) == bool 

def isAny(s): 
    return True 


#checker object made up of dictionary with string key and tuple value (a pair) 
#tuple first filed is flag indicating whether key is mandatory or not. 
# tuple 2nd key is value to expect or a checker function 
checker = { 
    "accessed": (True, isDate), 
    "created": (True, isDate), 
    "dnUrls": (True, isURL), 
    "expires": (True, isDate), 
    "modified": (True, isDate), 
    "name": (True, "KW50000"), 
    "person": (True, { 
     "employeeId": (True, isAlnum), 
     "firstName": (False, isAny), 
     "lastName": (False, isAny) 
    }), 
    "previewRedirect": (True, { 
     "destination": (False, isAny), 
     "enabled": (True, isBool), 
     "setupEnabled": (False, isBool) 
    }) 
} 


# returns dictionary with key= fieldname, value = result, either True (Test Pass), False (test Failed) 
def check_json(obj, checker): 
    """params json to check, template comparison object 
     returns dictionary of keys to pass/fail values""" 

    result = {} 
    for k, (mFlag, chk) in checker.iteritems(): 
     if not k in obj: 
      result[k] = not mFlag 
     elif isinstance(chk, collections.Callable):  
      result[k] = chk(obj[k]) 
     elif(isinstance(chk, collections.Mapping)): 
      result[k] = check_json(obj[k], chk) 
     else:  
      result[k] = chk == obj[k] 
    return result 

def with_and(v1, v2): 
    return functools.reduce(with_and, v2.itervalues(), v1) if isinstance(v2, collections.Mapping) else v1 and v2 


r= check_json(myjson, checker) 
print "r={}".format(r) 
isOK = functools.reduce(with_and, r.itervalues(), True) 
print "Result is {}: {}".format(isOK, r) 
+0

你可能可以做一些事情,比如在函数内部创建检查器模板,并在调用或修改“with”语句之前[改变它的命名空间](http://stackoverflow.com/q/1142068/646543)以某种方式提供这些功能并在其中创建模板功能。这种方法可能最终会变得更加混乱和更多的工作,然后它是值得的。 – Michael0x2a

回答

0

这是一个可行的方法。你将不得不决定它是否更易读/可维护/等等。

# check nested json 
import collections 
from functools import reduce 
import datetime 

#this is json from GET session 
myjson = { 
    "accessed": "Wed, 31 Jul 2013 13:03:38 GMT", 
    "created": "Wed, 31 Jul 2013 13:03:38 GMT", 
    "dnUrls": [ 
     "http://135.86.180.69:8580/ucc/api/v1/session/dns/50000" 
    ], 
    "expires": "Wed, 31 Jul 2013 13:03:48 GMT", 
    "modified": "Wed, 31 Jul 2013 13:03:38 GMT", 
    "name": "KW50000", 
    "person": { 
     "employeeId": "KW50000", 
     "firstName": "KW50000", 
     "lastName": "Dev5" 
    }, 
    "previewRedirect": { 
     "destination": "", 
     "enabled": False, 
     "setupEnabled": False 
    } 
} 


# returns dictionary with key= fieldname, value = result, 
# either True (Test Pass), False (test Failed) 
def check_json(obj, checker): 
    """params json to check, template comparison object 
     returns dictionary of keys to pass/fail values""" 

    result = {} 
    for k, (mFlag, chk) in checker.items(): 
     if not k in obj: 
      result[k] = not mFlag 
     elif isinstance(chk, collections.Callable): 
      result[k] = chk(obj[k]) 
     elif(isinstance(chk, collections.Mapping)): 
      result[k] = check_json(obj[k], chk) 
     else: 
      result[k] = chk == obj[k] 
    return result 

    def isDate(s): 
     try: 
      datetime.datetime.strptime(s, '%a, %d %b %Y %H:%M:%S GMT') 
      return True 
     except Exception: 
      print("conversion to date failed") 
      return False 


#checker object made up of dictionary with string key and tuple value (a pair) 
#tuple first filed is flag indicating whether key is mandatory or not. 
# tuple 2nd key is value to expect or a checker function 
checker = { 
    "accessed": (True, check_json.isDate), 
    "created": (True, check_json.isDate), 
    "dnUrls": (True, lambda l: (reduce(lambda c, v:\ 
        c + (1 if v.startswith('http://') else -1), l, 0) > 0)), 
    "expires": (True, check_json.isDate), 
    "modified": (True, check_json.isDate), 
    "name": (True, "KW50000"), 
    "person": (True, { 
     "employeeId": (True, lambda s: s.isalnum()), 
     "firstName": (False, True), 
     "lastName": (False, True) 
    }), 
    "previewRedirect": (True, { 
     "destination": (False, True), 
     "enabled": (True, lambda s: type(s) is bool), 
     "setupEnabled": (False, lambda s: type(s) is bool) 
    }) 
} 


def with_and(v1, v2): 
    return functools.reduce(with_and, v2.values(), v1)\ 
        if isinstance(v2, collections.Mapping) else v1 and v2 


r = check_json(myjson, checker) 
print("r={}".format(r)) 
isOK = functools.reduce(with_and, r.values(), True) 
print("Result is {}: {}".format(isOK, r)) 

请注意,代码已被修改为Python3。主要更改是尽可能使用lambdas,否则使用嵌套函数来消除全局名称空间依赖关系。

+0

如果我使用python 2.7运行,那么我得到例如“访问”:(True,check_json.isDate),AttributeError:'function'对象没有属性'isDate' –

+0

在这种情况下,不要使用嵌套函数并将'isDate功能回到全球范围。 – Jonathan