1
1
#!/usr/bin/python
2
+
2
3
###############################################################################
4
+ #
3
5
# Formatting filter for urllib2's HTTPHandler(debuglevel=1) output
4
6
# Copyright (c) 2013, Analytics Pros
5
- #
6
- # This project is free software, distributed under the BSD license.
7
- # Analytics Pros offers consulting and integration services if your firm needs
7
+ #
8
+ # This project is free software, distributed under the BSD license.
9
+ # Analytics Pros offers consulting and integration services if your firm needs
8
10
# assistance in strategy, implementation, or auditing existing work.
11
+ #
9
12
###############################################################################
10
13
14
+ # Standard library imports
15
+ from __future__ import division , print_function , with_statement
16
+ import re
17
+ import sys
11
18
12
- import sys , re , os
13
- from cStringIO import StringIO
14
-
19
+ # Third party libraries
20
+ from six . moves import cStringIO as StringIO # Used by tests
21
+ import six
15
22
16
23
17
24
class BufferTranslator (object ):
18
- """ Provides a buffer-compatible interface for filtering buffer content.
25
+ """
26
+ Provides a buffer-compatible interface for filtering buffer content.
19
27
"""
20
28
parsers = []
21
29
30
+ @staticmethod
31
+ def stripslashes (content ):
32
+ if six .PY3 :
33
+ content = content .encode ('UTF-8' )
34
+ return content .decode ('unicode_escape' )
35
+ else :
36
+ return content .decode ('string_escape' )
37
+
38
+ @staticmethod
39
+ def addslashes (content ):
40
+ if six .PY3 :
41
+ return content .encode ('unicode_escape' )
42
+ else :
43
+ return content .encode ('string_escape' )
44
+
22
45
def __init__ (self , output ):
23
46
self .output = output
24
47
self .encoding = getattr (output , 'encoding' , None )
@@ -27,56 +50,51 @@ def write(self, content):
27
50
content = self .translate (content )
28
51
self .output .write (content )
29
52
30
-
31
- @staticmethod
32
- def stripslashes (content ):
33
- return content .decode ('string_escape' )
34
-
35
- @staticmethod
36
- def addslashes (content ):
37
- return content .encode ('string_escape' )
38
-
39
53
def translate (self , line ):
40
54
for pattern , method in self .parsers :
41
55
match = pattern .match (line )
42
56
if match :
43
57
return method (match )
44
-
45
58
return line
46
-
59
+
60
+ def flush (self ):
61
+ pass
47
62
48
63
49
64
class LineBufferTranslator (BufferTranslator ):
50
- """ Line buffer implementation supports translation of line-format input
51
- even when input is not already line-buffered. Caches input until newlines
52
- occur, and then dispatches translated input to output buffer.
53
65
"""
54
- def __init__ (self , * a , ** kw ):
66
+ Line buffer implementation supports translation of line-format input
67
+ even when input is not already line-buffered. Caches input until newlines
68
+ occur, and then dispatches translated input to output buffer.
69
+ """
70
+ def __init__ (self , * args , ** kwargs ):
55
71
self ._linepending = []
56
- super (LineBufferTranslator , self ).__init__ (* a , ** kw )
57
-
72
+ super (LineBufferTranslator , self ).__init__ (* args , ** kwargs )
73
+
58
74
def write (self , _input ):
59
75
lines = _input .splitlines (True )
76
+ last = 0
60
77
for i in range (0 , len (lines )):
61
78
last = i
62
79
if lines [i ].endswith ('\n ' ):
63
- prefix = len (self ._linepending ) and '' .join (self ._linepending ) or ''
80
+ prefix = (len (self ._linepending ) and
81
+ '' .join (self ._linepending ) or '' )
64
82
self .output .write (self .translate (prefix + lines [i ]))
65
83
del self ._linepending [0 :]
66
84
last = - 1
67
-
68
- if last >= 0 :
69
- self ._linepending .append (lines [ last ])
70
85
86
+ if lines and last >= 0 :
87
+ self ._linepending .append (lines [last ])
71
88
72
89
def __del__ (self ):
73
90
if len (self ._linepending ):
74
91
self .output .write (self .translate ('' .join (self ._linepending )))
75
92
76
93
77
94
class HTTPTranslator (LineBufferTranslator ):
78
- """ Translates output from |urllib2| HTTPHandler(debuglevel = 1) into
79
- HTTP-compatible, readible text structures for human analysis.
95
+ """
96
+ Translates output from |urllib2| HTTPHandler(debuglevel = 1) into
97
+ HTTP-compatible, readible text structures for human analysis.
80
98
"""
81
99
82
100
RE_LINE_PARSER = re .compile (r'^(?:([a-z]+):)\s*(\'?)([^\r\n]*)\2(?:[\r\n]*)$' )
@@ -89,14 +107,13 @@ def spacer(cls, line):
89
107
return cls .RE_PARAMETER_SPACER .sub (r' &\1= ' , line )
90
108
91
109
def translate (self , line ):
92
-
93
110
parsed = self .RE_LINE_PARSER .match (line )
94
111
95
112
if parsed :
96
113
value = parsed .group (3 )
97
114
stage = parsed .group (1 )
98
115
99
- if stage == 'send' : # query string is rendered here
116
+ if stage == 'send' : # query string is rendered here
100
117
return '\n # HTTP Request:\n ' + self .stripslashes (value )
101
118
elif stage == 'reply' :
102
119
return '\n \n # HTTP Response:\n ' + self .stripslashes (value )
@@ -105,17 +122,17 @@ def translate(self, line):
105
122
else :
106
123
return value
107
124
108
-
109
125
return line
110
126
111
127
112
- def consume (outbuffer = None ): # Capture standard output
128
+ def consume (outbuffer = None ):
129
+ """
130
+ Capture standard output.
131
+ """
113
132
sys .stdout = HTTPTranslator (outbuffer or sys .stdout )
114
133
return sys .stdout
115
134
116
135
117
136
if __name__ == '__main__' :
118
137
consume (sys .stdout ).write (sys .stdin .read ())
119
- print '\n '
120
-
121
- # vim: set nowrap tabstop=4 shiftwidth=4 softtabstop=0 expandtab textwidth=0 filetype=python foldmethod=indent foldcolumn=4
138
+ print ('\n ' )
0 commit comments