changeset 5418:55f09ca366c4

Python 3 preparation: StringIO. This generally arranges for StringIO and cStringIO references to use io.StringIO for Python 3 but io.BytesIO for Python 2, consistent with the string representations generally used in Roundup. A special FasterStringIO in the TAL code, which referenced internals of the old Python 2 StringIO module, is cut down so it doesn't actually do anything beyond the StringIO class it inherits from (it would also be reasonable to remove FasterStringIO completely). One place in roundup_server.py clearly needing binary I/O is made to use io.BytesIO unconditionally.
author Joseph Myers <jsm@polyomino.org.uk>
date Wed, 25 Jul 2018 09:08:29 +0000
parents c749d6795bc2
children ef6631409171
files frontends/roundup.cgi roundup/anypy/strings.py roundup/cgi/PageTemplates/PageTemplate.py roundup/cgi/TAL/TALInterpreter.py roundup/cgi/engine_chameleon.py roundup/cgi/engine_zopetal.py roundup/cgi/templating.py roundup/mailer.py roundup/mailgw.py roundup/roundupdb.py roundup/scripts/roundup_mailgw.py roundup/scripts/roundup_server.py scripts/roundup-reminder test/test_cgi.py test/test_mailgw.py test/test_mailsplit.py test/test_multipart.py
diffstat 17 files changed, 43 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/roundup.cgi	Wed Jul 25 09:07:03 2018 +0000
+++ b/frontends/roundup.cgi	Wed Jul 25 09:08:29 2018 +0000
@@ -71,12 +71,13 @@
 # Set up the error handler
 # 
 try:
-    import traceback, StringIO, cgi
+    import traceback, cgi
+    from roundup.anypy.strings import StringIO
     from roundup.cgi import cgitb
 except:
     print("Content-Type: text/plain\n")
     print(_("Failed to import cgitb!\n\n"))
-    s = StringIO.StringIO()
+    s = StringIO()
     traceback.print_exc(None, s)
     print(s.getvalue())
 
--- a/roundup/anypy/strings.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/roundup/anypy/strings.py	Wed Jul 25 09:08:29 2018 +0000
@@ -7,6 +7,12 @@
 import sys
 _py3 = sys.version_info[0] > 2
 
+import io
+if _py3:
+    StringIO = io.StringIO
+else:
+    StringIO = io.BytesIO
+
 def b2s(b):
     """Convert a UTF-8 encoded bytes object to the internal string format."""
     if _py3:
--- a/roundup/cgi/PageTemplates/PageTemplate.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/roundup/cgi/PageTemplates/PageTemplate.py	Wed Jul 25 09:08:29 2018 +0000
@@ -25,7 +25,6 @@
 from roundup.cgi.TAL.TALParser import TALParser
 from roundup.cgi.TAL.HTMLTALParser import HTMLTALParser
 from roundup.cgi.TAL.TALGenerator import TALGenerator
-# Do not use cStringIO here!  It's not unicode aware. :(
 from roundup.cgi.TAL.TALInterpreter import TALInterpreter, FasterStringIO
 from .Expressions import getEngine
 
--- a/roundup/cgi/TAL/TALInterpreter.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/roundup/cgi/TAL/TALInterpreter.py	Wed Jul 25 09:08:29 2018 +0000
@@ -22,8 +22,7 @@
 import re
 from types import ListType
 from cgi import escape
-# Do not use cStringIO here!  It's not unicode aware. :(
-from StringIO import StringIO
+from roundup.anypy.strings import StringIO
 #from DocumentTemplate.DT_Util import ustr
 ustr = str
 
