From 5123d1a3b48920db78e5ec638d0b1c6a1d513380 Mon Sep 17 00:00:00 2001 From: Jon Bergli Heier Date: Sat, 25 Mar 2017 08:19:23 +0100 Subject: Added python 3 compatibility. We're now using the six module and some helper functions to deal with str, unicode and bytes. This is tested on python 2.7 and 3.6. --- pastepy.py | 51 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/pastepy.py b/pastepy.py index 8c715fa..32a2f74 100644 --- a/pastepy.py +++ b/pastepy.py @@ -21,9 +21,22 @@ import pygments from pygments import highlight from pygments.lexers import get_all_lexers, get_lexer_by_name from pygments.formatters import HtmlFormatter +import six base62_alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' +def b2t(s): + '''Convert binary types to text types.''' + if isinstance(s, six.binary_type): + return s.decode('utf-8') + return s + +def t2b(s): + '''Convert text types to binary types.''' + if isinstance(s, six.text_type): + return s.encode('utf-8') + return s + class PasteError(Exception): pass class UnknownSyntaxError(PasteError): pass @@ -89,7 +102,7 @@ class Paste(object): 'title': settings.pastebin_name, 'header': settings.pastebin_name, 'lexers': self.lexers, - 'nick': c['nick'].value if 'nick' in c else 'Anonymous', + 'nick': b2t(c['nick'].value if 'nick' in c else 'Anonymous'), 'syntax': c['syntax'].value if 'syntax' in c else settings.default, 'remember_me': 'nick' in c, 'remember_syntax': 'syntax' in c, @@ -97,27 +110,30 @@ class Paste(object): def preview(self, mp): try: - lexername, text = self.get_formatted(mp['syntax'].value.decode('utf-8'), mp['text'].value.decode('utf-8')) + lexername, text = self.get_formatted(mp['syntax'].value, mp['text'].value) except UnknownSyntaxError: return self.message('Could not find lexer "%s".' % mp['syntax'].value, 'Error') + # These values to be unicode in py2; in py3 they will be str which is OK. + nick = b2t(mp['nick'].value or 'Anonymous') + title = b2t(mp['title'].value or 'Untitled') return self.render_template('view.html', { 'title': settings.pastebin_name, 'header': '%s – Preview' % settings.pastebin_name, 'hash': None, - 'nick': mp['nick'].value.decode('utf-8') or 'Anoynmous', + 'nick': nick, 'date': '%s UTC' % datetime.datetime.utcnow().ctime(), 'syntax': lexername, - 'pastetitle': mp['title'].value.decode('utf-8') or 'Untitled', + 'pastetitle': title, 'text': text, 'rendered': (lexername or '').startswith('Rendered '), }) def add_paste(self, mp): - nick = mp['nick'].value.decode('utf-8') or None - syntax = mp['syntax'].value.decode('utf-8') or None - title = mp['title'].value.decode('utf-8') or None - text = mp['text'].value.decode('utf-8').replace('\r', '') or None + nick = b2t(mp['nick'].value or None) + syntax = b2t(mp['syntax'].value or None) + title = b2t(mp['title'].value or None) + text = b2t(mp['text'].value.replace('\r', '') or None) hash = ''.join(random.choice(base62_alphabet) for x in range(5)) @@ -131,13 +147,18 @@ class Paste(object): headers = [('Location', '/view/%s' % hash)] c = SimpleCookie() + if six.PY2: + # In py2 we need nick to be a str, or non-ascii characters will fail with UnicodeDecodeError. + # In py3 it must be a str or we will get garbage in the cookie value. + nick = t2b(nick) c['nick'] = nick dt = (datetime.datetime.utcnow() + datetime.timedelta(days = 30)) if 'remember_me' in mp else datetime.datetime.utcfromtimestamp(0) c['nick']['expires'] = dt.strftime('%a, %d-%b-%y %H:%M:%S GMT') c['syntax'] = syntax dt = (datetime.datetime.utcnow() + datetime.timedelta(days = 30)) if 'remember_syntax' in mp else datetime.datetime.utcfromtimestamp(0) c['syntax']['expires'] = dt.strftime('%a, %d-%b-%y %H:%M:%S GMT') - headers.append(('Set-Cookie', c.output())) + headers.append(('Set-Cookie', c['nick'].OutputString())) + headers.append(('Set-Cookie', c['syntax'].OutputString())) self.start_response('302 Found', headers) return [] @@ -169,7 +190,7 @@ class Paste(object): self.start_response('404 Not Found', []) return [] try: - lexername, text = self.get_formatted(paste.syntax, paste.text if type(paste.text) == unicode else paste.text.decode('utf-8')) + lexername, text = self.get_formatted(paste.syntax, paste.text) except UnknownSyntaxError: return self.message('Could not find the lexer "%s".' % paste.syntax, 'Error') cache = db.Cache(hash, lexername, text) @@ -185,10 +206,10 @@ class Paste(object): 'header': '%s – View paste' % settings.pastebin_name, 'hash': hash, 'date': '%s UTC' % paste.date.ctime(), - 'nick': paste.nick or 'Anonymous', + 'nick': b2t(paste.nick or 'Anonymous'), 'syntax': cache.syntax_name, - 'pastetitle': paste.title or 'Untitled', - 'text': cache.text, + 'pastetitle': b2t(paste.title or 'Untitled'), + 'text': b2t(cache.text), 'rendered': (cache.syntax_name or '').startswith('Rendered '), }) @@ -202,11 +223,11 @@ class Paste(object): session.close() self.start_response('200 OK', [('Content-Type', 'text/plain; charset=UTF-8')]) - return [paste.text.encode('utf-8')] + return [t2b(paste.text)] def highlight_stylesheet(self): self.start_response('200 OK', [('Content-Type', 'text/css')]) - return [self.formatter.get_style_defs()] + return [t2b(self.formatter.get_style_defs())] def static(self): filename = settings.static_root + os.path.sep + self.path[1] -- cgit v1.2.3