""" StringIO functionality This module provides essentially two types of StringIO's, and two types of modes of operation; text versus bytes, and readonly versus writable. The reason for separate classes is that when we're running on py2k, if all we're doing is consuming/reading the data it's heavily preferable to use ``cStringIO.StringIO`` if at all possible for performance reasons. Thus we have readonly and writable classes; the separation has clear performance benefits. Note that while this functionality is based on StringIO and friends, there is some differences in behaviour from stdlib- stdlib's ``cStringIO.StringIO`` is pseudo-writable; it has a truncate method (which works). This is suboptimal since the majority of consumers treat it as write only, thus in these classes we specifically raise a TypeError if you try to truncate a readonly instance. Further, instead of just lacking `write` and `writelines` methods, we supply those (to maintain file like IO compatibility) but have them raise TypeError if invoked Exempting the caveats above, usage of these classes is basically no different than interacting with a normal StringIO. Finally note that the __slots__ layout for py2k cStringIO differs from io.BytesIO (or io.TextIO) in py3k; as such if you're deriving from a writable instance you'll need to compensate for this if you want to have source that is usable under both py2k and py3k. """ # TODO: deprecated, remove in 0.9.0 __all__ = ('text_readonly', 'bytes_readonly') import io def _generic_immutable_method(self, *a, **kwds): raise TypeError(f"{self} isn't opened for writing") class _make_ro_cls(type): def __new__(cls, name, bases, dct): x = super().__new__(cls, name, bases, dct) for k in ("write", "writelines", "truncate"): setattr(x, k, _generic_immutable_method) return x class text_readonly(io.StringIO, metaclass=_make_ro_cls): ... class bytes_readonly(io.BytesIO, metaclass=_make_ro_cls): ...