Package restkit :: Package contrib :: Module console
[hide private]

Source Code for Module restkit.contrib.console

  1  # -*- coding: utf-8 - 
  2  # 
  3  # This file is part of restkit released under the MIT license.  
  4  # See the NOTICE for more information. 
  5   
  6  from __future__ import with_statement 
  7  import os 
  8  import optparse as op 
  9  import sys 
 10   
 11  # import pygments if here 
 12  try: 
 13      import pygments 
 14      from pygments.lexers import get_lexer_for_mimetype 
 15      from pygments.formatters import TerminalFormatter 
 16  except ImportError: 
 17      pygments = False 
 18       
 19  # import json    
 20  try: 
 21      import simplejson as json 
 22  except ImportError: 
 23      try: 
 24          import json 
 25      except ImportError: 
 26          json = False 
 27   
 28  from restkit import __version__, request, set_logging 
 29  from restkit.util import popen3, locate_program 
 30   
 31  __usage__ = "'%prog [options] url [METHOD] [filename]'" 
 32   
 33   
 34  pretties = { 
 35      'application/json': 'text/javascript', 
 36      'text/plain': 'text/javascript' 
 37  } 
 38   
39 -def external(cmd, data):
40 try: 41 (child_stdin, child_stdout, child_stderr) = popen3(cmd) 42 err = child_stderr.read() 43 if err: 44 return data 45 return child_stdout.read() 46 except: 47 return data
48
49 -def indent_xml(data):
50 tidy_cmd = locate_program("tidy") 51 if tidy_cmd: 52 cmd = " ".join([tidy_cmd, '-qi', '-wrap', '70', '-utf8', data]) 53 return external(cmd, data) 54 return data
55
56 -def indent_json(data):
57 if not json: 58 return data 59 info = json.loads(data) 60 return json.dumps(info, indent=2, sort_keys=True)
61 62 63 common_indent = { 64 'application/json': indent_json, 65 'text/html': indent_xml, 66 'text/xml': indent_xml, 67 'application/xhtml+xml': indent_xml, 68 'application/xml': indent_xml, 69 'image/svg+xml': indent_xml, 70 'application/rss+xml': indent_xml, 71 'application/atom+xml': indent_xml, 72 'application/xsl+xml': indent_xml, 73 'application/xslt+xml': indent_xml 74 } 75
76 -def indent(mimetype, data):
77 if mimetype in common_indent: 78 return common_indent[mimetype](data) 79 return data
80
81 -def prettify(response, cli=True):
82 if not pygments or not 'content-type' in response.headers: 83 return response.body_string() 84 85 ctype = response.headers['content-type'] 86 try: 87 mimetype, encoding = ctype.split(";") 88 except ValueError: 89 mimetype = ctype.split(";")[0] 90 91 # indent body 92 body = indent(mimetype, response.body_string()) 93 94 # get pygments mimetype 95 mimetype = pretties.get(mimetype, mimetype) 96 97 try: 98 lexer = get_lexer_for_mimetype(mimetype) 99 body = pygments.highlight(body, lexer, TerminalFormatter()) 100 return body 101 except: 102 return body
103
104 -def as_bool(value):
105 if value.lower() in ('true', '1'): 106 return True 107 return False
108
109 -def update_defaults(defaults):
110 config = os.path.expanduser('~/.restcli') 111 if os.path.isfile(config): 112 for line in open(config): 113 key, value = line.split('=', 1) 114 key = key.lower().strip() 115 key = key.replace('-', '_') 116 if key.startswith('header'): 117 key = 'headers' 118 value = value.strip() 119 if key in defaults: 120 default = defaults[key] 121 if default in (True, False): 122 value = as_bool(value) 123 elif isinstance(default, list): 124 default.append(value) 125 value = default 126 defaults[key] = value
127
128 -def options():
129 """ build command lines options """ 130 131 defaults = dict( 132 headers=[], 133 request='GET', 134 follow_redirect=False, 135 server_response=False, 136 prettify=False, 137 log_level=None, 138 input=None, 139 output=None, 140 ) 141 update_defaults(defaults) 142 143 def opt_args(option, *help): 144 help = ' '.join(help) 145 help = help.strip() 146 default = defaults.get(option) 147 if default is not None: 148 help += ' Default to %r.' % default 149 return dict(default=defaults.get(option), help=help)
150 151 return [ 152 op.make_option('-H', '--header', action='append', dest='headers', 153 **opt_args('headers', 154 'HTTP string header in the form of Key:Value. ', 155 'For example: "Accept: application/json".')), 156 op.make_option('-X', '--request', action='store', dest='method', 157 **opt_args('request', 'HTTP request method.')), 158 op.make_option('--follow-redirect', action='store_true', 159 dest='follow_redirect', **opt_args('follow_redirect')), 160 op.make_option('-S', '--server-response', action='store_true', 161 dest='server_response', 162 **opt_args('server_response', 'Print server response.')), 163 op.make_option('-p', '--prettify', dest="prettify", action='store_true', 164 **opt_args('prettify', "Prettify display.")), 165 op.make_option('--log-level', dest="log_level", 166 **opt_args('log_level', 167 "Log level below which to silence messages.")), 168 op.make_option('-i', '--input', action='store', dest='input', 169 metavar='FILE', 170 **opt_args('input', 'The name of the file to read from.')), 171 op.make_option('-o', '--output', action='store', dest='output', 172 **opt_args('output', 'The name of the file to write to.')), 173 op.make_option('--shell', action='store_true', dest='shell', 174 help='Open a IPython shell'), 175 ] 176
177 -def main():
178 """ function to manage restkit command line """ 179 parser = op.OptionParser(usage=__usage__, option_list=options(), 180 version="%prog " + __version__) 181 182 opts, args = parser.parse_args() 183 args_len = len(args) 184 185 if opts.shell: 186 try: 187 from restkit.contrib import ipython_shell as shell 188 shell.main(options=opts, *args) 189 except Exception, e: 190 print >>sys.stderr, str(e) 191 sys.exit(1) 192 return 193 194 if args_len < 1: 195 return parser.error('incorrect number of arguments') 196 197 if opts.log_level is not None: 198 set_logging(opts.log_level) 199 200 body = None 201 headers = [] 202 if opts.input: 203 if opts.input == '-': 204 body = sys.stdin.read() 205 headers.append(("Content-Length", str(len(body)))) 206 else: 207 fname = os.path.normpath(os.path.join(os.getcwd(),opts.input)) 208 body = open(fname, 'r') 209 210 if opts.headers: 211 for header in opts.headers: 212 try: 213 k, v = header.split(':') 214 headers.append((k, v)) 215 except ValueError: 216 pass 217 218 219 try: 220 if len(args) == 2: 221 if args[1] == "-" and not opts.input: 222 body = sys.stdin.read() 223 headers.append(("Content-Length", str(len(body)))) 224 225 if not opts.method and opts.input: 226 method = 'POST' 227 else: 228 method=opts.method.upper() 229 230 resp = request(args[0], method=method, body=body, 231 headers=headers, follow_redirect=opts.follow_redirect) 232 233 if opts.output and opts.output != '-': 234 with open(opts.output, 'wb') as f: 235 if opts.server_response: 236 f.write("Server response from %s:\n" % resp.final_url) 237 for k, v in resp.headerslist: 238 f.write( "%s: %s" % (k, v)) 239 else: 240 with resp.body_stream() as body: 241 for block in body: 242 f.write(block) 243 else: 244 if opts.server_response: 245 if opts.prettify: 246 print "\n\033[0m\033[95mServer response from %s:\n\033[0m" % ( 247 resp.final_url) 248 for k, v in resp.headerslist: 249 print "\033[94m%s\033[0m: %s" % (k, v) 250 print "\033[0m" 251 else: 252 print "Server response from %s:\n" % (resp.final_url) 253 for k, v in resp.headerslist: 254 print "%s: %s" % (k, v) 255 print "" 256 257 if opts.output == '-': 258 if opts.prettify: 259 print prettify(resp) 260 else: 261 print resp.body_string() 262 else: 263 if opts.prettify: 264 print prettify(resp) 265 else: 266 print resp.body_string() 267 268 except Exception, e: 269 sys.stderr.write("An error happened: %s" % str(e)) 270 sys.stderr.flush() 271 sys.exit(1) 272 273 sys.exit(0)
274