From 2d7f2c65a22edbe84f269069c53dc06d80272259 Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Thu, 26 Apr 2012 13:05:59 +0200 Subject: [PATCH 1/4] Use the Pygments HTTP and JSON lexers --- httpie/pretty.py | 43 +++++++-------------------- httpie/pygson.py | 77 ------------------------------------------------ setup.py | 2 +- 3 files changed, 12 insertions(+), 110 deletions(-) delete mode 100644 httpie/pygson.py diff --git a/httpie/pretty.py b/httpie/pretty.py index 7fea7969..acaf4da8 100644 --- a/httpie/pretty.py +++ b/httpie/pretty.py @@ -3,12 +3,10 @@ import json import pygments from pygments import token from pygments.util import ClassNotFound -from pygments.lexers import get_lexer_for_mimetype +from pygments.lexers import get_lexer_for_mimetype, HttpLexer from pygments.formatters.terminal256 import Terminal256Formatter from pygments.formatters.terminal import TerminalFormatter -from pygments.lexer import RegexLexer, bygroups from pygments.styles import get_style_by_name, STYLE_MAP -from .pygson import JSONLexer from . import solarized @@ -18,25 +16,6 @@ FORMATTER = (Terminal256Formatter if '256color' in os.environ.get('TERM', '') else TerminalFormatter) - -class HTTPLexer(RegexLexer): - name = 'HTTP' - aliases = ['http'] - filenames = ['*.http'] - tokens = { - 'root': [ - (r'\s+', token.Text), - # Request-Line - (r'([A-Z]+\s+)(/.*?)(\s+HTTP/[\d.]+)', bygroups( - token.Keyword, token.String, token.Keyword)), - # Status-Line - (r'(HTTP/[\d.]+\s+)(\d+)(\s+.+)', bygroups( - token.Keyword, token.Number, token.String)), - # Header - (r'(.*?:)(.+)', bygroups(token.Name, token.Keyword)) - ]} - - class PrettyHttp(object): def __init__(self, style_name): @@ -47,22 +26,22 @@ class PrettyHttp(object): self.formatter = FORMATTER(style=style) def headers(self, content): - return pygments.highlight(content, HTTPLexer(), self.formatter) + return pygments.highlight(content, HttpLexer(), self.formatter) def body(self, content, content_type): - lexer = None content_type = content_type.split(';')[0] + + try: + lexer = get_lexer_for_mimetype(content_type) + except ClassNotFound: + return content + if 'json' in content_type: - lexer = JSONLexer() try: # Indent the JSON data. content = json.dumps(json.loads(content), - sort_keys=True, indent=4) - except Exception: + sort_keys=True, indent=4) + except: pass - if not lexer: - try: - lexer = get_lexer_for_mimetype(content_type) - except ClassNotFound: - return content + return pygments.highlight(content, lexer, self.formatter) diff --git a/httpie/pygson.py b/httpie/pygson.py deleted file mode 100644 index be0492b3..00000000 --- a/httpie/pygson.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -JSON lexer by Norman Richards - -It's already been merged into Pygments but not released yet, -so we are temporarily bundling it with HTTPie. - -It can be removed once Pygments > 1.4 has been released. - -See for more details. - -""" -import re -from pygments import token -from pygments.lexer import RegexLexer, include - - -class JSONLexer(RegexLexer): - name = 'JSON Lexer' - aliases = ['json'] - filenames = ['*.json'] - mimetypes = [] - - - flags = re.DOTALL - tokens = { - 'whitespace': [ - (r'\s+', token.Text), - ], - - # represents a simple terminal value - 'simplevalue':[ - (r'(true|false|null)\b', token.Keyword.Constant), - (r'-?[0-9]+', token.Number.Integer), - (r'"(\\\\|\\"|[^"])*"', token.String.Double), - ], - - - # the right hand side of an object, after the attribute name - 'objectattribute': [ - include('value'), - (r':', token.Punctuation), - # comma terminates the attribute but expects more - (r',', token.Punctuation, '#pop'), - # a closing bracket terminates the entire object, so pop twice - (r'}', token.Punctuation, ('#pop', '#pop')), - ], - - # a json object - { attr, attr, ... } - 'objectvalue': [ - include('whitespace'), - (r'"(\\\\|\\"|[^"])*"', token.Name.Tag, 'objectattribute'), - (r'}', token.Punctuation, '#pop'), - ], - - # json array - [ value, value, ... } - 'arrayvalue': [ - include('whitespace'), - include('value'), - (r',', token.Punctuation), - (r']', token.Punctuation, '#pop'), - ], - - # a json value - either a simple value or a complex value (object or array) - 'value': [ - include('whitespace'), - include('simplevalue'), - (r'{', token.Punctuation, 'objectvalue'), - (r'\[', token.Punctuation, 'arrayvalue'), - ], - - - # the root of a json document would be a value - 'root': [ - include('value'), - ], - - } diff --git a/setup.py b/setup.py index 4628f54c..ee04cfb5 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ if sys.argv[-1] == 'test': sys.exit() -requirements = ['requests>=0.10.1', 'Pygments>=1.4'] +requirements = ['requests>=0.10.1', 'Pygments>=1.5'] if sys.version_info[:2] in ((2, 6), (3, 1)): # argparse has been added in Python 3.2 / 2.7 requirements.append('argparse>=1.2.1') From 4aa86cb438603850bc8864b529572c58255296d6 Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Thu, 26 Apr 2012 14:48:38 +0200 Subject: [PATCH 2/4] Use the full capability of HttpLexer --- httpie/__main__.py | 11 ++++++++--- httpie/httpmessage.py | 29 ++++++++++++++++++----------- httpie/pretty.py | 41 ++++++++++++----------------------------- 3 files changed, 38 insertions(+), 43 deletions(-) diff --git a/httpie/__main__.py b/httpie/__main__.py index faa4045e..3cf60c46 100644 --- a/httpie/__main__.py +++ b/httpie/__main__.py @@ -1,8 +1,11 @@ #!/usr/bin/env python import sys import json + import requests + from requests.compat import str + from . import httpmessage from . import cliparse from . import cli @@ -81,13 +84,14 @@ def _get_output(args, stdout_isatty, response): do_output_response = (cliparse.OUT_RESP_HEADERS in args.output_options or cliparse.OUT_RESP_BODY in args.output_options) - prettifier = pretty.PrettyHttp(args.style) if do_prettify else None + formatter = pretty.formatter(args.style) if do_prettify else None output = [] if do_output_request: output.append(httpmessage.format( message=httpmessage.from_request(response.request), - prettifier=prettifier, + pretty=do_prettify, + formatter=formatter, with_headers=cliparse.OUT_REQ_HEADERS in args.output_options, with_body=cliparse.OUT_REQ_BODY in args.output_options )) @@ -97,7 +101,8 @@ def _get_output(args, stdout_isatty, response): if do_output_response: output.append(httpmessage.format( message=httpmessage.from_response(response), - prettifier=prettifier, + pretty=do_prettify, + formatter=formatter, with_headers=cliparse.OUT_RESP_HEADERS in args.output_options, with_body=cliparse.OUT_RESP_BODY in args.output_options )) diff --git a/httpie/httpmessage.py b/httpie/httpmessage.py index e96dd691..d063a807 100644 --- a/httpie/httpmessage.py +++ b/httpie/httpmessage.py @@ -1,3 +1,7 @@ +import json + +from pygments import highlight +from pygments.lexers import HttpLexer from requests.compat import urlparse @@ -38,29 +42,32 @@ def from_response(response): return HTTPMessage( line='HTTP/{version} {status} {reason}'.format( version='.'.join(str(original.version)), - status=original.status, reason=original.reason,), + status=original.status, reason=original.reason), headers=str(original.msg), body=response.content.decode(encoding) if response.content else '', content_type=response_headers.get('Content-Type')) -def format(message, prettifier=None, +def format(message, formatter=None, pretty=False, with_headers=True, with_body=True): """Return a `unicode` representation of `message`. """ bits = [] if with_headers: - if prettifier: - bits.append(prettifier.headers(message.line)) - bits.append(prettifier.headers(message.headers)) - else: - bits.append(message.line) - bits.append(message.headers) + bits.append(message.line) + bits.append(message.headers) if with_body and message.body: bits.append('\n') if with_body and message.body: - if prettifier and message.content_type: - bits.append(prettifier.body(message.body, message.content_type)) + if (pretty and message.content_type and + message.content_type.split(';')[0] == 'application/json'): + # Indent and sort the JSON data. + bits.append(json.dumps(json.loads(message.body), + sort_keys=True, indent=4)) else: bits.append(message.body) bits.append('\n') - return '\n'.join(bit.strip() for bit in bits) + result = '\n'.join(bit.strip() for bit in bits) + if pretty: + return highlight(result, HttpLexer(), formatter) + + return result diff --git a/httpie/pretty.py b/httpie/pretty.py index acaf4da8..cc40b605 100644 --- a/httpie/pretty.py +++ b/httpie/pretty.py @@ -1,12 +1,15 @@ import os import json + import pygments + from pygments import token from pygments.util import ClassNotFound -from pygments.lexers import get_lexer_for_mimetype, HttpLexer -from pygments.formatters.terminal256 import Terminal256Formatter -from pygments.formatters.terminal import TerminalFormatter from pygments.styles import get_style_by_name, STYLE_MAP +from pygments.lexers import get_lexer_for_mimetype, HttpLexer +from pygments.formatters.terminal import TerminalFormatter +from pygments.formatters.terminal256 import Terminal256Formatter + from . import solarized @@ -16,32 +19,12 @@ FORMATTER = (Terminal256Formatter if '256color' in os.environ.get('TERM', '') else TerminalFormatter) -class PrettyHttp(object): - def __init__(self, style_name): - if style_name == 'solarized': - style = solarized.SolarizedStyle - else: - style = get_style_by_name(style_name) - self.formatter = FORMATTER(style=style) +def formatter(style_name): + if style_name == 'solarized': + style = solarized.SolarizedStyle - def headers(self, content): - return pygments.highlight(content, HttpLexer(), self.formatter) + else: + style = get_style_by_name(style_name) - def body(self, content, content_type): - content_type = content_type.split(';')[0] - - try: - lexer = get_lexer_for_mimetype(content_type) - except ClassNotFound: - return content - - if 'json' in content_type: - try: - # Indent the JSON data. - content = json.dumps(json.loads(content), - sort_keys=True, indent=4) - except: - pass - - return pygments.highlight(content, lexer, self.formatter) + return FORMATTER(style=style) From bced559496de7735b6cc37c77bf00d5c241542c0 Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Sat, 28 Apr 2012 14:13:40 +0200 Subject: [PATCH 3/4] use PrettyHttp class; working --headers and --body --- httpie/__main__.py | 8 +++----- httpie/httpmessage.py | 24 +++++++++--------------- httpie/pretty.py | 37 ++++++++++++++++++++++++++++--------- 3 files changed, 40 insertions(+), 29 deletions(-) diff --git a/httpie/__main__.py b/httpie/__main__.py index 3cf60c46..8cc48001 100644 --- a/httpie/__main__.py +++ b/httpie/__main__.py @@ -84,14 +84,13 @@ def _get_output(args, stdout_isatty, response): do_output_response = (cliparse.OUT_RESP_HEADERS in args.output_options or cliparse.OUT_RESP_BODY in args.output_options) - formatter = pretty.formatter(args.style) if do_prettify else None + prettifier = pretty.PrettyHttp(args.style) if do_prettify else None output = [] if do_output_request: output.append(httpmessage.format( message=httpmessage.from_request(response.request), - pretty=do_prettify, - formatter=formatter, + prettifier=prettifier, with_headers=cliparse.OUT_REQ_HEADERS in args.output_options, with_body=cliparse.OUT_REQ_BODY in args.output_options )) @@ -101,8 +100,7 @@ def _get_output(args, stdout_isatty, response): if do_output_response: output.append(httpmessage.format( message=httpmessage.from_response(response), - pretty=do_prettify, - formatter=formatter, + prettifier=prettifier, with_headers=cliparse.OUT_RESP_HEADERS in args.output_options, with_body=cliparse.OUT_RESP_BODY in args.output_options )) diff --git a/httpie/httpmessage.py b/httpie/httpmessage.py index d063a807..2a9b31c6 100644 --- a/httpie/httpmessage.py +++ b/httpie/httpmessage.py @@ -1,7 +1,3 @@ -import json - -from pygments import highlight -from pygments.lexers import HttpLexer from requests.compat import urlparse @@ -48,26 +44,24 @@ def from_response(response): content_type=response_headers.get('Content-Type')) -def format(message, formatter=None, pretty=False, +def format(message, prettifier=None, with_headers=True, with_body=True): """Return a `unicode` representation of `message`. """ + pretty = prettifier is not None bits = [] + if with_headers: bits.append(message.line) bits.append(message.headers) + if pretty: + bits = [prettifier.headers('\n'.join(bits))] if with_body and message.body: bits.append('\n') + if with_body and message.body: - if (pretty and message.content_type and - message.content_type.split(';')[0] == 'application/json'): - # Indent and sort the JSON data. - bits.append(json.dumps(json.loads(message.body), - sort_keys=True, indent=4)) + if pretty and message.content_type: + bits.append(prettifier.body(message.body, message.content_type)) else: bits.append(message.body) - bits.append('\n') - result = '\n'.join(bit.strip() for bit in bits) - if pretty: - return highlight(result, HttpLexer(), formatter) - return result + return '\n'.join(bit.strip() for bit in bits) diff --git a/httpie/pretty.py b/httpie/pretty.py index cc40b605..deb82bb3 100644 --- a/httpie/pretty.py +++ b/httpie/pretty.py @@ -3,12 +3,11 @@ import json import pygments -from pygments import token from pygments.util import ClassNotFound -from pygments.styles import get_style_by_name, STYLE_MAP from pygments.lexers import get_lexer_for_mimetype, HttpLexer -from pygments.formatters.terminal import TerminalFormatter from pygments.formatters.terminal256 import Terminal256Formatter +from pygments.formatters.terminal import TerminalFormatter +from pygments.styles import get_style_by_name, STYLE_MAP from . import solarized @@ -20,11 +19,31 @@ FORMATTER = (Terminal256Formatter else TerminalFormatter) -def formatter(style_name): - if style_name == 'solarized': - style = solarized.SolarizedStyle +class PrettyHttp(object): - else: - style = get_style_by_name(style_name) + def __init__(self, style_name): + if style_name == 'solarized': + style = solarized.SolarizedStyle + else: + style = get_style_by_name(style_name) + self.formatter = FORMATTER(style=style) - return FORMATTER(style=style) + def headers(self, content): + return pygments.highlight(content, HttpLexer(), self.formatter) + + def body(self, content, content_type): + content_type = content_type.split(';')[0] + try: + lexer = get_lexer_for_mimetype(content_type) + except ClassNotFound: + return content + + if content_type == 'application/json': + try: + # Indent and sort the JSON data. + content = json.dumps(json.loads(content), + sort_keys=True, indent=4) + except: + pass + + return pygments.highlight(content, lexer, self.formatter) From d89eeb0796b5dd3d009a8eb202628ac136e32d86 Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Sat, 28 Apr 2012 14:18:59 +0200 Subject: [PATCH 4/4] PEP-8 --- httpie/cliparse.py | 8 ++++++-- httpie/pretty.py | 2 +- httpie/solarized.py | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/httpie/cliparse.py b/httpie/cliparse.py index 8664edb4..c481fe3c 100644 --- a/httpie/cliparse.py +++ b/httpie/cliparse.py @@ -3,15 +3,19 @@ CLI argument parsing logic. """ import os -import json import re +import json +import argparse + from collections import namedtuple + try: from collections import OrderedDict except ImportError: OrderedDict = dict -import argparse + from requests.structures import CaseInsensitiveDict + from . import __version__ diff --git a/httpie/pretty.py b/httpie/pretty.py index deb82bb3..8c6bdbee 100644 --- a/httpie/pretty.py +++ b/httpie/pretty.py @@ -4,10 +4,10 @@ import json import pygments from pygments.util import ClassNotFound +from pygments.styles import get_style_by_name, STYLE_MAP from pygments.lexers import get_lexer_for_mimetype, HttpLexer from pygments.formatters.terminal256 import Terminal256Formatter from pygments.formatters.terminal import TerminalFormatter -from pygments.styles import get_style_by_name, STYLE_MAP from . import solarized diff --git a/httpie/solarized.py b/httpie/solarized.py index 903f32b6..69bee7da 100644 --- a/httpie/solarized.py +++ b/httpie/solarized.py @@ -27,7 +27,8 @@ THE SOFTWARE. """ from pygments.style import Style -from pygments.token import Token, Comment, Name, Keyword, Generic, Number, Operator, String +from pygments.token import (Token, Comment, Name, Keyword, Generic, Number, + Operator, String) BASE03 = '#002B36'