关于python:如何删除这些检查功能是全局的需要

How can I remove need for these checking functions to be global

我正在使用Python测试RESTAPI。我得到一个作为JSON的响应消息,并希望检查每个字段。我已经创建了一个check json函数,并对照一个checker字典进行检查。checker字典有一个字符串键,它是json中键的名称,值是一个具有第一个bool参数的元组(一对),无论item是强制的,第二个参数是要进行直接比较的对象,还是添加更多相关检查功能的函数。

我是这样开支票的:

1
r= check_json(myjson, checker)

其中r是格式为"field"的结果:true或false-取决于检查是否通过或失败

代码有点混乱,有很多全局函数。其中一个想法是在check-json中包含is-checking函数。我被告知我也可以使用闭包。但是怎么做呢?

这是我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# 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)


这是一种可能的方法。您必须决定它是否更可读/可维护/等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# 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,并使用嵌套函数,否则将消除全局名称空间依赖性。