]> jfr.im git - z_archive/twitter.git/blame - twitter/util.py
Ugly fix for the https://github.com/sixohsix/twitter/issues/245 issue
[z_archive/twitter.git] / twitter / util.py
CommitLineData
8ad2cf0b 1"""
2Internal utility functions.
3
4`htmlentitydecode` came from here:
5 http://wiki.python.org/moin/EscapingHtml
6"""
7
a7282452 8from __future__ import print_function
8ad2cf0b 9
907402f6 10import contextlib
8ad2cf0b 11import re
098660ce 12import sys
737cfb61 13import textwrap
a7282452 14import time
e107d209 15import socket
a7282452 16
3930cc7b
MV
17try:
18 from html.entities import name2codepoint
d9e92207 19 unichr = chr
62ec1b07 20 import urllib.request as urllib2
21 import urllib.parse as urlparse
3930cc7b
MV
22except ImportError:
23 from htmlentitydefs import name2codepoint
62ec1b07 24 import urllib2
25 import urlparse
8ad2cf0b 26
27def htmlentitydecode(s):
28 return re.sub(
a5e40197 29 '&(%s);' % '|'.join(name2codepoint),
1bb6d474 30 lambda m: unichr(name2codepoint[m.group(1)]), s)
8ad2cf0b 31
a5e40197
MV
32def smrt_input(globals_, locals_, ps1=">>> ", ps2="... "):
33 inputs = []
34 while True:
35 if inputs:
36 prompt = ps2
37 else:
38 prompt = ps1
7bfe7d97 39 inputs.append(input(prompt))
a5e40197
MV
40 try:
41 ret = eval('\n'.join(inputs), globals_, locals_)
42 if ret:
30e61103 43 print(str(ret))
a5e40197
MV
44 return
45 except SyntaxError:
46 pass
47
098660ce
MV
48def printNicely(string):
49 if hasattr(sys.stdout, 'buffer'):
50 sys.stdout.buffer.write(string.encode('utf8'))
368f536e
R
51 sys.stdout.buffer.flush()
52 sys.stdout.flush()
098660ce
MV
53 print()
54 else:
55 print(string.encode('utf8'))
56
a5e40197 57__all__ = ["htmlentitydecode", "smrt_input"]
a7282452
S
58
59def err(msg=""):
60 print(msg, file=sys.stderr)
61
62class Fail(object):
63 """A class to count fails during a repetitive task.
64
65 Args:
66 maximum: An integer for the maximum of fails to allow.
67 exit: An integer for the exit code when maximum of fail is reached.
68
69 Methods:
70 count: Count a fail, exit when maximum of fails is reached.
71 wait: Same as count but also sleep for a given time in seconds.
72 """
73 def __init__(self, maximum=10, exit=1):
74 self.i = maximum
75 self.exit = exit
76
77 def count(self):
78 self.i -= 1
79 if self.i == 0:
80 err("Too many consecutive fails, exiting.")
81 raise SystemExit(self.exit)
82
83 def wait(self, delay=0):
84 self.count()
85 if delay > 0:
86 time.sleep(delay)
907402f6 87
88
89def find_links(line):
90 """Find all links in the given line. The function returns a sprintf style
91 format string (with %s placeholders for the links) and a list of urls."""
62ec1b07 92 l = line.replace("%", "%%")
907402f6 93 regex = "(https?://[^ )]+)"
94 return (
be5f32da 95 re.sub(regex, "%s", l),
907402f6 96 [m.group(1) for m in re.finditer(regex, l)])
be5f32da 97
907402f6 98def follow_redirects(link, sites= None):
99 """Follow directs for the link as long as the redirects are on the given
100 sites and return the resolved link."""
101 def follow(url):
102 return sites == None or urlparse.urlparse(url).hostname in sites
be5f32da 103
907402f6 104 class RedirectHandler(urllib2.HTTPRedirectHandler):
105 def __init__(self):
106 self.last_url = None
107 def redirect_request(self, req, fp, code, msg, hdrs, newurl):
108 self.last_url = newurl
109 if not follow(newurl):
110 return None
111 r = urllib2.HTTPRedirectHandler.redirect_request(
112 self, req, fp, code, msg, hdrs, newurl)
113 r.get_method = lambda : 'HEAD'
114 return r
be5f32da 115
907402f6 116 if not follow(link):
117 return link
118 redirect_handler = RedirectHandler()
119 opener = urllib2.build_opener(redirect_handler)
120 req = urllib2.Request(link)
121 req.get_method = lambda : 'HEAD'
122 try:
e107d209 123 with contextlib.closing(opener.open(req,timeout=1)) as site:
907402f6 124 return site.url
62f2a207 125 except:
907402f6 126 return redirect_handler.last_url if redirect_handler.last_url else link
127
128def expand_line(line, sites):
129 """Expand the links in the line for the given sites."""
62f2a207
EB
130 try:
131 l = line.strip()
132 msg_format, links = find_links(l)
133 args = tuple(follow_redirects(l, sites) for l in links)
134 line = msg_format % args
135 except Exception as e:
136 try:
137 err("expanding line %s failed due to %s" % (line, unicode(e)))
138 except:
139 pass
140 return line
907402f6 141
142def parse_host_list(list_of_hosts):
143 """Parse the comma separated list of hosts."""
144 p = set(
145 m.group(1) for m in re.finditer("\s*([^,\s]+)\s*,?\s*", list_of_hosts))
146 return p
be5f32da 147
737cfb61 148
48a4e395 149def align_text(text, left_margin=17, max_width=160):
737cfb61
KLT
150 lines = []
151 for line in text.split('\n'):
152 temp_lines = textwrap.wrap(line, max_width - left_margin)
153 temp_lines = [(' ' * left_margin + line) for line in temp_lines]
154 lines.append('\n'.join(temp_lines))
155 ret = '\n'.join(lines)
156 return ret.lstrip()