The only other file-like objects that come to mind are sys.stdout / sys.stdin. They do have a name <stdout>/<stdin>.
For example, sys.stdin/out also have a mode. I do see your point though and don’t disagree, at some point they can’t have all the attributes a file has.
For sure it should be an optional argument to init. I like the above idea:
I just learned sys.stdout and sys.stdin do have a name.
I understand that python supports adding instance variables at runtime. Still, it never feels correct to change instances that way, it seems like a hacky approach. I understand this is a matter of personal preference.
Absolutely, but I think there could be a happy medium where it is an optional argument to the init method.
Would you consider it reasonable to subclass and add a new attribute? That’s an extremely common thing to do in many languages. And it has the same risk of name conflict.
Yes for sure, that’s what I did in the meantime for my codebase.
class NamedBytesIO(io.BytesIO):
"""
For the most part BytesIO behaves just like a file except that it doesn't
have a name attribute. Some code relies on this attribute, for example
the Requests library will use it to guess a file's mimetype.
"""
def __init__(self, name, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = name
I’d like to support the suggestion, that StringIO and BytesIO could have name properties by default, with some default name like <io>.
yes, one may monkeypatch those properties but type checkers do not know about that
the use case, at least for me, is to mock file descriptors, instead of opening files on disk, to just create an IO memory object and name it with a generated path.
the constructors could have an optional name= parameter but that is just sugar on top.
I am against this idea. File-like objects in general do not have the name attribute, and any code that does this right should support this. The writeable file-like object only needs the write() method, and optionally flush() and close(). The readable file-like object may need to support a wider set of methods: read() (with and without argument), readline(), readlines(), __iter__(), depending on how it is used. All other methods and attributes are optional.
sys.stdin and sys.stdout only have the name attribute because usually they are instances of io.TextIOWrapper. But they can be arbitrary file-like objects, and your code should support this. Actually, having special names like “<stdout>” does harm, because the user code needs to handle such special cases, and the code may not work with a real file named “<stdout>”.
There are other things besides file-likes, that have a name attribute and consider it in some way “special”, aren’t there?
What if typing.IO were changed not to promise a name attribute, and a separate protocol were provided to capture the concept of “has a name”? (Type checkers don’t have an issue handling type intersections, right?)