Mercurial > pybugzilla
annotate bugzilla.py @ 7:7a04d148ead6
Added tests
author | Atul Varma <avarma@mozilla.com> |
---|---|
date | Tue, 13 Apr 2010 11:31:13 -0700 |
parents | 548a4fe96851 |
children | 295c54288dd1 |
rev | line source |
---|---|
0 | 1 #! /usr/bin/env python |
2 | |
4 | 3 import os |
4 import sys | |
5
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
5 import base64 |
0 | 6 import httplib |
7 import urllib | |
5
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
8 import mimetypes |
0 | 9 from urlparse import urlparse |
4 | 10 from getpass import getpass |
0 | 11 |
12 try: | |
13 import json | |
14 except ImportError: | |
15 import simplejson as json | |
16 | |
4 | 17 DEFAULT_CONFIG = { |
18 'api_server': 'https://api-dev.bugzilla.mozilla.org/latest', | |
19 'server': 'https://bugzilla.mozilla.org' | |
20 } | |
21 | |
0 | 22 def json_request(method, url, query_args=None, body=None): |
23 if query_args is None: | |
24 query_args = {} | |
25 | |
26 headers = {'Accept': 'application/json', | |
27 'Content-Type': 'application/json'} | |
28 | |
29 urlparts = urlparse(url) | |
30 if urlparts.scheme == 'https': | |
31 connclass = httplib.HTTPSConnection | |
32 elif urlparts.scheme == 'http': | |
33 connclass = httplib.HTTPConnection | |
34 else: | |
35 raise ValueError('unknown scheme "%s"' % urlparts.scheme) | |
36 conn = connclass(urlparts.netloc) | |
37 path = urlparts.path | |
38 if query_args: | |
39 path += '?%s' % urllib.urlencode(query_args) | |
40 if body is not None: | |
41 body = json.dumps(body) | |
42 conn.request(method, path, body, headers) | |
43 response = conn.getresponse() | |
44 status, reason = response.status, response.reason | |
45 mimetype = response.msg.gettype() | |
46 data = response.read() | |
47 conn.close() | |
48 | |
49 if mimetype == 'application/json': | |
50 data = json.loads(data) | |
51 | |
52 return {'status': response.status, | |
53 'reason': response.reason, | |
54 'content_type': mimetype, | |
55 'body': data} | |
56 | |
3 | 57 def make_caching_json_request(cache, json_request=json_request): |
2 | 58 from hashlib import sha1 as hashfunc |
1
aca76355e4d8
Added make_caching_json_request() and .hgignore
Atul Varma <avarma@mozilla.com>
parents:
0
diff
changeset
|
59 |
aca76355e4d8
Added make_caching_json_request() and .hgignore
Atul Varma <avarma@mozilla.com>
parents:
0
diff
changeset
|
60 def caching_json_request(method, url, query_args=None, body=None): |
3 | 61 key = hashfunc(repr((method, url, query_args, body))).hexdigest() |
62 if not key in cache: | |
63 cache[key] = json_request(method=method, | |
64 url=url, | |
65 query_args=query_args, | |
66 body=body) | |
67 return cache[key] | |
1
aca76355e4d8
Added make_caching_json_request() and .hgignore
Atul Varma <avarma@mozilla.com>
parents:
0
diff
changeset
|
68 |
aca76355e4d8
Added make_caching_json_request() and .hgignore
Atul Varma <avarma@mozilla.com>
parents:
0
diff
changeset
|
69 return caching_json_request |
aca76355e4d8
Added make_caching_json_request() and .hgignore
Atul Varma <avarma@mozilla.com>
parents:
0
diff
changeset
|
70 |
3 | 71 class JsonBlobCache(object): |
72 def __init__(self, cachedir): | |
73 self.cachedir = cachedir | |
74 | |
75 def __pathforkey(self, key): | |
76 if not isinstance(key, basestring): | |
77 raise ValueError('key must be a string') | |
78 return os.path.join(self.cachedir, '%s.json' % key) | |
79 | |
80 def __getitem__(self, key): | |
81 if not key in self: | |
82 raise KeyError(key) | |
83 return json.loads(open(self.__pathforkey(key)).read()) | |
84 | |
85 def __setitem__(self, key, value): | |
86 open(self.__pathforkey(key), 'w').write(json.dumps(value)) | |
87 | |
88 def __contains__(self, key): | |
89 return os.path.exists(self.__pathforkey(key)) | |
90 | |
4 | 91 def getpass_or_die(prompt, getpass=getpass): |
92 try: | |
93 password = getpass(prompt) | |
94 except KeyboardInterrupt: | |
95 password = None | |
96 | |
97 if not password: | |
98 print "Aborted." | |
99 sys.exit(1) | |
100 | |
101 return password | |
102 | |
103 def load_config(filename=None, getpass=getpass_or_die): | |
104 config = {} | |
105 config.update(DEFAULT_CONFIG) | |
106 | |
107 if not filename: | |
108 filename = os.path.join('~', '.bugzilla-config.json') | |
109 filename = os.path.expanduser(filename) | |
110 if not os.path.exists(filename): | |
111 return config | |
112 | |
113 config.update(json.loads(open(filename).read())) | |
114 | |
115 if getpass and 'username' in config and 'password' not in config: | |
116 config['password'] = getpass('Enter password for %s: ' % | |
117 config['username']) | |
118 return config | |
119 | |
120 class BugzillaApi(object): | |
121 def __init__(self, config=None, jsonreq=None): | |
122 if config is None: | |
123 config = load_config() | |
124 | |
125 if jsonreq is None: | |
126 if 'cache_dir' in config: | |
127 cache = JsonBlobCache(os.path.expanduser(config['cache_dir'])) | |
128 jsonreq = make_caching_json_request(cache) | |
129 else: | |
130 jsonreq = json_request | |
131 | |
132 self.config = config | |
133 self.__jsonreq = jsonreq | |
134 | |
5
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
135 def post_attachment(self, bug_id, contents, filename, description, |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
136 content_type=None, is_patch=False, is_private=False, |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
137 is_obsolete=False, |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
138 guess_mime_type=mimetypes.guess_type): |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
139 if content_type is None: |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
140 content_type = guess_mime_type(filename)[0] |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
141 if not content_type: |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
142 raise ValueError('could not guess content type for "%s"' % |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
143 filename) |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
144 |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
145 attachment = { |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
146 'data': base64.b64encode(contents), |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
147 'description': description, |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
148 'encoding': 'base64', |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
149 'file_name': filename, |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
150 'flags': [], |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
151 'is_obsolete': is_obsolete, |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
152 'is_patch': is_patch, |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
153 'is_private': is_private, |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
154 'size': len(contents), |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
155 'content_type': content_type |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
156 } |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
157 |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
158 return self.request('POST', '/bug/%d/attachment' % bug_id, |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
159 body=attachment) |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
160 |
4 | 161 def request(self, method, path, query_args=None, body=None): |
162 if query_args is None: | |
163 query_args = {} | |
164 | |
165 if 'username' in self.config and 'password' in self.config: | |
166 for name in ['username', 'password']: | |
167 query_args[name] = self.config[name] | |
168 | |
169 url = '%s%s' % (self.config['api_server'], path) | |
170 | |
171 response = self.__jsonreq(method=method, | |
172 url=url, | |
173 query_args=query_args, | |
174 body=body) | |
175 | |
176 if response['content_type'] == 'application/json': | |
177 json_response = response['body'] | |
178 if 'error' in json_response and json_response['error']: | |
179 raise BugzillaApiError(response) | |
180 return json_response | |
181 raise BugzillaApiError(response) | |
182 | |
183 class BugzillaApiError(Exception): | |
184 pass | |
0 | 185 |
186 if __name__ == '__main__': | |
4 | 187 bzapi = BugzillaApi() |
188 print bzapi.request('GET', '/attachment/436897', | |
189 query_args={'attachmentdata': 1}) | |
5
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
190 #bzapi.post_attachment(bug_id=536619, |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
191 # contents="testing!", |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
192 # filename="contents.txt", |
7745feb7ca9c
Added BugzillaApi.post_attachment()
Atul Varma <avarma@mozilla.com>
parents:
4
diff
changeset
|
193 # description="test upload") |