@@ -275,10 +275,48 @@ def __init__(self, initial_bytes=None):
275275 self ._buffer = buf
276276 self ._pos = 0
277277
278+ # Jython: modelled after bytesio.c::bytesio_getstate
278279 def __getstate__ (self ):
279- if self .closed :
280- raise ValueError ("__getstate__ on closed file" )
281- return self .__dict__ .copy ()
280+ d = getattr (self , '__dict__' , None )
281+ if d is not None :
282+ d = d .copy ()
283+ return (self .getvalue (), self ._pos , d )
284+
285+ # Jython: modelled after bytesio.c::bytesio_setstate
286+ def __setstate__ (self , state ):
287+
288+ if not isinstance (state , tuple ) or len (state ) < 3 :
289+ fmt = "%s.__setstate__ argument should be 3-tuple got %s"
290+ raise TypeError ( fmt % (type (self ), type (state )) )
291+
292+ # Reset the object to its default state. This is only needed to handle
293+ # the case of repeated calls to __setstate__. */
294+ self ._buffer = bytearray ()
295+ self ._pos = 0
296+
297+ # Set the value of the internal buffer. If state[0] does not support the
298+ # buffer protocol, bytesio_write will raise the appropriate TypeError. */
299+ self .write (state [0 ]);
300+
301+ # Carefully set the position value. Alternatively, we could use the seek
302+ # method instead of modifying self._pos directly to better protect the
303+ # object internal state against erroneous (or malicious) inputs. */
304+ p = state [1 ]
305+ if not isinstance (p , (int , long )) :
306+ fmt = "second item of state must be an integer, got %s"
307+ raise TypeError ( fmt % type (p ) )
308+ elif p < 0 :
309+ raise ValueError ("position value cannot be negative" )
310+ self ._pos = p
311+
312+ # Set the dictionary of the instance variables. */
313+ d = state [2 ]
314+ if not d is None :
315+ if isinstance (d , dict ) :
316+ self .__dict__ = d
317+ else :
318+ fmt = "third item of state should be a dict, got %s"
319+ raise TypeError ( fmt % type (d ) )
282320
283321 def getvalue (self ):
284322 """Return the bytes value (contents) of the buffer
@@ -367,12 +405,15 @@ def truncate(self, pos=None):
367405 return pos
368406
369407 def readable (self ):
408+ self ._checkClosed ()
370409 return True
371410
372411 def writable (self ):
412+ self ._checkClosed ()
373413 return True
374414
375415 def seekable (self ):
416+ self ._checkClosed ()
376417 return True
377418
378419
@@ -1042,31 +1083,30 @@ def buffer(self):
10421083
10431084 def seekable (self ):
10441085 self ._checkInitialized () # Jython: to forbid use in an invalid state
1045- self ._checkClosed () # Jython: compatibility with C implementation
1086+ self ._checkClosed ()
10461087 return self ._seekable
10471088
10481089 def readable (self ):
10491090 self ._checkInitialized () # Jython: to forbid use in an invalid state
1050- self ._checkClosed () # Jython: compatibility with C implementation
10511091 return self .buffer .readable ()
10521092
10531093 def writable (self ):
10541094 self ._checkInitialized () # Jython: to forbid use in an invalid state
1055- self ._checkClosed () # Jython: compatibility with C implementation
10561095 return self .buffer .writable ()
10571096
10581097 def flush (self ):
1059- self ._checkInitialized () # Jython: to forbid use in an invalid state
1060- self ._checkClosed () # Jython: compatibility with C implementation
1098+ self ._checkInitialized () # Jython: to forbid use in an invalid state
10611099 self .buffer .flush ()
10621100 self ._telling = self ._seekable
10631101
10641102 def close (self ):
10651103 if self .buffer is not None and not self .closed :
1066- # Jython difference: flush and close via super.
1067- # Sets __closed for quick _checkClosed().
1068- super (TextIOWrapper , self ).close ()
1069- self .buffer .close ()
1104+ try :
1105+ # Jython difference: flush and close via super.
1106+ # Sets __closed for quick _checkClosed().
1107+ super (TextIOWrapper , self ).close ()
1108+ finally :
1109+ self .buffer .close ()
10701110
10711111 # Jython difference: @property closed(self) inherited from _IOBase.__closed
10721112
@@ -1483,6 +1523,11 @@ class StringIO(TextIOWrapper):
14831523 """
14841524
14851525 def __init__ (self , initial_value = "" , newline = "\n " ):
1526+
1527+ # Newline mark needs to be in bytes: convert if not already so
1528+ if isinstance (newline , unicode ) :
1529+ newline = newline .encode ("utf-8" )
1530+
14861531 super (StringIO , self ).__init__ (BytesIO (),
14871532 encoding = "utf-8" ,
14881533 errors = "strict" ,
@@ -1491,11 +1536,64 @@ def __init__(self, initial_value="", newline="\n"):
14911536 # C version, even under Windows.
14921537 if newline is None :
14931538 self ._writetranslate = False
1494- if initial_value :
1495- if not isinstance (initial_value , unicode ):
1496- initial_value = unicode (initial_value )
1497- self .write (initial_value )
1498- self .seek (0 )
1539+ # An initial value may have been supplied (and must be unicode)
1540+ if initial_value is not None :
1541+ if not isinstance (initial_value , unicode ) :
1542+ fmt = "initial value should be unicode or None, got %s"
1543+ raise TypeError ( fmt % type (initial_value ) )
1544+ if initial_value :
1545+ self .write (initial_value )
1546+ self .seek (0 )
1547+
1548+ # Jython: modelled after stringio.c::stringio_getstate
1549+ def __getstate__ (self ):
1550+ d = getattr (self , '__dict__' , None )
1551+ if d is not None :
1552+ d = d .copy ()
1553+ return (self .getvalue (), self ._readnl , self .tell (), d )
1554+
1555+ # Jython: modelled after stringio.c:stringio_setstate
1556+ def __setstate__ (self , state ):
1557+ self ._checkClosed ()
1558+
1559+ if not isinstance (state , tuple ) or len (state ) < 4 :
1560+ fmt = "%s.__setstate__ argument should be 4-tuple got %s"
1561+ raise TypeError ( fmt % (type (self ), type (state )) )
1562+
1563+ # Initialize the object's state, but empty
1564+ self .__init__ (None , state [1 ])
1565+
1566+ # Write the buffer, bypassing end-of-line translation.
1567+ value = state [0 ]
1568+ if value is not None :
1569+ if not isinstance (value , unicode ) :
1570+ fmt = "ivalue should be unicode or None, got %s"
1571+ raise TypeError ( fmt % type (value ) )
1572+ encoder = self ._encoder or self ._get_encoder ()
1573+ b = encoder .encode (state [0 ])
1574+ self .buffer .write (b )
1575+
1576+ # Reset the object to its default state. This is only needed to handle
1577+ # the case of repeated calls to __setstate__.
1578+ self .seek (0 )
1579+
1580+ # Set the position value using seek. A long is tolerated (e.g from pickle).
1581+ p = state [2 ]
1582+ if not isinstance (p , (int , long )) :
1583+ fmt = "third item of state must be an integer, got %s"
1584+ raise TypeError ( fmt % type (p ) )
1585+ elif p < 0 :
1586+ raise ValueError ("position value cannot be negative" )
1587+ self .seek (p )
1588+
1589+ # Set the dictionary of the instance variables. */
1590+ d = state [3 ]
1591+ if not d is None :
1592+ if isinstance (d , dict ) :
1593+ self .__dict__ = d
1594+ else :
1595+ fmt = "fourth item of state should be a dict, got %s"
1596+ raise TypeError ( fmt % type (d ) )
14991597
15001598 def getvalue (self ):
15011599 self .flush ()
0 commit comments