@@ -758,18 +757,7 @@
 
     This let's us have a much faster write() method.
     """
-    def close(self):
-        if not self.closed:
-            self.write = _write_ValueError
-            StringIO.close(self)
-
-    def seek(self, pos, mode=0):
-        raise RuntimeError("FasterStringIO.seek() not allowed")
-
-    def write(self, s):
-        #assert self.pos == self.len
-        self.buflist.append(s)
-        self.len = self.pos = self.pos + len(s)
+    pass
 
 
 def _write_ValueError(s):
--- a/roundup/cgi/engine_chameleon.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/roundup/cgi/engine_chameleon.py	Wed Jul 25 09:08:29 2018 +0000
@@ -5,7 +5,7 @@
 import os.path
 import chameleon
 
-from roundup.cgi.templating import StringIO, context, TALLoaderBase
+from roundup.cgi.templating import context, TALLoaderBase
 from roundup.anypy.strings import s2u
 
 class Loader(TALLoaderBase):
--- a/roundup/cgi/engine_zopetal.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/roundup/cgi/engine_zopetal.py	Wed Jul 25 09:08:29 2018 +0000
@@ -86,7 +86,7 @@
         c.update({'options': options})
 
         # and go
-        output = StringIO.StringIO()
+        output = StringIO()
         TALInterpreter.TALInterpreter(self._v_program, self.macros,
             getEngine().getContext(c), output, tal=1, strictinsert=0)()
         return output.getvalue()
--- a/roundup/cgi/templating.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/roundup/cgi/templating.py	Wed Jul 25 09:08:29 2018 +0000
@@ -29,7 +29,7 @@
 from roundup import hyperdb, date, support
 from roundup import i18n
 from roundup.i18n import _
-from roundup.anypy.strings import is_us, us2s, s2u, u2s
+from roundup.anypy.strings import is_us, us2s, s2u, u2s, StringIO
 
 from .KeywordsExpr import render_keywords_expression_editor
 
@@ -44,10 +44,6 @@
 except ImportError:
     import pickle
 try:
-    import cStringIO as StringIO
-except ImportError:
-    import StringIO
-try:
     from StructuredText.StructuredText import HTML as StructuredText
 except ImportError:
     try: # older version
@@ -647,7 +643,7 @@
         """ Return the items of this class as a chunk of CSV text.
         """
         props = self.propnames()
-        s = StringIO.StringIO()
+        s = StringIO()
         writer = csv.writer(s)
         writer.writerow(props)
         check = self._client.db.security.hasPermission
--- a/roundup/mailer.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/roundup/mailer.py	Wed Jul 25 09:08:29 2018 +0000
@@ -4,8 +4,6 @@
 
 import time, quopri, os, socket, smtplib, re, sys, traceback, email, logging
 
-from cStringIO import StringIO
-
 from roundup import __version__
 from roundup.date import get_timezone, Date
 
--- a/roundup/mailgw.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/roundup/mailgw.py	Wed Jul 25 09:08:29 2018 +0000
@@ -95,7 +95,7 @@
 from __future__ import print_function
 __docformat__ = 'restructuredtext'
 
-import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri
+import string, re, os, mimetools, smtplib, socket, binascii, quopri
 import time, random, sys, logging
 import codecs
 import traceback
@@ -108,6 +108,7 @@
 from roundup.mailer import Mailer, MessageSendError
 from roundup.i18n import _
 from roundup.hyperdb import iter_roles
+from roundup.anypy.strings import StringIO
 
 try:
     import pyme, pyme.core, pyme.constants, pyme.constants.sigsum
@@ -223,7 +224,7 @@
         '''
         boundary = self.getparam('boundary')
         mid, end = '--'+boundary, '--'+boundary+'--'
-        s = cStringIO.StringIO()
+        s = StringIO()
         while 1:
             line = self.fp.readline()
             if not line:
@@ -303,7 +304,7 @@
             # the subject of the actual e-mail embedded here
             # we add a '.eml' extension like other email software does it
             self.fp.seek(0)
-            s = cStringIO.StringIO(self.getbody())
+            s = StringIO(self.getbody())
             name = Message(s).getheader('subject')
             if name:
                 name = name + '.eml'
@@ -329,7 +330,7 @@
             data = binascii.a2b_base64(self.fp.read())
         elif encoding == 'quoted-printable':
             # the quopri module wants to work with files
-            decoded = cStringIO.StringIO()
+            decoded = StringIO()
             quopri.decode(self.fp, decoded)
             data = decoded.getvalue()
         elif encoding == 'uuencoded':
@@ -449,7 +450,7 @@
                 attachments = []
             html_part = False
         elif unpack_rfc822 and content_type == 'message/rfc822':
-            s = cStringIO.StringIO(self.getbody())
+            s = StringIO(self.getbody())
             m = Message(s)
             ig = ignore_alternatives and not content
             new_content, attachments, html_part = m.extract_content(m.gettype(), ig,
@@ -527,7 +528,7 @@
         # pyme.core.Data implements a seek method with a different signature
         # than roundup can handle. So we'll put the data in a container that
         # the Message class can work with.
-        c = cStringIO.StringIO()
+        c = StringIO()
         c.write(plaintext.read())
         c.seek(0)
         return Message(c)
@@ -1328,7 +1329,7 @@
 
             XXX: we may want to read this into a temporary file instead...
         """
