-
Notifications
You must be signed in to change notification settings - Fork 0
/
pm-sort.py
executable file
·156 lines (125 loc) · 4.12 KB
/
pm-sort.py
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python3
# vi:set ts=8 sw=4 sta et:
#
# Author: Clark Wang <dearvoid at gmail.com>
#
# Note:
# - Use v2.1 format when exporting Postman data.
# - Folders in a collection can be _nested_.
#
#--------------------------------------------------------------------#
import json
import sys
from types import SimpleNamespace
class NsEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, SimpleNamespace):
return self.encode_hook(obj)
else:
# should not reach here
return super().default(obj)
# obj --> dict
@staticmethod
def encode_hook(obj):
#assert isinstance(obj, SimpleNamespace)
return obj.__dict__
class NsDecoder(json.JSONDecoder):
def decode(self, s):
return json.JSONDecoder(object_hook=self.decode_hook).decode(s)
# obj <-- { 'k1': 'v1', 'k2': 'v2', ... }
@staticmethod
def decode_hook(d):
return SimpleNamespace(**d)
# obj <-- [('k1', 'v1'), ('k2', 'v2'), ...]
@staticmethod
def decode_pairs_hook(pairs):
d = dict(pairs)
return NsDecoder.decode_hook(d)
def hasattr_dotted(obj, attrs):
for attr in attrs.split('.'):
if hasattr(obj, attr):
obj = getattr(obj, attr)
else:
return False
return True
def getattr_dotted(obj, attrs, default=None):
assert attrs
for attr in attrs.split('.'):
if hasattr(obj, attr):
obj = getattr(obj, attr)
else:
return default
else:
return obj
# sort request's query params
def postman_sort_req(req):
if not req:
return req
if not hasattr_dotted(req, 'url.query'):
return req
queries = req.url.query
# 'key' may be null.
queries.sort(key=lambda x: (x.key or '').lower() )
req.url.query = queries
return req
# sort responses and responses' query params
def postman_sort_resp(resps):
if not resps:
return resps
resps.sort(key=lambda x: x.name.lower() )
for resp in resps:
if hasattr_dotted(resp, 'originalRequest.url.query'):
queries = resp.originalRequest.url.query
queries.sort(key=lambda x: (x.key or '').lower() )
resp.originalRequest.url.query = queries
return resps
def postman_sort(js, _level=1):
if not js or type(js) is not SimpleNamespace:
return js
items = js.item
if not items or type(items) is not list:
return js
for i in range(len(items) ):
item = items[i]
if hasattr(item, 'item'):
# folders (may be nested) under the collection
items[i] = postman_sort(item, _level=_level + 1)
else:
# requests
if hasattr(item, 'request'):
req = item.request
item.request = postman_sort_req(req)
# example responses
if hasattr(item, 'response'):
resps = item.response
item.response = postman_sort_resp(resps)
items[i] = item
js.item = sorted(items, key=lambda x: x.name.lower() )
# collection variables
if _level == 1 and getattr(js, 'variable', None):
assert type(js.variable) is list
js.variable.sort(key=lambda x: x.key if x.key.isupper() else x.key.lower() )
return js
def postman_sort_env(js):
js.values.sort(key=lambda x: x.key if x.key.isupper() else x.key.lower() )
return js
def main():
if len(sys.argv) > 1:
fp = open(sys.argv[1])
else:
fp = sys.stdin
js = json.load(fp, cls=NsDecoder)
dump_before = json.dumps(js, cls=NsEncoder)
# Postman environment
if getattr(js, '_postman_variable_scope', '') == 'environment':
js = postman_sort_env(js)
# Postman collection
elif '/collection/v2.1.0/' in getattr_dotted(js, 'info.schema', ''):
# https://schema.getpostman.com/json/collection/v2.1.0/collection.json
js = postman_sort(js)
else:
raise Exception('unknown format: neither collection nor environment')
dump_after = json.dumps(js, cls=NsEncoder)
assert len(dump_before) == len(dump_after)
print(dump_after)
main()