-        s = cStringIO.StringIO()
+        s = StringIO()
         s.write(sys.stdin.read())
         s.seek(0)
         self.main(s)
@@ -1424,7 +1425,7 @@
                 server.store(str(i), '+FLAGS', r'(\Deleted)')
 
                 # process the message
-                s = cStringIO.StringIO(data[0][1])
+                s = StringIO(data[0][1])
                 s.seek(0)
                 self.handle_Message(Message(s))
             server.close()
@@ -1493,7 +1494,7 @@
             #   [ array of message lines ],
             #   number of octets ]
             lines = server.retr(i)[1]
-            s = cStringIO.StringIO('\n'.join(lines))
+            s = StringIO('\n'.join(lines))
             s.seek(0)
             self.handle_Message(Message(s))
             # delete the message
--- a/roundup/roundupdb.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/roundup/roundupdb.py	Wed Jul 25 09:08:29 2018 +0000
@@ -21,7 +21,7 @@
 __docformat__ = 'restructuredtext'
 
 import re, os, smtplib, socket, time, random
-import cStringIO, base64, mimetypes
+import base64, mimetypes
 import os.path
 import logging
 from email import Encoders
--- a/roundup/scripts/roundup_mailgw.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/roundup/scripts/roundup_mailgw.py	Wed Jul 25 09:08:29 2018 +0000
@@ -37,7 +37,7 @@
 from roundup import version_check
 from roundup import __version__ as roundup_version
 
-import sys, os, re, cStringIO, getopt, socket, netrc
+import sys, os, re, getopt, socket, netrc
 
 from roundup import mailgw
 from roundup.i18n import _
--- a/roundup/scripts/roundup_server.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/roundup/scripts/roundup_server.py	Wed Jul 25 09:08:29 2018 +0000
@@ -36,8 +36,7 @@
 # --/
 
 
-import errno, cgi, getopt, os, socket, sys, traceback, time
-import StringIO
+import errno, cgi, getopt, io, os, socket, sys, traceback, time
 
 try:
     # Python 3.
@@ -64,6 +63,7 @@
 
 # Roundup modules of use here
 from roundup.anypy import http_, urllib_
+from roundup.anypy.strings import StringIO
 from roundup.cgi import cgitb, client
 from roundup.cgi.PageTemplates.PageTemplate import PageTemplate
 import roundup.instance
@@ -240,7 +240,7 @@
                         self.wfile.write(cgitb.breaker())
                         self.wfile.write(cgitb.html())
                     except:
-                        s = StringIO.StringIO()
+                        s = StringIO()
                         traceback.print_exc(None, s)
                         self.wfile.write("<pre>")
                         self.wfile.write(cgi.escape(s.getvalue()))
@@ -311,7 +311,7 @@
 
 
             if favicon_fileobj is None:
-                favicon_fileobj = StringIO.StringIO(favico)
+                favicon_fileobj = io.BytesIO(favico)
 
             self.send_response(200)
             self.send_header('Content-Type', 'image/x-icon')
--- a/scripts/roundup-reminder	Wed Jul 25 09:07:03 2018 +0000
+++ b/scripts/roundup-reminder	Wed Jul 25 09:08:29 2018 +0000
@@ -28,9 +28,10 @@
 '''
 
 from __future__ import print_function
-import sys, cStringIO, MimeWriter, smtplib
+import sys, MimeWriter, smtplib
 from roundup import instance, date
 from roundup.mailer import SMTPConnection
+from roundup.anypy.strings import StringIO
 
 # open the instance
 if len(sys.argv) != 2:
@@ -71,7 +72,7 @@
         continue
 
     # generate the email message
-    message = cStringIO.StringIO()
+    message = StringIO()
     writer = MimeWriter.MimeWriter(message)
     writer.addheader('Subject', 'Your active %s issues'%db.config.TRACKER_NAME)
     writer.addheader('To', address)
--- a/test/test_cgi.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/test/test_cgi.py	Wed Jul 25 09:08:29 2018 +0000
@@ -9,7 +9,7 @@
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 from __future__ import print_function
-import unittest, os, shutil, errno, sys, difflib, cgi, re, StringIO
+import unittest, os, shutil, errno, sys, difflib, cgi, re
 
 from roundup.cgi import client, actions, exceptions
 from roundup.cgi.exceptions import FormError, NotFound
@@ -18,6 +18,7 @@
 from roundup.cgi.templating import HTMLProperty, _HTMLItem, anti_csrf_nonce
 from roundup.cgi.form_parser import FormParser
 from roundup import init, instance, password, hyperdb, date
+from roundup.anypy.strings import StringIO
 
 # For testing very simple rendering
 from roundup.cgi.engine_zopetal import RoundupPageTemplate
@@ -1458,7 +1459,7 @@
         cl = self._make_client({'@columns': 'id,name'}, nodeid=None,
             userid='1')
         cl.classname = 'status'
-        output = StringIO.StringIO()
+        output = StringIO()
         cl.request = MockNull()
         cl.request.wfile = output
         actions.ExportCSVAction(cl).handle()
@@ -1471,7 +1472,7 @@
         cl = self._make_client({'@columns': 'falseid,name'}, nodeid=None,
             userid='1')
         cl.classname = 'status'
-        output = StringIO.StringIO()
+        output = StringIO()
         cl.request = MockNull()
         cl.request.wfile = output
         self.assertRaises(exceptions.NotFound,
@@ -1481,7 +1482,7 @@
         cl = self._make_client({'@columns': 'id,email,password'}, nodeid=None,
             userid='2')
         cl.classname = 'user'
-        output = StringIO.StringIO()
+        output = StringIO()
         cl.request = MockNull()
         cl.request.wfile = output
         # used to be self.assertRaises(exceptions.Unauthorised,
@@ -1496,7 +1497,7 @@
         cl = self._make_client({'@columns': 'id,address,password'}, nodeid=None,
             userid='2')
         cl.classname = 'user'
-        output = StringIO.StringIO()
+        output = StringIO()
         cl.request = MockNull()
         cl.request.wfile = output
         # used to be self.assertRaises(exceptions.Unauthorised,
--- a/test/test_mailgw.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/test/test_mailgw.py	Wed Jul 25 09:08:29 2018 +0000
@@ -28,7 +28,7 @@
         reason="Skipping PGP tests: 'pyme' not installed"))
 
 
-from cStringIO import StringIO
+from roundup.anypy.strings import StringIO
 
 if 'SENDMAILDEBUG' not in os.environ:
     os.environ['SENDMAILDEBUG'] = 'mail-test.log'
--- a/test/test_mailsplit.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/test/test_mailsplit.py	Wed Jul 25 09:08:29 2018 +0000
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 
-import unittest, cStringIO
+import unittest
 
 from roundup.mailgw import parseContent
 
--- a/test/test_multipart.py	Wed Jul 25 09:07:03 2018 +0000
+++ b/test/test_multipart.py	Wed Jul 25 09:08:29 2018 +0000
@@ -16,7 +16,7 @@
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 
 import unittest
-from cStringIO import StringIO
+from roundup.anypy.strings import StringIO
 
 from roundup.mailgw import Message
 

Roundup Issue Tracker: http://roundup-tracker.org/